Summary: Advanced deep dive into MQL4 OrderSend covering slippage modeling, ERR_TRADE_RETRY error handling, and a production-ready order wrapper with complete return code mapping for robust live trading.




The `OrderSend()` function is the heartbeat of any MQL4 Expert Advisor, yet most traders only understand its basic signature. Proper slippage control and error handling separate profitable live EAs from backtest-only relics.

1. Complete OrderSend Parameter Deconstruction

```cpp
int OrderSend(
string symbol, // symbol name
int cmd, // OP_BUY, OP_SELL, OP_BUYLIMIT, etc.
double volume, // lot size
double price, // requested price
int slippage, // maximum slippage in points
double stoploss, // stop loss level
double takeprofit, // take profit level
string comment, // order comment
int magic, // EA identifier
datetime expiration, // pending order expiration
color arrow_color // chart arrow color
);
```

The critical insight: `slippage` works differently for market orders versus pending orders. For `OP_BUY` and `OP_SELL`, slippage is the maximum allowable deviation from the requested price. For pending orders, slippage is ignored entirely.

2. Realistic Slippage Modeling For Backtest Accuracy

A common flaw in EA programming is using fixed slippage. Market conditions demand dynamic calculation:

```cpp
int CalculateDynamicSlippage(string symbol) {
double spread = MarketInfo(symbol, MODE_SPREAD);
double atr = iATR(symbol, PERIOD_M5, 14, 1);
double volatilitySlippage = MathCeil(atr / Point() * 0.1);
int spreadSlippage = (int)MathCeil(spread * 1.5);
return MathMax(3, (int)MathMax(volatilitySlippage, spreadSlippage));
}
```

3. Production-Grade OrderSend Wrapper With Retry Logic

The most common live trading failure is `ERR_TRADE_RETRY` (error 4) due to price changes between request and execution. This wrapper handles it:

```cpp
int SafeOrderSend(string sym, int cmd, double vol, double price, int slip, double sl, double tp, string cmt, int magic, datetime exp, color col) {
int ticket = -1;
int attempts = 0;
int maxAttempts = 5;
int error = 0;

while(attempts < maxAttempts && ticket < 0) {
ticket = OrderSend(sym, cmd, vol, price, slip, sl, tp, cmt, magic, exp, col);
error = GetLastError();

if(error == ERR_NO_ERROR) break;

// Handle requote and busy errors
if(error == ERR_REQUOTE || error == ERR_TRADE_CONTEXT_BUSY) {
Sleep(50);
attempts++;
continue;
}

// Handle price changed: refresh and retry
if(error == ERR_PRICE_CHANGED) {
RefreshRates();
if(cmd == OP_BUY) price = Ask;
else if(cmd == OP_SELL) price = Bid;
attempts++;
continue;
}

// Unknown errors: log and break
if(error != ERR_NO_ERROR) {
Print("OrderSend failed with error ", error, " after ", attempts, " attempts");
break;
}
attempts++;
}
return ticket;
}
```

4. Error Code Mapping For Diagnostic

Implement this error classification to quickly identify the root cause:

```cpp
string OrderSendErrorDescription(int errorCode) {
switch(errorCode) {
case ERR_TRADE_NOT_ALLOWED: return "Trading disabled";
case ERR_MARKET_CLOSED: return "Market closed";
case ERR_NOT_ENOUGH_MONEY: return "Insufficient margin";
case ERR_PRICE_CHANGED: return "Price changed - need RefreshRates";
case ERR_OFF_QUOTES: return "No quotes - check connection";
case ERR_BROKER_BUSY: return "Broker busy - increase retry delay";
case ERR_REQUOTE: return "Requote - increase slippage";
case ERR_TRADE_CONTEXT_BUSY: return "Context busy - wait or use critical section";
case ERR_NO_ERROR: return "Success";
default: return "Unknown error: " + (string)errorCode;
}
}
```

5. Avoiding The Future Function Trap In OrderSend Backtesting

When backtesting, never use `OrderSend()` with `Volume[0]` or `Close[0]` inside the same tick that generated the signal. This creates look-ahead bias. Always use the previous bar's close:

```cpp
// Dangerous - future function
if(Close[1] > SMA && Close[0] > Close[1])
OrderSend(...); // Uses current incomplete bar

// Correct - no look-ahead
if(Close[1] > SMA && Close[2] > Close[1])
OrderSend(...); // Only confirmed data
```

6. Complete Open Position Example With All Best Practices

```cpp
int OpenBuyPosition(double lot, int magic) {
double ask = Ask;
double spread = MarketInfo(Symbol(), MODE_SPREAD);
int slippage = CalculateDynamicSlippage(Symbol());
double sl = ask - spread * 20 * Point();
double tp = ask + spread * 40 * Point();

int ticket = SafeOrderSend(Symbol(), OP_BUY, lot, ask, slippage, sl, tp, "EA_Trade", magic, 0, clrNONE);

if(ticket > 0) {
Print("Position opened: ", ticket, " at ", ask, " slippage: ", slippage);
} else {
Print("Failed to open position. Error: ", OrderSendErrorDescription(GetLastError()));
}
return ticket;
}
```

Reference: MQL4 Documentation (docs.mql4.com/trading/OrderSend), Pardo, Robert. "The Evaluation and Optimization of Trading Strategies." Wiley Trading, 2008.