OnTradeTransaction mal function in StrategyTester.

 

Hey guys, i've been trying to fix something bugging hell out of me.

The situation is:

I have the code to prevent multiple trades on the same Bar/Candle, works most of time, but sometimes on StrategyTester... it doesnt.


The code works with OnTradeTransaction(), when theres a DEAL_ENTRY_OUT, it stores the datetime of the deal in a variable,
then back there on OnTick() it checks if TimeCurrent()>varBlockTradeUntil .. but look the screenshot, and code, and the logs..

Looks like the OnTick got priorized instead of OnTradeTransaction, who gives not enough time to the Anti Multiple Bar Trade code to work.


void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest &request,
                        const MqlTradeResult &result)
   {
   ENUM_TRADE_TRANSACTION_TYPE type=trans.type;
   if(type==TRADE_TRANSACTION_DEAL_ADD)
      {
      if(HistoryDealSelect(trans.deal)) m_deal.Ticket(trans.deal);
      else return;
      
      if(m_deal.Magic()==InpEAMagic && (m_deal.DealType()==DEAL_TYPE_BUY || m_deal.DealType()==DEAL_TYPE_SELL))
         {
         ResetSignals();
         varBlockTradeUntil = varPrevBarTime+(ENUM_TIMEFRAMES(InpEATimeFrame)*60)*varTradingInterval; // this is the variable that will be checked on OnTick()
         Alert("trigger control, varBlockTradeUntil updated");
	 if(m_deal.Entry()==DEAL_ENTRY_OUT)
            {
            long position_id=m_deal.PositionId(); // Deal associated PositionID
            if(HistorySelectByPosition(position_id)) //Select Position History
               {
               ResetLastTradeInfo();
               ClosePendingOrders(position_id); //close pending orders for DEAL_ENTRY_OUT pos
               uint     total = HistoryDealsTotal();
               ulong    ticket= 0;
               for(uint i=0; i<total; i++)
                  {
                  if((ticket=HistoryDealGetTicket(i))>0)
                     {
                     varLastDealTime         = HistoryDealGetInteger(ticket,DEAL_TIME); // stores EPOCH time to variable
                     varLastDealLotSize      = HistoryDealGetDouble(ticket,DEAL_VOLUME);
                     double profit = (HistoryDealGetDouble(ticket,DEAL_COMMISSION)+HistoryDealGetDouble(ticket,DEAL_SWAP)+HistoryDealGetDouble(ticket,DEAL_PROFIT));
                     varLastDealProfit       = profit;
                     }
                  }
               }
            }
         }
      }
   }


Looks fine until now, right? But.. look at the bugg.png attachment:


And, look what we got on the log:


