English 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Рецепты MQL5 - История сделок и библиотека функций для получения свойств позиции

Рецепты MQL5 - История сделок и библиотека функций для получения свойств позиции

MetaTrader 5Примеры | 18 апреля 2013, 16:56
9 374 14
Anatoli Kazharski
Anatoli Kazharski

Введение

Пришло время подвести краткий итог по материалам предыдущих статей о свойствах позиции. В этой статье мы создадим несколько дополнительных функций для получения тех свойств, которые можно получить только после обращения к истории сделок. Мы также познакомимся со структурами данных, что сделает доступ к свойствам позиции и символа еще удобнее.

Для торговых систем, в которых объем позиции в течение своего существования не меняется, особой надобности в функциях, которые будут здесь приведены, нет. Но, если вы в дальнейшем планируете внедрить в торговую стратегию систему управления капиталом и управлять объемом позиции, то эти функции станут вашими незаменимыми помощниками.

Прежде чем начать, хотел бы предложить читателям, которые перешли по ссылке на эту статью, впервые на этом сайте или только начали изучать язык MQL5, начать с самых первых статей серии "Рецепты MQL5".


Процесс разработки эксперта

Чтобы увидеть, как будут действовать новые функции в эксперте, который мы модифицировали в предыдущей статье Рецепты MQL5 - Как не получить ошибку при установке/изменении торговых уровней?, добавим возможность увеличения объема позиции, если сигнал на открытие приходит повторно в момент существования позиции.

В истории позиции может быть несколько сделок, и если объем позиции изменялся в процессе торговли, то текущая цена позиции тоже изменялась. И чтобы узнать цену первой точки входа, нужно обращаться к истории сделок именно этой позиции. Ниже на рисунке показана ситуация, когда у позиции только одна сделка (точка входа):

Рис. 1. Первая сделка позиции

Рис. 1. Первая сделка позиции.

На следующем рисунке видно, как изменилась цена позиции после совершения второй сделки:

Рис. 2. Вторая сделка позиции

Рис. 2. Вторая сделка позиции.

С помощью стандартных идентификаторов, как это было уже показано в предыдущих статьях, можно получить только текущую цену позиции (POSITION_PRICE_OPEN) и текущую цену символа (POSITION_PRICE_CURRENT), на котором открыта позиция.

Но в некоторых торговых системах нужно знать, какое расстояние прошла цена от первой точки входа, а также по какой цене была совершена последняя сделка. Вся эта информация содержится в истории сделок/ордеров счета. Ниже показан список сделок относительно последней картинки:

Рис. 3. История сделок счета

Рис. 3. История сделок счета.

Думаю, ситуация прояснилась, цели установлены. Продолжим модифицировать эксперта из предыдущих статей. Сначала дополним перечисление свойств позиции новыми идентификаторами под номерами 0, 6, 9, 12, 16:

//--- Перечисление свойств позиции
enum ENUM_POSITION_PROPERTIES
  {
   P_TOTAL_DEALS     = 0,
   P_SYMBOL          = 1,
   P_MAGIC           = 2,
   P_COMMENT         = 3,
   P_SWAP            = 4,
   P_COMMISSION      = 5,
   P_PRICE_FIRST_DEAL= 6,
   P_PRICE_OPEN      = 7,
   P_PRICE_CURRENT   = 8,
   P_PRICE_LAST_DEAL = 9,
   P_PROFIT          = 10,
   P_VOLUME          = 11,
   P_INITIAL_VOLUME  = 12,
   P_SL              = 13,
   P_TP              = 14,
   P_TIME            = 15,
   P_DURATION        = 16,
   P_ID              = 17,
   P_TYPE            = 18,
   P_ALL             = 19
  };

Комментарии к каждому свойству будут написаны в структуре, которую будем рассматривать чуть ниже.

Пополним количество внешних параметров. Теперь можно будет указывать:

  • MagicNumber - уникальный идентификатор эксперта (магический номер);
  • Deviation - проскальзывание;
  • VolumeIncrease - значение, на которое будет увеличиваться объем позиции;
  • InfoPanel - параметр, с помощью которого можно включить/отключить показ информационной панели.

