Discussion of article "MQL5 Cookbook: Processing of the TradeTransaction Event"

 

New article MQL5 Cookbook: Processing of the TradeTransaction Event has been published:

In this article I would like to introduce one of the ways to control trade events using the means of MQL5. I must mention that a few articles have already been dedicated to this topic. "Processing of trade events in Expert Advisor using the OnTrade() function" is one of them. I am not going to repeat other authors and will use another handler - OnTradeTransaction().

I would like to draw the readers' attention to the following point. The current version of the MQL5 language formally counts 14 event handlers of the Client Terminal. In addition, a programmer has a possibility to create custom events with EventChartCustom() and process them with OnChartEvent(). However, the term 'Event-driven programming' (EDP) is not mentioned in Documentation at all. It is strange, given the fact, that any program in MQL5 is created based on the EDP principles. For instance, the user is offered to make a choice at the step 'Events handler for the Expert' in a template of any Expert Advisor.

It is obvious that the mechanism of the Event-driven Programming is used in MQL5 one way or another. The language may contain program blocks consisting of two parts: selecting and processing of an event. Moreover, if we are talking about events of the Client Terminal, a programmer has control only over the second part, i.e. the event handler. To be fair, there are exceptions for some events. Timer and custom event are among them. Control of these events is left entirely for the programmer.

Fig.6. The first scheme of the transaction process

Fig.6. The first scheme of the transaction process

Author: Dennis Kirichenko

 
Thanks for this article. It is very useful.
 
VikMorroHun #:
Thanks for this article. It is very useful.

Hi,

My situation seems to be quite simple: I place a pending order (Sell_Stop) and I want to be able to react in case a) the pending order is filled and finally b) the open position was closed by either stop loss or profit target.

