Discussion of article "Library for easy and quick development of MetaTrader programs (part X): Compatibility with MQL4 - Events of opening a position and activating pending orders" - page 3

 
Alexey Viktorov:

Artem, please tell me what role the highlighted code section plays.

How can this code be executed if the timer is not enabled?

But if this code section is deleted, the event messages are not printed. But everything works with it.

And I would like to be able to get a ticket, prices and maybe some other properties of positions and orders along with the event message.

I think you have changed the comment. In OnTimer() the EA is tested not in the tester:

/************************Expert tick function************************/
void OnTick()
{
//--- Initialisation of the last trade event
   static ENUM_TRADE_EVENT last_event=WRONG_VALUE;
//--- If working in the tester
   if(MQLInfoInteger(MQL_TESTER))
     {
      engine.OnTimer();
     }
//--- If the last trade event has changed
   if(engine.LastTradeEvent()!=last_event)
     {
      last_event=engine.LastTradeEvent();
      Comment("last_event: ",EnumToString(last_event));
      Print(__FUNCTION__, " last_event: ",EnumToString(last_event));
      //engine.ResetLastTradeEvent();
      //Print("last_event: ",EnumToString(last_event));
     }

}
/***************************Timer function***************************/
void OnTimer()
{
//--- Initialisation of the last trade event
   static ENUM_TRADE_EVENT last_event=WRONG_VALUE;
//--- If the job is not  в тестере
   if(!MQLInfoInteger(MQL_TESTER))
     {
      engine.OnTimer();
     }
}
/*******************************************************************/

And compare the two handlers: in OnTick() the library timer is started only in the tester, and in OnTimer() the library timer is started only not in the tester - because in MQL4 the timer does not work in the tester, and we work on ticks in the tester.

I will make an example now.

 
Artyom Trishkin:

I think you changed the comment.

The comment changed on its own, I didn't touch it.))))))

I just copied in one place and pasted in different places and didn't pay attention. But then put a negation in the form of ! and not important did not touch.

But the question remains unanswered: If the timer is not started in OnInit(), what is the point of the OnTimer() handler and why the code in it is executed at least once.

Basically, I got the messages to the log. It remains to get the properties of the items. Type, ticket, prices and time of opening, closing, modification.

 
Alexey Viktorov:

And I would like to be able to get ticket, prices and maybe some other properties of positions and orders along with the event message.

Not in the tester you can get the order ticket of the last event in OnChartEvent() - parameter lparam. In dparam the price is stored. In sparam - symbol.

To get data in the tester, you should currently use the event code that you get with engine.LastTradeEvent() - because everything depends on the event - if it is a modification, you need to get a list of modifications, and if it is a change in the number of orders, you need to get lists of these new orders.

We need to add in CEngine to return the necessary values to the programme. I have not yet got to the point of sending information to the programme - I am still describing the preparation of the necessary data. In future articles we will reach the class that gives easy access to all the necessary data. And now - if you need it urgently, you need to add to CEngine the return of the list from the class-collection of events - the class itself has the receipt of this list, here they are - all the lists in the public section CEventCollection:

public:
//--- Selects events from the collection with times ranging from begin_time to end_time
   CArrayObj        *GetListByTime(const datetime begin_time=0,const datetime end_time=0);
//--- Returns the complete list-collection of events "as is"
   CArrayObj        *GetList(void)                                                                       { return &this.m_list_events;                                           }
//--- Returns a list by the selected (1) integer, (2) real, and (3) string property that satisfies the criterion being compared
   CArrayObj        *GetList(ENUM_EVENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL)  { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }
   CArrayObj        *GetList(ENUM_EVENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }
   CArrayObj        *GetList(ENUM_EVENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }

All events are stored in the m_list_events list, and these methods return either the full list or filtered by a given criterion.

To get the last event it is enough to create in CEngine the return of this list to the programme, and in the programme to take the required event from the list.

