🚀 AI One-Click Generation of mql4 Strategy Code

Mql4 Error Handling: How to Use IsTradeAllowed() and IsTradeContextBusy()

mql4 | Published on: 2025/12/11
The following content is generated by EasyQuant .

Problem Description

My trading robot sometimes fails with a 'trade context is busy' error. How do I prevent this?

Solution

The "Trade context is busy" error (Error code 146) occurs because the MetaTrader 4 terminal is single-threaded regarding trade operations. If your robot attempts to send an order while the terminal is already processing another request (from a different EA, a script, or a manual trade), the request is rejected.

To prevent this, you must implement a retry mechanism that checks the trade context state and waits if it is busy.

Here is a robust implementation of a SafeOrderSend function. It replaces the standard OrderSend and handles the busy context automatically.

MQL4 Implementation

Copy this function into your Expert Advisor and replace your existing OrderSend() calls with SafeOrderSend().

//+------------------------------------------------------------------+
//| SafeOrderSend                                                    |
//| A wrapper for OrderSend that handles Error 146 (Context Busy)    |
//+------------------------------------------------------------------+
int SafeOrderSend(string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment="", int magic=0, datetime expiration=0, color arrow_color=CLR_NONE)
{
   int ticket = -1;
   int err = 0;
   int retry_count = 0;
   int max_retries = 10;      // Maximum number of attempts
   int sleep_time = 1000;     // Wait time in milliseconds between attempts

   while(retry_count < max_retries)
   {
      // 1. Check if the terminal is currently busy before attempting
      while(IsTradeContextBusy())
      {
         Sleep(100); // Wait 100ms and check again
         // Optional: Add a timeout break here if needed
      }

      // 2. Refresh rates to ensure we use the latest prices after waiting
      RefreshRates();
      
      // 3. Update price for Market Orders to prevent Requotes (Error 138)
      // If we waited for the context to free up, the price passed in arguments might be stale.
      if(cmd == OP_BUY)       price = MarketInfo(symbol, MODE_ASK);
      else if(cmd == OP_SELL) price = MarketInfo(symbol, MODE_BID);
      // Note: For pending orders (OP_BUYLIMIT, etc.), we usually keep the original requested price.

      // 4. Attempt to send the order
      ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color);

      // 5. Check the result
      if(ticket > 0)
      {
         // Order successful
         return(ticket);
      }
      else
      {
         err = GetLastError();
         
         // Handle specific "Busy" errors
         if(err == 146 || err == 137) // 146 = ERR_TRADE_CONTEXT_BUSY, 137 = ERR_BROKER_BUSY
         {
            Print("Trade context busy. Retrying... (Attempt ", retry_count + 1, " of ", max_retries, ")");
            Sleep(sleep_time);
            retry_count++;
            continue; // Restart the loop
         }
         else
         {
            // Fatal error (e.g., Invalid Volume, Not Enough Money) - Do not retry
            Print("OrderSend failed with fatal error: ", err);
            return(-1);
         }
      }
   }

   Print("SafeOrderSend failed after ", max_retries, " attempts.");
   return(-1);
}

//+------------------------------------------------------------------+
//| Example Usage in OnTick                                          |
//+------------------------------------------------------------------+
void OnTick()
{
   // Example condition
   if(OrdersTotal() == 0)
   {
      double lotSize = 0.1;
      int slippage = 3;
      
      // Call SafeOrderSend instead of OrderSend
      int ticket = SafeOrderSend(Symbol(), OP_BUY, lotSize, Ask, slippage, 0, 0, "My Robot", 12345, 0, clrBlue);
      
      if(ticket > 0)
      {
         Print("Order opened successfully. Ticket: ", ticket);
      }
   }
}

Key Logic Explained

  1. IsTradeContextBusy() Check: Before even calling OrderSend, the code checks if the terminal is busy. If it is, it enters a small loop (Sleep(100)) until the context is free.
  2. RefreshRates(): This is critical. If the robot waits for 2 seconds because the context was busy, the Ask or Bid price passed to the function initially is now old. Sending an order with an old price will result in an "Off Quotes" or "Requote" error. RefreshRates() updates the internal MQL4 price variables.
  3. Price Update: Inside the loop, for market orders (OP_BUY or OP_SELL), the code re-fetches the current Ask or Bid using MarketInfo. This ensures that when the retry happens, it uses the valid current market price.
  4. Error Handling (146 & 137): Even with the pre-check, OrderSend might still fail with error 146 (if a trade occurred in the millisecond between the check and the send). The code catches this specific error code and triggers a retry loop.
  5. Fatal Error Exit: If the error is not related to the context (e.g., "Not Enough Money" or "Invalid Volume"), the loop breaks immediately to prevent spamming the server with invalid requests.

Q&A

Q: Can I use this logic for OrderClose and OrderModify as well?
A: Yes. The logic is identical. You should create wrapper functions like SafeOrderClose and SafeOrderModify that wrap the standard functions in a while loop checking for IsTradeContextBusy() and Error 146.

Q: Why is RefreshRates() necessary inside the loop?
A: MQL4 does not automatically update Ask, Bid, or Close[] arrays within a single execution of OnTick. If you Sleep() for 1 second, the market moves, but your variables do not. RefreshRates() forces the EA to fetch the newest data from the terminal memory.

Q: Will this slow down my backtesting?
A: No. Sleep() is ignored in the Strategy Tester, and IsTradeContextBusy() always returns false in the tester (unless simulated otherwise by specialized tools), so the code will execute instantly during backtests.