Stopout event Dosn't catch on OnTradeTransaction

 
I've tried multiple methods to detect the stop-out event while running an Expert Advisor in the Strategy Tester, but none have worked so far. The OnTradeTransaction function doesn’t seem to catch it, even though there's an ENUM_DEAL_REASON type 
DEAL_REASON_SO
that should indicate a stop-out. I haven’t tested this in a live market yet, so I’m not sure whether the issue is specific to backtesting. However, I need a reliable way to detect stop-outs during backtests. Any suggestions?
void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest     &request,
                        const MqlTradeResult      &result)
{
   //--- filter the transaction types we care about
   if(trans.type==TRADE_TRANSACTION_DEAL_ADD     ||   // live Stop-Out
      trans.type==TRADE_TRANSACTION_DEAL_UPDATE  ||   // partial close
      trans.type==TRADE_TRANSACTION_HISTORY_ADD)      // tester Stop-Out
   {
      if(trans.deal==0)               // ignore empty tickets occasionally sent by tester
         return;

      /*  Put something in the history cache first.
             We don’t know the deal time yet, so use a 1-minute window
             around the current tester/server time. */
      datetime now = TimeCurrent();   // server time in forward-test, virtual time in tester
      HistorySelect(now-3600, now+1);   // 60-min span is enough

      if(!HistoryDealSelect(trans.deal))
         return;                      // deal still not visible — exit and wait for next tick

      /*  Only interested in closing deals */
      ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(trans.deal, DEAL_ENTRY);
      if(entry!=DEAL_ENTRY_OUT && entry!=DEAL_ENTRY_OUT_BY)
         return;

      /*  Detect Stop-Out */
      ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(trans.deal, DEAL_REASON);
      if(reason==DEAL_REASON_SO)      // margin stop-out
         DebugBreak();                // ← execution stops here under MetaEditor debugger
   }
 
}
 
you can use this simple EA to check this fact :
use on EURUSD from 01.01.2025 on 10K deposit
#include <Trade/Trade.mqh>
CTrade trade;
datetime tr_time;
bool open_pos;

int OnInit()
  {

   tr_time = TimeCurrent();
   open_pos=true;

   return(INIT_SUCCEEDED);
  }

void OnTick()
  {

   if(open_pos &&TimeCurrent() > tr_time + 12000)
     {
      tr_time = TimeCurrent();
      trade.Sell(3);
      uint ret_code = trade.ResultRetcode();
      if(ret_code != 10009 && ret_code != 1004){
      open_pos=false;
      }
     }

  }

void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest     &request,
                        const MqlTradeResult      &result)
  {
//--- filter the transaction types we care about
   if(trans.type==TRADE_TRANSACTION_DEAL_ADD     ||   // live Stop-Out
      trans.type==TRADE_TRANSACTION_DEAL_UPDATE  ||   // partial close
      trans.type==TRADE_TRANSACTION_HISTORY_ADD)      // tester Stop-Out
     {
      if(trans.deal==0)               // ignore empty tickets occasionally sent by tester
         return;

      /*  Put something in the history cache first.
             We don’t know the deal time yet, so use a 1-minute window
             around the current tester/server time. */
      datetime now = TimeCurrent();   // server time in forward-test, virtual time in tester
      HistorySelect(now-3600, now+1);   // 60-min span is enough

      if(!HistoryDealSelect(trans.deal))
         return;                      // deal still not visible — exit and wait for next tick

      /*  Only interested in closing deals */
      ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(trans.deal, DEAL_ENTRY);
      if(entry!=DEAL_ENTRY_OUT && entry!=DEAL_ENTRY_OUT_BY)
         return;

      /*  Detect Stop-Out */
      ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(trans.deal, DEAL_REASON);
      if(reason==DEAL_REASON_SO)      // margin stop-out
         DebugBreak();                // ← execution stops here under MetaEditor debugger
     }

  }

you can see the stop-out but in theh journal and also in history but code can not catch it.
The mq5 code file is attached.

 

if you are sure it is a bug, then, i recommend that you search for a thread "release XXXX" the x's being the version of your terminal.

And create a message on that thread with a reference to this thread.

 
Michael Charles Schefe #:

if you are sure it is a bug, then, i recommend that you search for a thread "release XXXX" the x's being the version of your terminal.

