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)
`
slippage:仅适用于市价单(OP_BUY/OP_SELL)。对挂单忽略此参数但语法上必须填写。
expiration:仅适用于挂单(OP_BUYLIMIT、OP_BUYSTOP、OP_SELLLIMIT、OP_SELLSTOP)。市价单忽略。
2. 高级错误处理模式
常见错误码:
130 - 无效止损(距离市价太近)
138 - 重新报价(价格已变动)
145 - 修改被拒绝(过于频繁)
生产级封装函数:
`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 - 50Point() : price + 50Point(), Digits);
tp = NormalizeDouble((cmd == OP_BUY) ? price + 100Point() : price - 100Point(), 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,需稍后从订单池查询。
参考来源