`OrderSend()`函数是任何MQL4专家顾问的心脏。然而许多进阶用户仍然误用其参数或忽略返回值验证,导致回测隐藏偏差和实盘交易失败。本文涵盖生产级用法、错误处理模式及滑点控制。
1. 函数原型与各参数详解
```cpp
int OrderSend(
string symbol, // 品种名称
int cmd, // 交易指令
double volume, // 手数
double price, // 订单价格
int slippage, // 允许滑点(点数)
double stoploss, // 止损价
double takeprofit, // 止盈价
string comment, // 订单注释
int magic, // EA标识码
datetime expiration, // 挂单有效期
color arrow_color // 图表箭头颜色
);
```
关键细节:`slippage`以点为单位,而非大点。对于5位报价经纪商,10个点=1个大点。使用`Point`转换:`滑点数 = 10 * Point`。
2. 返回值与验证逻辑
`OrderSend()`成功返回订单号,失败返回-1。切勿假定成功。立即检查订单号并调用`GetLastError()`。
生产模式:
```cpp
int ticket = OrderSend(Symbol(), OP_BUY, lot, Ask, slippage, stopLoss, takeProfit, "EA", magic, 0, clrNONE);
if(ticket < 0) {
int error = GetLastError();
Print("OrderSend失败。错误码:", error, " | ", ErrorDescription(error));
// 可选:带指数退避的重试逻辑
return;
}
```
常见错误码:130(无效止损/止盈)、148(订单过多)、146(交易上下文繁忙)。对于错误146,使用`Sleep(50)`并最多重试5次。
3. 滑点数学模型
滑点不只是一个安全缓冲,它影响成交概率。对于市价单,成交条件:
卖出订单:`Ask - price <= slippage * Point`
买入订单:`price - Bid <= slippage * Point`
根据历史数据计算统计安全的滑点:
`slippage = max(3, ceil( (avg_slippage + 2 * stddev_slippage) / Point ))`
其中`avg_slippage`和`stddev_slippage`来自分笔数据。
4. 在回测中用OrderSend避免未来函数
常见错误:在引用`Close[0]`的循环内使用`OrderSend()`而不验证K线是否完整。这会产生前视偏差。正确做法:
```cpp
static datetime lastBarTime = 0;
if(Time[0] != lastBarTime) {
lastBarTime = Time[0];
// 仅在新K线开仓,避免日内未来数据泄露
OrderSend(...);
}
```
这确保了回测准确性,与实时K线收盘对齐。
5. 挂单与有效期
MQL4允许为挂单(OP_BUYLIMIT、OP_SELLLIMIT、OP_BUYSTOP、OP_SELLSTOP)设置`expiration`参数。有效期计算公式:
`expiration = TimeCurrent() + 有效秒数`
最大有效期为当前时间后1个月。超出范围的值会被静默截断。
带自动取消的示例:
```cpp
datetime expiry = TimeCurrent() + 3600; // 1小时
int ticket = OrderSend(Symbol(), OP_BUYLIMIT, 0.1, buyLimitPrice, 3, 0, 0, "Limit", magic, expiry, clrBlue);
```
6. OrderSend与OrderSendAsync(MQL5提及)
MQL4没有异步下单。每次`OrderSend()`都会阻塞直到经纪商响应或超时。MQL5中存在`OrderSendAsync()`但语义不同。迁移到MQL5时,用`CTrade::PositionOpen()`替代`OrderSend()`,详见跨平台迁移说明。
7. 对优化性能的影响
在EA参数优化期间,如果每次调用都包含大量计算,`OrderSend()`会成为瓶颈。将止损/止盈的计算移到调用外部:
```cpp
double sl = Ask - stopLossPoints * Point;
double tp = Ask + takeProfitPoints * Point;
int ticket = OrderSend(Symbol(), OP_BUY, lot, Ask, slippage, sl, tp, comment, magic, 0, clrNONE);
```
减少`OrderSend`上下文内的运算可使MT4优化速度提升高达30%。
参考来源