And create a message on that thread with a reference to this thread.

I’ve already tested multiple approaches without success, but I’m still open to the possibility that there’s a specific method or lesser-known trick I’m missing. That’s why I’ve shared the full code here, in the hope that other developers—especially those from MetaQuotes—might propose a working solution. I’ll wait to see whether this is truly a bug or if there’s a proper way to handle it.
 
What is your goal ? A stop-out in the Strategy Tester means an end of the backtest. There is no point trying to catch it.
 
Alain Verleyen #:
What is your goal ? A stop-out in the Strategy Tester means an end of the backtest. There is no point trying to catch it.

I think just because you can’t define a point to catch them, it doesn’t mean there isn’t one.

I finally realized that stop-out closures are handled behind the scenes, and no existing method can catch them in the Strategy Tester. I had to use a trick in the OnDeinit method just to detect them.

Since you're a moderator, I suggest reporting this so it can be included in the documentation.

All the best

Documentation on MQL5: Event Handling / OnTradeTransaction
Documentation on MQL5: Event Handling / OnTradeTransaction
  • www.mql5.com
The function is called in EAs when the TradeTransaction event occurs. The function is meant for handling trade request execution results...
 
Mobin Zarekar #:

I think just because you can’t define a point to catch them, it doesn’t mean there isn’t one.

I finally realized that stop-out closures are handled behind the scenes, and no existing method can catch them in the Strategy Tester. I had to use a trick in the OnDeinit method just to detect them.

Since you're a moderator, I suggest reporting this so it can be included in the documentation.

All the best

I am sure there are a few threads on the forum and i am sure i remember reading that in the documents of OnTradeTransaction(s), that strategy tester may not catch them. So, it is clear that they already know about it, so no one seems to care or they would have fixed it.

 
Mobin Zarekar:
I've tried multiple methods to detect the stop-out event while running an Expert Advisor in the Strategy Tester, but none have worked so far. The OnTradeTransaction function doesn’t seem to catch it, even though there's an ENUM_DEAL_REASON type  that should indicate a stop-out. I haven’t tested this in a live market yet, so I’m not sure whether the issue is specific to backtesting. However, I need a reliable way to detect stop-outs during backtests. Any suggestions?

In Tester, DEAL_REASON_SO often doesn't trigger. Use PositionsTotal() + equity drop to detect stop-out manually.

 
Michael Charles Schefe #:

I am sure there are a few threads on the forum and i am sure i remember reading that in the documents of OnTradeTransaction(s), that strategy tester may not catch them. So, it is clear that they already know about it, so no one seems to care or they would have fixed it.

Could you please refer me to just one of them?

A programmer is working based on the documentation, not forum topics. I don't have to read the whole forum to understand this issue—even though no topic is shown for this issue in the search, except mine.

Even my question has been left unanswered for two days, which means the programmers don’t know about it.

Is the documentation correct? Yes, it is. The doc indicates the following situations to trigger OnTradeTransaction:

  • sending a trade request from an MQL5 program using the OrderSend()/OrderSendAsync() functions and its subsequent execution;

  • sending a trade request manually via the GUI and its subsequent execution;

  • activation of pending and stop orders on the server;

  • performing operations on the trade server side.

Yes—no transaction would occur on the server side when using the strategy tester. I can NOT say the document is not correct, but assembling all this data to understand that triggering stop-out is not handled by OnTradeTransaction in the strategy tester is an unnecessary, absurd waste of time, while the documentation could state it outright.

On the other hand, I didn’t test stop-out catching in the live market to see if OnTradeTransaction can catch it there, and if it doesn’t, it’s definitely a BUG that needs fixing.

In addition, I believe a strategy-tester platform should simulate all trading conditions of the live market—which MQL5 doesn’t do at all. There are many modifications and complexities that differ between backtesting and live-market runs.

 
Arda Kaya #:

In Tester, DEAL_REASON_SO often doesn't trigger. Use PositionsTotal() + equity drop to detect stop-out manually.

Thank you Arda, I did solve it using OnDeinit() , in Tester,  DEAL_REASON_SO never catch.

 
Mobin Zarekar #:


A search of "OnTradeTransaction" brings up several forum posts and articles; all mentioning that responses "is not guaranteed". No real reason given, altho each post makes a claim of why, but each post has a different reason.