Создание советника по ТС "Колобок" (мод. трин)

Программирование прибыли: от азов к секретам мастерства. Читайте, спрашивайте, делитесь опытом.
Бонус за сообщение 0.5$
Ответственный Модератор - Haos

Создание советника по ТС "Колобок" (мод. трин)

Сообщение Haos » 03 янв 2021, 21:16

Введем её в месте для описания глобальных переменных модуля (перед функцией OnInit), а присвоение значение сделаем в самой функции OnInit().

08-Создание советника Колобок (мод трин).png

Эта переменная intLoDi не меняет своего значения после запуска советника никогда, поэтому она должна быть именно в теле функции OnInit(). Нет надобности её пересчитывать на каждом тике и т.п., загружая бессмысленными операциями повторного пересчета процессор.

Как видно, для ее расчета испльзуется функция f_GetLotDigits("0"); Это пользовательская функция. Подробно с ней можно ознакомиться в теме Количество цифр после точки в величине лота.

Код её приведен ниже:
Код: выделить все
int f_GetLotDigits(string sy)
{
/*
   Описание : Количество цифр после запятой в величине лота
   Параметры:                                                               
   sy - наименование инструмента   ("0" - текущий символ) 
*/
   if(sy == "0") sy = Symbol();

return((int)MathLog10(1 / MarketInfo(sy, MODE_LOTSTEP)));
}
Аватар пользователя
Haos
Специалист MQL
 
Сообщений: 24699
Зарегистрирован: 29 мар 2014, 16:07
Средств на руках: 193.70 Доллар
Группа: Главные модераторы
Благодарил (а): 3379 раз.
Поблагодарили: 8200 раз.

Создание советника по ТС "Колобок" (мод. трин)

Сообщение Haos » 03 янв 2021, 21:20

Код функции f_GetLotDigits() нужно расположить ниже фукнции f_OpenPosition().

Теперь код этого этапа советника будет выглядеть так:
Код: выделить все
//+------------------------------------------------------------------+
//|                                     EA-Kolobok-(mod Trin)-v1.mq4 |
//|                                                             Haos |
//|                                                        vhe@bk.ru |
//+------------------------------------------------------------------+
#property copyright "Haos"
#property link      "vhe@bk.ru"
#property version   "1.00"
#property strict

input double dblQ0 = 0.1;     // Начальный размер торгового лота
input double dbldQ = 0.05;    // Суммарный обоих направлений торговли
input double dblYh = 1.0050;  // Верхняя граница диапазона
input double dblYl = 1.0000;  // Нижняя граница диапазона
input int    intSI = 30;      // Проскальзывание цены (пнт.)

int intMagic = 30102020; // Идентификатор эксперта
int intLoDi;

//***********************************************************************************************

int OnInit()
{
   if(dblYl >= dblYh)
   {
      Alert("Значения границ диапазона указаны неверно!");
      return(-1);   
   }
   intLoDi = f_GetLotDigits("0");
   
return(INIT_SUCCEEDED);
}

//***********************************************************************************************

void OnDeinit(const int reason)
{

}

//***********************************************************************************************

void OnTick()
{
   // количество открытых покупок и продаж:
   int    intBuys = f_GetNumberOfPositions("0", OP_BUY,  intMagic);
   int    intSels = f_GetNumberOfPositions("0", OP_SELL, intMagic);
   double dblQ;
   double dblQs; // суммарный лот всех позиций
   
   if(intBuys == 0 && intSels == 0)
   {
      if(Ask >= dblYh) f_OpenPosition("0", OP_BUY, dblQ0, 0, 0, intMagic, intSI, "");
      else if(Bid <= dblYl) f_OpenPosition("0", OP_SELL, dblQ0, 0, 0, intMagic, intSI, "");
   }
   else if(intBuys == 1 && intSels == 0)   
   {
      dblQ = NormalizeDouble(dblQ0 + dbldQ, intLoDi);
      if(Bid <= dblYl) f_OpenPosition("0", OP_SELL, dblQ, 0, 0, intMagic, intSI, "");
   }

   //-------------------------------------------------------------------------------------
}

//***********************************************************************************************

