The
OrderSend() function is the heart of any MQL4 Expert Advisor. Despite its ubiquity, improper usage leads to order rejection, slippage loss, and backtest inaccuracies. This guide covers advanced parameter control, error diagnosis, and production patterns.1. Function Signature & Hidden Parameters
``
cpp
int OrderSend(string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment, int magic, datetime expiration, color arrow_color)
`
slippage: Only applies to market orders (OP_BUY/OP_SELL). For pending orders, this parameter is ignored but still required.
expiration: Only for pending orders (OP_BUYLIMIT, OP_BUYSTOP, OP_SELLLIMIT, OP_SELLSTOP). Market orders ignore this.
2. Advanced Error Handling Pattern
Common error codes:
130 - Invalid stops (too close to market)
138 - Requote (price changed)
145 - Modification denied (too frequent)
Production-ready wrapper:
`cpp
int SafeOrderSend(int cmd, double volume, double price, int slippage, double sl, double tp) {
int ticket = -1;
int attempts = 0;
while(attempts < 3 && ticket < 0) {
ticket = OrderSend(Symbol(), cmd, volume, price, slippage, sl, tp, "EA", magic, 0, clrNONE);
if(ticket < 0) {
int err = GetLastError();
if(err == 138) { // Requote: refresh prices
RefreshRates();
price = (cmd == OP_BUY) ? Ask : Bid;
attempts++;
continue;
}
if(err == 130) { // Invalid stops: recalculate SL/TP
sl = NormalizeDouble((cmd == OP_BUY) ? price - 50Point() : price + 50Point(), Digits);
tp = NormalizeDouble((cmd == OP_BUY) ? price + 100Point() : price - 100Point(), Digits);
attempts++;
continue;
}
break; // Unrecoverable error
}
}
return ticket;
}
`
3. Slippage Calculation Model
Slippage in points: actual execution price = requested price ± slippage. Formula for maximum acceptable deviation:
`
acceptable_deviation = slippage Point
if(|execution_price - requested_price| <= acceptable_deviation) -> fill
else -> requote (error 138)
`
For volatile markets, dynamic slippage:
`cpp
int DynamicSlippage() {
double spread = (Ask - Bid) / Point;
return (int)MathMax(spread 2, 3);
}
`
4. Pending Orders & Expiration Math
Set expiration based on bar count:
`cpp
datetime expiration = TimeCurrent() + periods Period() 60;
`
Example: 5-hour limit order on H1 chart:
`cpp
int periods = 5;
datetime expiry = TimeCurrent() + periods 60 60;
OrderSend(Symbol(), OP_BUYLIMIT, 0.1, price, 3, 0, 0, "Limit", magic, expiry, clrNONE);
`
5. Backtest Accuracy Considerations
Future function alert: Using OrderSend() inside start() with Volume[0] or Close[0] creates look-ahead bias. Correct pattern:
`cpp
if(NewBar()) {
double signal_price = Close[1]; // previous bar close, no future data
if(signal_price > some_level)
OrderSend(..., Ask, ...);
}
`
Never use Close[0] or Open[0] for decision before OrderSend() in same tick—this matches live market where current price is unknown for signal.
6. OrderSend Alternative for Scalping
For high-frequency EAs, OrderSend() with zero slippage may cause repeated requotes. Use OrderSendAsync() (MQL4 build 600+) for non-blocking placement:
`cpp
int ticket = OrderSendAsync(Symbol(), OP_BUY, 0.1, Ask, 0, 0, 0, "Async", magic, 0, clrNONE);
``But note: async orders don't return ticket immediately; check orders pool later.
Reference