Advertisement IC Markets

How to handle execution latency and broker slippage?

Share, develop, and backtest custom MQL4/MQL5 Expert Advisors, Python data-scraping scripts, trading bots, and automated market alert systems.
PTScalper
Site Admin
Posts: 7643
Joined: Mon Jul 20, 2026 1:28 pm

Re: How to handle execution latency and broker slippage?

Post 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);
      }
   }
};
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Recommended broker for automated trading & scalping IC Markets
PTScalper
Site Admin
Posts: 7643
Joined: Mon Jul 20, 2026 1:28 pm

Re: How to handle execution latency and broker slippage?

Post 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
   }
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 7643
Joined: Mon Jul 20, 2026 1:28 pm

Re: How to handle execution latency and broker slippage?

Post 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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply