彻底解决Unsupported filling mode(MT5错误10030)
目录
- 什么是10030(TRADE_RETCODE_INVALID_FILL)
- 填单方式(type_filling)的四种类型
- 为什么会"不合法"——SYMBOL_FILLING_MODE
- 为什么偏偏在"更换经纪商当天"出现
- 与执行模式(SYMBOL_TRADE_EXEMODE)的关系
- 先用30秒完成初步排查
- ① 查看品种的允许方式(MT5界面)
- ② 查看EA的输入参数
- ③ 用代码确认(面向开发者)
- 根治方案——读取允许标志位自动选择的MQL5代码
- 自动判断函数
- 在OrderSend中的用法
- 使用CTrade的情况
- 使用限价单(BOC)时的注意事项
- 关于经纪商的注意事项(更换时需重新确认)
- 优先级检查清单
- 总结
- 常见问题
- Q: 昨天还能正常运行的EA,换了经纪商之后完全无法下单,一直报10030,是EA坏了吗?
- Q: FOK和IOC应该用哪个?
- Q: 回测中不出现,但实盘账户却报10030,这是为什么?
- Q: 同一家经纪商,为什么有的品种报10030,有的不报?
- Q: 无法修改EA代码(只持有.ex5文件),该怎么办?
彻底解决Unsupported filling mode(MT5错误10030)
昨天还在别的经纪商正常运行的EA,一转到新账户,Expert标签页里就接连出现 Unsupported filling mode 或 OrderSend error 10030,导致一笔订单都下不出去——这是MT5使用EA时更换经纪商最常见的典型故障之一。这并不代表EA坏了,也不代表账户有问题。问题仅仅在于:订单指定的"填单方式(filling mode)"在新经纪商的该品种上不被允许而已。
本文面向使用MT5运行EA的交易者,以及用MQL5编写EA的开发者,将TRADE_RETCODE_INVALID_FILL(10030)的真相、FOK/IOC/RETURN的含义、30秒即可完成的排查方法,以及代码层面的根治方案一次性整理清楚。关于错误代码的完整列表,请参阅MQL5 / MT5 错误代码处理综合指南。
本文以2026年7月时点的MT5(build 4xxx系列)为前提。界面名称与表述可能因经纪商或版本略有差异。
什么是10030(TRADE_RETCODE_INVALID_FILL)
OrderSend() 的执行结果会写入 MqlTradeResult.retcode。其中返回的 10030 = TRADE_RETCODE_INVALID_FILL,是服务器端的拒绝通知,意思是"请求中指定的 type_filling(填单方式)在该品种上不被允许"。
含义: 指定的填单方式(filling type)不被支持
常量: TRADE_RETCODE_INVALID_FILL
值 : 10030
显示: Unsupported filling mode / Invalid order filling type
// 日志中常见的典型输出示例
2026.07.07 09:15:32.441 EA_NAME EURUSD,M15: OrderSend error 10030
2026.07.07 09:15:32.441 EA_NAME EURUSD,M15: failed market buy 0.10 EURUSD [Unsupported filling mode]
关键点在于,这与资金、手数、价格完全无关。10030仅仅是请求中 MqlTradeRequest.type_filling 这一个字段的问题,只要修正它,同一笔订单就能顺利通过。
填单方式(type_filling)的四种类型
MQL5的 ENUM_ORDER_TYPE_FILLING 中共有4个取值。
| 常量 | 通称 | 含义 |
|---|---|---|
ORDER_FILLING_FOK | Fill or Kill | 仅在能全部成交时才执行。若1手订单只有0.7手的流动性,则整笔订单取消 |
ORDER_FILLING_IOC | Immediate or Cancel | 能成交多少就立即成交多少,剩余部分取消。0.7手成交,0.3手作废 |
ORDER_FILLING_RETURN | Return | 执行可成交的部分,剩余数量作为挂单留在盘口(等待后续成交)。多用于交易所式执行 |
ORDER_FILLING_BOC | Book or Cancel | 仅在能挂入盘口(被动等待成交)时才接受,若价格会立即成交则拒绝。专用于限价/止损限价单(较新版本中新增) |
在常见的外汇EA中,实际使用的几乎都是FOK或IOC。RETURN主要用于股票、期货等交易所式执行(Exchange execution),BOC则是需要强制挂单(Maker)的特殊用途。
为什么会"不合法"——SYMBOL_FILLING_MODE
接受哪种填单方式,是由经纪商针对每个品种设置的标志位(SYMBOL_FILLING_MODE)决定的。可在MQL5中这样读取:
long flags = SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);
// 若 SYMBOL_FILLING_FOK 标志位置1,则允许 FOK
// 若 SYMBOL_FILLING_IOC 标志位置1,则允许 IOC
SYMBOL_FILLING_MODE 是位标志,包含FOK和IOC的允许情况(若两者都允许,则两个标志位都会置1)。RETURN不包含在此标志位中,能否使用取决于该品种的执行模式(后文详述)。
也就是说,10030的成因非常简单:
EA发送的 type_filling ∉ 该品种允许的填单方式 → 10030
仅此而已。
为什么偏偏在"更换经纪商当天"出现
10030之所以被称为"更换经纪商的经典错误",原因如下:
- 允许的填单方式因经纪商、品种而异。 有的经纪商对外汇品种只允许FOK,有的只允许IOC,还有的两者都允许。即便在同一经纪商内,外汇与CFD、股票之间的设置也常常不同。
- 许多EA将type_filling写死在代码中。 例如写有
request.type_filling = ORDER_FILLING_FOK;的EA,在允许FOK的经纪商A上可以运行多年而毫无问题。由于在作者的环境中一直正常运行,这个问题往往不会被当作bug识别出来。 - 一旦转移到不允许FOK的经纪商B,从第一笔下单开始就全部失败。 由于策略测试器的成交处理往往比真实服务器宽松,这个问题在回测中常常不会暴露,而是恰好在转到实盘账户当天才显现出来。
也就是说,10030与其说是EA的bug,不如说是"对运行环境的想当然假设"被暴露了出来。反过来说,只要改为读取品种的允许标志位并动态选择填单方式,EA就能在任何经纪商上正常运行(具体代码见后文)。
与执行模式(SYMBOL_TRADE_EXEMODE)的关系
除填单方式外,品种还有执行模式这一属性,它会影响哪种填单方式真正有意义。
| 执行模式 | 常量 | 典型场景 | 填单方式倾向 |
|---|---|---|---|
| Instant | SYMBOL_TRADE_EXECUTION_INSTANT | 部分外汇品种(多见于做市商模式) | 按指定价格执行。FOK/IOC与拒price(requote)并存 |
| Market | SYMBOL_TRADE_EXECUTION_MARKET | 多数外汇/CFD(无交易台模式) | 市价执行。FOK或IOC(取决于经纪商设置) |
| Exchange | SYMBOL_TRADE_EXECUTION_EXCHANGE | 股票、期货 | 挂入盘口执行。以RETURN为基本方式 |
| Request | SYMBOL_TRADE_EXECUTION_REQUEST | 遗留模式 | 请求式执行(目前罕见) |
严格来说,具体允许哪种组合取决于经纪商的服务器设置,但实务上只需记住"外汇/CFD的Market执行通常是FOK或IOC,交易所式品种则以RETURN为前提"即可。执行模式也可以通过 SymbolInfoInteger(_Symbol, SYMBOL_TRADE_EXEMODE) 确认。
先用30秒完成初步排查
① 查看品种的允许方式(MT5界面)
打开**"市场报价" → 右键点击品种 → 规格(Specification),查看"填充"(Filling)**这一行。会显示 Fill or Kill / Immediate or Cancel 或两者皆有。若EA发送的方式没有出现在这里,即可确定是10030问题。
② 查看EA的输入参数
设计良好的EA通常会提供 FillingType / Filling Mode 之类的输入参数。如果有,只需按①中确认的允许方式进行修改即可解决问题(无需改代码)。
③ 用代码确认(面向开发者)
long flags = SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);
PrintFormat("%s filling: FOK=%s IOC=%s exemode=%d",
_Symbol,
((flags & SYMBOL_FILLING_FOK) != 0) ? "yes" : "no",
((flags & SYMBOL_FILLING_IOC) != 0) ? "yes" : "no",
(int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_EXEMODE));
用脚本执行以上代码,即可在一行输出中看到该经纪商、该品种的实际允许情况。
根治方案——读取允许标志位自动选择的MQL5代码
10030的正确解决方式并非"每次更换经纪商都手动调整",而是让EA自身读取品种的允许标志位并自动选择填单方式。以下是可以直接使用的标准实现。
自动判断函数
// 返回该品种实际允许的填单方式
// 优先级: FOK → IOC → RETURN(交易所式的兜底方案)
ENUM_ORDER_TYPE_FILLING GetFillingMode(const string symbol)
{
long flags = SymbolInfoInteger(symbol, SYMBOL_FILLING_MODE);
if((flags & SYMBOL_FILLING_FOK) != 0)
return ORDER_FILLING_FOK; // 仅在能全部成交时执行(不产生部分成交)
if((flags & SYMBOL_FILLING_IOC) != 0)
return ORDER_FILLING_IOC; // 能成交多少就执行多少,剩余取消
return ORDER_FILLING_RETURN; // 无标志位 = 交易所式等情况,使用RETURN发送
}
在OrderSend中的用法
MqlTradeRequest req; MqlTradeResult res;
ZeroMemory(req); ZeroMemory(res);
req.action = TRADE_ACTION_DEAL;
req.symbol = _Symbol;
req.volume = lots;
req.type = ORDER_TYPE_BUY;
req.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
req.deviation = 20;
req.magic = MagicNumber;
req.type_filling = GetFillingMode(_Symbol); // ← 不再写死
if(!OrderSend(req, res) || res.retcode != TRADE_RETCODE_DONE)
{
if(res.retcode == TRADE_RETCODE_INVALID_FILL) // 10030
PrintFormat("Unsupported filling mode: sent=%d, allowed flags=%d",
(int)req.type_filling,
(int)SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE));
else
PrintFormat("OrderSend failed: retcode=%d", res.retcode);
}
这样一来,无论是仅支持FOK的经纪商,还是仅支持IOC的经纪商,同一份程序都能正常运行,不再需要每次更换经纪商都手动调整。
使用CTrade的情况
标准库中的 CTrade 提供了 SetTypeFillingBySymbol(),可根据品种的允许标志位自动设置填单方式。
#include <Trade/Trade.mqh>
CTrade trade;
int OnInit()
{
trade.SetExpertMagicNumber(MagicNumber);
trade.SetTypeFillingBySymbol(_Symbol); // 读取允许标志位并自动设置
return INIT_SUCCEEDED;
}
如果EA是因为旧式写法 trade.SetTypeFilling(ORDER_FILLING_FOK);(写死指定)而出现10030,只需替换为这一行即可解决。若想手动指定,也可以将前述 GetFillingMode() 的返回值传给 SetTypeFilling(),效果相同。
使用限价单(BOC)时的注意事项
ORDER_FILLING_BOC(Book or Cancel)专用于限价单、止损限价单,若指定的价格会立即成交,则会被拒绝。将其用于市价单是错误用法,市价类EA无需将BOC纳入选项。
关于经纪商的注意事项(更换时需重新确认)
- 填单方式的允许设置不仅因经纪商而异,即使在同一经纪商内,也会因品种(品种分组)不同而不同。 外汇允许IOC,而股票CFD仅允许RETURN,这种配置很常见。
- 账户类型或服务器变更也可能导致设置发生变化。 不仅是更换经纪商,在同一经纪商内的服务器迁移、账户类型变更、品种规格修订后,也可能突然出现10030。
- 因此,作为运维规则,建议养成"只要账户、服务器、品种中任一项发生变化,就在规格界面(或脚本中)重新确认填单方式"的习惯,这样更为稳妥。若EA已内置自动判断代码,则这项确认本身也就不再需要了。
由于特定经纪商"该品种仅支持FOK"之类的信息会随服务器设置变更而过时,本文不做具体列举。请务必以自己账户的品种规格为准进行确认。
优先级检查清单
| 优先级 | 确认事项 | 处理方法 |
|---|---|---|
| 🚨 首先 | 品种规格中的"填充"一栏与EA指定的方式是否一致 | 改为使用允许的方式 |
| 🚨 首先 | EA是否有FillingType输入参数 | 仅需修改参数即可解决(无需改代码) |
| ⚠️ 其次 | EA代码中type_filling是否被写死 | 替换为GetFillingMode() / SetTypeFillingBySymbol() |
| ⚠️ 其次 | 是否更换过经纪商、服务器、账户类型 | 变更后务必重新确认规格 |
| ✅ 确认 | 执行模式(Instant/Market/Exchange)的差异 | 交易所式品种以RETURN为前提 |
| 🛠 开发 | 是否针对10030的retcode进行了单独处理 | 记录发送的方式与允许标志位的日志 |
总结
Unsupported filling mode(10030 / TRADE_RETCODE_INVALID_FILL)是当订单的type_filling(FOK / IOC / RETURN / BOC)在该品种上不被允许时,服务器发出的拒绝通知,与资金或手数无关。- 由于允许的方式因经纪商、品种而异,将type_filling写死的EA会在更换经纪商当天集中出现10030,这是该错误的典型模式。
- 用户只需"查看品种规格的填充栏 → 修改EA的输入参数"即可立即解决。开发者则可以通过读取
SymbolInfoInteger(SYMBOL_FILLING_MODE)的标志位自动选择(或使用CTrade::SetTypeFillingBySymbol())来实现根治。
关于错误代码的完整内容,请参阅MQL5 / MT5 错误代码处理综合指南。FXEA365提供的EA均已实现填单方式的自动判断,无论使用哪家经纪商都能正常运行(EA一览)。
常见问题
Q: 昨天还能正常运行的EA,换了经纪商之后完全无法下单,一直报10030,是EA坏了吗?
并非EA故障。只是EA指定的填单方式(例如FOK)在新经纪商的该品种上不被允许而已。请确认品种规格中的"填充"一栏,调整EA的输入参数(如FillingType),或将代码改为自动判断方式,即可恢复正常运行。
Q: FOK和IOC应该用哪个?
如果品种两者都允许,两者的差异主要体现在"流动性不足时"。FOK在无法全部成交时会取消整笔订单(不会产生仓位不完整的情况),IOC则只持有能成交的部分(可能产生部分成交)。对于个人外汇交易的手数规模而言,流动性不足本身较为少见,实际使用中两者差别不大。像自动判断代码那样以FOK优先并无问题。
Q: 回测中不出现,但实盘账户却报10030,这是为什么?
策略测试器的成交处理无法完全还原真实服务器的设置,因此type_filling不匹配的问题有时不会在测试中暴露出来。建议在实盘或模拟账户首次运行时,先核对品种规格中的填充栏。
Q: 同一家经纪商,为什么有的品种报10030,有的不报?
这是正常(可能出现)的现象。填单方式的允许设置是按品种单独配置的,因此外汇货币对允许IOC、股票CFD仅允许RETURN这类差异,会因品种分组而不同。多品种EA务必针对每个品种分别读取 SYMBOL_FILLING_MODE。
Q: 无法修改EA代码(只持有.ex5文件),该怎么办?
请先确认EA的输入参数中是否有FillingType相关选项。如果没有,说明该EA在当前经纪商的该品种上无法使用。可以联系作者请求支持,或者改用允许该EA所依赖的填单方式的经纪商/账户类型进行运营。
相关文章
📧 涨价预告 + 免费5天邮件课程
所有EA目前均为首发价,并将随销量阶梯式上调。在每次涨价前收到通知,另有每日一封邮件:自动交易本质、正确解读回测、券商选择技巧。
※ 严格保护隐私。可随时取消订阅。