整合基于MQL的EA交易和数据库 (SQL Server, .NET 和 C#)(基础篇)
📘

整合基于MQL的EA交易和数据库 (SQL Server, .NET 和 C#)(基础篇)

第 1/2 篇

「用 .NET 把 MT5 EA 接进 SQL Server」

想把 MT5 里的 EA 跑出来的信号、成交、持仓数据落到外部关系库,光靠 MQL5 自带的文件函数很难支撑并发查询。常见做法是让 EA 通过 DLL 调用 .NET 写的桥接层,再由 C# 用 ADO.NET 写进 SQL Server,这样回测和实盘日志都能直接进表做分析。 这套架构在 2018 年 9 月的一篇公开示例里被完整放出,原帖累计浏览 6 554 次、跟帖 14 条,说明用外部库接管 MT5 数据持久化在量化交易者里一直有真实需求。外汇与贵金属品种波动大、滑点不可控,接库做分析前先确认桥接 DLL 在实盘账户下不会被防病毒或 broker 侧 DLL 限制拦掉。 落地时最省事的验证路径:先在 MT5 策略测试器跑一个只写心跳时间戳的 EA,C# 端建一张单列表,看每秒插入是否稳定不丢包;通了再扩字段。

为什么 EA 要外挂数据库

论坛里反复有人问:用 MQL5 写的 EA 怎么接数据库。这需求不奇怪——终端自带记录关掉就没了,数据库里的数据持久、可排序、可过滤,还能反向给 EA 下指令。 更实用的是统计视角:写一行查询就能拉出每个货币对在指定时段的总利润和均值,人工在终端算要耗多久根本没法比。 MetaTrader 本身没有内建数据库交互接口,只能从 DLL 引入函数。活不算轻松,但能跑通。 我用 Microsoft.NET + C# 封了一个 DLL,让 MQL5 EA 直连 SQL Server;本文只讲建 DLL 和引入过程,EA 示例代码极简,要编译成 MQL4 需改几处。外汇与贵金属杠杆高,接数据库做统计也只是辅助,不代表信号胜率。

◍ 打通 MT5 与 SQL Server 的环境前置

要让 MQL5 的 EA 去碰 SQL Server,先得把本地环境铺平。一台装好 MetaTrader 5 且有活跃账户的机器是底线,模拟账户就能跑测试 EA,不涉及真金白银风险,但外汇和贵金属本身波动剧烈,后续上真实数据也别掉以轻心。 数据库端用 Microsoft SQL Server 即可,Express 版免费且在官网可下,对绝大多数个人用户限制可忽略。若首次安装,老系统可能先要补 PowerShell 与 .NET 4.5;偶发 SQL Server 与 VS C++ 2017 冲突时,进控制面板→程序和功能→VS C++ 2017→修改→修复即可,不是必现问题。 MQL 不能直接调托管 .NET 代码,所以 DLL 必须做非托管导出。我用 Robert Giesecke 的 UnmanagedExports 包,VS 2012 以上可直接从 IDE 加进项目,具体用法后文再拆。 一个隐蔽坑:系统“非 Unicode 程序语言”若不是“英语(美国)”,UnmanagedExports 会在编译 .il 阶段报无法修正的语法错,哪怕 C# 源码干净。64 位应用必须切到英语(美国)并重启;32 位可绕开用 DllExporter.exe。切语言只编译时需要,编完可切回,但过程里部分软件会短暂失常。

「用 C# 封一个能被 MT5 调用的 SQL 桥接 DLL」

在 Visual Studio 里新建 Visual C# 的 Class Library 工程,改名 MqlSqlDemo,第一件事是把 Build 里的 Platform target 从 Any CPU 改成 x64,Debug 和 Release 两种配置都要改。原因很硬:要向外导出给非托管代码用的函数,必须锁定处理器架构,否则 MT5 加载会直接失效。 工程默认拉的是 .NET Framework 4.5,一般不用动。自动生成的 Class1.cs 重命名为 MqlSqlDemo.cs,类也同名;导出到非托管环境的函数只能是 static,所以干脆把类声明成静态类,漏写 static 编译期就会报错。 依赖只留 System 和 System.Data,再通过 NuGet 装 UnmanagedExports 1.2.7(包管理器控制台执行 Install-Package UnmanagedExports -Version 1.2.7,回显出现 Successfully added 即成功)。using 区只保留 System、System.Data、System.Data.SqlClient、System.Runtime.InteropServices 和 RGiesecke.DllExport。 静态类里放静态连接对象、命令对象和消息字符串 sMessage;常量 iResSuccess=0、iResError=1 贯穿所有导出函数。MQL5 侧能用的类型严格限制在 int / string / double,Boolean 也用 int 传,避免两边解释不一致。 每个导出函数前标 [DllExport("函数名", CallingConvention.StdCall)],字符串参数加 [MarshalAs(UnmanagedType.LPWStr)]——MT5 走的是 Unicode。CreateConnection 收连接串返回 0/1;Open 抛异常就清对象写 sMessage 返 1;GetLastMessage 用 [return: MarshalAs(UnmanagedType.LPWStr)] 把错误文本抛回 EA。 ExecuteSql 只管写/删/改不返数据;读整数用 ExecuteScalar 取首行首列,读字符串同理换返回类型。CloseConnection 无参无返释放资源。编译分两步:先出普通 .NET 版,UnmanagedExports 自动反编 IL 并重写导出表,成功会多出 .exp 和 .lib 两个文件作信号。 一个坑点:静态类在终端内只有一份实例,多个 EA 共用同一连接和命令对象,并发访问可能打架。演示够用,真要多 EA 各连各的得改架构。

MQL5 / C++
class="kw">public class="kw">static class MqlSqlDemo
{
  class=class="str">"cmt">// ...
}
Install-Package UnmanagedExports -Version class="num">1.2.class="num">7
PM> Install-Package UnmanagedExports -Version class="num">1.2.class="num">7
Installing &class="macro">#x27;UnmanagedExports class="num">1.2.class="num">7&class="macro">#x27;.
Successfully installed &class="macro">#x27;UnmanagedExports class="num">1.2.class="num">7&class="macro">#x27;.
Adding &class="macro">#x27;UnmanagedExports class="num">1.2.class="num">7&class="macro">#x27; to MqlSqlDemo.
Successfully added &class="macro">#x27;UnmanagedExports class="num">1.2.class="num">7&class="macro">#x27; to MqlSqlDemo.
PM>

常见问题

MT5本地文件存大量历史会拖慢读取,外挂SQL Server可用索引快速检索;订单超万笔就建议接库。
需装.NET运行时、SQL Server实例并建好库表,EA端通过C#写的桥接DLL调用,端口和网络权限先开好。
小布可帮你梳理表结构设计和DLL调用要点,把重复的环境排查交给它,你专注逻辑。
多是DLL未释放连接或非托管内存泄漏;确保用using关连接,且EA侧声明参数类型匹配。
轻量场景SQLite够用、免服务;但多EA并发写或远程查时,SQL Server更稳且易扩。