All of this will be automated soon - it's not in the queue yet.

If you still need to make a crutch, its discussion - in a private. It's not worth it here - it doesn't apply to the library, as it's under development, and further normal and proper work will be done to get all and any required events in the programme.

 
Alexey Viktorov:

The comment changed on its own, I didn't touch it.)))))

I just copied in one place and pasted in different places and did not pay attention. But then I put a negation in the form of ! and did not touch the important one.

But the question remains unanswered: If the timer is not started in OnInit(), what is the point of the OnTimer() handler and why the code in it is executed at least once.

Basically, I got the messages to the log. It remains to get the properties of the items. Type, ticket, prices and time of opening, closing, modification.

Explain what do you mean? Are you talking about creating a timer? It is created in the CEngine constructor:

//+------------------------------------------------------------------+
//| CEngine constructor|
//+------------------------------------------------------------------+
CEngine::CEngine() : m_first_start(true),m_last_trade_event(TRADE_EVENT_NO_EVENT)
  {
   this.m_list_counters.Sort();
   this.m_list_counters.Clear();
   this.CreateCounter(COLLECTION_COUNTER_ID,COLLECTION_COUNTER_STEP,COLLECTION_PAUSE);
   this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif;
   this.m_is_tester=::MQLInfoInteger(MQL_TESTER);
   ::ResetLastError();
   #ifdef __MQL5__
      if(!::EventSetMillisecondTimer(TIMER_FREQUENCY))
         ::Print(DFUN,"Failed to create timer. Error: ","Could not create timer. Error: ",(string)::GetLastError());
   //---__MQL4__
   #else 
      if(!this.IsTester() && !::EventSetMillisecondTimer(TIMER_FREQUENCY))
         ::Print(DFUN,"Failed to create timer. Error: ","Could not create timer. Error: ",(string)::GetLastError());
   #endif 
  }
//+------------------------------------------------------------------+
 
Artyom Trishkin:

Not in the tester you can get the order ticket of the last event in OnChartEvent() - parameter lparam. In dparam the price is stored. In sparam - symbol.

I have already found it, thank you. And by getting a ticket you can get everything you need. Except from what price there was a modification. Or make a real crutch to know the price before modification. In principle it is not very necessary yet.

 
Alexey Viktorov:

Basically I got the log messages. I just need to get the properties of the positions. Type, ticket, prices and time of opening, closing, modification.

However, for a quick solution, add an event list return to the public section of CEngine:

public:
   //--- Returns a list of market (1) positions, (2) pending orders and (3) market orders
   CArrayObj*           GetListMarketPosition(void);
   CArrayObj*           GetListMarketPendings(void);
   CArrayObj*           GetListMarketOrders(void);
   //--- Returns the list of historical (1) orders, (2) deleted pending orders, (3) trades, (4) all market orders of a position by its identifier
   CArrayObj*           GetListHistoryOrders(void);
   CArrayObj*           GetListHistoryPendings(void);
   CArrayObj*           GetListDeals(void);
   CArrayObj*           GetListAllOrdersByPosID(const ulong position_id);
//--- Returns a list of events
   CArrayObj*           GetListAllEvents(void)                          { return this.m_events.GetList();      }
//--- Resets the last trade event
   void                 ResetLastTradeEvent(void)                       { this.m_events.ResetLastTradeEvent(); }
//--- Returns (1) last trade event, (2) hedge account flag, (3) tester operation flag
   ENUM_TRADE_EVENT     LastTradeEvent(void)                      const { return this.m_last_trade_event;      }
   bool                 IsHedge(void)                             const { return this.m_is_hedge;              }
   bool                 IsTester(void)                            const { return this.m_is_tester;             }
//--- Creates a timer counter
   void                 CreateCounter(const int id,const ulong frequency,const ulong pause);
//--- Timer
   void                 OnTimer(void);
//--- Constructor/Destructor
                        CEngine();
                       ~CEngine();
  };