Вот, как это выглядит в коде:

//--- Внешние параметры эксперта
sinput   long        MagicNumber=777;     // Магический номер
sinput   int         Deviation=10;        // Проскальзывание
input    int         NumberOfBars=2;      // Кол-во Бычьих/Медвежьих баров для покупки/продажи
input    double      Lot=0.1;             // Лот
input    double      VolumeIncrease=0.1;  // Приращение объема позиции
input    double      StopLoss=50;         // Стоп Лосс
input    double      TakeProfit=100;      // Тейк Профит
input    double      TrailingStop=10;     // Трейлинг Стоп
input    bool        Reverse=true;        // Разворот позиции
sinput   bool        ShowInfoPanel=true;  // Показ информационной панели

Обратите внимание на параметры, у которых задан модификатор sinput. С помощью этого модификатора можно запретить оптимизацию в тестере. На самом деле, когда пишешь программу для себя, то и сам отлично понимаешь, какие параметры влияют на результат, и просто не отмечаешь их флажками на оптимизацию. Но когда параметров становится очень много, то таким способом их проще визуально отделить от других, так как они недоступны для выбора:

Рис. 4. Запрещенные для оптимизации параметры недоступны для выбора

Рис. 4. Запрещенные для оптимизации параметры недоступны для выбора.

Теперь заменим глобальные переменные, в которых сохранялись значения свойств позиции и символа, структурами данных (struct):

//--- Свойства позиции
struct position_properties
  {
   uint              total_deals;      // Количество сделок
   bool              exists;           // Признак наличия/отсутствия открытой позиции
   string            symbol;           // Символ
   long              magic;            // Магический номер
   string            comment;          // Комментарий
   double            swap;             // Своп
   double            commission;       // Комиссия   
   double            first_deal_price; // Цена первой сделки позиции
   double            price;            // Текущая цена позиции
   double            current_price;    // Текущая цена символа позиции      
   double            last_deal_price;  // Цена последней сделки позиции
   double            profit;           // Прибыль/убыток позиции
   double            volume;           // Текущий объём позиции
   double            initial_volume;   // Начальный объём позиции
   double            sl;               // Stop Loss позиции
   double            tp;               // Take Profit позиции
   datetime          time;             // Время открытия позиции
   ulong             duration;         // Длительность позиции в секундах
   long              id;               // Идентификатор позиции
   ENUM_POSITION_TYPE type;            // Тип позиции
  };
//--- Свойства символа
struct symbol_properties
  {
   int               digits;        // Количество знаков в цене после запятой
   int               spread;        // Размер спреда в пунктах
   int               stops_level;   // Ограничитель установки Stop ордеров
   double            point;         // Значение одного пункта
   double            ask;           // Цена ask
   double            bid;           // Цена bid
   double            volume_min;    // Минимальный объем для заключения сделки
   double            volume_max;    // Максимальный объем для заключения сделки
   double            volume_limit;  // Максимально допустимый объем для позиции и ордеров в одном направлении
   double            volume_step;   // Минимальный шаг изменения объема для заключения сделки
   double            offset;        // Отступ от максимально возможной цены для операции
   double            up_level;      // Цена верхнего уровня stop level
   double            down_level;    // Цена нижнего уровня stop level
  }

Теперь, чтобы получить доступ к тому или иному элементу структуры, нужно создать переменную типа этой структуры. Это делается так же, как создание объекта для торгового класса, который рассматривался в статье Рецепты MQL5 - Изучение свойств позиции в тестере MetaTrader 5.

//--- переменные свойств позиции и символа
position_properties  pos;
symbol_properties    symb;

Доступ к элементам можно получить так же, как и для методов класса. То есть, достаточно после имени переменной структуры ввести точку, после чего будет отображен список элементов, которые содержатся именно в этой структуре. Это очень удобно. А если к полям структуры есть однострочные комментарии (как в нашем примере), то они будут показаны во всплывающей подсказке справа.

Рис. 5a. Список полей структуры свойств позиции Рис. 5b. Список полей структуры свойств символа

Рис. 5. Список полей структуры.