int f_GetNumberOfPositions(string sy = "", int op = -1, int mn = -1)
{
/*
   Версия   : 28.10.2015 г.                                                 
   Описание : Возвращает количество позиций (покупок или продаж или тех и других вместе)
   Сторонних ресурсов не использует           
   Параметры:                                                               
   sy - наименование инструмента   (""   - любой символ, "0"- текущий символ)             
   op - операция {-1 любая; OP_BUY; OP_SELL}
   mn - MagicNumber  (-1 - любой маджик)               
*/

  int i, k = OrdersTotal(), kp = 0;
  if(k == 0) return(0); // нет позиций вообще никаких
 
  if(sy == "0") sy = Symbol();
  for(i = 0; i < k; i++)
  {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
      if(OrderSymbol() == sy || sy == "")
      {
        if(OrderType() == OP_BUY || OrderType() == OP_SELL)
        {
          if(op < 0 || OrderType() == op)
          {
            if(mn < 0 || OrderMagicNumber() == mn) kp++;
          }
        }
      }
    }
  }
return(kp);
}

//***********************************************************************************************

void f_OpenPosition(string sy, int op, double ll, double sl, double tp, int mn, int si, string co)
{
/*
   Версия   : 13.09.2015                                                     
   Описание : Открывает позицию по рыночной цене   
   Сторонних ресурсов не использует!!!                       
   Параметры:                                                               
   sy - наименование инструмента   ("0" - текущий символ)         
   op - операция {OP_BUY; OP_SELL}                                                           
   ll - лот                                                               
   sl - уровень стоп (0)                                                     
   tp - уровень тейк  (0)                                                   
   mn - MagicNumber
   si - проскальзывание (slippage) (пнт.)                                                       
   co - комментарий ("" - нет комментария)                                                       
*/
   double   pp;
   int      int_Tic     = 0;
   int      int_Try     = 5;              // Количество торговых попыток
   bool     bol_Sou     = true;           // Использовать звуковой сигнал
   string   str_Suc     = "ok.wav";       // Звук успеха
   string   str_Err     = "timeout.wav";  // Звук ошибки
   bool     bol_Sin     = false;           // Использовать значок открытия сделки?
   color    clOpen      = clrNONE,
            clOpenBuy   = LightBlue,      // Цвет значка открытия покупки
            clOpenSell  = LightCoral;     // Цвет значка открытия продажи
   double   dbl_Ask,
            dbl_Bid;
   
   if(sy == "0") sy = Symbol();   
   int int_Dig  = (int) MarketInfo(sy, MODE_DIGITS);
   
   for(int i = 1; i <= int_Try; i++)
   {
      if(!IsTesting() && (!IsExpertEnabled() || IsStopped()))
      {
         Print("OpenPosition(): Остановка работы функции");
         break;
      }
      while(!IsTradeAllowed()) Sleep(5000);
      RefreshRates();
      if(op == OP_BUY)
      {
         dbl_Ask  = MarketInfo(sy, MODE_ASK);
         pp = dbl_Ask;
         if(bol_Sin) clOpen = clOpenBuy;
      }
      else if(op == OP_SELL)
      {
         dbl_Bid  = MarketInfo(sy, MODE_BID);
         pp = dbl_Bid;
         if(bol_Sin) clOpen = clOpenSell;
      }
      pp = NormalizeDouble(pp, int_Dig);
      int_Tic = OrderSend(sy, op, ll, pp, si, sl, tp, co, mn, 0, clOpen);
      if(int_Tic > 0)
      {
         if(bol_Sou) PlaySound(str_Suc);
         Print("Функция OrderSend успешно выполнена");
         break;
      }
      else if(int_Tic < 0)
      {
         if(bol_Sou) PlaySound(str_Err);
         Print("OrderSend завершилась с ошибкой #", GetLastError());
      }
   }
}

//*********************************************************************************************

int f_GetLotDigits(string sy)
{
/*
   Описание : Количество цифр после запятой в величине лота
   Параметры:                                                               
   sy - наименование инструмента   ("0" - текущий символ) 
*/
   if(sy == "0") sy = Symbol();

return((int)MathLog10(1 / MarketInfo(sy, MODE_LOTSTEP)));
}

