如何准备 MetaTrader 5 报价用于其他应用程序(基础篇)
◍ 把 MT5 报价导出来给外部程序用
在 MT5 里做价格行为分析时,常常需要把实时或历史报价喂给 Python、Excel 或其他自研工具。终端本身不提供一键导出面板,但通过 MQL5 脚本可以直接落盘成 CSV,外部程序按行读取即可。 核心思路是用 CopyRates 把指定品种的柱数据拷到数组,再写文件到终端的 Files 目录。下面这段代码在 EURUSD 的 H1 上取最近 100 根 K 线,输出带时间、开高低收和成交量的文本。外汇及贵金属杠杆高、滑点大,外部回测结论仅代表历史样本,实盘可能偏离。 注意 Files 目录路径是沙盒化的,外部程序要读得先知道终端 Data 文件夹位置。想验证就开 MT5 新建脚本粘进去,跑完去 Files 里找 csv。
class="type">int OnInit() { class="type">MqlRates rates[class="num">100]; class="type">int copied = CopyRates("EURUSD", PERIOD_H1, class="num">0, class="num">100, rates); if(copied <= class="num">0) class="kw">return INIT_FAILED; class="type">int file = FileOpen("eurusd_h1.csv", FILE_WRITE|FILE_CSV, ","); if(file == INVALID_HANDLE) class="kw">return INIT_FAILED; for(class="type">int i=class="num">0; i<copied; i++) { FileWrite(file, rates[i].time, rates[i].open, rates[i].high, rates[i].low, rates[i].close, rates[i].tick_volume); } FileClose(file); class="kw">return INIT_SUCCEEDED; }
「先看清这套程序要管什么」
这一节把整个指标/脚本要覆盖的内容摊开,等于先给你一张地图。它列出八个板块:从简介、数据格式、外部参数,到参数校验、全局变量、信息面板,再到主逻辑和归档目录。 读目录的意义不是背下来,而是开 MT5 前先想清楚:你要改的是哪一块。比如只想调预警灵敏度,就直奔「程序的外部参数」和「检查用户输入的参数」两块,别在主体逻辑里瞎逛。 外汇与贵金属波动剧烈、杠杆高风险大,任何参数改动都先在策略测试器跑一遍历史数据再上实盘。
为何从现成工具转向 MQL5
在接触 MQL5 之前,我试过不少第三方工具来搭交易系统。不能说白费功夫,有些确实能省时间、破迷思,让人不碰编程也能跑策略。 这些工具大多要吃历史数据,但业内没有统一格式,往往得先在 Excel 里手动改成形,才能喂给程序。即便摸清了所有细节,大量整理仍是手工活。 MetaTrader 4 时代有各种脚本能把报价扒成指定格式,若真有需要,同样可以写个 MQL5 版脚本来干这事。外汇与贵金属波动剧烈、杠杆高风险大,手工搬运数据容易引入错误,用代码固化流程更稳。
◍ 这套数据引擎到底管哪几件事
做 MT5 历史数据归档,先得厘清边界:它要打通 Market Watch 窗口里的交易品种,以及服务器侧常用品种列表,两边不全就跑不动。 数据深度是硬门槛。脚本必须先检查本地可用深度,缺失就触发下载,并且对超时、部分返回、品种停更这几种情形分别处理,否则后面算出来的东西会 quietly 失真。 界面层要把请求状态打到自定义面板图表和日志里,方便你实时看哪一行卡住了。 落地动作就四件:按用户格式整理数据、建文件目录、执行归档、留痕。开 MT5 按 F4 建个脚本骨架,先把 Market Watch 品种枚举出来,比直接啃文档快。
「把 MT5 报价喂给 NSDT 要先改格式」
MetaTrader 5 能把报价导出成 *.csv,但原文件日期格式和表头都不直接兼容 NeuroShell DayTrader(NSDT)。NSDT 5 与 6 对数据列的要求不一样:5 版要把日期和时间拆成两列,首行写 "Date" "Time" "Open" "High" "Low" "Close" "Volume";6 版则合并成一列,首行是 Date,Open,High,Low,Close,Volume。 光改表头不够,MT5 出来的日期也得重排。对应 NSDT 5 要变成 dd.mm.yyyy,hh:mm,Open,High,Low,Close,Volume;NSDT 6 则是 dd/mm/yyyy hh:mm,Open,High,Low,Close,Volume。这两类差异是写导出脚本时第一个要处理的坑。 脚本用下拉参数让用户选格式,同时还能决定覆盖范围:只导当前图表品种、导市场报价窗口里的品种、或导服务器全部可用品种。下面这段枚举就是外部参数前的类型定义,直接决定了下拉框里出现什么选项。 别把正态当圣经:NSDT 版本差异是实测出来的,作者试过 5 和 6 两版行为不同,你本地若用其他第三方分析器,表头约定大概率还得再改一次,先开 MT5 导一份 csv 对照最稳。
class=class="str">"cmt">//_________________________________ class=class="str">"cmt">// HEADER_FORMATS_ENUMERATION enum FORMAT_HEADERS { NSDT_5 = class="num">0, class=class="str">"cmt">// "Date" "Time" "Open" "High" "Low" "Close" "Volume" NSDT_6 = class="num">1 class=class="str">"cmt">// Date,Open,High,Low,Close,Volume }; class=class="str">"cmt">//--- class=class="str">"cmt">//___________________________ class=class="str">"cmt">// ENUMERATION_OF_DATA_FORMATS enum FORMAT_DATETIME { SEP_POINT1 = class="num">0, class=class="str">"cmt">// dd.mm.yyyy hh:mm SEP_POINT2 = class="num">1, class=class="str">"cmt">// dd.mm.yyyy, hh:mm SEP_SLASH1 = class="num">2, class=class="str">"cmt">// dd/mm/yyyy hh:mm SEP_SLASH2 = class="num">3 class=class="str">"cmt">// dd/mm/yyyy, hh:mm }; class=class="str">"cmt">//--- class=class="str">"cmt">//____________________________ class=class="str">"cmt">// ENUMERATION_OF_FILING_MODES enum CURRENT_MARKETWATCH { CURRENT = class="num">0, class=class="str">"cmt">// ONLY CURRENT SYMBOLS MARKETWATCH = class="num">1, class=class="str">"cmt">// MARKETWATCH SYMBOLS ALL_LIST_SYMBOLS = class="num">2 class=class="str">"cmt">// ALL LIST SYMBOLS };
脚本外部参数怎么配
这套归档脚本把可控项全丢进了 input 区,跑之前先在属性框里定好范围与格式,比改代码省事。 起始与结束日期用 start_date / end_date 两个 datetime 变量框死回测区间,默认给的是 2011.01.01 到 2012.09.18,换品种时直接改这两行就能缩窄或拉长样本。 format_headers 和 format_date 是下拉枚举,管表头样式和时间戳显示,NSDT_5 与 SEP_POINT2 只是预设常量,不影响数据本身。curr_mwatch 决定往市场报价窗口写几个标的,CURRENT 表示只处理当前图关联的那些。 clear_mwatch 设为 true 会在归档完清掉市场报价里的对应标的,注意它只动「无活动图表」的那部分,不会误删你正盯着的图;show_progress 开的话数据面板走百分比,关掉能略微提速。 下面这段就是外部参数原貌,逐行拆一下方便你直接抄进 MT5 脚本里改: start_date 与 end_date 是 datetime 输入,默认区间约 20 个月;format_headers 选 NSDT_5 表头格式;format_date 用 SEP_POINT2 日期分隔;curr_mwatch 取 CURRENT 只写当前市场观察项;clear_mwatch 与 show_progress 是两个 bool 开关,默认都开。
<span class="comment">class=class="str">"cmt">//____________________________________________________________________</span> <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="comment">class=class="str">"cmt">//| EXTERNAL_PARAMETERS |</span> <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="keyword">input</span> <span class="keyword">class="type">class="kw">datetime</span> start_date = <span class="class="type">class="kw">string">D&class="macro">#x27;class="num">01.01.class="num">2011&class="macro">#x27;</span>; <span class="comment">class=class="str">"cmt">// Start Date</span> <span class="keyword">input</span> <span class="keyword">class="type">class="kw">datetime</span> end_date = <span class="class="type">class="kw">string">D&class="macro">#x27;class="num">18.09.class="num">2012&class="macro">#x27;</span>; <span class="comment">class=class="str">"cmt">// End Date</span> <span class="keyword">input</span> FORMAT_HEADERS format_headers = NSDT_5; <span class="comment">class=class="str">"cmt">// Format Headers</span> <span class="keyword">input</span> FORMAT_DATETIME format_date = SEP_POINT2; <span class="comment">class=class="str">"cmt">// Format Datetime</span> <span class="keyword">input</span> CURRENT_MARKETWATCH curr_mwatch = CURRENT; <span class="comment">class=class="str">"cmt">// Mode Write Symbols</span> <span class="keyword">input</span> <span class="keyword">class="type">bool</span> clear_mwatch = <span class="keyword">true</span>; <span class="comment">class=class="str">"cmt">// Clear Market Watch</span> <span class="keyword">input</span> <span class="keyword">class="type">bool</span> show_progress = <span class="keyword">true</span>; <span class="comment">class=class="str">"cmt">// Show Progress(%)</span>