Еще один важный момент. Так как мы сейчас модифицируем эксперта и заменили в нем практически все глобальные переменные, которые использовались во многих функциях, необходимо заменить их на соответствующие поля структуры со свойствами символа и позиции. Например, глобальная переменная pos_open, которая использовалась для сохранения признака существования/отсутствия позиции, заменилась полем exists структуры типа position_properties. Поэтому теперь везде, где использовалась переменная pos_open нужно написать pos.exists.

Вручную делать это долго и утомительно, куда лучше автоматизировать эту задачу с помощью средств редактора MetaEditor: команда Поиск и замена -> Заменить в меню Правка или сочетание клавиш Ctrl+H:


Рис. 6. Поиск и замена текста.

Рис. 6. Поиск и замена текста.

Необходимо выполнить поиск и замену всех глобальных переменных со свойствами позиции и символа, а затем сделать проверку, скомпилировав файл. Отсутствие ошибок будет означать, что все сделано правильно. Я не буду приводить здесь код, чтобы статья не стала слишком объемной, к тому же в конце статьи можно скачать готовый исходник.

С переменными разобрались и теперь займемся модификацией имеющихся функций, а затем и созданием новых.

Во внешних параметрах можно теперь задать магический номер и проскальзывание в пунктах. Поэтому нужно внести соответствующие изменения и в коде эксперта. Создадим пользовательскую служебную функцию OpenPosition(), в которой перед отправкой приказа на открытие позиции будем устанавливать эти свойства с помощью функций торгового класса CTrade.

//+------------------------------------------------------------------+
//| Открывает позицию                                                |
//+------------------------------------------------------------------+
void OpenPosition(double lot,
                  ENUM_ORDER_TYPE order_type,
                  double price,
                  double sl,
                  double tp,
                  string comment)
  {
   trade.SetExpertMagicNumber(MagicNumber); // Установим номер мэджика в торговую структуру
   trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation)); // Установим размер проскальзывания в пунктах
//--- Если позиция не открылась, вывести сообщение об этом
   if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
     { Print("Ошибка при открытии позиции: ",GetLastError()," - ",ErrorDescription(GetLastError())); }
  }

Осталось внести небольшие изменения в код главной торговой функции эксперта TradingBlock(). Ниже приведена только та часть кода функции, где были произведены изменения:

//--- Если позиции нет
   if(!pos.exists)
     {
      //--- Скорректируем объем
      lot=CalculateLot(Lot);
      //--- Откроем позицию
      OpenPosition(lot,order_type,position_open_price,sl,tp,comment);
     }
//--- Если позиция есть
   else
     {
      //--- Получим тип позиции
      GetPositionProperties(P_TYPE);
      //--- Если позиция противоположна сигналу и включен переворот позиции
      if(pos.type==opposite_position_type && Reverse)
        {
         //--- Получим объём позиции
         GetPositionProperties(P_VOLUME);
         //--- Скорректируем объем
         lot=pos.volume+CalculateLot(Lot);
         //--- Перевернем позицию
         OpenPosition(lot,order_type,position_open_price,sl,tp,comment);
         return;
        }
      //--- Если сигнал по направлению позиции и включено наращивание объема, увеличим объём позиции
      if(!(pos.type==opposite_position_type) && VolumeIncrease>0)
        {
         //--- Получим Stop Loss текущей позиции
         GetPositionProperties(P_SL);
         //--- Получим Take Profit текущей позиции
         GetPositionProperties(P_TP);
         //--- Скорректируем объем
         lot=CalculateLot(Increase);
         //--- Увеличим объем позиции
         OpenPosition(lot,order_type,position_open_price,pos.sl,pos.tp,comment);
         return;
        }

В коде выше был добавлен блок, в котором проверяется направление текущей позиции и сигнала. Если они в одном направлении и во внешних параметрах включено наращивание объема позиции (значение параметра VolumeIncrease больше нуля), то проверяем/корректируем установленный лот и отправляем приказ. Для отправки приказа на открытие, переворота и увеличение объема теперь достаточно написать одну строку кода.

Теперь создадим функции для получения свойств позиции из истории сделок. Начнем с функции CurrentPositionTotalDeals(), которая возвращает количество сделок в текущей позиции:

//+------------------------------------------------------------------+
//| Возвращает количество сделок текущей позиции                     |
//+------------------------------------------------------------------+
uint CurrentPositionTotalDeals()
  {
   int    total       =0;  // Всего сделок в списке выбранной истории
   int    count       =0;  // Счетчик сделок по символу позиции
   string deal_symbol =""; // символ сделки
//--- Если история позиции получена
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Получим количество сделок в полученном списке
      total=HistoryDealsTotal();
      //--- Пройдем по всем сделкам в полученном списке
      for(int i=0; i<total; i++)
        {
            //--- Получим символ сделки
            deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
            //--- Если символ сделки и текущий символ совпадают, увеличим счетчик
            if(deal_symbol==_Symbol)
               count++;
        }
     }
//---
   return(count);
  }

