Обсуждение статьи "Библиотека для простого и быстрого создания программ для MetaTrader (Часть XI). Совместимость с MQL4 - События закрытия позиций"

 

Опубликована статья Библиотека для простого и быстрого создания программ для MetaTrader (Часть XI). Совместимость с MQL4 - События закрытия позиций:

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

Теперь у нас события частичного закрытия и удаления отложенного ордера не определяются как одно и то же событие закрытия позиции, а различаются.

Запустим ещё раз и понажимаем кнопки, наблюдая за определением событий:


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

Автор: Artyom Trishkin

 

У меня есть несколько замечаний, связанных с эффектом переменных миллисекундного времени, и в частности сфункцией CHistoryCollection::GetListByTime(...) , касающихся версии MQL5.

Вот они (в порядке убывания актуальности):

1) Как переменные времени даты , так и длинные миллисекундные временные переменные представляют время, прошедшее с 01/01/1970. Однако между эффективно хранимыми значениями существует коэффициент 1000. Поэтому оба типа не могут быть напрямую присвоены друг другу. Как следствие, GetListByTime(...) перестал работать после этого изменения, поскольку он напрямую хранит параметры времени в свойстве time millisecond экземпляра COrder m_order_instance. Возможным решением может быть включение двух новых функций преобразования (возможно, в delib.mqh), чтобы позаботиться об этом факторе 1000:

//+------------------------------------------------------------------+
//| Преобразует время в миллисекундах в дату |
//+------------------------------------------------------------------+
datetime TimeMSCtoDate(const long time_msc)
  {
   return datetime(time_msc/1000);
  }
//+------------------------------------------------------------------+
//| Конвертирует время в миллисекунды |
//+------------------------------------------------------------------+
long DatetoTimeMSC(const datetime time_sec)
  {
   return long(time_sec * 1000);
  }
.
Подобной проблемы не возникло бы, если бы MetaQuotes с самого начала определила переменные datetime как прошедшее время в миллисекундах или даже в микросекундах (кто сказал, что через десять лет роботы не будут торговать менее чем в миллисекундах?).
В любом случае, проблема также присутствует, по крайней мере, в функциях GetListByTime(...) в классах CEventsCollection и CMarketCollection, возможно, и в других местах...
2) Коллекция History - это объект, который знает, отсортирована она или нет, и если отсортирована, то каким свойством сортировки (функция.SortMode() ), в то время как функция GetListByTime(...) предполагает, что коллекция уже отсортирована по свойствам ORDER_PROP_TIME_OPEN или ORDER_PROP_TIME_CLOSE (просто ORDER_PROP_TIME_OPEN в версиях CEventsCollection и CMarketCollection ). Следуя философии ООП, GetListByTime(...) должен проверять, правильно ли отсортирована коллекция, прежде чем идти дальше.
На самом деле, в примере программы TestDoEasyPart03_1.mq5 была создана коллекция истории, упорядоченная по ORDER_PROP_TIME_OPEN (по умолчанию в MT5), а затем был вызван GetListByTime(...,SELECT_BY_TIME_CLOSE). При такой проверке это бы отобразилось!
3) Не очень важно, но поскольку MT5 должен стать новым стандартом, почему бы не сделать SELECT_BY_TIME_OPEN значением по умолчанию для параметра select_time_mode функции CHistoryCollection::GetListByTime(...)?

Следуя предыдущим предложениям, это будет код функции CHistoryCollection::GetListByTime(...):

public:
        .......

   //--- Выберите заказы из коллекции с временем от начала_времени до конца_времени
   CArrayObj        *GetListByTime(const datetime begin_time=0,const datetime end_time=0,
                                   const ENUM_SELECT_BY_TIME select_time_mode=SELECT_BY_TIME_OPEN);
        .......

