🚀 AI One-Click Generation of mql4 Strategy Code

How to Properly Handle Trading Errors in Mql4 using GetLastError()?

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

Problem Description

How do I check if a trade failed to open and find out why?

Solution

To check if a trade failed to open in MQL4, you must evaluate the return value of the OrderSend() function. If OrderSend() returns -1, the trade failed. Immediately after detecting a failure, you call GetLastError() to retrieve the specific error code.

Here is the standard implementation pattern for robust error checking.

MQL4 Implementation

//+------------------------------------------------------------------+
//| Function to open a trade with error checking                     |
//+------------------------------------------------------------------+
void OpenBuyOrder(double volume, int slippage, double sl, double tp)
{
   // 1. Reset the last error variable before the operation
   ResetLastError();
   
   // 2. Attempt to send the order
   int ticket = OrderSend(Symbol(), OP_BUY, volume, Ask, slippage, sl, tp, "My Buy Order", 0, 0, clrGreen);
   
   // 3. Check the return value
   if(ticket < 0) 
   {
      // 4. Retrieve the specific error code
      int errorCode = GetLastError();
      
      // 5. Log the error for analysis
      Print("OrderSend failed. Error Code: ", errorCode, " Description: ", GetErrorDescription(errorCode));
      
      // Optional: Handle specific errors programmatically
      if(errorCode == ERR_NOT_ENOUGH_MONEY) {
         Print("Critical: Insufficient funds to open trade.");
      }
      else if(errorCode == ERR_REQUOTE) {
         Print("Warning: Price changed (Requote). Consider increasing slippage or retrying.");
      }
   }
   else 
   {
      Print("Order opened successfully. Ticket #", ticket);
   }
}

//+------------------------------------------------------------------+
//| Helper function to translate common error codes to text          |
//+------------------------------------------------------------------+
string GetErrorDescription(int errCode)
{
   switch(errCode)
   {
      case 0:   return("No error");
      case 2:   return("Common error");
      case 64:  return("Account disabled");
      case 128: return("Trade timeout");
      case 129: return("Invalid price");
      case 130: return("Invalid stops");
      case 131: return("Invalid trade volume");
      case 132: return("Market is closed");
      case 133: return("Trade is disabled");
      case 134: return("Not enough money");
      case 135: return("Price changed");
      case 136: return("Off quotes");
      case 138: return("Requote");
      case 146: return("Trade context is busy");
      case 148: return("Too many orders");
      default:  return("Unknown error");
   }
}

Key Concepts

  1. ResetLastError(): Always call this before OrderSend. If you don't, GetLastError() might return an old error code from a previous operation, leading to confusion.
  2. Return Value Check: OrderSend returns the ticket number (int) if successful. If it fails, it returns -1.
  3. GetLastError(): This system function returns the code of the last error that occurred. It resets to 0 after being called, so store it in a variable (like errorCode in the example) if you need to use it multiple times in your logic.

Common Trade Error Codes

When debugging, these are the most frequent codes you will encounter:

  • 129 (ERR_INVALID_PRICE): The Ask/Bid price used is outdated or normalized incorrectly. Ensure you are using RefreshRates() before sending the order.
  • 130 (ERR_INVALID_STOPS): Your Stop Loss or Take Profit is too close to the current price (inside the MODE_STOPLEVEL) or calculated incorrectly.
  • 131 (ERR_INVALID_TRADE_VOLUME): The lot size is incorrect (e.g., trying to trade 0.05 lots on a broker that only allows steps of 0.1).
  • 134 (ERR_NOT_ENOUGH_MONEY): Not enough free margin to open the position.
  • 138 (ERR_REQUOTE): The price moved while the request was being processed. This is common during high volatility.
  • 146 (ERR_TRADE_CONTEXT_BUSY): The terminal is busy processing another order. You usually need a retry loop with Sleep() to handle this.

Q&A

Q: Can I automatically retry the trade if it fails?
A: Yes, but only for specific errors. You should implement a retry loop for "transient" errors like 138 (Requote) or 146 (Trade Context Busy). Do not retry immediately for logical errors like 134 (Not Enough Money) or 130 (Invalid Stops), as these will fail indefinitely until parameters are changed.

Q: Why do I get Error 130 (Invalid Stops) even when my math seems correct?
A: This often happens if you do not normalize the price. Always wrap your calculated SL/TP prices in NormalizeDouble(price, Digits). Also, check MarketInfo(Symbol(), MODE_STOPLEVEL) to ensure your stops are not too close to the entry price.

Q: Does GetLastError() work in the Strategy Tester?
A: Yes, it works exactly the same way in the Strategy Tester as it does in live trading, which is essential for debugging your strategy logic before going live.