彻底解决 Market closed(10018 / 错误132)
目录
- Market closed 是什么(10018 与 132 的区别)
- ① TRADE_RETCODE_MARKET_CLOSED = 10018(MT5 / `OrderSend()` 的返回代码)
- ② ERR_MARKET_CLOSED = 132(MT4 / MQL4 的 `GetLastError()`)
- 先用30秒排查
- 成因与对策(6种情况)
- ① 周末或节假日导致整体市场关闭
- ② 品种独有的交易时段之外(每日休市)
- ③ 服务器时间与本地时间混淆
- ④ 品种被设为禁止交易/仅可平仓(SYMBOL_TRADE_MODE)
- ⑤ 周一开盘后或休市结束后的瞬间
- ⑥ 因新闻或重大事件导致的交易暂停
- 用MQL5防范该错误的代码(面向EA开发者)
- 确认是否处于交易时段内
- 确认交易模式(SYMBOL_TRADE_MODE)
- 整合为下单前的统一检查
- 即便如此仍返回10018时的处理
- 优先级检查清单
- 总结
- 常见问题
- Q: 明明是工作日白天,却出现 Market closed。这是为什么?
- Q: 10018 与 132 有什么区别?
- Q: EA在周末持续报错。放着不管可以吗?
- Q: 加密货币(BTCUSD)也出现了 Market closed。它不是应该24小时可交易吗?
彻底解决 Market closed(MT5/MQL5)
当EA日志中出现 Market closed 或 market is closed 时,只有一半的情况能用"周末很正常"来解释。明明是工作日白天却报错,或者其他品种能正常下单,唯独某个品种报错——被这类问题困扰的人非常多。
原因并不仅限于"周末",还包括各品种独有的交易时段(黄金、股指等的每日休市)、经纪商服务器时间与本地时间的偏差、品种交易模式限制(close-only 等)等多种因素。本文面向所有在MT5上使用EA、以及用MQL5编写EA的人,全面梳理 Market closed 的本质、6种成因、30秒排查法,以及代码层面的永久防范措施。关于错误代码的完整列表,请参阅 MQL5 / MT5 错误代码应对方法全指南。
本文以2026年7月时的MT5(build 4xxx系列)为准。交易时段与界面名称可能因经纪商和版本不同而有所差异。
Market closed 是什么(10018 与 132 的区别)
表示"市场已关闭"的代码,在MT5与MT4(MQL4)中是不同的。请根据你使用的平台以及获取该值的位置来对应理解。
① TRADE_RETCODE_MARKET_CLOSED = 10018(MT5 / OrderSend() 的返回代码)
在MQL5中下单后,OrderSend() 的结果会存入 MqlTradeResult.retcode。当交易服务器判定"该品种当前不在交易时间内"并拒绝下单时,返回的代码就是 10018。这并非MT5内部错误,而是来自经纪商服务器的拒绝通知。
含义: 市场已关闭(Market is closed)
常量: TRADE_RETCODE_MARKET_CLOSED
值 : 10018
// 日志中常见的典型输出示例
2026.07.06 23:05:11.204 EA_NAME XAUUSD,M5: OrderSend error 10018 [Market closed]
② ERR_MARKET_CLOSED = 132(MT4 / MQL4 的 GetLastError())
在MT4(MQL4)中,OrderSend() 失败后调用 GetLastError() 会返回 132。含义与10018相同,都是"市场关闭中"。如果同时使用MT4版本的EA,同一个原因会在MT5中表现为10018,在MT4中表现为132。
含义: 市场已关闭(Market is closed)
常量: ERR_MARKET_CLOSED(MQL4)
值 : 132
实际使用中的区分方式:
| 平台 | 获取来源 | 值 |
|---|---|---|
| MT5 (MQL5) | MqlTradeResult.retcode / CTrade.ResultRetcode() | 10018 |
| MT4 (MQL4) | OrderSend() 失败后的 GetLastError() | 132 |
两者的根本原因是一致的:"在服务器交易时段之外发送了订单(或该品种的交易受到限制)"。应对方法也是通用的,下文将统一讲解。
先用30秒排查
在盲目重启EA之前,看这4点就能大致锁定原因。
- 查看品种的交易时段 — 在市场报价(Market Watch)中右键点击对应品种 → "规格(Specification)"→ "交易时段"。上面会列出按星期划分的可交易时间(服务器时间)。如果当前时间不在这个范围内,那就是答案。
- 确认服务器时间 — 市场报价窗口上方显示的时间即为经纪商的服务器时间。交易时段的判定依据不是你电脑的时钟,而是这个时间。它通常与日本时间相差数小时,与中国时间同样存在时差。
- 确认交易模式 — 在同一"规格"界面的"交易"栏中,检查是否不是
Full access(例如显示Disabled/Close only等)。若是,即便在交易时段内,新开仓也会被拒绝。 - 换一个品种试试 — 如果EURUSD等主要外汇货币对能正常执行同一EA/手动下单,就可以确定问题不在账户或EA本身,而是集中在该品种的交易时段/限制上。
成因与对策(6种情况)
① 周末或节假日导致整体市场关闭
症状: 周六、周日,或元旦、圣诞节等时段出现报错。所有品种都会出现。
原因: 外汇市场大致在服务器时间的周五收盘至周一开盘之间无法交易。节假日(元旦、圣诞节等)即使是工作日,也可能休市或缩短交易时间。如果EA因K线残留处理或时间周期原因,在周末仍尝试下单,就会连续出现10018/132。
对策:
- 该错误本身无害,市场开盘后会自然消失
- 若不想让日志变乱,可在EA中加入星期/时段检查,从源头上不发送订单(代码见下文)
- 由于各经纪商的节假日日历不同,请务必查看经纪商公布的休市安排
② 品种独有的交易时段之外(每日休市)
症状: 明明是工作日,但特定品种(黄金、白银、股指CFD、能源等)报错。且几乎每天在同一时段出现。
原因: 外汇货币对在工作日基本可实现近24小时交易,但贵金属和股指CFD每天都有数十分钟至数小时的交易休止时间(每日休市)。这通常与标的资产交易所的维护或展期安排有关,具体时段因经纪商和品种而异。若EA在此休市时段下单,就会返回10018。
对策:
- 在"规格 → 交易时段"中确认该品种准确的休市时间段(这里显示的时间才是唯一正确答案,切勿轻信他人博客上的时间——不同经纪商各不相同)
- 通过EA的时间过滤器(
TradeStartHour/TradeEndHour等)规避休市时段 - 开发者可在代码中通过
SymbolInfoSessionTrade()查询(详见下文)
另外,部分经纪商支持加密货币(BTCUSD等)在周末交易,但这同样取决于经纪商。请勿想当然地认为"加密货币应该是24/7交易",务必在规格界面中确认。
③ 服务器时间与本地时间混淆
症状: "规格中显示的交易时段明明是可交易时间"却仍然报错。使用海外经纪商时较为常见。
原因: 无论是规格中显示的交易时段,还是MT5内的时间显示,全部都是经纪商的服务器时间。许多海外经纪商采用GMT+2/+3(以纽约收盘作为0点的设定),与中国时间相差6~8小时左右。用中国时间看"还是周五晚上",但按服务器时间可能早已是周六,这是典型的偏差场景。
对策:
- 养成以市场报价窗口显示的时间(=服务器时间)为基准思考的习惯
- EA的参数(交易时间过滤器等)通常都是按服务器时间设定的规范。请检查自己是否误以为按本地时间设置
- 代码中应使用
TimeTradeServer()(不要用TimeLocal()来判定交易时段)
④ 品种被设为禁止交易/仅可平仓(SYMBOL_TRADE_MODE)
症状: 明明在交易时段内、又是工作日,但特定品种的新开仓全部被拒绝。有时平仓操作仍可执行。
原因: 经纪商可以按品种单独设置交易模式。
| SYMBOL_TRADE_MODE | 含义 |
|---|---|
SYMBOL_TRADE_MODE_FULL | 无限制(正常状态) |
SYMBOL_TRADE_MODE_CLOSEONLY | 仅可平仓(禁止新开仓)。常见于即将下市或临近合约到期的CFD |
SYMBOL_TRADE_MODE_DISABLED | 完全禁止交易 |
SYMBOL_TRADE_MODE_LONGONLY / SHORTONLY | 仅可做多/仅可做空 |
模拟账户与实盘账户的设置可能不同,账户类型不同,可交易品种也可能不同。
对策:
- 查看"规格"界面中"交易"栏的设置
- 若为
Close only,应放弃新开仓,转而整理现有持仓。如需长期使用该品种,可查看是否存在同名不同到期月份、或不同后缀的替代品种(如US500.f等) - 若持续显示
Disabled,请向经纪商确认该账户类型下是否可交易该品种
⑤ 周一开盘后或休市结束后的瞬间
症状: 仅在周一市场开盘后的最初几分钟,或每日休市结束后的瞬间,出现报错或成交被拒。
原因: 从交易时段"开启"的那一刻到实际能够稳定成交之间,存在一个过渡期。开盘瞬间往往流动性稀薄、点差极端扩大,部分经纪商在报价开始正常流转之前会暂不接受订单(即按市场关闭处理并拒绝)。在周一开盘第一时间发出信号的EA、以及瞄准休市结束后突破行情的黄金EA,都容易碰到这个问题。
对策:
- 设置开盘后N分钟内暂不新开仓的过滤条件(如
AvoidMondayOpen)。本站提供的EA默认会规避周一0-3点(服务器时间)正是出于这个原因 - 务必同时配合使用点差过滤器(
MaxSpread)。开盘瞬间异常点差下的成交,其造成的损失往往比报错本身更痛 - 出现10018时不要立即重试,而应设计为等待至下一根K线
⑥ 因新闻或重大事件导致的交易暂停
症状: 在重要经济数据公布前后,或个别品种出现异常波动时,暂时出现报错。
原因: 部分经纪商或品种在重大事件发生时,会临时暂停交易(熔断)或限制新开仓。股指CFD有时会随标的市场的熔断机制联动暂停。此期间的订单会被作为市场关闭类型拒绝。
对策:
- 属于临时性问题,过一段时间即可恢复
- 使用经济数据过滤器(本站EA的
UseEconomicFilter)在数据公布前后暂停新开仓,可同时规避报错风险与剧烈波动风险
用MQL5防范该错误的代码(面向EA开发者)
Market closed 不应"出错后再处理",而应在下单前先确认交易时段与交易模式,若市场关闭则不发送订单,这才是正确的设计思路。这样不仅能让日志更清晰,还能避免无谓的服务器请求与失控重试。
确认是否处于交易时段内
SymbolInfoSessionTrade() 会返回指定星期第 i 个交易时段的开始/结束时间(以服务器时间0点为起点的秒数)。为兼容存在多个时段的品种(如包含每日休市的指数),需要用循环遍历所有时段。
// 判断当前服务器时间是否处于该品种的交易时段内
bool IsTradeSessionOpen(const string symbol)
{
MqlDateTime dt;
TimeToStruct(TimeTradeServer(), dt); // 必须以服务器时间为准判定
int now = dt.hour*3600 + dt.min*60 + dt.sec; // 从0点起的经过秒数
datetime from, to;
for(uint i = 0; SymbolInfoSessionTrade(symbol, (ENUM_DAY_OF_WEEK)dt.day_of_week, i, from, to); i++)
{
int f = (int)from; // 从0点起的秒数
int t = (int)to; // 24:00结束时为 86400
if(now >= f && now < t)
return true;
}
return false; // 当天无对应时段(如周末)或不在任何时段内
}
确认交易模式(SYMBOL_TRADE_MODE)
// 判断当前交易模式是否允许新开仓
bool IsNewEntryAllowed(const string symbol, ENUM_ORDER_TYPE type)
{
long mode = SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE);
if(mode == SYMBOL_TRADE_MODE_DISABLED) return false; // 禁止交易
if(mode == SYMBOL_TRADE_MODE_CLOSEONLY) return false; // 仅可平仓=禁止新开仓
if(mode == SYMBOL_TRADE_MODE_LONGONLY && type != ORDER_TYPE_BUY) return false;
if(mode == SYMBOL_TRADE_MODE_SHORTONLY && type != ORDER_TYPE_SELL) return false;
return true; // SYMBOL_TRADE_MODE_FULL 等情况
}
整合为下单前的统一检查
// OnTick 内: 即使信号成立,只要市场关闭就不发送订单
if(!IsTradeSessionOpen(_Symbol) || !IsNewEntryAllowed(_Symbol, ORDER_TYPE_BUY))
{
// 提前防止10018。只留一行日志,等待下一根K线
return;
}
即便如此仍返回10018时的处理
由于交易时段信息的更新时机、开盘瞬间的拒绝等原因,总有极少数情况会绕过前置检查。查看 OrderSend() 的retcode,对于10018绝不立即重试(应等待至下一根K线),这是铁律。在市场关闭期间连续重试,只会让日志变乱,没有任何实际改善。
MqlTradeRequest req; MqlTradeResult res;
ZeroMemory(req); ZeroMemory(res);
// ... 构建 req ...
if(!OrderSend(req, res) || res.retcode != TRADE_RETCODE_DONE)
{
if(res.retcode == TRADE_RETCODE_MARKET_CLOSED) // 10018
Print("Market closed. Skip and wait for the next session.");
else
PrintFormat("OrderSend failed: retcode=%d, lastError=%d", res.retcode, GetLastError());
}
坦白说,在周一开盘瞬间或每日休市前后(尤其是黄金、股指)下单的EA,会经常性地遇到这个错误。具备时间调度意识的EA——包含时段确认、开盘瞬间暂缓、周末前平仓等机制——不仅能避免无谓的报错,还能规避流动性稀薄时段的糟糕成交。FXEA365提供的EA标准搭载了**周一开盘规避(AvoidMondayOpen)、时间过滤器、周末前平仓(CloseAllBeforeWeekend)**等功能。
优先级检查清单
| 优先级 | 检查项 | 对策 |
|---|---|---|
| 🚨 首先 | 当前是否为周末/节假日(以服务器时间为准) | 只需等待。该错误本身无害 |
| 🚨 首先 | 是否在规格中"交易时段"的范围内 | 用时间过滤器规避该品种的休市时段 |
| ⚠️ 其次 | 是否混淆了服务器时间与本地时间 | 以市场报价显示的时间为基准重新设置 |
| ⚠️ 其次 | 交易模式是否为 Full access | 若为 Close only / Disabled,请确认经纪商规范 |
| ✅ 确认 | 是否处于开盘瞬间/休市结束瞬间 | 暂缓N分钟+点差过滤器 |
| 🛠 开发 | 下单前是否已确认交易时段/模式 | 实现 SymbolInfoSessionTrade 前置检查 |
总结
Market closed在MT5中为10018(TRADE_RETCODE_MARKET_CLOSED),在MT4中为132(ERR_MARKET_CLOSED)。含义相同,都是"在交易时段之外/交易受限期间发出的订单"。- 不仅限于周末,品种独有的每日休市(黄金、指数)、服务器时间偏差、SYMBOL_TRADE_MODE限制、开盘瞬间的拒绝同样会触发该错误。若在工作日出现,请先查看"规格 → 交易时段"。
- 交易时段因经纪商和品种而异。只有你MT5规格界面中显示的时间才是正确答案。
- EA开发者应通过
SymbolInfoSessionTrade()+SYMBOL_TRADE_MODE+TimeTradeServer()构建下单前检查,实现永久防范。返回10018时不要立即重试,应等待至下一根K线。
关于错误代码的完整列表,请参阅 MQL5 / MT5 错误代码应对方法全指南;标准搭载时段规避与时间过滤器的免费EA,请参阅 EA一览。
常见问题
Q: 明明是工作日白天,却出现 Market closed。这是为什么?
原因通常是该品种独有的交易休止时段(每日休市),或品种交易模式受限。黄金、白银、股指CFD即使在工作日也存在每天固定的不可交易时段。请在市场报价中右键点击该品种 → "规格"→ 确认"交易时段"和"交易"栏。
Q: 10018 与 132 有什么区别?
两者含义相同,只是平台不同。10018(TRADE_RETCODE_MARKET_CLOSED)是MT5中 OrderSend() 的返回代码,132(ERR_MARKET_CLOSED)是MT4(MQL4)中 GetLastError() 的返回值。应对方法是通用的。
Q: EA在周末持续报错。放着不管可以吗?
不会造成实际损害,市场开盘后会自然停止。但如果日志变乱、或推送通知持续不断让人在意,根本对策是在EA中加入星期/时段检查,直接跳过下单动作(详见正文代码)。
Q: 加密货币(BTCUSD)也出现了 Market closed。它不是应该24小时可交易吗?
加密货币CFD在周末是否可交易取决于经纪商。部分经纪商会在周末暂停交易,或设有短暂的维护休市时段。与外汇货币对一样,请通过"规格 → 交易时段"确认你所用经纪商的实际可交易时间。
相关文章
📧 涨价预告 + 免费5天邮件课程
所有EA目前均为首发价,并将随销量阶梯式上调。在每次涨价前收到通知,另有每日一封邮件:自动交易本质、正确解读回测、券商选择技巧。
※ 严格保护隐私。可随时取消订阅。