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)
```
2. Advanced Error Handling Pattern
Common error codes:
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 - 50*Point() : price + 50*Point(), Digits);
tp = NormalizeDouble((cmd == OP_BUY) ? price + 100*Point() : price - 100*Point(), 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