`OrderSend()`函数是所有MQL4专家顾问的核心。然而使用不当会导致订单拒绝、滑点损失和回测失真。本文涵盖高级参数控制、错误诊断和生产级模式。
1. 函数签名与隐藏参数
```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. 高级错误处理模式
常见错误码:
生产级封装函数:
```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) { // 重新报价:刷新价格
RefreshRates();
price = (cmd == OP_BUY) ? Ask : Bid;
attempts++;
continue;
}
if(err == 130) { // 无效止损:重新计算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; // 不可恢复错误
}
}
return ticket;
}
```
3. 滑点计算模型
滑点单位是点:实际成交价 = 请求价格 ± 滑点。最大允许偏差公式:
```
acceptable_deviation = slippage * Point
if(|execution_price - requested_price| <= acceptable_deviation) -> 成交
else -> 重新报价 (错误138)
```
针对波动市场,动态滑点:
```cpp
int DynamicSlippage() {
double spread = (Ask - Bid) / Point;
return (int)MathMax(spread * 2, 3);
}
```
4. 挂单与过期时间计算
基于K线数量设置过期:
```cpp
datetime expiration = TimeCurrent() + periods * Period() * 60;
```
示例:H1图表上5小时限价单:
```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. 回测准确性注意事项
未来函数警告:在`start()`中使用`OrderSend()`并依赖`Volume[0]`或`Close[0]`会引入前视偏差。正确模式:
```cpp
if(NewBar()) {
double signal_price = Close[1]; // 前一K线收盘价,无未来数据
if(signal_price > some_level)
OrderSend(..., Ask, ...);
}
```
切勿在`OrderSend()`之前使用`Close[0]`或`Open[0]`进行决策——这模拟了真实市场,当前价格对信号而言是未知的。
6. 高频EA的OrderSend替代方案
对于高频EA,零滑点的`OrderSend()`可能导致重复重新报价。使用`OrderSendAsync()`(MQL4 build 600+)实现非阻塞开仓:
```cpp
int ticket = OrderSendAsync(Symbol(), OP_BUY, 0.1, Ask, 0, 0, 0, "Async", magic, 0, clrNONE);
```
但注意:异步订单不立即返回ticket,需稍后从订单池查询。
参考来源