//+------------------------------------------------------------------+
//| Выберите заказы из коллекции с указанием времени |
//| от начала_времени до конца_времени|
//+------------------------------------------------------------------+
CArrayObj *CHistoryCollection::GetListByTime(const datetime begin_time=0,const datetime end_time=0,
                                             const ENUM_SELECT_BY_TIME select_time_mode=SELECT_BY_TIME_OPEN)
  {
   ENUM_ORDER_PROP_INTEGER property=(select_time_mode==SELECT_BY_TIME_CLOSE ? ORDER_PROP_TIME_CLOSE : ORDER_PROP_TIME_OPEN);
   
   if(property != (ENUM_ORDER_PROP_INTEGER)m_list_all_orders.SortMode())
      {
      ::Print(DFUN+"History list not prpperly sorted");           //Возможно, сообщение нужно добавить в ENUM_MESSAGES_LIB
      return NULL;
      }

   CArrayObj *list=new CArrayObj();
   if(list==NULL)
     {
      ::Print(DFUN+CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_TEMP_LIST));
      return NULL;
     }
   datetime begin=begin_time,end=(end_time==0 ? END_TIME : end_time);
   if(begin_time>end_time) begin=0;
   list.FreeMode(false);
   ListStorage.Add(list);
   //---
   this.m_order_instance.SetProperty(property,DatetoTimeMSC(begin));
   int index_begin=this.m_list_all_orders.SearchGreatOrEqual(&m_order_instance);
   if(index_begin==WRONG_VALUE)
      return list;
   this.m_order_instance.SetProperty(property,DatetoTimeMSC(end));
   int index_end=this.m_list_all_orders.SearchLessOrEqual(&m_order_instance);
   if(index_end==WRONG_VALUE)
      return list;
   for(int i=index_begin; i<=index_end; i++)
      list.Add(this.m_list_all_orders.At(i));
   return list;
  }



 
Alvaro Arioni :

У меня есть несколько замечаний, связанных с эффектом переменных миллисекундного времени, и в частности с функцией CHistoryCollection::GetListByTime(...) для версии MQL5.

Вот они (в порядке убывания актуальности):

1) Как переменные времени даты , так и длинные миллисекундные временные переменные представляют время, прошедшее с 01/01/1970. Однако между эффективно хранимыми значениями существует коэффициент 1000. Поэтому оба типа не могут быть напрямую присвоены друг другу. Как следствие, GetListByTime(...) перестал работать после этого изменения, поскольку он напрямую хранит параметры времени в свойстве time millisecond экземпляра COrder m_order_instance. Возможным решением может быть включение двух новых функций преобразования (возможно, в delib.mqh ), чтобы позаботиться об этом факторе 1000:

Подобной проблемы не возникло бы, если бы MetaQuotes с самого начала определила переменные datetime как прошедшее время в миллисекундах или даже в микросекундах (кто сказал, что через десять лет роботы не будут торговать менее чем в миллисекундах?).
В любом случае, проблема присутствует, по крайней мере, в функциях GetListByTime(...) в классах CEventsCollection и CMarketCollection, возможно, и в других местах
...

2) Коллекция History - это объект, который знает, отсортирован он или нет, и если отсортирован, то какое свойство сортировки (. SortMode() ), а функция GetListByTime(...) предполагает, что коллекция уже отсортирована по свойствам ORDER_PROP_TIME_OPEN или ORDER_PROP_TIME_CLOSE (просто ORDER_PROP_TIME_OPEN в версиях CEventsCollection и CMarketCollection ). Следуя философии ООП, GetListByTime(...) должна проверять, правильно ли отсортирована коллекция, прежде чем продолжить работу.
На самом деле, в примере программы TestDoEasyPart03_1.mq5 была создана коллекция истории, упорядоченная по ORDER_PROP_TIME_OPEN (по умолчанию в MT5), а затем был вызван GetListByTime(...,SELECT_BY_TIME_CLOSE). При такой проверке это бы отобразилось!
3) Не очень важно, но поскольку MT5 должен стать новым стандартом, почему бы не сделать SELECT_BY_TIME_OPEN значением по умолчанию для параметра select_time_mode функции CHistoryCollection::GetListByTime(...)?

Если следовать предыдущим предложениям, то код функции CHistoryCollection::GetListByTime(...) будет выглядеть следующим образом:



Спасибо. В последующих версиях библиотеки (в статьях выше XI), похоже, уже используется преобразование времени (я вообще оставил datetime - все в long).

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