你的 EA 突然不下单了,怎么办?
上周有个朋友找我,说他挂了三个月的网格 EA 突然罢工了。日志里一堆红字,全是 "OrderSend Error 130"。他慌得不行,以为是 EA 代码坏了,差点花钱找人重写。
其实就是经纪商悄悄改了最小止损距离,从 10 个点变成了 20 个点。
MT4/MT5 的报错信息看着吓人,但 90% 的问题都有固定解法。你不需要懂编程,只要会查表、会看日志,大部分问题自己就能搞定。
交易操作类报错:最常见的四个错误
这四个错误占了 EA 报错的 70% 以上。你大概率会碰到其中至少一个。
Error 130:Invalid Stops(无效止损/止盈)
这是新手碰到最多的错误,没有之一。
原因很简单:你设置的止损或止盈离当前价格太近了。每个经纪商、每个品种都有一个"最小止损距离"(Stop Level)。比如 EURUSD 的 Stop Level 是 20 个点,你的止损离现价只有 15 个点,单子就发不出去。
怎么查 Stop Level?在 MT4 里右键点击品种,选"规格",找到"止损水平"那一行。MT5 里是"交易"标签页下的"Stops level"。
解决办法:
- 在 EA 代码里用 MarketInfo(Symbol(), MODE_STOPLEVEL) 获取最小距离
- 把止损止盈设大一点,至少比 Stop Level 多 5 个点留余量
- 注意:有些经纪商在高波动时段会临时加大 Stop Level,比如非农前后
还有一种情况容易被忽略:你用的是五位报价经纪商(比如 EURUSD 报价 1.08765),但 EA 里的止损是按四位算的。差了十倍,当然报错。
Error 131:Invalid Trade Volume(无效交易量)
你下了 0.03 手,但经纪商的最小手数是 0.1 手。或者你下了 15 手,但最大单笔手数是 10 手。又或者你下了 0.07 手,但手数步长是 0.05,只接受 0.05、0.10、0.15 这种。
这三种情况都会触发 Error 131。
检查三个参数就行:
- MODE_MINLOT:最小手数
- MODE_MAXLOT:最大手数
- MODE_LOTSTEP:手数步长
写一个手数规范化函数,先检查范围,再用 MathRound 按步长取整,问题就解决了。
举个例子:你的 EA 算出来要下 0.123 手,步长是 0.01,那规范化之后就是 0.12 手。步长是 0.1 的话,就是 0.1 手。
Error 138:Requote(重新报价)
你发出去的价格和服务器当前价格对不上。在快速行情里特别常见,比如非农公布那几秒钟。
这个错误本身不算严重,重试一次往往就好了。但如果你的 EA 没有重试逻辑,单子就丢了。
标准做法是加一个重试循环:
int retries = 3;
while(retries > 0) {
RefreshRates();
ticket = OrderSend(...);
if(ticket > 0) break;
retries--;
Sleep(500);
}
另一个办法是增大滑点参数(Slippage)。OrderSend 函数里有一个 slippage 参数,默认填 3 就是接受 3 个点的滑点。行情快的时候可以填 10 到 20。
注意:五位报价的经纪商,slippage 也要乘以 10。你填 3 其实只接受 0.3 个大点的滑点,几乎等于不接受。
Error 146:Trade Context Busy(交易上下文繁忙)
MT4 的交易操作是单线程的。同一时刻只能有一个 EA 在执行交易指令。如果你同时跑了五个 EA,其中一个在下单的时候,其他四个都得等。等不到就报 146。
解决办法:
- 在下单前检查 IsTradeAllowed() 函数
- 如果返回 false,Sleep 一小段时间再检查
- 设置一个超时上限,比如最多等 10 秒,超时就放弃这次操作
int wait = 0;
while(!IsTradeAllowed() && wait < 20) {
Sleep(500);
wait++;
}
MT5 里这个问题基本没有了,因为 MT5 支持多线程交易。如果你经常碰到 146,认真考虑一下迁移到 MT5。
OrderSend 返回 -1 了,怎么定位问题?
OrderSend 失败会返回 -1。这时候你需要立刻调用 GetLastError() 来获取具体的错误码。
很多人写 EA 时犯的一个低级错误:没有检查 OrderSend 的返回值。单子发没发成功完全不知道,账户里的持仓和 EA 的逻辑对不上,越跑越乱。
标准写法:
int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, sl, tp);
if(ticket < 0) {
int err = GetLastError();
Print("OrderSend failed. Error: ", err);
}
OrderSend 常见的错误码清单:
| 错误码 | 含义 | 常见原因 |
|---|---|---|
| 129 | Invalid price(无效价格) | 买单用了 Bid 或卖单用了 Ask |
| 130 | Invalid stops | 止损止盈太近 |
| 131 | Invalid trade volume | 手数不合规 |
| 132 | Market is closed | 非交易时段下单 |
| 133 | Trade is disabled | 品种被禁止交易 |
| 134 | Not enough money | 保证金不足 |
| 135 | Price changed | 价格变动,类似 requote |
| 136 | Off quotes | 没有报价 |
| 137 | Broker is busy | 服务器繁忙 |
| 138 | Requote | 重新报价 |
| 145 | Modification denied | 订单太靠近市价无法修改 |
| 146 | Trade context busy | 交易线程被占用 |
| 148 | Too many orders | 持仓/挂单数量超限 |
Error 134 特别值一说。很多人以为"保证金不足"就是没钱了,其实不完全是。如果你同时开了很多单,浮亏很大,可用保证金可能只剩几百美元,不够开新仓。EA 没有检查余额就直接下单,自然报 134。
好的做法是下单前调用 AccountFreeMargin() 算一下,够不够开这一手。
Error 4109 和 4051:EA 权限和参数问题
Error 4109:Trade is Not Allowed(不允许交易)
这个错误 99% 不是代码问题,是设置问题。
检查这三个地方:
- MT4 上方工具栏有个"自动交易"按钮,看看是不是绿色的。灰色就是关了。
- EA 属性里的"允许实时交易"复选框,打勾了没有。
- 菜单栏 → 工具 → 选项 → EA 交易 → "允许自动交易"要勾上。
三个开关缺一个都不行。每次更新 MT4 或者换电脑装新终端,这些设置可能会被重置,记得检查。
还有一种情况:你在回测的时候调用了实时交易函数。回测环境里没有实时交易权限,也会报 4109。
Error 4051:Invalid Function Parameter Value(函数参数值无效)
某个函数的输入参数超出了合法范围。最常见的场景:
- iMA 之类的指标函数,周期参数填了 0 或负数
- ArrayResize 的大小参数是负数
- 字符串函数的起始位置超出了字符串长度
这种错误通常是变量没有正确初始化。比如你从外部输入读取了一个参数,用户填了 0,你没做检查就直接传给了指标函数。
养成习惯:所有外部输入都先做范围检查。
连接断了、超时了怎么办?
EA 跑着跑着突然不干活了,很可能是网络问题。
常见连接错误
- No connection:MT4 右下角显示"无连接",和服务器完全断开了
- Common error / Timeout:请求发出去了,但服务器没回应
- Too frequent requests:你的 EA 发请求太快,被服务器限流了
网络问题的排查步骤:
- 看 MT4 右下角的连接状态,有没有数据在传输
- 试试手动下一笔单,看能不能成交
- 换一个服务器地址试试(文件 → 登录 → 服务器列表)
- 检查你的 VPS 网络是否正常,ping 一下经纪商的服务器地址
如果你用 VPS 跑 EA,特别注意 VPS 的内存和 CPU 占用。MT4 吃的内存超过 VPS 上限,系统开始用虚拟内存,速度会断崖式下降,看起来就像"卡死了"。
Too frequent requests 这个报错要重视。有些 EA 每个 tick 都调用 OrderSend 或 OrderModify,一秒钟可能发几十个请求。经纪商的服务器会把你暂时屏蔽。解决办法是在交易操作之间加 Sleep,或者用计时器控制操作频率,比如最多每秒执行一次交易操作。
怎么看 Experts 和 Journal 标签页?
MT4 底部有两个关键标签页:Experts 和 Journal。很多人从来不看,出了问题才去翻,结果看不懂。
Experts 标签页
这里显示的是 EA 通过 Print() 函数输出的信息,以及 EA 运行时产生的错误。
关键信息怎么看:
- 红色文字 = 错误,必须处理
- 黄色文字 = 警告,最好关注
- 白色/灰色文字 = 普通日志
每一行的格式是:时间 + EA名称 + 品种 + 信息内容。
比如你看到这么一行:
2024.01.15 09:30:05 MyEA EURUSD,H1: OrderSend error 130
意思就是:1 月 15 日 9 点 30 分,MyEA 在 EURUSD H1 图表上发单失败,错误码 130。
Journal 标签页
这里记录的是 MT4 终端本身的操作日志,包括连接状态、登录信息、订单执行结果。
你能在这里看到:
- 什么时候连上/断开了服务器
- 每一笔订单的实际执行情况(成交价、手数、滑点)
- 终端的错误和警告
一个实用技巧:右键点击 Journal 区域,选"打开",可以直接跳转到日志文件所在的文件夹。日志文件是纯文本的,可以用搜索功能快速定位问题。
用日志定位问题的标准流程
- 记下出问题的大致时间
- 先看 Experts 标签页,有没有 EA 报错
- 再看 Journal 标签页,有没有连接中断或服务器错误
- 两边对照时间线,基本就能判断是 EA 的问题还是网络/服务器的问题
完整错误码速查表
这张表涵盖了你可能碰到的绝大部分错误码。收藏起来,出问题直接查。
服务器返回的错误(0-150 范围)
| 错误码 | 英文名称 | 中文说明 | 处理建议 |
|---|---|---|---|
| 0 | No error | 没有错误 | 操作成功 |
| 1 | No error but result unknown | 没有错误但结果未知 | 检查订单是否真的创建了 |
| 2 | Common error | 通用错误 | 重试,检查参数 |
| 3 | Invalid trade parameters | 交易参数无效 | 检查手数、价格、止损止盈 |
| 4 | Trade server is busy | 交易服务器忙 | 等几秒再重试 |
| 5 | Old version of client terminal | 终端版本太旧 | 更新 MT4/MT5 |
| 6 | No connection with trade server | 没有连接到交易服务器 | 检查网络 |
| 8 | Too frequent requests | 请求太频繁 | 降低请求频率 |
| 64 | Account disabled | 账户被禁用 | 联系经纪商 |
| 65 | Invalid account | 无效账户 | 检查账号密码 |
| 128 | Trade timeout | 交易超时 | 检查网络后重试 |
| 129 | Invalid price | 无效价格 | 刷新报价再下单 |
| 130 | Invalid stops | 无效止损/止盈 | 加大止损距离 |
| 131 | Invalid trade volume | 无效手数 | 调整为合规手数 |
| 132 | Market is closed | 市场已关闭 | 等开盘 |
| 133 | Trade is disabled | 交易被禁止 | 联系经纪商确认品种状态 |
| 134 | Not enough money | 资金不足 | 减小手数或入金 |
| 135 | Price changed | 价格已变动 | 刷新后重试 |
| 136 | Off quotes | 无报价 | 等待恢复报价 |
| 137 | Broker is busy | 经纪商服务器忙 | 等几秒重试 |
| 138 | Requote | 重新报价 | 增大滑点或重试 |
| 139 | Order is locked | 订单被锁定 | 等待解锁 |
| 141 | Too many requests | 请求过多 | 降低频率 |
| 145 | Modification denied | 不允许修改 | 检查是否太接近市价 |
| 146 | Trade context busy | 交易上下文忙 | 等待释放后重试 |
| 147 | Expiration denied | 不允许设置过期时间 | 去掉挂单过期参数 |
| 148 | Too many orders | 订单数量超限 | 关闭部分订单 |
| 149 | Hedge not allowed | 不允许对冲 | 检查账户类型 |
MQL 运行时错误(4000+ 范围)
| 错误码 | 英文名称 | 中文说明 | 处理建议 |
|---|---|---|---|
| 4000 | No error | 无错误 | 正常 |
| 4001 | Wrong function pointer | 错误的函数指针 | 检查代码逻辑 |
| 4002 | Array index out of range | 数组越界 | 检查数组大小 |
| 4051 | Invalid function parameter | 无效函数参数 | 检查参数范围 |
| 4052 | Internal error | 内部错误 | 重启终端 |
| 4055 | Custom indicator error | 自定义指标错误 | 检查指标是否正确安装 |
| 4059 | Function not allowed | 不允许调用该函数 | 检查是否在合适的上下文中调用 |
| 4062 | String parameter expected | 需要字符串参数 | 检查参数类型 |
| 4063 | Integer parameter expected | 需要整数参数 | 检查参数类型 |
| 4106 | Unknown symbol | 未知品种 | 检查品种名拼写 |
| 4107 | Invalid price parameter | 无效价格参数 | 用 Ask/Bid 刷新价格 |
| 4108 | Invalid ticket | 无效订单号 | 确认订单是否存在 |
| 4109 | Trade not allowed | 不允许交易 | 检查三个交易开关 |
| 4110 | Longs not allowed | 不允许做多 | 检查账户交易权限 |
| 4111 | Shorts not allowed | 不允许做空 | 检查账户交易权限 |
| 4200 | Object exists already | 图形对象已存在 | 先删除再创建 |
| 4202 | Object does not exist | 图形对象不存在 | 先检查再操作 |
调试 EA 的实用技巧
光知道错误码不够,还得会排查。这几个方法是我这些年用下来最有效的。
加打印日志,别猜
在关键位置加 Print() 语句,把变量值打印出来。比如下单前把价格、手数、止损止盈全打印一遍:
Print("准备下单: Price=", Ask, " Lots=", lots, " SL=", sl, " TP=", tp);
Print("StopLevel=", MarketInfo(Symbol(), MODE_STOPLEVEL));
Print("当前点差=", MarketInfo(Symbol(), MODE_SPREAD));
出错了直接看日志,一目了然。
用策略测试器复现问题
能在回测里复现的 bug,修起来快十倍。先在策略测试器里跑一遍,看看能不能重现错误。回测的日志和实盘的格式一样,排查方法也一样。
检查经纪商的交易条件
换了经纪商或者换了账户类型,EA 很容易出问题。重点检查:
- 最小手数和步长
- 止损距离限制
- 最大持仓数量
- 品种名称(有的经纪商叫 EURUSD,有的叫 EURUSD.pro,有的叫 EURUSDm)
- 报价位数(四位还是五位)
一次只改一个地方
排查的时候别一次改好几个参数。改一个,测一次,确认有没有效果。不然你都不知道到底是哪个改动解决了问题。
做好错误处理
好的 EA 不是不会出错,而是出错了能正确应对。每一个交易操作后面都应该有错误检查,每一个错误都应该记录日志。如果错误是可以重试的(比如 138、146),就自动重试。如果错误是致命的(比如 134 资金不足),就停止交易并发出告警。
常见问题
EA 回测正常但实盘报错是什么原因?
回测环境和实盘环境有很多不同。回测里没有网络延迟,没有 requote,不会出现交易上下文被占用的情况。最常见的原因是:实盘的止损距离限制比回测严格,实盘有点差扩大的情况,或者实盘的品种名称和回测用的历史数据不一致。先把 EA 挂模拟盘跑几天再上实盘,能避免大部分问题。
同一个 EA 在不同经纪商表现不一样怎么办?
每家经纪商的交易条件不同:最小手数、止损距离、最大订单数、品种名称、报价位数都可能有差异。好的 EA 应该在代码里动态获取这些参数,而不是写死固定值。用 MarketInfo 函数获取当前品种的实际参数,用 SymbolInfoInteger/SymbolInfoDouble(MT5)获取交易条件,这样换经纪商也不用改代码。
报错 "OrderSend Error 0" 是什么意思?
Error 0 的意思是"没有错误",但 OrderSend 确实返回了 -1。这种情况通常是你在错误的时机调用了 GetLastError()。GetLastError() 只返回最近一次错误,而且调用后会被重置。如果你在 OrderSend 和 GetLastError() 之间调用了其他函数,错误码可能已经被覆盖了。解决办法:OrderSend 返回 -1 后,立刻调用 GetLastError(),中间不要插入任何其他操作。
MT4 和 MT5 的错误码一样吗?
不完全一样。服务器返回的错误码(0-150 范围)基本一致,但 MQL 运行时错误在 MT5 里有较大变化。MT5 用了新的错误码体系,函数名也不同(比如 OrderSend 的参数结构完全变了)。如果你在做 MT4 到 MT5 的迁移,错误处理部分需要重写,不能简单复制。
怎么让 EA 在出错时自动通知我?
MT4/MT5 支持推送通知和邮件告警。在 EA 的错误处理代码里加上 SendNotification() 或 SendMail() 函数就行。比如检测到 Error 134(资金不足),立刻推送一条消息到你手机上。设置方法:工具 → 选项 → 通知,填入你的 MetaQuotes ID。邮件通知在"邮箱"标签页配置 SMTP 信息。
EA 报错不可怕,可怕的是不知道错在哪、不知道怎么查。把这篇指南收藏好,下次碰到问题先查错误码表,再看 Experts 日志,八成的问题你自己就能解决。如果你想找更多 EA 工具和外汇交易资源,可以看看 FXTool 上的工具合集。