//*********************************************************************************************


//*********************************************************************************************
Аватар пользователя
Haos
Специалист MQL
 
Сообщений: 24699
Зарегистрирован: 29 мар 2014, 16:07
Средств на руках: 193.70 Доллар
Группа: Главные модераторы
Благодарил (а): 3379 раз.
Поблагодарили: 8200 раз.

Создание советника по ТС "Колобок" (мод. трин)

Сообщение Haos » 03 янв 2021, 21:25

Условие
Код: выделить все
if(Bid <= dblYl) f_OpenPosition("0", OP_SELL, dblQ, 0, 0, intMagic, intSI, "");

проверяет стала ли цена бид меньше либо равно нижней границы диапазона и если ИСТИНА, то открывается продажа функцией f_OpenPosition().

Аналогично можно сделать код для условия "есть продажа и нет покупок":
Код: выделить все
   else if(intBuys == 0 && intSels == 1)   
   {
      dblQ = NormalizeDouble(dblQ0 + dbldQ, intLoDi);
      if(Ask >= dblYh) f_OpenPosition("0", OP_BUY, dblQ, 0, 0, intMagic, intSI, "");
   }

и вставить его в код после аналогичного ветвления, рассмотренного выше.

Итак, у нас будет полностью поставлена под контроль ситуация когда есть одна позиция и может быть открыта противоположная, т.е. станет две позиции. Осталость рассмотреть ситуацию, когда позиций на покупку и на продажу больше либо равно одна позиция.

Этим займемся далее.
Аватар пользователя
Haos
Специалист MQL
 
Сообщений: 24699
Зарегистрирован: 29 мар 2014, 16:07
Средств на руках: 193.70 Доллар
Группа: Главные модераторы
Благодарил (а): 3379 раз.
Поблагодарили: 8200 раз.

Создание советника по ТС "Колобок" (мод. трин)

Сообщение Haos » 03 янв 2021, 21:31

Кстати, забыл упомянуть о том, что у нас появилась еще один параметр: суммарный объем направленной торговли.
Откуда он возник, как была получена формула, на основе которой написан этот советник см. здесь.
Код: выделить все
input double dbldQ = 0.05;    // Суммарный обоих направлений торговли

Мы вставили данный параметр после определения величины начального лота:
Вложения
09-Создание советника Колобок (мод трин).png
Аватар пользователя
Haos
Специалист MQL
 
Сообщений: 24699
Зарегистрирован: 29 мар 2014, 16:07
Средств на руках: 193.70 Доллар
Группа: Главные модераторы
Благодарил (а): 3379 раз.
Поблагодарили: 8200 раз.

Создание советника по ТС "Колобок" (мод. трин)

Сообщение Haos » 17 янв 2021, 21:18

Теперь нам осталось написать блок кода для условия:
Код: выделить все
else if(intBuys >= 1 && intSels >= 1)
...

Вначале рассмотрим ситуацию когда цена поднимается выше верхней границы:
Код: выделить все
      if(Ask >= dblYh)
      {
         dblQs = f_GetPosSumLots("0", -1, intMagic);
         if(dblQs < dbldQ)
         {
            dblQ = NormalizeDouble(2 * dbldQ, intLoDi);
            f_OpenPosition("0", OP_BUY, dblQ, 0, 0, intMagic, intSI, "");
         }
      }

Вначале определяем величину сумму лотов всех открытых позиций:
Код: выделить все
dblQs = f_GetPosSumLots("0", -1, intMagic);

Если эта сумма меньше начального лота dbldQ, то находим удвоенный объем лотов:
Код: выделить все
dblQ = NormalizeDouble(2 * dbldQ, intLoDi);

И открываем позицию на покупку с найденным объемом:
Код: выделить все
f_OpenPosition("0", OP_BUY, dblQ, 0, 0, intMagic, intSI, "");
Аватар пользователя
Haos
Специалист MQL
 
Сообщений: 24699
Зарегистрирован: 29 мар 2014, 16:07
Средств на руках: 193.70 Доллар
Группа: Главные модераторы
Благодарил (а): 3379 раз.
Поблагодарили: 8200 раз.

