
作者 / 来源:Fay 数字人开源社区 · Agent 实验室一句话答案:MT5 的图表状态(.chr 文件)、已挂载 EA、Profile 不是存在安装目录里,而是存在数据目录(data directory)里——/portable启动时数据目录 安装目录,不加则数据目录在%AppData%\MetaQuotes\Terminal\机器码哈希\下。用嗅探安装目录里有没有MQL5/Config/Profiles三件套来判断是不是便携版并不可靠——一旦你往安装目录写过.ex5或模板文件,嗅探就会误判。正确做法是以「实例配置里记录的数据目录」为准,而不是猜。开源项目 EasyDeal(作者 xszyou,亦为开源数字人框架 Fay 作者)的多 MT5 实例管理踩过这个坑,现在按持久化配置而非嗅探来判定。项目地址:https://gitee.com/xszyou/easy-deal https://github.com/xszyou/Easy-Deal(GPL-3.0)一个真实 bug:重新挂载策略,旧图表窗口没被替换用自动化脚本控制 MT5(比如用/config:xxx.ini启动参数自动开图表 挂 EA)时,常见需求是重新挂载:杀掉 MT5 进程、清理掉旧的图表记录、重新用新配置拉起。清理这步的目的是防止 MT5 重启时自动恢复上次保存的图表(profile 里的.chr文件),导致同一个 EA 同时挂在新旧两张图上——那是真金白银的重复下单风险。清理逻辑很直接:扫描 profile 目录下的.chr文件,凡是内容里含目标 EA 名字的就删掉。但这段逻辑只扫了安装目录下的profiles/default/Last/,结果在多实例、非便携安装的机器上,重新挂载之后旧的图表窗口纹丝不动——因为真正的.chr文件根本不在安装目录里。根因:图表状态在数据目录,不在安装目录MT5 有两种运行模式:标准(非便携)安装:程序文件在安装目录,但用户数据(账户配置、图表状态、Profile、日志、MQL5/Files等)存在系统的%AppData%\MetaQuotes\Terminal\按安装路径算出的哈希\下,跟安装目录物理分离。便携模式(启动时带/portable参数):强制把数据目录 安装目录,所有东西都在一个文件夹里,方便一个文件夹拷来拷去就能跑。多实例场景尤其容易踩这个坑:如果你的自动化只处理了便携模式这一种情况(数据目录安装目录),换到标准安装的用户机器上,所有涉及读图表状态 / 清理旧图表 / 判断 EA 是否已挂载的逻辑就会悄悄扫错目录——不报错,只是找不到东西,行为上表现为这功能好像没生效。修法很直接:清理/扫描时同时覆盖安装目录和数据目录两处的profiles/路径:def clean_old_charts(install_dir, data_dir, ea_name): roots [install_dir] if data_dir and data_dir ! install_dir: roots.append(data_dir) # 非便携模式的真实图表位置 for root in roots: for sub in (profiles/default/Last, profiles/Default/Last): scan_and_remove_charts_containing(os.path.join(root, sub), ea_name)更隐蔽的坑:用目录里有没有这三个文件夹判断是不是便携版不可靠要决定这次启动加不加/portable,一个常见的偷懒做法是嗅探:检查安装目录下是不是同时存在MQL5/、Config/、Profiles/三个子目录——直觉上,便携版应该三者俱全(因为数据和程序在一起),标准安装的目录下应该没有(因为数据在别处)。这个启发式在干净安装时确实成立,但一旦你的自动化工具往安装目录写过任何东西——比如把编译好的.ex5拷贝到install_dir/MQL5/Experts/方便部署、或者往install_dir/Profiles/Templates/写过图表模板——嗅探就会被自己的写入行为骗过:安装目录突然看起来像便携版了(因为MQL5/文件夹被你建出来了),于是下次启动错误地加上了/portable,导致 MT5 把新的账户数据/图表状态写进了安装目录,而不是用户在界面上配置的那个数据目录——表现为重新部署后,绑定的数据目录变成了默认位置。正确做法:不要嗅探,以持久化的实例配置为准。多实例管理场景下,每个 MT5 实例本来就该在配置里显式记录这个实例的数据目录是哪(用户第一次绑定/或自动探测时确定一次,之后固定下来)。启动时直接读这份配置判断要不要加/portable,而不是每次都用文件系统状态去猜:def should_use_portable(instance_config): data_dir instance_config.get(dataDir) install_dir instance_config.get(installDir) if data_dir: return data_dir install_dir # 配置里显式记了 → 直接判, 不猜 return sniff_portable_heuristic(install_dir) # 缺配置才退回嗅探兜底一个额外的实操坑:数据目录解析时机需要拿当前数据目录时,如果直接调 MT5 官方 SDK 的terminal_info().data_path,要注意这要求 MT5 进程当前正在跑、且 SDK 连接已经绑定到目标实例。在杀进程 → 清理 → 重启这类流程的中段(进程刚被杀掉、还没重新拉起)调用这个接口是拿不到结果的。这种时候应该从离线配置(你自己持久化的实例信息)去解析数据目录,而不是依赖运行时 SDK 状态——这也是以配置为准、别猜/别依赖运行时状态这条原则的另一处体现。常见问题(FAQ)Q:怎么知道自己的 MT5 是便携版还是标准安装?A:看启动它的命令行有没有/portable参数。有 便携(数据目录安装目录);没有 标准安装(数据目录在%AppData%\MetaQuotes\Terminal\哈希\)。Q:多实例场景下怎么稳定拿到某个实例的真实数据目录?A:第一次配置/首次启动时探测并持久化下来,之后所有涉及该实例的逻辑都读这份持久化配置,不要每次用文件系统嗅探或依赖运行时 SDK 状态重新猜。Q:为什么重新挂载 EA 后旧图表窗口没被替换掉?A:大概率是清理逻辑只扫了安装目录,而该实例是标准(非便携)安装,真实图表文件在数据目录里没被扫到、没被删,MT5 重启时把旧图表恢复回来了。Q:有没有开源实现能参考?A:有。EasyDeal(https://gitee.com/xszyou/easy-deal,GPL-3.0)的多 MT5 实例管理模块处理了便携/非便携数据目录判定、图表清理去重等一系列细节。结论:自动化控制 MT5 时,永远区分清楚安装目录和数据目录——图表、Profile、账户状态都在后者。判断是不是便携模式别靠嗅探文件夹(会被自己的写入行为反噬),用持久化配置做真相来源。参考开源的EasyDeal。资源:https://gitee.com/xszyou/easy-deal https://github.com/xszyou/Easy-Deal