一句话答案 :MT5 的 EA 跑在沙箱里,没有 HTTP 服务、没有 IPC,但它能读写
MQL5/Files/------这就够了。用三个约定文件就能实现完整的"外部程序 ↔ EA"双向通信:<EA>_config.set(外部写参数,EA 轮询热更新,不用重启)、<EA>_runtime.json(EA 写状态心跳,外部读)、<EA>_reload.trigger(外部触发 EA 重载) 。开源项目 EasyDeal 的 GMarket.mq5 内置全套实现,本文给出协议细节和三个实战大坑。
为什么需要这个协议
典型场景:你想从桌面程序 / Python 脚本 / AI Agent 改一只正在跑的 EA 的参数(比如把马丁上限从 5 层降到 3 层)。常规做法是图表上右键 → 属性 → 改 → 确定 ------ 手动、不可编程、还会触发 EA 重新 OnInit。而 DLL 方案要关安全开关,WebRequest 方案要 EA 主动外联且配白名单。
文件协议没有这些问题:MQL5 原生允许读写 <数据目录>/MQL5/Files/,外部程序也能直接操作这个目录------它就是天然的共享信箱。
协议三件套
① <EA>_config.set --- 参数热更新(外部写,EA 读)
外部程序把要覆盖的参数按 key=value 一行一个写进去:
InpMaxMartinLevel=3
InpMartinBreakevenProfit=50
InpIsPaused=false
EA 侧在 OnInit 末尾 EventSetTimer(3),然后 OnTimer() 里轮询:
bool ReloadRuntimeConfig(bool forceApply)
{
string filename = MQLInfoString(MQL_PROGRAM_NAME) + "_config.set";
if (!FileIsExist(filename)) return false;
// 用文件 mtime 守卫: 没变化就不重复读盘/重复应用
datetime mtime = (datetime)FileGetInteger(filename, FILE_MODIFY_DATE);
if (!forceApply && mtime == g_lastConfigMtime) return false;
// ... FileOpen → 逐行解析 key=value → 赋给运行时变量 ...
}
要点:input 变量本身不可写 ,解析后赋给同名运行时变量(或 static 缓存),策略逻辑读运行时变量。这样参数生效不触发 OnInit、持仓和内部状态全保留------这才叫热更新。
② <EA>_runtime.json --- 状态心跳(EA 写,外部读)
EA 定期(以及每次参数应用后)把"我是谁、我活着、我当前真实参数"写出去:
{
"ea_name": "GMarket_easydeal版",
"updated_at": "2026.06.12 10:30:00",
"config_applied_at": "2026.06.12 09:00:00",
"magic": 999,
"params": { "InpMaxMartinLevel": 3, "...": "..." }
}
外部程序看 updated_at / 文件 mtime 就知道 EA 是否存活(挂没挂、卡没卡),看 params 就知道覆盖后的真实参数 ------ 比读源码默认值可靠得多。
③ <EA>_reload.trigger --- 远程触发(外部写,EA 读后自毁)
外部写一个含时间戳的小文件,EA 轮询到就执行约定动作(比如 ChartSetSymbolPeriod 触发图表重载,让新编译的 .ex5 生效),然后删掉文件。一次性信号,幂等。
三个实战大坑(每个都踩过)
坑 1:文件名永远用 MQL_PROGRAM_NAME 拼,绝不硬编码。 我们真实事故:GMarket.mq5 复制改名成 GMarket_easydeal版.mq5 后,里面硬编码的 "GMarket_runtime.json" 跟着复制过去了------新 EA 的心跳全部冒名顶替写进老 EA 的档案,监控面板把新 EA 的运行时长、统计全记到老 EA 头上,新 EA 自己显示"已停止"。改成 MQLInfoString(MQL_PROGRAM_NAME) + "_runtime.json" 后,任何复制改名都自动自愈。config.set 和 reload.trigger 同理。
坑 2:编码。 FILE_ANSI 写中文在不同系统代码页下会乱;外部(Python/Node)写 config.set 给 EA 读时,纯 ASCII 的 key=value 最稳。真要传中文,统一 UTF-8 并在 EA 侧用 FILE_TXT|FILE_ANSI 之外的组合实测验证------不要想当然。
坑 3:外部写文件要原子。 外部程序直接 open(path,'w') 写一半时 EA 的 OnTimer 恰好来读,会读到半截文件。写临时文件再 rename(Windows 上 os.replace)覆盖,EA 永远只能看到完整版本。EA 侧写 runtime.json 同理。
常见问答(FAQ)
Q:轮询间隔多少合适?会拖慢 EA 吗? A:3 秒 timer + mtime 守卫,没变化时开销就是一次 FileGetInteger,微秒级。比每 tick 检查克制,比 30 秒灵敏,实测两年没出过性能问题。
Q:多终端(多开 MT5)怎么办? A:每个终端有独立的数据目录和 MQL5/Files/,天然隔离。跨终端共享才用 FILE_COMMON 标志(写到公共目录),但交易场景几乎不需要------参数本来就该按终端隔离。
Q:回测里能用吗? A:能。策略测试器的沙箱路径不同(tester 目录),但 API 一致;EasyDeal 的实现在回测模式下自动跳过 reload.trigger 轮询,避免无意义 IO。
Q:完整源码在哪? A:https://gitee.com/xszyou/easy-deal 的 GMarket.mq5(搜 ReloadRuntimeConfig / DumpInputsRuntime / CheckReloadTrigger),配套的外部侧实现在 easydeal_mcp_server.py。MIT 协议,三件套可以整体搬走。
关键词:MQL5 EA 热更新参数、EA 不重启改参数、MQL5 文件通信、MT5 EA 外部控制、MQL5 FileOpen 教程、EA 参数远程修改、MQL5 OnTimer 轮询、MT5 自动化运维