MT4对接MS SQL实战指南
🗄️

MT4对接MS SQL实战指南

用外部数据库扩展终端历史与信号能力

MQL5 编程 难度 · 进阶 2026-03-27 7 分钟阅读
#MT4#MSSQL#DLL#外部集成#历史数据

为什么要把 MT4 与 MS SQL Server 集成

MetaTrader 4 自身以本地文件方式存储报价与历史,当交易品种多、周期长时,终端会占用大量内存且历史调取不够灵活。将 MT4 与 MS SQL Server 集成,本质是把数据层与计算层从终端剥离:终端负责执行与轻量采集,数据库负责海量存储与复杂查询,第三方程序(如神经网络、Excel)可直接消费数据。这种架构在 2000 年代中后期剥头皮策略兴起时尤为实用,因为基于真实tick的回测需要极细粒度的历史。

集成的典型用途包括:收集价格变动传入SQL做后续分析;从其他应用导入数据快速分析;把整个历史中心数据上传SQL以减少MT4内存;用SQL中存储的报价训练神经网络并通过信号回传控制MT4;用另一种语言写信号程序,仅让终端保留执行函数。这样自动交易综合体中的任务被合理分配,终端不再被重计算拖慢。

✦ 适用场景
若你需长期存储多品种多周期历史、用外部统计/AI工具分析、或想让EA只做轻量执行,本方案值得研究。注意原文基于MT4与SQL2000,思路可迁移至MT5与其他数据库。

所需软件与环境准备

原文项目使用以下产品:MS SQL Server 2000 Developer 作为数据库;Visual C++ 6.0 SP5 用于编译桥接DLL“YZMSSQLExpertSample.dll”;MDAC 7(或8)提供ADO访问能力。若仅运行不编译,可省略VC++,但需使用现成DLL,其中DSN、用户名、密码被硬连接,你必须按自己环境重复配置。

安装SQL与VC不在本文范围。装好后需创建系统DSN,例如原文中DLL连接的字符串片段为 dsn=MT4_SQL_BASE; 用户 yuraz 密码 qwerty,你需要在ODBC中建立同名DSN并建好账号。这是后续DLL能连通数据库的前提。

在 SQL 中创建库、表与存储过程

所有试验在SQL2000执行。先在SQL新建库 MT4TRADE,然后建表 MT4TICK 存放价格变动。表结构如下:idc为自增主键;ServerDateTime由SQL默认约束填服务器本地时间,与MT4传来的时间无关;iDateTime为MT4格式时间;sSymbol为6字符品种;cAsk/cBid为报价。建表脚本节选:

CREATE TABLE [dbo].[MT4TICK] (
    [idc] [bigint] IDENTITY (1, 1) NOT NULL ,
    [ServerDateTime] [datetime] NULL ,
    [iDateTime] [bigint] NULL ,
    [sSymbol] [char] (6) COLLATE SQL_Latin1_General_CP1251_CI_AS NULL ,
    [cAsk] [numeric](18, 4) NULL ,
    [cBid] [numeric](18, 4) NULL 
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[MT4TICK] ADD 
    CONSTRAINT [DF_MT4TICK_ServerDateTime] DEFAULT (getdate()) FOR [ServerDateTime]
GO

接着建存储过程 YZ_MT4_TICK,接收品种、MT4时间、Ask、Bid与返回码,将tick插入表。该过程仅返回0表示成功,便于MQL4判断写入是否到达。脚本如下:

CREATE PROCEDURE dbo.YZ_MT4_TICK
    @RetCode int out
   ,@psSymbol char(6)
   ,@piDateTime  bigint
   ,@pdAsk  float
   ,@pdBid  float
AS
insert into  MT4TICK   ( sSymbol, iDateTime, cAsk, cBid   )  values  ( @psSymbol , @piDateTime,  @pdAsk ,  @pdBid  )
select @RetCode=0
return @RetCode

附件 CreateSQLallDate.txt 提供完整建库、建表、建过程脚本,可照抄生成标准配置。完成这些,SQL端就具备接收tick与历史的基础。

MQL4 与 DLL 的桥接原理

MQL4不能直接连SQL,需借助C++写的DLL通过ADO操作。DLL导出函数供EA/脚本调用,例如 SQLProcedureTickPut 把当前tick传给SQL过程;SQLProcedureGetInt 从SQL取回整数(如外部算好的参数或信号)。DLL内部用ADO连接DSN并执行对应存储过程。原文DLL项目 YZMSSQLExpertSample 包含连接、调用过程、历史写入等静态函数。

EA示例 YZMSSQLSample.mq4 挂载到图表后,每次start()执行就用 SQLProcedureTickPut(Symbol(),TimeCurrent(),Ask,Bid,"YZ_MT4_TICK") 把实时tick写入SQL。init()中可调用 SQLProcedureGetInt 拉取服务端参数。注释中还演示了从SQL取信号 OP_BUY/OP_SELL 的思路,把决策权交给外部软件。

#import "YZMSSQLExpertSample.dll"
int SQLProcedureTickPut( string,  int , double , double ,string );
int SQLProcedureGetInt(string);
int Prc = 0;
int init(){
   Prc = SQLProcedureGetInt ("YZ_MT4_T1");
   return(0);
}
int start(){
   int RetCode = SQLProcedureTickPut( Symbol(), TimeCurrent() , Ask, Bid ,"YZ_MT4_TICK");
   Print(" SQLProcedureTickPut "+ RetCode );
   return(0);
}
⚠ 硬连接风险
原文DLL把DSN、用户名、密码写死,你若直接套用会连到作者环境。实际部署必须改VC源码重编,或自行写配置化DLL,否则无法连通自己的SQL。

批量加载历史数据到 SQL

除实时tick,还可把MT4历史中心数据整批搬入SQL。脚本 SQLGETHISTORY.mq4 遍历EURUSD等品种的全部9个周期(M1到MN1),用 iBars/iOpen 等取每根K线,调用 SQLProcedureHistoryPut 写入。片段如下:

static int mPeriod[8]={PERIOD_M1,PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H4,PERIOD_D1,PERIOD_W1,PERIOD_MN1};
void PutHistor(string sSymbol){
  for(int iPeriod=0;iPeriod<=8;iPeriod++){
     int pPERIOD_XX=mPeriod[iPeriod];
     int Bar=iBars(sSymbol,pPERIOD_XX);
     for(int iBar=Bar;iBar>=0;iBar--){
       double o=iOpen(sSymbol,pPERIOD_XX,iBar);
       double h=iHigh(sSymbol,pPERIOD_XX,iBar);
       double l=iLow(sSymbol,pPERIOD_XX,iBar);
       double c=iClose(sSymbol,pPERIOD_XX,iBar);
       double v=iVolume(sSymbol,pPERIOD_XX,iBar);
       datetime d=iTime(sSymbol,pPERIOD_XX,iBar);
       int RetCode=SQLProcedureHistoryPut(sSymbol,pPERIOD_XX,d,o,h,l,c,v,iBar,"YZ_MT4_HISTORY");
     }
  }
}

作者指出此MQL脚本加载全历史很慢,但能清晰对应柱号。更好做法是把报价导成文本文件,用SQL的DTS导入导出工具批量装载,1999–2008的M1历史几分钟即可完成。不过文本导出不含柱索引,若把柱号当行号,遇缺柱或重载会导致MT4与SQL数量不一致,该问题原文未彻底解决,建议先在MT4高质量更新历史后再重载。

降低终端负担的配置技巧

当历史已外置SQL,终端无需保留大量本地历史。可在“工具>选项>图表”中把“最多柱数”设小,例如5000。因不必为长历史分配内存,终端运行更轻快。同时外部应用可实时抽信号与历史,分析后把执行信号写回SQL,EA再读取执行,实现功能分配。

✦ 内存优化
历史外置+限制图表柱数,是老版MT4在低配机跑多EA的实用招数。MT5用户可用内置SQL插件或零延迟历史API获得类似效果。

方案对比与今日可替代路径

与纯MT4文件历史相比,SQL方案支持并发查询、跨语言分析、集中备份,但部署复杂、需维护数据库与DLL。与现代方案比:MT5自带更完善的历史API与Python/R集成,可直接用ZeroMQ或MySQL ODBC;云时序库(InfluxDB)更适合tick流。若维护老MT4系统,本文DLL思路仍有效;新项目建议用MT5+外部语言轻量桥接。

总结而言,MT4与MS SQL集成展示了把执行与数据分离的经典架构:终端采集tick、SQL存历史、第三方算信号、EA回读执行。虽软件老旧,但分层思想对今日的量化系统仍有启发。附件中四个文件(建库脚本、历史脚本、DLL工程、EA示例)构成了可运行闭环,研究时请以原文链接 https://www.mql5.com/zh/articles/1533 获取。

常见实施坑与排查清单

常见问题

需写C++ DLL用ADO连SQL,MQL4用#import调用DLL的导出函数(如SQLProcedureTickPut),在EA的start()里把Symbol()、TimeCurrent()、Ask、Bid传给SQL存储过程YZ_MT4_TICK插入表MT4TICK,并提前建好库表与系统DSN。
不要用MQL脚本逐根K线写(很慢)。应先用MT4把历史释放到文本文件,再用SQL Server的DTS导入导出向导批量装载,M1十年数据几分钟可完成;注意文本不含柱索引,需先确保MT4历史完整再重载。
检查三点:ODBC系统DSN名称是否为MT4_SQL_BASE之类且与DLL内一致;SQL账号密码是否匹配(原文硬连接yuraz/qwerty需改);MDAC是否安装且版本≥7。自编译DLL才能改连接串。
在MT4“工具>选项>图表”中将“最多柱数”设为较小值(如5000),终端不再为长历史分配内存;同时报价历史已存SQL,可用外部程序分析,终端只保留执行与轻量采集。
可以。将真实tick存入MT4TICK表后,可用SQL按任意非标准时段提取tick,配合第三方或MQL重建剥头皮逻辑;比用MT4合成tick更贴近真实点差与跳动,但需注意ServerDateTime与iDateTime的时区差异。