Do I understand it correctly that:

  1. when the pending order was filled I can get the magic number onlyby requesting it from the list of positions despite the parameter "request" of OnTradeTransaction() owns the field "magic" like:
             if(!PositionSelectByTicket(trans.position)) {Print(__LINE__," PositionSelectByTicket FAILED ",err());}
             else {      
                OpnPos[sz].mag  = PositionGetInteger(POSITION_MAGIC);
             }   
    

  2. the various transaction types in a way that I cannot know whether the sell position was opened or closed:
    void OnTradeTransaction(const MqlTradeTransaction& trans,
                            const MqlTradeRequest& request,
                            const MqlTradeResult& result)
      {
    //---
    
    //--- 
       static int counter=0;   // counter of OnTradeTransaction() calls 
       static uint lasttime=0; // time of the OnTradeTransaction() last call 
    //--- 
       uint time=GetTickCount(); 
    //--- if the last transaction was performed more than 1 second ago, 
       if(time-lasttime>1000) 
         { 
          counter=0; // then this is a new trade operation, an the counter can be reset 
          if(IS_DEBUG_MODE) 
             Print(__LINE__," "," New trade operation dTime",time-lasttime); 
         } 
       Print(__LINE__," ",counter," ",DoubleToString((double(lasttime=time)/1000.0,2)
                ," Tr.Type: ",EnumToString(trans.type)," DL.Type: ",EnumToString(trans.deal_type)
                ," RQ.Type: ",EnumToString(request.type)," RQ.Fill: ",EnumToString(request.type_filling)
             ); 
    This Print produces in case of opening a position at 01:00:40 and closing this position at 10:04:40:
    01:00:40   322 0 81952.76 Tr.Type: TRADE_TRANSACTION_DEAL_ADD DL.Type: DEAL_TYPE_SELL RQ.Type: ORDER_TYPE_BUY RQ.Fill: ORDER_FILLING_FOK // open sell position
    10:04:40   322 0 81970.73 Tr.Type: TRADE_TRANSACTION_DEAL_ADD DL.Type: DEAL_TYPE_BUY  RQ.Type: ORDER_TYPE_BUY RQ.Fill: ORDER_FILLING_FOK // close sell position
    
    01:00:40   322 0 81955.30 Tr.Type: TRADE_TRANSACTION_ORDER_DELETE DL.Type: DEAL_TYPE_BUY RQ.Type: ORDER_TYPE_BUY RQ.Fill: ORDER_FILLING_FOK // open sell position
    10:04:40   322 0 81980.91 Tr.Type: TRADE_TRANSACTION_ORDER_DELETE DL.Type: DEAL_TYPE_BUY RQ.Type: ORDER_TYPE_BUY RQ.Fill: ORDER_FILLING_FOK // close sell position
    
    01:00:40   322 0 81965.14 Tr.Type: TRADE_TRANSACTION_HISTORY_ADD DL.Type: DEAL_TYPE_BUY RQ.Type: ORDER_TYPE_BUY RQ.Fill: ORDER_FILLING_FOK // open sell position
    10:04:40   322 0 81982.69 Tr.Type: TRADE_TRANSACTION_HISTORY_ADD DL.Type: DEAL_TYPE_BUY RQ.Type: ORDER_TYPE_BUY DL.Type: ORDER_FILLING_FOK // close sell position
    
    01:00:59   322 0 81968.50 Tr.Type: TRADE_TRANSACTION_REQUEST     DL.Type: DEAL_TYPE_BUY RQ.Type: ORDER_TYPE_SELL RQ.Fill: ORDER_FILLING_FOK // open sell position
    
    The calls look pretty much the same - how that? At 1:00 a sell was opened - why are there  12  ..TYPE_BUY and only 2 TYPE_SELL??
    Why and what is the meaning of request.type = ORDER_TYPE_BUY in case a sell stop gets triggered and becomes a sell (position)?? From where is the _BUY?
Do you know an elegant way to determine that a position has been closed by stop loss or profit target with the means (parameters) of OnTradeTransaction() without knowing whether it was a sell or a buy position is closed?
 

Here are the log entries of a position closed by a triggered Take Profit. How can this detected in OnTradeTransaction( const MqlTradeTransaction& trans,  const MqlTradeRequest& request,  const MqlTradeResult& result)??

Neither the return code of const MqlTradeResult& result (result.retcode) is set (0 is no option, TRADE_RETCODE_DONE = 10009) nor one of the ids (Deal ticket, Order ticket, Request ID ) in order to find them without looping every time through all deal.

This is the Print at line #376 that print the relevant(?) flags:

void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
  {
...// line 376:
   Print(__LINE__," ",counter," prc:",_ToStr2Dig(trans.price)," tckt: ",trans.position //," pTrigg:",_ToStr2Dig(trans.price_trigger)
            ," Tr.Type: ",EnumToString(trans.type)//," DL.Type: ",EnumToString(trans.deal_type)
            ," Tr.OrdType: ",EnumToString(trans.order_type)," Tr.OrdFill: ",EnumToString(trans.order_state)
            ," Tr.tckt:",trans.order," ",trans.position," ",trans.position_by
            ," retCode:",result.retcode," ",result.deal," ",result.order," ",result.deal," ",result.request_id         );
...
  }

 And this is what I can read in the journal:

10:04:40   take profit triggered #2 sell 0.01 EURUSD 1.00319 sl: 1.00816 tp: 1.00171 [#3 buy 0.01 EURUSD at 1.00171]
10:04:40   deal #3 buy 0.01 EURUSD at 1.00171 done (based on order #3)
10:04:40   deal performed [#3 buy 0.01 EURUSD at 1.00171]
10:04:40   order performed buy 0.01 at 1.00171 [#3 buy 0.01 EURUSD at 1.00171]
10:04:40   373  New trade operation dTime1970.01.01 09:03:41
10:04:40   376 0 prc:trans.price=1.00171   tckt: 2 Tr.Type: TRADE_TRANSACTION_DEAL_ADD Tr.OrdType: ORDER_TYPE_BUY Tr.OrdFill: ORDER_STATE_STARTED Tr.tckt:3 2 0 retCode:0 0 0 0 0
10:04:40   489 MqlTradeTransaction: TRADE_TRANSACTION_DEAL_ADD deal #3 DEAL_TYPE_BUY EURUSD 0.01 lot   
10:04:40   376 1 prc:trans.price=1.00171   tckt: 2 Tr.Type: TRADE_TRANSACTION_ORDER_DELETE Tr.OrdType: ORDER_TYPE_BUY Tr.OrdFill: ORDER_STATE_FILLED Tr.tckt:3 2 0 retCode:0 0 0 0 0
10:04:40   383 1 prc:trans.price=1.00171   tckt: 2  res.Ord:0 Tr.Type: TRADE_TRANSACTION_ORDER_DELETE Tr.OrdFill: ORDER_STATE_FILLED Tr.OrdType: ORDER_TYPE_BUY Tr.tckt:3 2 0 Res::0 0 0 0 0
10:04:40   408 PosExists #3 2 mag:0 ORDER_STATE_FILLED ORDER_TYPE_BUY
10:04:40   376 2 prc:trans.price=1.00171   tckt: 2 Tr.Type: TRADE_TRANSACTION_HISTORY_ADD Tr.OrdType: ORDER_TYPE_BUY Tr.OrdFill: ORDER_STATE_FILLED Tr.tckt:3 2 0 retCode:0 0 0 0 0
10:04:40   408 PosExists #3 2 mag:0 ORDER_STATE_FILLED ORDER_TYPE_BUY
2022.09.26 14:08:33.755    disconnected

The terminal writes so beautifully "take profit triggered #2 sell 0.01 EURUSD 1.00319 sl: 1.00816 tp: 1.00171 [#3 buy 0.01 EURUSD at 1.00171]"

So why the hell isn't there a flag like TRADE_TRANSACTION_TRIGGERED_PT and TRADE_TRANSACTION_TRIGGERED_SL??

And is the return code of the request always not set?

 
Part of the confusion is due to the fact that ENUM_ORDER_TYPE 0 = ORDER_TYPE_BUY. So an EA can not distinguish is the value of the field set with ORDER_TYPE_BUY or nullified therefore not set - great!!!
Reason: