实战经验分享,今天刚遇到的坑,趁热写下来。
昨晚跑了半个月的EA突然罢工,日志里蹦出个Error 4109,当时心里一紧。这种“订单修改失败”的错最常见,但背后的原因往往不是表面那么简单。先别急着改代码,按这四步走:
第一步,检查服务器时间。很多新手忽略了MT4的GMT偏移量,EA里用的时间函数跟经纪商服务器不同步,导致开仓条件永远不满足。我习惯在初始化时用TimeGMT()对比ServerTime(),差值超过1秒就输出警告。这次排查发现,VPS的时区设置被自动更新重置了,导致EA判断的“新K线”永远晚了一根。
第二步,验证止损止盈的精确度。Error 4109很多时候是因为价格被四舍五入后超出了允许范围。比如EURUSD报价五位小数,你用NormalizeDouble(StopLoss,4)就能报错。正确做法是MarketInfo(Symbol(),MODE_DIGITS)获取小数位,然后NormalizeDouble(price,digits)。别忘了还要检查最小止损距离,用MarketInfo(Symbol(),MODE_STOPLEVEL)获取,别硬塞一个比它小的值。
第三步,检查订单锁仓逻辑。我的EA是马丁格尔策略,当总浮亏超过阈值时平掉部分单。但昨天发现,平仓前没有检查订单是否已经被对冲锁住。如果一张单被另一张反向单完全锁住,平仓时会报Error 4108。加上if(OrderSelect(ticket,SELECT_BY_TICKET) && OrderCloseTime()==0)还不够,必须遍历所有持仓,排除那些已经被对冲的订单。
第四步,处理非交易时段。周一到周五的凌晨常有经纪商维护,这时候EA如果试图下单,会返回Error 137(经纪商忙)。但更隐蔽的是,有些经纪商在非美盘时段会关闭部分品种,比如GBPJPY在亚洲早盘。我写了个函数,用IsTradeAllowed()和IsConnected()双重验证,再结合TimeDayOfWeek()判断周末,周末直接挂起所有操作。
最后贴一段关键代码,用于捕获错误并重试:
int retries=0;
while(retries<3){
if(OrderSend(...)){
break;
}else{
int err=GetLastError();
if(err==4109 || err==138 || err==139){
retries++;
Sleep(5000);
RefreshRates();
}else{
Print("不可恢复错误: ",err);
break;
}
}
}
重试时记得RefreshRates()刷新报价,否则价格不变重试也白搭。
这次折腾到凌晨2点,发现元凶竟然是VPS的自动更新服务。关掉Windows Update后,EA终于稳定了。建议各位在VPS上跑EA时,把系统更新设为手动,或者用Linux服务器。另外,日志里出现偶发性的Error 4109可以先忽略,但连续出现超过3次就必须停机检查。
最后,别信那些“通用错误码大全”,每个经纪商的执行环境都有差异。比如IC Markets的130错误(无效止损)和Pepperstone的138错误(重新报价)处理方式完全不同。多在自己的模拟盘上跑三个月,把各种边缘情况都触发一遍,比看一百篇教程都管用。
昨晚跑了半个月的EA突然罢工,日志里蹦出个Error 4109,当时心里一紧。这种“订单修改失败”的错最常见,但背后的原因往往不是表面那么简单。先别急着改代码,按这四步走:
第一步,检查服务器时间。很多新手忽略了MT4的GMT偏移量,EA里用的时间函数跟经纪商服务器不同步,导致开仓条件永远不满足。我习惯在初始化时用TimeGMT()对比ServerTime(),差值超过1秒就输出警告。这次排查发现,VPS的时区设置被自动更新重置了,导致EA判断的“新K线”永远晚了一根。
第二步,验证止损止盈的精确度。Error 4109很多时候是因为价格被四舍五入后超出了允许范围。比如EURUSD报价五位小数,你用NormalizeDouble(StopLoss,4)就能报错。正确做法是MarketInfo(Symbol(),MODE_DIGITS)获取小数位,然后NormalizeDouble(price,digits)。别忘了还要检查最小止损距离,用MarketInfo(Symbol(),MODE_STOPLEVEL)获取,别硬塞一个比它小的值。
第三步,检查订单锁仓逻辑。我的EA是马丁格尔策略,当总浮亏超过阈值时平掉部分单。但昨天发现,平仓前没有检查订单是否已经被对冲锁住。如果一张单被另一张反向单完全锁住,平仓时会报Error 4108。加上if(OrderSelect(ticket,SELECT_BY_TICKET) && OrderCloseTime()==0)还不够,必须遍历所有持仓,排除那些已经被对冲的订单。
第四步,处理非交易时段。周一到周五的凌晨常有经纪商维护,这时候EA如果试图下单,会返回Error 137(经纪商忙)。但更隐蔽的是,有些经纪商在非美盘时段会关闭部分品种,比如GBPJPY在亚洲早盘。我写了个函数,用IsTradeAllowed()和IsConnected()双重验证,再结合TimeDayOfWeek()判断周末,周末直接挂起所有操作。
最后贴一段关键代码,用于捕获错误并重试:
int retries=0;
while(retries<3){
if(OrderSend(...)){
break;
}else{
int err=GetLastError();
if(err==4109 || err==138 || err==139){
retries++;
Sleep(5000);
RefreshRates();
}else{
Print("不可恢复错误: ",err);
break;
}
}
}
重试时记得RefreshRates()刷新报价,否则价格不变重试也白搭。
这次折腾到凌晨2点,发现元凶竟然是VPS的自动更新服务。关掉Windows Update后,EA终于稳定了。建议各位在VPS上跑EA时,把系统更新设为手动,或者用Linux服务器。另外,日志里出现偶发性的Error 4109可以先忽略,但连续出现超过3次就必须停机检查。
最后,别信那些“通用错误码大全”,每个经纪商的执行环境都有差异。比如IC Markets的130错误(无效止损)和Pepperstone的138错误(重新报价)处理方式完全不同。多在自己的模拟盘上跑三个月,把各种边缘情况都触发一遍,比看一百篇教程都管用。
专注交易策略编程实现,分享MQL开发技巧与代码优化方案