ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MT4 DLL接口实战:从解压Demo到跨账户跟单系统搭建

MT4 DLL接口实战:从解压Demo到跨账户跟单系统搭建 简介适合正在研究MT4自动化交易与跟单功能的C#开发者这份压缩包提供了一套可直接引用的MT4服务器接口动态链接库并附带一份扩展标记语言格式的接口配置或说明文档。资源定位为轻量级接口封装工具主要作用是帮助使用者免去自行编写底层通信逻辑的繁琐过程在项目中快速获得与MT4服务器交互的能力从而把开发重点放在交易策略、订单管理、账户数据读取或程序化同步跟单等上层业务环节。压缩包内共有2个文件分别是提供调用接口的动态链接库以及记录接口参数或调用方式的扩展标记语言文档二者配合即可完成基础集成工作整体大小只有174KB体量小巧下载和部署都很方便。目前已有331人浏览学习尤其适合刚接触MT4二次开发的技术人员作为接口应用样板进行研读也适合需要搭建简易跟单系统或交易盯盘工具的中级开发者做参考借鉴。通过对照说明文档与动态链接库中的可用接口能够较快理清MT4服务器接口的调用脉络节省项目初期的调研和试验成本。1. 拆开 mt4demo.zip 之前先搞懂这个包要解决什么问题拿到一个名为mt4demo.zip_gravity1qr_mt4apidll_mt4api跟单_mt4dll接口_zip的压缩包第一反应不是急着解压而是先看它把哪几样东西捆在了一起demo 示例、一个叫 gravity1qr 的策略或信号源标识、MT4 API 的 DLL、还有跟单。合起来翻译成人话就是——一包集齐了「用 MT4 DLL 接口做跨账户跟单」的最小可跑工程。MT4 本身不带跟单功能跨账户复制订单要么靠 EA 之间用全局变量或文件传信号要么靠 DLL 直接拉信号源的持仓数据再加工后者是多数商用跟单系统的底座。这篇笔记就沿着这个包背后的技术路线展开DLL 接口怎么写、MQL4 怎么调、跟单参数怎么设、哪些坑绕不开。适合手里攥着这种 demo 但不知道怎么下手的开发者也适合想从零搭一套 MT4 跟单桥的人照着复现。2. 认识 mt4demo 包内的标准配置DLL 接口原理与文件真伪2.1 一个规范的 MT4 DLL 跟单包通常长什么样这类压缩包解压之前先按 MT4 的标准目录习惯预判它的内部结构。大多数跟单 demo 包会包含四个部分路径文件类型作用MQL4/Experts/.mq4/.ex4跟单主 EA负责轮询、下单、平仓MQL4/Libraries/.dllMT4 API 扩展负责拉取信号源持仓、处理数据MQL4/Include/.mqh公共常量与函数声明比如订单类型映射、参数结构体docs/或包根目录.txt/.pdf部署说明、参数含义、DLL 依赖说明gravity1qr多半是包内某个策略代号或者信号源的标识符1qr可能是手数档位或资金档位具体含义以包内说明文档为准。拿到包先别双击运行任何.exe先把 README 找出来看一遍确认这个 DLL 依赖什么版本的 MT4 编译器。MT4 从 build 600 之后语法变化很大新版本不再支持老式#property写法直接把旧.mq4硬编译进新平台会出现大量报错。2.2 MT4 API DLL 到底解决了什么原生做不到的事MQL4 是一门能力被刻意收窄的语言。它跑在 MT4 终端进程内能下单、能读行情、能读写文件但没有稳定的网络请求接口跨进程通信手段也十分有限。而 DLL 接口正好补上这块短板用 C 写一个动态链接库MQL4 通过#import把函数引进来双方在同一进程内直接调用传递参数、拿返回值。跟单场景对 DLL 的需求尤其明显。一个账户要复制另一个账户的订单有两条常见路线信号源 EA 把每次开平仓写入本地文件或全局变量跟随端 EA 周期性读取。实现简单但文件写入延迟高且多账户、多终端并行时有写锁冲突。用 DLL 直接连接信号源所在的 MT4 终端或 broker 接口拉取持仓列表和成交记录。跟随端拿到的是订单级数据可以精确复制方向、手数、止损止盈这是多数人选择 DLL 跟单的核心原因。常见做法是 DLL 内部通过 MT4 提供的 API比如 MT4 Manager API或者操作终端本地数据库读取指定账户的持仓快照封装成简单结构体或数组返回给 MQL4 层。2.3 解压与文件真伪检查别让 DLL 当黑匣子在 Windows 上解压可以直接用资源管理器但建议用命令行或 7-Zip 拿到完整输出方便看隐藏文件和路径长度。PowerShell 下可以用Expand-Archive -Path mt4demo.zip -DestinationPath .\mt4demo_src然后立即做三件事。第一确认 DLL 的位数。MT4 终端是 32 位进程DLL 必须是 32 位编译否则加载直接报LoadError 113。用 Visual Studio 自带的 dumpbin 查dumpbin /headers mt4apidll.dll | Select-String machine输出x86表示 32 位x64表示 64 位。第二看 DLL 的导出函数列表dumpbin /exports mt4apidll.dll导出表里应该能看到QueryPositions、GetServerTime这类函数名。如果导出表空空如也或者只有DllMain说明这个 DLL 不是按 MT4 调用约定导出的八成加载后调不到。第三跑一遍哈希校验和文档里给出的 SHA256 比对防止下载过程文件损坏或被人替换过Get-FileHash .\mt4demo_src\MQL4\Libraries\mt4apidll.dll -Algorithm SHA2562.4 压缩包自身的坑伪加密、密码与损坏文件热词里反复出现 zip 伪加密和 zip 密码移除这确实是接手不明压缩包时常遇到的第一个门槛。伪加密的典型表现是用 Windows 资源管理器双击能列出文件名但解压时提示输入密码而包内又没有密码说明。原因是 zip 的加密标志位被手工改过或者制作方用工具做了个假加密外壳。判断方法很简单用 7-Zip 打开如果能看到文件列表且每个文件前没有锁形图标那基本就是伪加密。处理方式是把加密标志位还原常见做法是用十六进制编辑器打开 zip定位到全局位标志的第 0 位把09改成00保存后即可正常解压。这个操作只对伪加密有效真加密拿不到密码时不要硬来找包作者要才是正路。另一种翻车是解压中途报missing zip entry或unexpected end of data通常是文件在传输过程中被截断。先用zip -T或 7-Zip 的测试功能确认损坏范围再考虑重新下载。这个包如果是从网盘下的优先重下一次而不是花时间修复。3. 编译 mt4apidll从 C 导出函数到 MQL4 的 Import 声明3.1 为什么 MT4 只认 32 位 DLL以及编译环境怎么选MT4 终端本身是 32 位程序所以它只能加载 32 位的 DLL。如果你拿 Visual Studio 默认的 x64 配置编译放到MQL4/Libraries目录里MT4 日志会不停刷cannot load library或者LoadError 113而且MessageBox都弹不出来。这不是 DLL 写得不对是位数不匹配。编译环境选择上Visual Studio 2019/2022 用 x86 平台工具集是最省事的不想装 VS 的话MinGW-w64 配合-m32参数也可以但要注意运行库依赖MinGW 编出来的 DLL 在别的机器上可能缺 libgcc 运行时。MT4 调用 DLL 时默认按stdcall调用约定工作所以导出函数要显式写成__stdcall。很多人图省事用__cdecl在本地测试偶尔能跑换台机器或换个 MT4 build 就随机崩溃这种玄学问题最浪费排查时间。3.2 用 C 写一个最小可用的导出函数打开一个空项目新建mt4apidll.cpp下面是一个从 MT4 终端取服务器时间的示例。这里故意不碰复杂业务先把调用链路跑通。#include windows.h #include ctime extern C __declspec(dllexport) int __stdcall GetServerTime(int* year, int* month, int* day) { time_t rawTime; time(rawTime); struct tm timeInfo; localtime_s(timeInfo, rawTime); *year timeInfo.tm_year 1900; *month timeInfo.tm_mon 1; *day timeInfo.tm_mday; return 0; } BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved) { return TRUE; }extern C避免 C 符号改编__declspec(dllexport)声明导出__stdcall匹配 MT4 的调用约定。三个指针参数用于回写数据返回0代表成功。编译成mt4apidll.dll后放到MQL4/Libraries/目录下。然后在 MT4 的 MetaEditor 里新建一个测试脚本调用它。#import mt4apidll.dll int GetServerTime(int year, int month, int day); #import void OnStart() { int year, month, day; int ret GetServerTime(year, month, day); Print(ret, ret, time, year, ., month, ., day); }这里int在 MQL4 里对应 C 的指针参数year、month、day是输出型参数。跑通后你会看到日志打印当前时间说明 DLL 加载、调用、参数传递三个环节全部正常。这一步是整个跟单工程的骨架后面所有持仓数据、账户信息都要走同一个通道。3.3 字符串和数组跨 DLL 边界该怎么传跟单 DLL 必然涉及字符串比如账户号、订单注释、品种代码。MQL4 的string是宽字符而 C 侧常用char*直接当指针传最容易出乱码甚至崩溃。常见做法是避开字符串用int或double数组传数据。例如要传一个订单注释标签先把它编码成整数常量在 DLL 侧再映射回字符串。如果非得传字符串MQL4 侧声明uchar数组调用StringToCharArray转成字节DLL 侧按char*接收uchar commentBytes[]; StringToCharArray(order_copied, commentBytes); #import mt4apidll.dll int SetCommentTag(uchar tag[], int length); #import数组传递的规则MQL4 侧用引用方式uchar tag[]C 侧接收char* tag配合长度参数确保不会越界。这是 MT4 DLL 开发里最容易被忽略的边界一旦越界写坏内存MT4 终端会直接崩溃而不只是报错。3.4 编译产物放置与首次加载的开关设置DLL 放错目录是新手最常见的翻车点。MQL4/Libraries/下的文件MT4 才能通过#import按文件名加载。如果你把 DLL 直接丢到Experts目录MT4 加载时会提示找不到库。另外注意 64 位操作系统下的重定向问题不要往C:\Windows\System32里放这个 DLL就放在终端数据目录下。首次加载还会遇到安全策略拦截。MT4 在「工具 → 选项 → EA」里有两道开关允许导入 DLL 的全局开关以及每个 EA 单独设置里「允许导入外部 DLL 的勾选」。两道都开才放行。打开的瞬间日志会刷一条 DLL 加载记录没刷就是被拦了。这条记录很重要后面排错全靠它。4. 用 MT4 API 跑通跟单从信号源到跟随端的核心参数映射4.1 跟单的三种主流模式与实际场景选型MT4 跟单在散户里热度一直不减「雪球跟单」这类社区模式让很多人以为跟单就是输入一个账号密码然后自动复制。放到 MT4 生态里跟单桥的实现模式大致分三种。第一种是文件信号模式。信号源 EA 把每次开单、平仓的订单信息追加写入本地 CSV跟随端 EA 轮询读取。优点是实现简单、不依赖 DLL缺点是同一终端多账户时文件锁冲突明显且不能跨机部署。第二种是内存共享模式。DLL 内部用 Windows 共享内存或命名管道和另一个进程通信信号源端进程把持仓变化写进共享内存跟随端进程读取。延迟低但需要额外维护一个信号采集进程。第三种是 API 拉取模式也是这个 demo 包最典型的架构。跟随端 DLL 直接调用 MT4 Manager API 或终端本地数据库读取信号源账户的持仓列表按需映射下单。Manager API 方式需要代理服务器地址和权限终端本地数据库方式则要求信号源和跟随端在同一台机器的同一 MT4 数据目录下。个人跟单场景推荐从终端数据库方式起步零权限成本先跑通再考虑升级到 Manager API。4.2 信号流设计DLL 怎么把持仓快照交给跟随端我一般会把 DLL 设计成无状态查询模式跟随端 EA 按固定间隔调用一个查询函数DLL 读取信号源持仓快照写入调用方传入的数组返回订单数量。一个最小化的导出函数长这样extern C __declspec(dllexport) int __stdcall QueryPositions( int account, int* ticketArray, int* typeArray, double* lotArray, double* openPriceArray, int maxCount) { // 伪代码从 MT4 终端数据库读取 account 的当前持仓 // rows ReadOpenOrders(account); // for (i 0; i min(rows, maxCount); i) // { // ticketArray[i] rows[i].ticket; // typeArray[i] rows[i].type; // OP_BUY / OP_SELL // lotArray[i] rows[i].lots; // openPriceArray[i] rows[i].openPrice; // } // return min(rows, maxCount); return 0; }account是信号源账户号maxCount限制单次最大返回条数防止跟随端数组越界。调用者需要预先按maxCount大小初始化四个数组。这里没有传字符串全部是整数和浮点数避开字符串编码问题。DLL 内部实际读取逻辑依赖 broker 类型和 MT4 安装方式可能是解析MQL4/Profiles下的配置也可能是走 Manager API 的持仓接口。4.3 跟随端 EA 的轮询与幂等开平仓跟随端 EA 的核心职责是定时调用QueryPositions拿信号源持仓快照跟本地已复制的持仓做差量然后开新单、平缺失单。一个基础版 EA 的骨架如下#import mt4apidll.dll int QueryPositions(int account, int tickets[], int types[], double lots[], double openPrices[], int maxCount); #import input int SourceAccount 123456; input int MasterMagic 202401; input double LotMultiplier 1.0; input int ScanIntervalSeconds 1; int copiedTickets[]; datetime lastScan 0; void OnTick() { if (TimeCurrent() - lastScan ScanIntervalSeconds) return; lastScan TimeCurrent(); int maxCount 200; ArrayResize(copiedTickets, maxCount); int tickets[], types[]; double lots[], openPrices[]; ArrayResize(tickets, maxCount); ArrayResize(types, maxCount); ArrayResize(lots, maxCount); ArrayResize(openPrices, maxCount); int count QueryPositions(SourceAccount, tickets, types, lots, openPrices, maxCount); for (int i 0; i count; i) { if (!IsAlreadyCopied(tickets[i])) { OpenCopyOrder(types[i], lots[i] * LotMultiplier); MarkCopied(tickets[i]); } } SyncClosedOrders(count, tickets); }IsAlreadyCopied检查全局变量或数组里是否已存在这个信号源 ticket防止同一订单被重复开。MarkCopied记录已处理订单。SyncClosedOrders对比两边持仓信号源已平掉的单子跟随端也要平。TimeCurrent() - lastScan做秒级节流避免OnTick每跳都去拉 DLL把 CPU 打满。4.4 必调参数表从 demo 到实盘只动这几个参数默认值说明调整建议SourceAccount无信号源账户号确认是真实账户号而非 MT4 登录名MasterMagic202401信号源 EA 的魔法数只跟这个 magic 的订单避免混入手动单LotMultiplier1.0手数倍率资金差大时调到 0.1单位净值小配 0.01ScanIntervalSeconds1轮询间隔实盘不小于 1低于 1 秒无意义MaxSlippage3最大滑点点行情剧烈时调到 5 以上MaxLot10单笔最大手数防手数倍率乘出超限仓位严格止损和控制手数倍率是跟单的底线。倍率设成 0 会被当成平仓信号这是最常见的误配置后面避坑章会细说。4.5 手数映射的策略逻辑固定倍率与资金占比手数映射只有两种主流做法。固定倍率用源单量 × LotMultiplier线性透明适合两账户资金量级接近的情况。资金占比映射则是源单量 × (跟随端净值 / 信号源净值)能自适应资金差异但 D 值一旦剧烈波动开单量会忽大忽小。实盘里我习惯在 demo 阶段先用固定倍率跑两周确认信号源风格——如果是马丁策略单量波动极大必须套一层MaxLot上限否则一次跟单就能把账户打到爆仓边缘。5. MT4 DLL 接口与跟单排错5 个绕不开的踩坑点5.1 现象DLL 加载失败日志报 LoadError 113原因最常见的 64 位与 32 位不匹配其次是 DLL 依赖的 VC 运行库缺失。日志里cannot load library后面跟的数字113 就是位数错误。解决确认 MT4 安装目录下的terminal.exe是 32 位进程然后用 dumpbin 核对 DLL 的 machine 字段。VC 运行库缺失的话装对应版本的vcredist_x86.exe。另外检查 DLL 是否被 Windows 标记为「来自网络」而锁定右键属性 → 解除锁定这个细节能卡住一整天的部署进度。5.2 现象DLL 调用成功后频繁乱码或闪退原因字符串参数在 MQL4 与 C 之间的编码不一致。MQL4 的string默认是宽字符C 按 ANSI 或 UTF-8 处理两种编码在内存里长度完全不同读错一个字节就是乱码写越界就是闪退。解决跟单业务里尽量不用字符串传参。订单注释、品种代码这类数据在 DLL 侧全部映射成int常量边界传递用整型数组字符串只留在两边的配置映射表里。确实需要字符串时用uchar数组加长度参数并提前ArrayResize足够容量。5.3 现象DLL 调试进程里正常挂到 MT4 里就随机崩溃原因MT4 终端是长时间运行的进程DLL 的函数在每根 tick 上被反复调用任何内存泄漏或越界都会被放大。调试器里运行几分钟没问题挂一天就崩多半是数组长度上限写死、没有检查越界。解决所有数组读写都加上限判断查询函数里的maxCount严格约束写入长度EA 侧传入的数组容量必须大于等于maxCount留有 10% 冗余。DLL 内部不要用静态缓冲区存订单快照改用局部std::vector或每次调用重新分配避免线程冲突。5.4 现象同一信号单被重复开仓原因跟随端 EA 没有记录已处理的信号源 tick每次查询都把同一持仓当成新单。这是轮询式跟单最容易翻车的业务逻辑。解决已复制映射表要做到「持久化」。用GlobalVariableSet存一个序列化字符串或者写入本地 CSV重启终端后还能恢复。否则 MT4 一重启内存里的已复制列表清空全部历史订单会再来一轮账户瞬间堆满。5.5 现象zip 解压时提示密码但包内文档说无密码原因包制作者打包时不小心设置了伪加密或者用了带密码工具但忘记把密码写进 README。伪加密的特征是 7-Zip 能预览文件内容但资源管理器解压时要求输入密码。解决优先联系包作者问密码。如果只是标志位被修改的伪加密用十六进制编辑器把 zip 头部的全局位标志从09改回00即可这个操作只对伪加密生效对真加密无效。改完后重新解压先跑哈希校验再进下一步。顺带提醒一句从不明渠道下载的跟单 DLL 不要直接放在主力交易终端里先在虚拟机或隔离环境跑干净再转投实盘。6. Demo 账户验证跟单质量延迟、手数映射与稳定性检查验证跟单质量不能靠肉眼看要量化三个指标延迟、映射正确率、DLL 内存稳定性。搭一个双 demo 测试环境装两份 MT4 客户端一份跑信号源一份跑跟随端。延迟测试用同一个品种、同一时刻手动开单在跟随端日志里打两行时间戳——signal_source_time和copy_order_done_time差值就是总延迟。常见环境下轮询间隔 1 秒、同机部署时延迟在 1.5 到 2.5 秒之间属正常。如果超过 5 秒先看经纪商服务器时区是不是跟本地时间差太多再看轮询间隔和 DLL 查询耗时。批量开平仓测试建议连续开 50 笔迷你单中间带方向切换覆盖 OP_BUY 和 OP_SELL 的双向映射。逐一核对每笔复制单的方向、手数倍率、止损止盈偏移最多允许一两笔因为点差问题滑点超限方向反了必须零容忍。稳定性检查看两项MT4 终端内存占用是否随时间线性增长以及 DLL 调用耗时是否逐渐变大。连续跑 24 小时用任务管理器记录 terminal.exe 的内存曲线如果持续上涨超过 30%基本可以断定 DLL 里有内存泄漏必须回头检查每个数组释放逻辑。我自己的习惯是任何跟单桥先跑满一周 demo中间手动模拟一次断网重连、一次 MT4 重启确认已复制列表能自动恢复才考虑放小资金实盘。跟单这种自动执行系统黑匣子状态越少越好日志打不满宁可不跑也不要裸奔。希望帮到你。本文还有配套的精品资源点击获取
返回列表