Создание советника по ТС "Колобок" (мод. трин)

Сообщение Haos » 17 янв 2021, 21:20

Для ситуации когда цена становится ниже нижней границы:
Код: выделить все
else if(Bid <= dblYl)

Действуем примерно так же:
Код: выделить все
else if(Bid <= dblYl)
      {
         dblQs = f_GetPosSumLots("0", -1, intMagic);
         if(dblQs > -dbldQ)
         {
            dblQ = NormalizeDouble(2 * dbldQ, intLoDi);
            f_OpenPosition("0", OP_SELL, dblQ, 0, 0, intMagic, intSI, "");         
         }
      }

За исключением того, что суммарный лот сравнивается с отрицательным значением "-dbldQ", согласно спецификации расчетов самой функции f_GetPosSumLots().
Аватар пользователя
Haos
Специалист MQL
 
Сообщений: 24699
Зарегистрирован: 29 мар 2014, 16:07
Средств на руках: 193.70 Доллар
Группа: Главные модераторы
Благодарил (а): 3379 раз.
Поблагодарили: 8200 раз.

Создание советника по ТС "Колобок" (мод. трин)

Сообщение Haos » 17 янв 2021, 21:21

Таким образом, полностью завершающий блок кода выглядит так:
Код: выделить все
else if(intBuys >= 1 && intSels >= 1)   
   {
      if(Ask >= dblYh)
      {
         dblQs = f_GetPosSumLots("0", -1, intMagic);
         if(dblQs < dbldQ)
         {
            dblQ = NormalizeDouble(2 * dbldQ, intLoDi);
            f_OpenPosition("0", OP_BUY, dblQ, 0, 0, intMagic, intSI, "");
         }
      }
      else if(Bid <= dblYl)
      {
         dblQs = f_GetPosSumLots("0", -1, intMagic);
         if(dblQs > -dbldQ)
         {
            dblQ = NormalizeDouble(2 * dbldQ, intLoDi);
            f_OpenPosition("0", OP_SELL, dblQ, 0, 0, intMagic, intSI, "");         
         }
      }
   }
Аватар пользователя
Haos
Специалист MQL
 
Сообщений: 24699
Зарегистрирован: 29 мар 2014, 16:07
Средств на руках: 193.70 Доллар
Группа: Главные модераторы
Благодарил (а): 3379 раз.
Поблагодарили: 8200 раз.

Создание советника по ТС "Колобок" (мод. трин)

Сообщение Haos » 17 янв 2021, 21:22

Окончательно полный листинг кода советника выглядит так:
Код: выделить все
//+------------------------------------------------------------------+
//|                                     EA-Kolobok-(mod Trin)-v1.mq4 |
//|                                                             Haos |
//|                                                        vhe@bk.ru |
//+------------------------------------------------------------------+
#property copyright "Haos"
#property link      "vhe@bk.ru"
#property version   "1.00"
#property strict

input double dblQ0 = 0.1;     // Начальный размер торгового лота
input double dbldQ = 0.05;    // Суммарный обоих направлений торговли
input double dblYh = 1.0050;  // Верхняя граница диапазона
input double dblYl = 1.0000;  // Нижняя граница диапазона
input int    intSI = 30;      // Проскальзывание цены (пнт.)

int intMagic = 30102020; // Идентификатор эксперта
int intLoDi;

//***********************************************************************************************

int OnInit()
{
   if(dblYl >= dblYh)
   {
      Alert("Значения границ диапазона указаны неверно!");
      return(-1);   
   }
   intLoDi = f_GetLotDigits("0");
   
return(INIT_SUCCEEDED);
}

//***********************************************************************************************

void OnDeinit(const int reason)
{

}

//***********************************************************************************************