//+------------------------------------------------------------------+

In the EA, add this code:

//+------------------------------------------------------------------+
//| Expert tick function|
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Initialisation of the last trade event
   static ENUM_TRADE_EVENT last_event=WRONG_VALUE;
//--- If working in the tester
   if(MQLInfoInteger(MQL_TESTER))
     {
      engine.OnTimer();
      PressButtonsControl();
     }
//--- If the last trade event has changed
   if(engine.LastTradeEvent()!=last_event)
     {
      last_event=engine.LastTradeEvent();
      Comment("\nlast_event: ",EnumToString(last_event));
      CArrayObj* list=engine.GetListAllEvents();
      if(list!=NULL)
        {
         if(list.Total()>0)
           {
            CEvent* event=list.At(list.Total()-1);
            if(event!=NULL)
              {
               event.Print();
              }
           }
        }
     }
//--- If the trailing flag is set
   if(trailing_on)
     {
      TrailingPositions();
      TrailingOrders();
     }
  }
//+------------------------------------------------------------------+

And the last event will be printed in the log

 
Artyom Trishkin:

Explain what do you mean? Are you talking about creating a timer? It is created in the CEngine constructor:

Well, you had to go through the whole library for that. )))

 
Alexey Viktorov:

I already found that, thank you. And if you get a ticket, you can get everything you need. Except for the price of the modification. Or make a real crutch to know the price before modification. I don't really need it yet.

I've already given you the code - there is everything there, and the price before modification too.

 
Alexey Viktorov:

Well, you had to go through the whole library for that. )))

No. Just read the articles

 

And this is what happened:

While I was running this code on the demo, a limit order was set and deleted

443342388 2019.05.27 14:54:10 buy limit 0.01 eurusd 1.11835 0.00000 0.00000 2019.05.27 15:01:14 1.11972 cancelled 

And suddenly, during the next mocking, one position was modified, one position was opened and one position was closed. But where did the record of deleting a long deleted order come from?

2019.05.27 18:34:11.903 00 EURUSD,H1: OnChartEvent: id=1002, event=TRADE_EVENT_PENDING_ORDER_REMOVED, lparam=443342388, dparam=1.11835, sparam=EURUSD
2019.05.27 18:34:11.903 00 EURUSD,H1: OnChartEvent: id=1024, event=TRADE_EVENT_POSITION_CLOSED, lparam=443417294, dparam=1.11933, sparam=EURUSD
2019.05.27 18:34:11.903 00 EURUSD,H1: - Отложенный ордер удалён: 2019.05.27 14:54:10.000 -
EURUSD Удалён 0.01 Buy Limit #443342388  по цене 1.11835
2019.05.27 18:34:11.903 00 EURUSD,H1: - Позиция закрыта: 2019.05.27 18:33:02.000 -
EURUSD Закрыт Sell #443417294  по цене 1.11912, профит -0.21 USD
2019.05.27 18:33:02.755 00 EURUSD,H1: OnChartEvent: id=1022, event=TRADE_EVENT_POSITION_OPENED, lparam=443417294, dparam=1.11912, sparam=EURUSD
2019.05.27 18:33:02.755 00 EURUSD,H1: - Позиция открыта: 2019.05.27 18:33:02.000 -
EURUSD Открыт 0.01 Sell #443417294 [0.01 Market order Sell #443417294]  по цене 1.11912
2019.05.27 18:29:21.913 00 EURUSD,H1: OnChartEvent: id=1050, event=TRADE_EVENT_MODIFY_POSITION_TAKE_PROFIT, lparam=443218277, dparam=1.12218, sparam=EURUSD
2019.05.27 18:29:21.913 00 EURUSD,H1: - Модифицирован TakeProfit позиции: 2019.05.27 18:27:45.000 -
EURUSD Buy #443218277:  модифицирован TakeProfit: [1.12240 --> 1.12218]