Discussion of article "Library for easy and quick development of MetaTrader programs (part XI). Compatibility with MQL4 - Position closure events"

MetaQuotes
Moderator
236384
MetaQuotes  

New article Library for easy and quick development of MetaTrader programs (part XI). Compatibility with MQL4 - Position closure events has been published:

We continue the development of a large cross-platform library simplifying the development of programs for MetaTrader 5 and MetaTrader 4 platforms. In the tenth part, we resumed our work on the library compatibility with MQL4 and defined the events of opening positions and activating pending orders. In this article, we will define the events of closing positions and get rid of the unused order properties.

Now the events of partial closure and pending order removal are defined as separate events.

Launch the EA once again and click the buttons observing the definition of events:


As we can see, the events are defined correctly. A close by event is defined, modifications of stop levels and pending order prices are also tracked.

Author: Artyom Trishkin

Alvaro Arioni
13
Alvaro Arioni  

I have some remarks related to the effect of the millisecond time variables, and particularly about the CHistoryCollection::GetListByTime(…) function regarding MQL5 version.

They are ( in decreasing order of relevance):

1) Both datetime variables and long millisecond time variables represent the time elapsed since 01/01/1970. However, there is a factor of 1000 between the values effectively stored. Therefore, both types cannot be directly assigned to each other. As a consequence GetListByTime(..) stopped working after the change, since it directly stores datetime parameters in time millisecond property of COrder m_order_instance. A possible solution could be to include two new conversion functions (probably in delib.mqh) to take care of that 1000 factor:

//+------------------------------------------------------------------+
//| Converts time in milliseconds to datetime                        |
//+------------------------------------------------------------------+
datetime TimeMSCtoDate(const long time_msc)
  {
   return datetime(time_msc/1000);
  }
//+------------------------------------------------------------------+
//| Converts datetime to time in milliseconds                        |
//+------------------------------------------------------------------+
long DatetoTimeMSC(const datetime time_sec)
  {
   return long(time_sec * 1000);
  }
This type of problem wouldn’t happen if MetaQuotes had defined form the beginning datetime variables to be the elapsed time in milliseconds, or even in microseconds (who says that in ten years robots will not be trading in less than millisecons?).
Anyway, the problem is also present at least in GetListByTime(…) functions in CEventsCollection and CMarketCollection classes, perhaps in some other places…
2) The History collection is an object which knows whether it is sorted or not, and if it is, which is the sorting property (.SortMode() function), while GetListByTime(…) function assumes that the collection is already sorted by ORDER_PROP_TIME_OPEN or ORDER_PROP_TIME_CLOSE properties (just ORDER_PROP_TIME_OPEN in the CEventsCollection and CMarketCollection versions). Following OOP philosophy, GetListByTime(…) should check if the collection is properly sorted before going on.
As a matter of fact, the program example TestDoEasyPart03_1.mq5 created a history collection ordered by ORDER_PROP_TIME_OPEN (the default in MT5) and then called GetListByTime(…,SELECT_BY_TIME_CLOSE). With that check, this would have shown up!
3) Not great deal, but since MT5 is supposed to be the new standard, why don’t let SELECT_BY_TIME_OPEN be the default value of select_time_mode parameter of CHistoryCollection::GetListByTime(…) function?

Following the former suggestions, this would be the code of CHistoryCollection::GetListByTime(…) function:

public:
        .......

   //--- Select orders from the collection with time from begin_time to end_time
   CArrayObj        *GetListByTime(const datetime begin_time=0,const datetime end_time=0,
                                   const ENUM_SELECT_BY_TIME select_time_mode=SELECT_BY_TIME_OPEN);
        .......

//+------------------------------------------------------------------+
//| Select orders from the collection with time                      |
//| from begin_time to end_time                                      |
//+------------------------------------------------------------------+
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");           //Perhaps message to add to 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;
  }



Artyom Trishkin
Moderator
80867
Artyom Trishkin  
Alvaro Arioni :

I have some remarks related to the effect of the millisecond time variables, and particularly about the CHistoryCollection::GetListByTime(…) function regarding MQL5 version.

They are ( in decreasing order of relevance):

1) Both datetime variables and long millisecond time variables represent the time elapsed since 01/01/1970. However, there is a factor of 1000 between the values effectively stored. Therefore, both types cannot be directly assigned to each other. As a consequence GetListByTime(..) stopped working after the change, since it directly stores datetime parameters in time millisecond property of COrder m_order_instance . A possible solution could be to include two new conversion functions (probably in delib.mqh ) to take care of that 1000 factor:

This type of problem wouldn’t happen if MetaQuotes had defined form the beginning datetime variables to be the elapsed time in milliseconds, or even in microseconds (who says that in ten years robots will not be trading in less than millisecons?).
Anyway, the problem is also present at least in GetListByTime(…) functions in CEventsCollection and CMarketCollection classes, perhaps in some other places…
2) The History collection is an object which knows whether it is sorted or not, and if it is, which is the sorting property (. SortMode() function), while GetListByTime(…) function assumes that the collection is already sorted by ORDER_PROP_TIME_OPEN or ORDER_PROP_TIME_CLOSE properties (just ORDER_PROP_TIME_OPEN in the CEventsCollection and CMarketCollection versions). Following OOP philosophy, GetListByTime(…) should check if the collection is properly sorted before going on.
As a matter of fact, the program example TestDoEasyPart03_1.mq5 created a history collection ordered by ORDER_PROP_TIME_OPEN (the default in MT5) and then called GetListByTime(…,SELECT_BY_TIME_CLOSE) . With that check, this would have shown up!
3) Not great deal, but since MT5 is supposed to be the new standard, why don’t let SELECT_BY_TIME_OPEN be the default value of select_time_mode parameter of CHistoryCollection::GetListByTime(…) function?

Following the former suggestions, this would be the code of CHistoryCollection::GetListByTime(…) function:



Thank. In subsequent versions of the library (in the articles above XI), it seems that time conversion is already used (I generally left datetime - everything is in long).

I did not understand a little about collections - please show an example of wrong sorting. Desirable in the most recent article available (since the articles describe the sequence of creating a library, and everything changes)