void OnTick()
{
   // количество открытых покупок и продаж:
   int    intBuys = f_GetNumberOfPositions("0", OP_BUY,  intMagic);
   int    intSels = f_GetNumberOfPositions("0", OP_SELL, intMagic);
   double dblQ;
   double dblQs; // суммарный лот всех позиций
   
   if(intBuys == 0 && intSels == 0)
   {
      if(Ask >= dblYh) f_OpenPosition("0", OP_BUY, dblQ0, 0, 0, intMagic, intSI, "");
      else if(Bid <= dblYl) f_OpenPosition("0", OP_SELL, dblQ0, 0, 0, intMagic, intSI, "");
   }
   else if(intBuys == 1 && intSels == 0)   
   {
      dblQ = NormalizeDouble(dblQ0 + dbldQ, intLoDi);
      if(Bid <= dblYl) f_OpenPosition("0", OP_SELL, dblQ, 0, 0, intMagic, intSI, "");
   }
   else if(intBuys == 0 && intSels == 1)   
   {
      dblQ = NormalizeDouble(dblQ0 + dbldQ, intLoDi);
      if(Ask >= dblYh) f_OpenPosition("0", OP_BUY, dblQ, 0, 0, intMagic, intSI, "");
   }
   //-------------------------------------------------------------------------------
   else if(intBuys >= 1 && intSels >= 1)   
   {
      if(Ask >= dblYh)
      {
         dblQs = f_GetPosSumLots("0", -1, intMagic);
         if(dblQs < dbldQ)
         {
            dblQ = NormalizeDouble(2 * dbldQ, intLoDi);
            f_OpenPosition("0", OP_BUY, dblQ, 0, 0, intMagic, intSI, "");
         }
      }
      else if(Bid <= dblYl)
      {
         dblQs = f_GetPosSumLots("0", -1, intMagic);
         if(dblQs > -dbldQ)
         {
            dblQ = NormalizeDouble(2 * dbldQ, intLoDi);
            f_OpenPosition("0", OP_SELL, dblQ, 0, 0, intMagic, intSI, "");         
         }
      }
   }
   //-------------------------------------------------------------------------------------
}

//***********************************************************************************************

int f_GetNumberOfPositions(string sy = "", int op = -1, int mn = -1)
{
/*
   Версия   : 28.10.2015 г.                                                 
   Описание : Возвращает количество позиций (покупок или продаж или тех и других вместе)
   Сторонних ресурсов не использует           
   Параметры:                                                               
   sy - наименование инструмента   (""   - любой символ, "0"- текущий символ)             
   op - операция {-1 любая; OP_BUY; OP_SELL}
   mn - MagicNumber  (-1 - любой маджик)               
*/

  int i, k = OrdersTotal(), kp = 0;
  if(k == 0) return(0); // нет позиций вообще никаких
 
  if(sy == "0") sy = Symbol();
  for(i = 0; i < k; i++)
  {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
      if(OrderSymbol() == sy || sy == "")
      {
        if(OrderType() == OP_BUY || OrderType() == OP_SELL)
        {
          if(op < 0 || OrderType() == op)
          {
            if(mn < 0 || OrderMagicNumber() == mn) kp++;
          }
        }
      }
    }
  }
return(kp);
}

//***********************************************************************************************