OR      0       05:18:01.958    Trade   2022.09.01 12:00:40   order [#30 sell stop 1 INDICE at 109800] triggered
PS      0       05:18:01.958    Trades  2022.09.01 12:00:40   deal #9 sell 1 INDICE at 109800 done (based on order #30)
DG      0       05:18:01.958    Trade   2022.09.01 12:00:40   deal performed [#9 sell 1 INDICE at 109800]
RF      0       05:18:01.958    Trade   2022.09.01 12:00:40   order performed sell 1 at 109800 [#30 sell stop 1 INDICE at 109800]
FE      0       05:18:01.958    Trade   2022.09.01 12:04:40   stop loss triggered #28 sell 2 INDICE 109875 sl: 109850 [#40 buy 2 INDICE at 109850]
GF      0       05:18:01.958    Trades  2022.09.01 12:04:40   deal #10 buy 2 INDICE at 109850 done (based on order #40)
JP      0       05:18:01.958    Trade   2022.09.01 12:04:40   deal performed [#10 buy 2 INDICE at 109850]
KO      0       05:18:01.958    Trade   2022.09.01 12:04:40   order performed buy 2 at 109850 [#40 buy 2 INDICE at 109850]
GF      0       05:18:01.958    Trade   2022.09.01 12:04:40   exchange buy 1 INDICE at 109900 tp: 110650 (109895 / 109900 / 109895)
RJ      0       05:18:01.958    Trades  2022.09.01 12:04:40   deal #11 buy 1 INDICE at 109900 done (based on order #41)
HD      0       05:18:01.958    Trade   2022.09.01 12:04:40   deal performed [#11 buy 1 INDICE at 109900]
HR      0       05:18:01.958    Trade   2022.09.01 12:04:40   order performed buy 1 at 109900 [#41 buy 1 INDICE at 109900]
RL      0       05:18:02.024    MyEA (INDICE,M1)        2022.09.01 12:04:40   Alert: trigger control, varBlockTradeUntil updated
DS      0       05:18:02.024    MyEA (INDICE,M1)        2022.09.01 12:04:40   Alert: trigger control, varBlockTradeUntil updated
NI      0       05:18:02.024    MyEA (INDICE,M1)        2022.09.01 12:04:40   Alert: trigger control, varBlockTradeUntil updated
PL      0       05:18:02.024    MyEA (INDICE,M1)        2022.09.01 12:04:40   Alert: trigger control, varBlockTradeUntil updated


The YELLOW line shows that the stop loss was triggered, ok, THEN, it should go to TradeTransaction, update the varBlockTradeUntil variable, THEN go back (or async) to OnTick to perform a new Deal or Order like in the RED line.

And, for those wondering, unfortunately due to the strategy, RIGHT in the moment that the Trade was closed due to StopLoss, a new TradeSignal was generated for the BEGINNING of 12:04:00 candle.


My point is, HOW can i avoid that operation to happen? 

Files:
bugg.png  8 kb
 
  1. carlosenrick_: My point is, HOW can i avoid that operation to happen? 

    Stop making assumptions about the order of events.

    carlosenrick_: The YELLOW line shows that the stop loss was triggered, ok, THEN, it should go to TradeTransaction, update the varBlockTradeUntil variable, THEN go back (or async) to OnTick to perform a new Deal or Order like in the RED line.

    Set your variable when you create the order (onTick). Update your variable when the position closes (onTrade).

    Or, on a new bar (onTick) check for a position open before creating a new one.

  2. There is no need to create pending orders in code.

    1. The pending has the slight advantage, A) you are closer to the top of the queue (filled quicker), B) there's no round trip network delay (filled quicker.)

      Don't worry about it unless you're scalping M1 or trading news.

    2. Humans can't watch the screen 24/7, so they use pending orders; EAs can, so no need for pending orders, have it wait until the market reaches the trigger price and just open an order.

 
William Roeder #:
  1. Stop making assumptions about the order of events.

    Set your variable when you create the order (onTick). Update your variable when the position closes (onTrade).

    Or, on a new bar (onTick) check for a position open before creating a new one.

That's the point, the "logical" process i fully understand, but it didnt go as it usually should go.. let me brief my EA programming diagram..

> Oninit, confirms if inputs are valid, create handles, choose the signal method, etc.
> OnTick:
> refreshrates function
> check if trading is allowed due time filter inputs
> check for new signals (inside that function, signals are generated only when a new bar is born)
> check if theres an opened expert position
> if exists, do the trailing stop, breakeven, whatever's enabled
> if not:
> check if  TimeCurrent()>varBlockTradeUntil and allow opening position 
> open position since global bool variables "varLongSignal" or "varShortSignal" was setted to true back there
> keep doing that loop.
>OnTradeTransaction: > if theres a DEAL_ENTRY_IN or DEAL_ENTRY_OUT, it setts the varBlockTradeUntil to the TimeCurrent()

SO FAR, everything LOGICALLY speaking is in right place.. but, sometimes it DOESNT give the enough time to work.. because sometimes: the boolean variable for signals and setted to True, and the OnTick accepts to open a new position BEFORE the OnTradeTransaction got the change to update the varBlockTradeUntil

I've tried for far to:
> check if the ontrade got delay for any logical process, but even when i put a AlertFlag right after the OnTrade {} it still printing AFTER the trade was opened
> block signal from being generated if seconds higher than 5, eg: 09:33:06 would skip the signal.
> many other things.. 

William Roeder #:
  1. Stop making assumptions about the order of events.

    Set your variable when you create the order (onTick). Update your variable when the position closes (onTrade).

    Or, on a new bar (onTick) check for a position open before creating a new one.

  2. There is no need to create pending orders in code.

    1. The pending has the slight advantage, A) you are closer to the top of the queue (filled quicker), B) there's no round trip network delay (filled quicker.)

      Don't worry about it unless you're scalping M1 or trading news.

    2. Humans can't watch the screen 24/7, so they use pending orders; EAs can, so no need for pending orders, have it wait until the market reaches the trigger price and just open an order.

I've read your comments like that in other posts, i just place pending orders, cause it is more "comfortable" to the user to see what could possibly happen when price walks in chart..
and, it like you said it helps on Slippage and Spread, cause yes, i trade M1 on Brazillian index market.

 
For some reason it makes sense to have like 150 milliseconds sleep in the beginning of OnTradeTransaction yo make sure that the other actions on server side have already run through.
It seems to be a trade-off of speed for the benefit of accuracy.

There is an article about it with a nice code example to download.
 
Tobias Johannes Zimmer #:
For some reason it makes sense to have like 150 milliseconds sleep in the beginning of OnTradeTransaction yo make sure that the other actions on server side have already run through.
It seems to be a trade-off of speed for the benefit of accuracy.

There is an article about it with a nice code example to download.

Sleep doesn't do anything in the strategy tester.

 
Tobias Johannes Zimmer #:
For some reason it makes sense to have like 150 milliseconds sleep in the beginning of OnTradeTransaction yo make sure that the other actions on server side have already run through.
It seems to be a trade-off of speed for the benefit of accuracy.

There is an article about it with a nice code example to download.

No, it does not make sense. It IS the server that invokes OnTradeTransaction.

 
Enrique Dangeroux #:

No, it does not make sense. It IS the server that invokes OnTradeTransaction.

You are right I am not deep enough into this stuff to explain it.

Some time ago I was writing an EA with some pending order handling but it didn't really work in debug.
After I implemented the Transactions.mqh from the related article which has a Sleep(150) function at the beginning.
https://www.mql5.com/en/articles/1111
I don't know why exactly but all of a sudden it worked.

And I have read some more experienced member recommend sleep here on the forum for some similar case. Just of course I don't remember the name.

 
Keith Watford #:

Sleep doesn't do anything in the strategy tester.

Exactly, its irrelevant.. all this question is about its just the fact tho: OnTradeTransaction doesnt see to be fast enough! OnTick goes FIRST/FASTERS than it, so, a new position on the same candle is opened if FOR SOME REASON it coincides with a new signal was generated by OnTick, and then, an open position just hitts TP or SL, then BEFORE OnTradeTransaction had enough time to update my variable, OnTick confirms that is the signal boolean is True, and do the OrderSend function..


and for those wondering: why dont you put a filter that DOESNT allow to signal be generated if theres an open position? cause my EA allow new signal to invert trade direction.

 

There is no problem with OntradeTransaction. The problem is in your logic and understanding of events. There is no chronological order for event handlers for example.

Also

Sending a buy trade request leads to a chain of trade transactions on a trading account: 1) request is accepted for processing, 2) an appropriate purchase order is created for the account, 3) the order is then executed, 4) the executed order is removed from the list of active ones, 5) adding to the history of orders, 6) the subsequent transaction is added to history and 7) a new position is created. All these stages are trade transactions. The arrival of each such transaction to the terminal is the TradeTransaction event. Priority of these transactions' arrival at the terminal is not guaranteed. Thus, you should not expect that one group of transactions will arrive after another one when developing your trading algorithm.


https://www.mql5.com/en/docs/event_handlers/ontradetransaction

 
Enrique Dangeroux #:

There is no problem with OntradeTransaction. The problem is in your logic and understanding of events. There is no chronological order for event handlers for example.

Also

yes, i've read that before, and many other things.. nothing really helpful, so i consider this topic closed, cause i gonna fix it my own.