Summary: 本文深度剖析MQL4的OrderSend函数,涵盖返回值验证、系统化错误处理、动态滑点模型及订单修改模式,提供可直接应用于生产环境的代码模板。




`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。挂单需要特定价格计算:
  • 买入限价:低于当前Ask

  • 买入止损:高于当前Ask

  • 卖出限价:高于当前Bid

  • 卖出止损:低于当前Bid


  • 距离验证公式:
    \[
    d = |p_{\text{订单}} - p_{\text{当前}}| \geq \text{StopLevel} \times \text{Point}
    \]
    发送前必须使用`MarketInfo(symbol, MODE_STOPLEVEL)`验证距离。

    生产环境错误码参考
  • 0:成功

  • 129:无效价格(需要处理重新报价)

  • 130:无效止损(距离过近)

  • 136/138:报价已变更/重新报价(刷新价格后重试)

  • 146:交易环境繁忙(等待后重试)

  • 148:订单过多(先检查订单数量)

  • 4108:未知品种(验证品种存在性)


  • 参考来源:MQL4官方文档 - OrderSend(https://docs.mql4.com/trading/ordersend),《MetaTrader 4专家顾问编程》Andrew R. Young著,2019年。