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

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

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

Сообщение Haos » 30 окт 2020, 14:42

Создадим советник по торговой системе "Колобок", для модификации первоначальной версии для торговли по треугольнику. Эта модификация имеет отношение к теме быстрой отработки бонусов (см. тему Как быстро отработать необходимый объем лотов) и тестирование торговой системы на её основе ТС на основе "Колобок" (быстрая отработка бонусов).

Прежде всего, разработчик должен представить (или записать на бумаге) весь алгоритм работы будущего эксперта.

Итак, информация к размышлению (с).

1. Торговля по ТС Колобок ведется в коридоре цен, от верхнего и нижнего уровня. Значит нужно будет их специфицировать во внешних параметрах советника. Возникает вопрос: "А может задать ширину коридора?" А как тогда мы будем определять начало коридора? Всё равно надо его будет специфицировать. Если указать нижнюю и верхнюю границы коридора в виде значения цены, то это те же два параметра что и одна граница и ширина коридора. Значит без разницы. Но удобнее через верхнюю и нижнюю границы.

Так, значит будет две переменных типа double для верхней и нижней границе коридора. С этим разобрались.
Также определяем начальный размер лота с которого начинает работу Колобок.

Начинаем новый эксперт и вносим следующие параметры:

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

В качестве имени советника выбрано: EA-Kolobok-(mod Trin)-v1;
Нижний уровень диапазона обозначен переменной: dblYl ("l" на конце от слова Low - нижний (индекс));
Верхний уровень диапазона обозначен переменной: dblYh ("h" на конце от слова High - верхнийий (индекс));
Размер начального лота обозначаем переменной dblQ0;
(продолжени следует)
Аватар пользователя
Haos
Специалист MQL
 
Сообщений: 24699
Зарегистрирован: 29 мар 2014, 16:07
Средств на руках: 193.70 Доллар
Группа: Главные модераторы
Благодарил (а): 3379 раз.
Поблагодарили: 8200 раз.

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

Сообщение Haos » 30 окт 2020, 15:00

2. Далее, прикидываем как будет открываться сделка (первая) по EURUSD на границах коридора:
- если Ask станет больше либо равно верхней границы диапазон dblYh, то покупаем,
- если Bid станет меньше либо равно нижней границы диапазона dblYl, то продаем.
Это так, потому, что покупка идет по цене Ask, а продажа по цене Bid.

По положению цены относительно заданного диапазона, цена может быть:
- в середине его;
- выше верхней границы;
- ниже нижней границы.

Специфицируем план действий советника:
- если Ask >= dblYh, то BUY;
- если Ask < dblYh AND Bid > dblYl, то ничего не делать, что равносильно отсутствию кода для этого условия.
- если Bid <= dblYl, то SELL;

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

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

Сообщение Haos » 10 ноя 2020, 17:06

На каждом тике нам нужно будет контролировать количество открытых позиций (покупок и продаж). Для этого используем заготовочку из функции f_GetNumberOfPositions() (см. тему Как определить количество открытых позиций в MQL4).

Введем две переменные типа int для подсчета количества покупок и продаж. Проинициализируем функцию f_GetNumberOfPositions() при их идентификации:

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

Также нам нужно ввести переменную для мэджика эксперта. Она вводится в области глобальных переменных данного модуля (эксперта), однако, внешней переменной её делать не нужно, чтобы пользователь на начал её менять и не напутал. Для одного советника, в основном, достаточно одного мэджика, когда правильно идет идентификация по торговым инструментам. Я формирую мэджик просто по цифрам даты начала создания эксперта. В данном случае это 30102020.
Аватар пользователя
Haos
Специалист MQL
 
Сообщений: 24699
Зарегистрирован: 29 мар 2014, 16:07
Средств на руках: 193.70 Доллар
Группа: Главные модераторы
Благодарил (а): 3379 раз.
Поблагодарили: 8200 раз.

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

Сообщение Haos » 10 ноя 2020, 17:08

Согласно п. 2. (см. выше) теперь мы можем формализовать условия на попадания цены в установленные нами диапазоны когда нет открытых позиций:

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

Для проверки условий используем конструкцию if-else, операция логическое И обозначается &&. Всё это нужно уметь смотреть в справке для MQL, вызываемой по F1 и т.п.

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

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

Сообщение Haos » 29 ноя 2020, 07:48

