`OrderSend()`函数是EA与交易服务器之间的核心通道。尽管这是MQL4中最常用的函数之一,但正确实现方式仍被广泛误解。糟糕的错误处理和执行逻辑导致了70%的EA运行时故障。
函数签名与返回值
```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);
```
返回值:成功时返回订单号(>=0),失败时返回-1,并通过`GetLastError()`获取错误代码。
系统化错误处理框架
每次`OrderSend()`调用都必须包含重试逻辑。永远不要假设第一次尝试就会成功。
```cpp
// MQL4 - 生产级OrderSend,带重试和错误分类
int OrderSendWithRetry(string sym, int cmd, double vol, double price,
int slip, double sl, double tp, string cmt,
int magic, datetime exp) {
int attempt = 0;
int maxAttempts = 3;
int ticket = -1;
while(attempt < maxAttempts) {
attempt++;
RefreshRates();
ticket = OrderSend(sym, cmd, vol, price, slip, sl, tp, cmt, magic, exp, clrNONE);
int error = GetLastError();
if(ticket > 0) {
return ticket;
}
// 错误分类与恢复策略
switch(error) {
case 129: // 无效价格
case 136: // 报价已变更
case 138: // 重新报价
Sleep(100 * attempt); // 指数退避
price = NormalizeDouble(MarketInfo(sym, MODE_ASK), Digits);
break;
case 146: // 交易环境繁忙
Sleep(150 * attempt);
while(IsTradeContextBusy()) Sleep(50);
break;
case 148: // 订单过多
return -1; // 立即失败
default:
Print("OrderSend错误 ", error, " 尝试次数 ", attempt);
Sleep(100);
}
}
return -1;
}
```
滑点计算模型
滑点参数以点数为单位。实际执行价偏差为:
\[
\Delta p_{\text{实际}} = |p_{\text{请求}} - p_{\text{成交}}| \leq \text{滑点} \times \text{Point}
\]
激进执行场景下,使用基于波动率的动态滑点:
```cpp
int DynamicSlippage() {
double spread = MarketInfo(Symbol(), MODE_SPREAD);
double atr = iATR(NULL, 0, 14, 1);
double volatilitySlippage = MathMax(spread, atr / Point * 0.05);
return (int)MathMin(volatilitySlippage, 50);
}
```
挂单修改逻辑
市价单使用price=Ask/Bid。挂单需要特定价格计算:
距离验证公式:
\[
d = |p_{\text{订单}} - p_{\text{当前}}| \geq \text{StopLevel} \times \text{Point}
\]
发送前必须使用`MarketInfo(symbol, MODE_STOPLEVEL)`验证距离。
生产环境错误码参考
参考来源:MQL4官方文档 - OrderSend(https://docs.mql4.com/trading/ordersend),《MetaTrader 4专家顾问编程》Andrew R. Young著,2019年。