void f_OpenPosition(string sy, int op, double ll, double sl, double tp, int mn, int si, string co)
{
/*
   Версия   : 13.09.2015                                                     
   Описание : Открывает позицию по рыночной цене   
   Сторонних ресурсов не использует!!!                       
   Параметры:                                                               
   sy - наименование инструмента   ("0" - текущий символ)         
   op - операция {OP_BUY; OP_SELL}                                                           
   ll - лот                                                               
   sl - уровень стоп (0)                                                     
   tp - уровень тейк  (0)                                                   
   mn - MagicNumber
   si - проскальзывание (slippage) (пнт.)                                                       
   co - комментарий ("" - нет комментария)                                                       
*/
   double   pp;
   int      int_Tic     = 0;
   int      int_Try     = 5;              // Количество торговых попыток
   bool     bol_Sou     = true;           // Использовать звуковой сигнал
   string   str_Suc     = "ok.wav";       // Звук успеха
   string   str_Err     = "timeout.wav";  // Звук ошибки
   bool     bol_Sin     = false;           // Использовать значок открытия сделки?
   color    clOpen      = clrNONE,
            clOpenBuy   = LightBlue,      // Цвет значка открытия покупки
            clOpenSell  = LightCoral;     // Цвет значка открытия продажи
   double   dbl_Ask,
            dbl_Bid;
   
   if(sy == "0") sy = Symbol();   
   int int_Dig  = (int) MarketInfo(sy, MODE_DIGITS);
   
   for(int i = 1; i <= int_Try; i++)
   {
      if(!IsTesting() && (!IsExpertEnabled() || IsStopped()))
      {
         Print("OpenPosition(): Остановка работы функции");
         break;
      }
      while(!IsTradeAllowed()) Sleep(5000);
      RefreshRates();
      if(op == OP_BUY)
      {
         dbl_Ask  = MarketInfo(sy, MODE_ASK);
         pp = dbl_Ask;
         if(bol_Sin) clOpen = clOpenBuy;
      }
      else if(op == OP_SELL)
      {
         dbl_Bid  = MarketInfo(sy, MODE_BID);
         pp = dbl_Bid;
         if(bol_Sin) clOpen = clOpenSell;
      }
      pp = NormalizeDouble(pp, int_Dig);
      int_Tic = OrderSend(sy, op, ll, pp, si, sl, tp, co, mn, 0, clOpen);
      if(int_Tic > 0)
      {
         if(bol_Sou) PlaySound(str_Suc);
         Print("Функция OrderSend успешно выполнена");
         break;
      }
      else if(int_Tic < 0)
      {
         if(bol_Sou) PlaySound(str_Err);
         Print("OrderSend завершилась с ошибкой #", GetLastError());
      }
   }
}

//*********************************************************************************************

int f_GetLotDigits(string sy)
{
/*
   Описание : Количество цифр после запятой в величине лота
   Параметры:                                                               
   sy - наименование инструмента   ("0" - текущий символ) 
*/
   if(sy == "0") sy = Symbol();

return((int)MathLog10(1 / MarketInfo(sy, MODE_LOTSTEP)));
}

//*********************************************************************************************

double f_GetPosSumLots(string sy, int op, int mn)
{
/*
Проверено! Работает правильно
Описание : Возвращает сумму лотов открытых позиций   
Если выбран тип операции "-1" (любая позиция), то функция вернет
разность лотов покупок и продаж. Если она будет положительной,
то суммарный лот больше покупок если отрицательной - суммарный лот
больше продаж.
Параметры:                                                               
sy - наименование инструмента   ("0" - текущий символ)                 
op - операция                   (-1   - любая позиция)                 
mn - MagicNumber                (-1   - любой магик)                   
*/
   double dbl_Y = 0, dbl_BuyQ = 0, dbl_SelQ = 0;

   if(sy == "0") sy = Symbol();
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == sy)
         {
            if(mn < 0 || OrderMagicNumber() == mn)
            {
               if(op < 0)
               {
                  if(OrderType() == OP_BUY)  dbl_BuyQ += OrderLots();
                  if(OrderType() == OP_SELL) dbl_SelQ += OrderLots();                 
               }
               else if(OrderType() == OP_BUY && op == OP_BUY) 
               {
                  dbl_BuyQ += OrderLots();
               }
               else if(OrderType() == OP_SELL && op == OP_SELL) 
               {
                  dbl_SelQ += OrderLots();
               }
            }
         }
      }
   }
   if(op == OP_BUY)  dbl_Y = dbl_BuyQ;
   if(op == OP_SELL) dbl_Y = dbl_SelQ;
   if(op < 0) dbl_Y = dbl_BuyQ - dbl_SelQ;

return(dbl_Y);
}   

//*********************************************************************************************

Можно вставить его в созданный файл советника для использования.

На этом разработка советника "Колобок" окончена.
Аватар пользователя
Haos
Специалист MQL
 
Сообщений: 24699
Зарегистрирован: 29 мар 2014, 16:07
Средств на руках: 193.70 Доллар
Группа: Главные модераторы
Благодарил (а): 3379 раз.
Поблагодарили: 8200 раз.


Вернуться в MQL – теория и практика

Кто сейчас на форуме?

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 76

Права доступа к форуму

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения