Page 2 of 2

Re: How to handle execution latency and broker slippage?

Posted: Thu Nov 05, 2026 9:51 am
by PTScalper
MQL5 Implementation: Asynchronous Execution Class

Here is a production-grade asynchronous trade executor class (CAsyncTradeExecutor) that dispatches orders without blocking and tracks them via request IDs and trade transactions:

Code: Select all

//+------------------------------------------------------------------+
//|                                          CAsyncTradeExecutor.mqh |
//|                                  Copyright 2026, Quant Systems   |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026"
#property link      "https://www.mql5.com"
#property version   "1.00"

class CAsyncTradeExecutor
private:
   // Dictionary or tracking buffer for active asynchronous request IDs
   ulong   m_tracked_requests[];

   void AddTrackedRequest(ulong req_id)
   {
      int size = ArraySize(m_tracked_requests);
      ArrayResize(m_tracked_requests, size + 1);
      m_tracked_requests[size] = req_id;
   }

   void RemoveTrackedRequest(ulong req_id)
   {
      int size = ArraySize(m_tracked_requests);
      for(int i = 0; i < size; i++)
      {
         if(m_tracked_requests[i] == req_id)
         {
            // Shift array elements down
            for(int j = i; j < size - 1; j++)
               m_tracked_requests[j] = m_tracked_requests[j + 1];
            ArrayResize(m_tracked_requests, size - 1);
            break;
         }
      }
   }

public:
   CAsyncTradeExecutor()
   {
      ArrayFree(m_tracked_requests);
   }

   ~CAsyncTradeExecutor() {}

   // 1. Non-Blocking Order Dispatch
   bool SendAsync(MqlTradeRequest &request, MqlTradeResult &result)
   {
      // OrderSendAsync places the packet in the terminal queue and returns immediately
      bool dispatched = OrderSendAsync(request, result);
      
      if(dispatched)
      {
         // Track the request ID to correlate with OnTradeTransaction callbacks
         AddTrackedRequest(result.request_id);
         Print("[Async Dispatch] Request queued successfully. Request ID: ", result.request_id, " Symbol: ", request.symbol);
         return true;
      }
      else
      {
         Print("[Async Error] OrderSendAsync failed to queue. System Error: ", GetLastError());
         return false;
      }
   }

   // 2. Asynchronous Event Handler (Must be called from EA's OnTradeTransaction)
   void HandleTransaction(const MqlTradeTransaction& trans,
                          const MqlTradeRequest& request,
                          const MqlTradeResult& result)
   {
      // Filter transactions related to our dispatched requests
      if(trans.type == TRADE_TRANSACTION_DEAL_ADD)
      {
         Print("[Transaction] Deal successfully added! Deal Ticket: ", trans.deal, 
               " Symbol: ", trans.symbol, " Price: ", trans.price, " Volume: ", trans.volume);
      }
      else if(trans.type == TRADE_TRANSACTION_REQUEST)
      {
         // Request processing completed by terminal/broker
         Print("[Transaction] Request processed. Retcode: ", result.retcode, 
               " Description: ", ResultRetcodeDescription(result.retcode));
         
         // Clean up tracking buffer
         RemoveTrackedRequest(result.request_id);
      }
   }
};

Re: How to handle execution latency and broker slippage?

Posted: Thu Nov 05, 2026 9:51 am
by PTScalper
Integrating Into Your Expert Advisor (.mq5)

To hook the asynchronous executor into your main EA structure, wire HandleTransaction directly into the terminal's global OnTradeTransaction event listener:

Code: Select all

#include "CAsyncTradeExecutor.mqh"

CAsyncTradeExecutor *async_trader;

int OnInit()
{
   async_trader = new CAsyncTradeExecutor();
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason)
{
   delete async_trader;
}

// Global MQL5 Event Hook
void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
{
   // Pass incoming transaction feedback to our async executor
   async_trader.HandleTransaction(trans, request, result);
}

void OnTick()
{
   // Example: Triggering an asynchronous buy order without freezing the tick thread
   MqlTradeRequest request;
   MqlTradeResult  result;
   ZeroMemory(request);
   ZeroMemory(result);

   request.action   = TRADE_ACTION_DEAL;
   request.symbol   = _Symbol;
   request.volume   = 0.1;
   request.type     = ORDER_TYPE_BUY;
   request.price    = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   request.deviation= 10;
   request.magic    = 123456;
   request.comment  = "Async Scalper Entry";
   request.type_filling = ORDER_FILLING_IOC;

   // Non-blocking dispatch
   if(async_trader.SendAsync(request, result))
   {
      // Thread continues immediately without waiting for server network ACK
   }
}

Re: How to handle execution latency and broker slippage?

Posted: Thu Nov 05, 2026 9:51 am
by PTScalper
Key Engineering Considerations

Race Conditions in Multi-Symbol EAs: Because OnTradeTransaction is asynchronous, your transaction handler may fire milliseconds or seconds later while your EA is already processing ticks for a completely different symbol. Ensure your data structures and position-state variables are thread-safe or properly locked/synchronized.

Request ID Correlation: Always capture result.request_id upon dispatch. When OnTradeTransaction triggers TRADE_TRANSACTION_REQUEST, match the incoming ID against your internal state machine to verify whether your limit order was successfully placed or rejected.

Queue Overflows: Avoid flooding OrderSendAsync() in a tight loop without rate-limiting; if you push hundreds of requests per second faster than the terminal's IPC queue can process them, the terminal will return trade queue congestion errors.