Код выше довольно подробно прокомментирован. Но о том, как выбирается история для работы, все же нужно написать пару слов. В данном случае с помощью функции HistorySelect() был получен список от точки открытия текущей позиции, которая определяется временем открытия, до текущего момента. После того как история выбрана, можно узнать количество сделок в списке с помощью функции HistoryDealsTotal(). Дальше все должно быть понятно по комментариям.

Историю той или иной позиции можно выбрать и по ее идентификатору с помощью функции HistorySelectByPosition(). В этом случае нужно учитывать, что при перевороте позиции, как это и происходит иногда в нашем эксперте, идентификатор у позиции не меняется. А вот время открытия позиции при перевороте меняется, поэтому такой вариант проще реализовать. Но если нужно работать с историей сделок, которая относится не только к открытой в текущий момент позиции, то нужно использовать идентификаторы. К истории сделок еще не раз вернемся в будущих статьях.

Далее создадим функцию CurrentPositionFirstDealPrice(), которая возвращает цену самой первой сделки позиции, т.е. цену той сделки, с которой позиция была открыта.

//+------------------------------------------------------------------+
//| Возвращает цену первой сделки текущей позиции                    |
//+------------------------------------------------------------------+
double CurrentPositionFirstDealPrice()
  {
   int      total       =0;    // Всего сделок в списке выбранной истории
   string   deal_symbol ="";   // символ сделки
   double   deal_price  =0.0;  // Цена сделки
   datetime deal_time   =NULL; // Время сделки
//--- Если история позиции получена
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Получим количество сделок в полученном списке
      total=HistoryDealsTotal();
      //--- Пройдем по всем сделкам в полученном списке
      for(int i=0; i<total; i++)
        {
         //--- Получим цену сделки
         deal_price=HistoryDealGetDouble(HistoryDealGetTicket(i),DEAL_PRICE);
         //--- Получим символ сделки
         deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
         //--- Получим время сделки
         deal_time=(datetime)HistoryDealGetInteger(HistoryDealGetTicket(i),DEAL_TIME);
         //--- Если время сделки и время открытия позиции равны, 
         //    а также равны символ сделки и текущий символ, выйдем из цикла
         if(deal_time==pos.time && deal_symbol==_Symbol)
            break;
        }
     }
//---
   return(deal_price);
  }

Принцип такой же, как и у предыдущей функции. Получаем историю от точки открытия позиции, затем на каждой итерации проверяем время сделки и время открытия позиции. При получении цены сделки заодно получаем имя символа и время сделки. Как только время сделки и позиции совпали, то это значит, что найдена самая первая сделка. Так как ее цена уже присвоена соответствующей переменной, осталось только вернуть это значение.

Двигаемся дальше. Иногда может понадобиться получить цену последней сделки текущей позиции, поэтому сделаем функцию CurrentPositionLastDealPrice():

//+------------------------------------------------------------------+
//| Возвращает цену последней сделки текущей позиции                 |
//+------------------------------------------------------------------+
double CurrentPositionLastDealPrice()
  {
   int    total       =0;   // Всего сделок в списке выбранной истории
   string deal_symbol ="";  // Символ сделки 
   double deal_price  =0.0; // Цена
//--- Если история позиции получена
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Получим количество сделок в полученном списке
      total=HistoryDealsTotal();
      //--- Пройдем по всем сделкам в полученном списке от последней сделки в списке к первой
      for(int i=total-1; i>=0; i--)
        {
         //--- Получим цену сделки
         deal_price=HistoryDealGetDouble(HistoryDealGetTicket(i),DEAL_PRICE);
         //--- Получим символ сделки
         deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
         //--- Если символ сделки и текущий символ равны, остановим цикл
         if(deal_symbol==_Symbol)
            break;
        }
     }
