MT4对接MS SQL实战指南
用外部数据库扩展终端历史与信号能力
为什么要把 MT4 与 MS SQL Server 集成
MetaTrader 4 自身以本地文件方式存储报价与历史,当交易品种多、周期长时,终端会占用大量内存且历史调取不够灵活。将 MT4 与 MS SQL Server 集成,本质是把数据层与计算层从终端剥离:终端负责执行与轻量采集,数据库负责海量存储与复杂查询,第三方程序(如神经网络、Excel)可直接消费数据。这种架构在 2000 年代中后期剥头皮策略兴起时尤为实用,因为基于真实tick的回测需要极细粒度的历史。
集成的典型用途包括:收集价格变动传入SQL做后续分析;从其他应用导入数据快速分析;把整个历史中心数据上传SQL以减少MT4内存;用SQL中存储的报价训练神经网络并通过信号回传控制MT4;用另一种语言写信号程序,仅让终端保留执行函数。这样自动交易综合体中的任务被合理分配,终端不再被重计算拖慢。
所需软件与环境准备
原文项目使用以下产品:MS SQL Server 2000 Developer 作为数据库;Visual C++ 6.0 SP5 用于编译桥接DLL“YZMSSQLExpertSample.dll”;MDAC 7(或8)提供ADO访问能力。若仅运行不编译,可省略VC++,但需使用现成DLL,其中DSN、用户名、密码被硬连接,你必须按自己环境重复配置。
- MS SQL Server 2000 Developer(最低安装集)
- MDAC 7 或 8(ADO 数据访问组件)
- Visual C++ 6.0 SP5(仅当需重新编译DLL时)
- Windows 系统并配置好系统DSN指向SQL库
安装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);
}
批量加载历史数据到 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文件历史相比,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 获取。
常见实施坑与排查清单
- DSN名、账号、密码必须与DLL硬连接或重编后一致,否则ADO连不上
- MDAC版本过低会导致ADO接口异常,建议7/8
- SQL2000默认仅本地连接,需开TCP/IP与端口
- MQL4调用DLL需允许“调用DLL”选项,且32/64位匹配
- 历史脚本慢且缺柱索引,大量数据请用DTS文本导入
- 时间字段双轨:ServerDateTime是SQL主机时间,iDateTime才是MT4时间,分析时别混淆