Для открытия позиций воспользуемся заготовкой функцией для открытия позиций f_OpenPosition(). Для этого добавим её в код советника в конец.
Также понадобится ввести переменную типа int intSI, для задания величины проскальзывания. Вводим её во внешний блок переменных, чтобы пользователь мог её индентифицировать конкретным значением.
Тогда код будет выглядеть так:
Код: выделить все
//+------------------------------------------------------------------+
//|                                     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 dblYl = 1.0000;  // Верхняя граница диапазона
input double dblYh = 1.0050;  // Нижняя граница диапазона
input int    intSI = 30;      // Проскальзывание цены (пнт.)

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

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

int OnInit()
{

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);
   
   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, "");
     
   }
}

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

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());
      }
   }
}

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

В Пн. на работающем рынке можно проверить эту начальную часть работы советника. Без теста лучше не спешить идти дальше. Так возможные ошибки можно отлавлить самом начале.

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

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

Сообщение Haos » 04 дек 2020, 09:27

Итак, запускаем на проверку на данном этапе советник.
Пара - EURGBP
Лот 0,1
Нижняя граница: 0,905
Верхняя граница: 0,908
Цена сейчас внутри заданной области, т.е. сделок не должно быть, но советник открыл покупку.

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

Смотрим в чем причина и находим ошибку:

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

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

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

Сообщение Haos » 04 дек 2020, 09:33

Для введения указанной выше проверки, введем следующий код в функцию OnInit():
Код: выделить все
int OnInit()
{
   if(dblYl >= dblYh)
   {
      Alert("Значения границ диапазона указаны неверно!");
      return(-1);   
   }
   
return(INIT_SUCCEEDED);
}

Суть кода в том, что если сравнение dblYl >= dblYh дает истину, т.е. нижняя граница диапазона больше либо равна верхней, то советник прерывает работу с сообщением: "Значения границ диапазона указаны неверно!". Так мы избежим ошибок при вводе границ диапазона. Т.е. противоположное логическое условие когда dblYl < dblYh, т.е. нижняя граница строго меньше верхней (по значению) будет проходным параметром.
Аватар пользователя
Haos
Специалист MQL
 
Сообщений: 24699
Зарегистрирован: 29 мар 2014, 16:07
Средств на руках: 193.70 Доллар
Группа: Главные модераторы
Благодарил (а): 3379 раз.
Поблагодарили: 8200 раз.

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

Сообщение Haos » 04 дек 2020, 09:41

Осуществляем проверку. Вначале указываем неправильные значения и получаем запрограммированное предупреждение о том, что границы диапазона введены неверно. Потом задаем правильно границы и видим, что сделка, как и положено, не открывается:

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

Теперь зададим границы диапазона так, чтобы открывалась сделка на продажу:

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

Видно, что как и положено, сделка на продажу открылась. Также проверяем октрытие сделки на покупку (сделать самостоятельно) и убеждаемся, что данный этап работы советника работает правильно.
Код данного этапа:
Код: выделить все
//+------------------------------------------------------------------+
//|                                     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 dblYh = 1.0050;  // Верхняя граница диапазона
input double dblYl = 1.0000;  // Нижняя граница диапазона
input int    intSI = 30;      // Проскальзывание цены (пнт.)

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

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

int OnInit()
{
   if(dblYl >= dblYh)
   {
      Alert("Значения границ диапазона указаны неверно!");
      return(-1);   
   }
   
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);
   
   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, "");
     
   }
}

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

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());
      }
   }
}

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

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

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

Поедем дальше. Теперь рассмотрим ситуацию, когда у нас открыта одна позиция. В коде мы должны определить эту ситуацию более подробно, а именно:
1. когда открыта одна покупка и нет открытых продаж;
2. когда открыта одна продажа и нет открытых покупок.

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

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

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

Поскольку это проверка условия, мы должны использовать конструкцию if.... Но, поскольку, у нас уже есть одно "ветвление" выше, то теперь нужно использовать: else if... (имеется ввиду, что одновременно не может быть выполнены два условия!).
Данная конструкция else if... будет говорить, что вход в неё будет проверяться в случае возвращения значения ЛОЖЬ первого ветвления (if...).

Далее мы должны расчитать величину лота с которым будет открываться продажа (в данном случае).
Его величина формируется как сумма начального лота dblQ0 и dbldQ.

Также видно, что необходимо сделать нормализацию цифр после точки в размере лота. Да, их обычно всегда две, но программист должен учитывать "невозможные" ситуации.

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


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

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

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

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

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