//---
   return(deal_price);
  }

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

Текущий объем позиции можно получить с помощью стандартного идентификатора POSITION_VOLUME. А вот, чтобы узнать начальный объем позиции (объем первой сделки) создадим функцию CurrentPositionInitialVolume():

//+------------------------------------------------------------------+
//| Возвращает начальный объем текущей позиции                       |
//+------------------------------------------------------------------+
double CurrentPositionInitialVolume()
  {
   int             total       =0;           // Всего сделок в списке выбранной истории
   ulong           ticket      =0;           // Тикет сделки
   ENUM_DEAL_ENTRY deal_entry  =WRONG_VALUE; // Способ изменения позиции
   bool            inout       =false;       // Признак наличия разворота позиции
   double          sum_volume  =0.0;         // Счетчик совокупного объема всех сделок кроме первой
   double          deal_volume =0.0;         // Объем сделки
   string          deal_symbol ="";          // Символ сделки 
   datetime        deal_time   =NULL;        // Время совершения сделки
//--- Если история позиции получена
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Получим количество сделок в полученном списке
      total=HistoryDealsTotal();
      //--- Пройдем по всем сделкам в полученном списке от последней сделки в списке к первой
      for(int i=total-1; i>=0; i--)
        {
         //--- Если тикет ордера по его позиции в списке получен, то...
         if((ticket=HistoryDealGetTicket(i))>0)
           {
            //--- Получим объем сделки
            deal_volume=HistoryDealGetDouble(ticket,DEAL_VOLUME);
            //--- Получим способ изменения позиции
            deal_entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket,DEAL_ENTRY);
            //--- Получим время совершения сделки
            deal_time=(datetime)HistoryDealGetInteger(ticket,DEAL_TIME);
            //--- Получим символ сделки
            deal_symbol=HistoryDealGetString(ticket,DEAL_SYMBOL);
            //--- Когда время совершения сделки будет меньше или равно времени открытия позиции, выйдем из цикла
            if(deal_time<=pos.time)
               break;
            //--- иначе считаем совокупный объем сделок по символу позиции, кроме первой
            if(deal_symbol==_Symbol)
               sum_volume+=deal_volume;
           }
        }
     }
//--- Если способ изменения позиции - разворот
   if(deal_entry==DEAL_ENTRY_INOUT)
     {
      //--- Если объем позиции увеличивался/уменьшался
      //    То есть, сделок больше одной
      if(fabs(sum_volume)>0)
        {
         //--- Текущий объем минус объем всех сделок кроме первой
         double result=pos.volume-sum_volume;
         //--- Если итог больше нуля, вернем итог, иначе вернем текущий объем позиции         
         deal_volume=result>0 ? result : pos.volume;
        }
      //--- Если сделок кроме входа больше не было,
      if(sum_volume==0)
         deal_volume=pos.volume; // вернём текущий объем позиции
     }
//--- Вернем начальный объем позиции
   return(NormalizeDouble(deal_volume,2));
  }

Функция выше получилась уже посложнее, чем предыдущие. Я постарался учесть все возможные ситуации, когда может быть неправильный результат. При тщательном тестировании проблем не было обнаружено. Подробные комментарии в коде помогут разобраться с заложенным в него смыслом.

Очень полезным будет иметь функцию, которая возвращает длительность позиции. Сделаем так, чтобы результат возвращался на выбор пользователя: в секундах, минутах, часах или днях. Для этого создадим еще одно перечисление:

//--- Длительность позиции
enum ENUM_POSITION_DURATION
  {
   DAYS     = 0, // Дни
   HOURS    = 1, // Часы
   MINUTES  = 2, // Минуты
   SECONDS  = 3  // Секунды
  };

А ниже представлен код функции CurrentPositionDuration(), в которой и производятся необходимые расчеты:

//+------------------------------------------------------------------+
//| Возвращает длительность текущей позиции                          |
//+------------------------------------------------------------------+
ulong CurrentPositionDuration(ENUM_POSITION_DURATION mode)
  {
   ulong     result=0;   // Итоговый результат
   ulong     seconds=0;  // Количество секунд
//--- Вычислим длительность позиции в секундах
   seconds=TimeCurrent()-pos.time;
//---
   switch(mode)
     {
      case DAYS      : result=seconds/(60*60*24);   break; // Посчитаем кол-во дней
      case HOURS     : result=seconds/(60*60);      break; // Посчитаем кол-во часов
      case MINUTES   : result=seconds/60;           break; // Посчитаем кол-во минут
      case SECONDS   : result=seconds;              break; // Без расчетов (кол-во секунд)
      //---
      default        :
         Print(__FUNCTION__,"(): Передан неизвестный режим длительности!");
         return(0);
     }
//--- Вернем результат
   return(result);
  }

Для информационной панели, на которой отображаются свойства позиции, напишем функцию CurrentPositionDurationToString(), которая будет переводить длительность позиции из секунд в понятный для пользователя формат. Сделаем так, что в функцию нужно передать количество секунд, а она возвратит строку, которая покажет длительность позиции в днях, часах, минутах и секундах:

//+------------------------------------------------------------------+
//| Преобразует длительность позиции в строку                        |
//+------------------------------------------------------------------+
string CurrentPositionDurationToString(ulong time)
  {
//--- Прочерк в случае отсутствия позиции
   string result="-";
//--- Если есть позиция
   if(pos.exists)
     {
      //--- Переменные для результата расчетов
      ulong days=0;
      ulong hours=0;
      ulong minutes=0;
      ulong seconds=0;
      //--- 
      seconds=time%60;
      time/=60;
      //---
      minutes=time%60;
      time/=60;
      //---
      hours=time%24;
      time/=24;
      //---
      days=time;
      //--- Сформируем строку в указанном формате DD:HH:MM:SS
      result=StringFormat("%02u d: %02u h : %02u m : %02u s",days,hours,minutes,seconds);
     }
//--- Вернем результат
   return(result);
  }

Все готово. Я уже не буду приводить код функций GetPositionProperties() и GetPropertyValue(), которые нужно изменить в соответствии со всеми изменениями выше. Если вы читали все предыдущие статьи цикла, то это не сложно будет выполнить самостоятельно. В любом случае, в приложении к статье есть файл с исходниками.

Информационная панель должна получиться такой, как на рисунке ниже:

Рис. 7. Демонстрация работы всех свойств позиции на информационной панели

Рис. 7. Демонстрация работы всех свойств позиции на информационной панели.

В итоге, у нас получилась библиотека функций для получения свойств позиции, которую, возможно еще будем дополнять в будущих статьях по мере необходимости.


Оптимизация параметров и тестирование эксперта

Попробуем в качестве эксперимента провести оптимизацию параметров эксперта. Хоть это еще и неполноценная торговая система, но, тем не менее, полученный результат, каким бы он ни был, откроет глаза на некоторые вещи и обогатит опыт разработчика торговых систем.

Настройки тестера установим так, как на рисунке ниже:

Рис. 8. Настройки тестера для оптимизации параметров

Рис. 8. Настройки тестера для оптимизации параметров.

Настройки внешних параметров эксперта установим так:

Рис. 9. Настройки параметров эксперта для оптимизации

Рис. 9. Настройки параметров эксперта для оптимизации.

После оптимизации отсортируем полученные результаты по максимальному фактору восстановления:

Рис. 10. Сортировка по максимальному фактору восстановления

Рис. 10. Сортировка по максимальному фактору восстановления.

Теперь протестируем самый верхний набор параметров, у которого значение показателя "Фактор восстановления" равен 4.07. Даже с учетом того, что оптимизация проводилась для EURUSD, на многих символах можно увидеть положительный результат с такими же параметрами:

Результат для EURUSD:

Рис. 11. Результат для EURUSD

Рис. 11. Результат для EURUSD.

Результат для AUDUSD:

Рис. 12. Результат для AUDUSD

Рис. 12. Результат для AUDUSD.

Результат для NZDUSD:

Рис. 13. Результат для NZDUSD

Рис. 13. Результат для NZDUSD.


Заключение

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

Прикрепленные файлы |
Последние комментарии | Перейти к обсуждению на форуме трейдеров (14)
Anatoli Kazharski
Anatoli Kazharski | 27 сент. 2013 в 12:25
denkir:

Вижу, что при умолчательных настройках скрипта идёт запись типа "Неудача возврата функции HistoryOrderGetDouble()".

Т.е. булевый вариант функции не получает значение свойства.

У меня всё успешно проходит. Посмотрите всё более подробно (вывод в журнал) для выяснения причины. Количество ордеров, тикеты, номер ошибки и т.д.
Denis Kirichenko
Denis Kirichenko | 27 сент. 2013 в 12:47
tol64:
У меня всё успешно проходит. Посмотрите всё более подробно (вывод в журнал) для выяснения причины. Количество ордеров, тикеты, номер ошибки и т.д.

Ясно.

Наверное у брокера что-то не так. Получаю ошибку за нумером 4755 (Сделка не найдена). Напишу в СервисДеск.

Anatoli Kazharski
Anatoli Kazharski | 27 сент. 2013 в 13:58
denkir:

Ясно.

Наверное у брокера что-то не так. Получаю ошибку за нумером 4755 (Сделка не найдена). Напишу в СервисДеск.

Сообщите потом, в чём было дело, интересно.
Ramiz Mavludov
Ramiz Mavludov | 23 февр. 2019 в 05:09
Интересная статья и примеры,  спасибо. 
Roman Kutemov
Roman Kutemov | 15 авг. 2019 в 10:39
Интересная статья.
А нет случайно функции увеличения лота, для покрытия убытка от предыдущих сделок, зная размер тэйкпрофита открываемой сделки ?
Рецепты MQL5 - Использование индикаторов для формирования условий торговли в эксперте Рецепты MQL5 - Использование индикаторов для формирования условий торговли в эксперте
В этой статье мы продолжим модифицировать эксперта, над которым до этого работали на протяжении всех последних статей по программированию на MQL5. На этот раз подключим к эксперту индикаторы, по значениям которых будут проверяться условия на открытие позиции. Чтобы было интересней, сделаем во внешних параметрах выпадающий список, в котором можно будет выбрать один из трех индикаторов для торговли.
Три аспекта ручного автотрейдинга. Часть 1 - Торговля Три аспекта ручного автотрейдинга. Часть 1 - Торговля
Эта статья открывает цикл статей по вопросам автоматизации ручного трейдинга на платформе МetaТrader 4. Каждая из них будет посвящена одному отдельному аспекту ручного автотрейдинга: автоматизация ручной торговли, автоматизация отображения текущего состояния торговли и автоматизация формирования отчетов о результатах торговли. В этой статье я расскажу об одной интересной технике для написания советников, управляемых трейдером вручную.
Рецепты MQL5 - Разработка схемы для торговой системы типа "Три экрана Элдера" Рецепты MQL5 - Разработка схемы для торговой системы типа "Три экрана Элдера"
В этой статье мы разработаем схему для торговой системы типа "Три экрана Элдера" на MQL5. Писать эксперта будем не с нуля, а просто модифицируем уже практически готовую под эту схему программу из предыдущей статьи "Рецепты MQL5 - Использование индикаторов для формирования условий торговли в эксперте". То есть, целью статьи будет также показать, как можно легко модифицировать схемы уже готовых программ.
Индикатор "ЗигЗаг": новый взгляд и новые решения Индикатор "ЗигЗаг": новый взгляд и новые решения
В статье рассматривается возможность создания опережающего индикатора ЗигЗаг. Идея поиска узлов базируется на использовании индикатора Envelopes. Есть предположение, что найдётся такая комбинация входных параметров серии конвертов, при которых все узлы ЗигЗага будут находиться в пределах линий Envelopes. Следовательно, можно попробовать прогнозировать координаты нового узла.