MQL5中的结构及其数据打印方法(基础篇)
用 MQL5 结构把订单字段一次性打印出来
在 MQL5 里,结构(struct)能把一组相关字段打包成一个类型,方便在调试时整体观察。对做价格行为分析的交易者来说,把某根 K 线的开高低收、成交量、时间打包打印,比逐个 Print 更不容易漏看。 下面这段结构定义了一个常见的行情快照,包含时间、四个价格和成交量。把它塞进数组就能批量存历史 K 线,再用 Print 输出验证数据是否和 MT5 图表一致。 在 MT5 里新建脚本贴入代码,跑在 EURUSD 的 M1 周期上,控制台会按行打出最近 10 根 K 线。外汇与贵金属杠杆高、滑点大,打印出的历史数据仅用于逻辑验证,不代表任何未来走势概率。
class="kw">struct BarData { class="type">class="kw">datetime time; class=class="str">"cmt">// 对应K线开盘时间 class="type">class="kw">double open; class=class="str">"cmt">// 开盘价 class="type">class="kw">double high; class=class="str">"cmt">// 最高价 class="type">class="kw">double low; class=class="str">"cmt">// 最低价 class="type">class="kw">double close; class=class="str">"cmt">// 收盘价 class="type">long volume; class=class="str">"cmt">// 成交量(tick数) }; BarData bars[class="num">10]; class=class="str">"cmt">// 取最近10根K线填入结构数组 for(class="type">int i=class="num">0;i<class="num">10;i++) { bars[i].time = iTime(_Symbol,_Period,i); bars[i].open = iOpen(_Symbol,_Period,i); bars[i].high = iHigh(_Symbol,_Period,i); bars[i].low = iLow(_Symbol,_Period,i); bars[i].close = iClose(_Symbol,_Period,i); bars[i].volume = iVolume(_Symbol,_Period,i); Print("Bar ",i," time=",bars[i].time," O=",bars[i].open," H=",bars[i].high," L=",bars[i].low," C=",bars[i].close," V=",bars[i].volume); }
「时间价格与深度数据的结构地图」
在 MT5 的 EA 与指标开发里,三类核心行情结构必须先摸清楚:MqlDateTime 管时间拆解,MqlTick 管逐笔报价,MqlRates 管 K 线聚合,MqlBookInfo 管市场深度。 MqlDateTime 把时间戳拆成 year、mon、day、hour、min、sec、day_of_week、day_of_year 八个字段,方便按周期过滤信号。MqlTick 除 bid/ask/last 外,还带 time_msc(毫秒级)与 flags 分时标志,last_volume 与 volume_real 提供更高精度成交量。 MqlRates 是常规 K 线载体:time、open、high、low、close 之外,tick_volume 与 real_volume 分开记录,spread 直接给出点差原始值。MqlBookInfo 则按 type/price/volume 描述订单簿每一档,适合做深度失衡策略。 原文给出的目录显示,每个结构都配有打印方法与辅助函数,并至少附一段使用示例;开 MT5 按 F1 搜 MqlTick 即可对照字段写第一句 Print(tick.bid)。外汇与贵金属杠杆高,结构用错会直接错判报价精度,回测前先确认字段含义。
◍ MQL5 十二种预置结构到底归谁填
MQL5 里预定义了 12 种结构,用来存和传服务信息。MqlDateTime 管日期时间,MqlRates 给历史价量点差,MqlTick 取实时最优价,MqlBookInfo 拉深度报价,经济日历结构直连源头发宏观事件——这些字段基本由终端子系统或交易服务器回填。 另一类是 MqlParam、MqlTradeRequest 这种,靠你自己在代码里按接口要求填字段,再拿去建指标句柄或发交易请求;MqlTradeCheckResult、MqlTradeResult、MqlTradeTransaction 则是发单前后由系统返回校验与成交响应。 分清楚「谁填」很关键:服务器回填的结构要用 ArrayPrint() 打表看,或逐字段读出来做程序化判断;自己填的结构若字段错漏,OrderSend 直接报错。外汇和贵金属波动大、滑点频繁,结构字段填错可能在高风险时段发出畸形订单。 标准 ArrayPrint() 出的是表格,但盯大量日志时,把结构压成一行(带字段名+值)反而更易扫;有些场景又要展开字段描述和多格式呈现。下边先给个一行打印思路的骨架,后面章节再写完整自定义函数。
把时间拆进八个整型字段
MqlDateTime 是 MT5 里承载日期时间的基础结构,内部就是八个 int 字段:年、月、日、时、分、秒,外加星期几和年内第几天(1 月 1 日计为 0)。想填结构别手写,用 TimeCurrent()、TimeGMT()、TimeLocal()、TimeTradeServer() 这几个都有引用传参的重载,或者直接用 TimeToStruct() 把 datetime(1970-01-01 起秒数)灌进去,成功返回 true。 TimeToString() 只吃 datetime 不吃结构,别绕回去转类型。要整结构打印,用 ArrayPrint() 最直:它按表输出简单结构数组,列是字段、行是数组元素。只显示一个时间就开长度为 1 的数组;若按 D1 拉一个交易周,通常就是 5 根 K 线对应 5 行。 外汇和贵金属行情受杠杆与跳空影响,时间字段错位可能让回测与实盘偏差放大,验证前先确认终端时区与交易服务器时区。
class="kw">struct class="type">MqlDateTime { class="type">int year; class=class="str">"cmt">// year class="type">int mon; class=class="str">"cmt">// month class="type">int day; class=class="str">"cmt">// day class="type">int hour; class=class="str">"cmt">// hour class="type">int min; class=class="str">"cmt">// minutes class="type">int sec; class=class="str">"cmt">// seconds class="type">int day_of_week; class=class="str">"cmt">// day of the week(class="num">0-Sunday, class="num">1-Monday, ... ,class="num">6-Saturday) class="type">int day_of_year; class=class="str">"cmt">// number of a day in the year(1st of January has number class="num">0) }; class="type">bool TimeToStruct( class="type">class="kw">datetime dt, class=class="str">"cmt">// date and time class="type">MqlDateTime& dt_struct class=class="str">"cmt">// structure for accepting values );
「把 MqlDateTime 打成人能读的日志」
MT5 里 MqlDateTime 结构默认靠 ArrayPrint() 输出,可读性很差。上面那段样例里,2023 年 7 月 17 日 12:08:37 在日志里只显示成 2023 7 17 12 8 37 1 197,1 是周一、197 是年内第几天,扫一眼根本分不清。
直接封装一个 MqlDateTimePrint() 把结构塞进单元素数组再 ArrayPrint,能原样打印单条时间;若要批量,就传 datetime 数组填进 MqlDateTime 数组统一输出。
真要省脑力的话,自己写辅助函数把星期和月份转成文字。MQL5 有内建星期枚举,转小写仅首字母大写即可;月份没有枚举,用 switch 按数字返字符串。再包一层返回「DW, Month DD, YYYY, HH:MM:SS」短格式的函数,日志里看柱形时间一眼就懂。
表格视图也能做:给字段标题传缩进与宽度参数(默认 0 即无缩进),年、月、日、时、分、秒、星期、年内天数的字段就能对齐排开。下面这段代码是最小可跑样例,开 MT5 新建脚本粘进去就能验证当前时间的结构打印。
class="type">void OnStart() { class=class="str">"cmt">//--- Declare a date structure variable class="type">MqlDateTime time; class=class="str">"cmt">//--- Get the current time and at the same time fill in the date structure TimeCurrent(time); class=class="str">"cmt">//--- Declare an array with the class="type">MqlDateTime type and write the data of the filled structure into it class="type">MqlDateTime array[class="num">1]; array[class="num">0]=time; class=class="str">"cmt">//--- Display the header and time using the standard ArrayPrint() Print("Time current(ArrayPrint):"); ArrayPrint(array); class=class="str">"cmt">/* Sample output: Time current(ArrayPrint): [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] [class="num">0] class="num">2023 class="num">7 class="num">17 class="num">12 class="num">8 class="num">37 class="num">1 class="num">197 */ } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Take a date structure and display its data to the journal. | class=class="str">"cmt">//| Use ArrayPrint() for display | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void MqlDateTimePrint(class="kw">const class="type">MqlDateTime& time_struct) { class=class="str">"cmt">//--- Declare an array with the class="type">MqlDateTime type and write the data of the obtained structure into it class="type">MqlDateTime array[class="num">1]; array[class="num">0]=time_struct; class=class="str">"cmt">//--- Print the array ArrayPrint(array); class=class="str">"cmt">/* Sample output: Time current(ArrayPrint): [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] [class="num">0] class="num">2023 class="num">7 class="num">17 class="num">12 class="num">8 class="num">37 class="num">1 class="num">197 */ } class="type">void OnStart() { class=class="str">"cmt">//--- Declare a date structure variable class="type">MqlDateTime time; class=class="str">"cmt">//--- Get the current time and at the same time fill in the date structure TimeCurrent(time); class=class="str">"cmt">//--- Display the header and time using the standard ArrayPrint() Print("Time current(ArrayPrint):"); MqlDateTimePrint(time); /* Sample output: Time current(ArrayPrint): [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
◍ 把时间数组拆成可读结构
做跨周期或批量 K 线统计时,datetime 整数不直观,直接打印就是一串秒数,肉眼难对应到「周几、第几天」。下面这个函数把 datetime 数组整体转成 MqlDateTime 结构数组,再用 ArrayPrint 输出成表。 以 GBPUSD H1 最近 10 根 bar 为例,转换后首行输出为:2023 年 7 月 17 日 7 时 0 分 0 秒,星期一,年内第 197 天。这种结构让你在 EA 日志里一眼看清时间分布,而不是去心算时间戳。 函数先按传入数组大小 Resize 结构体数组,再用 TimeToStruct 逐元素转换,任何一步失败都会带错误码打印出来,方便你定位是空数组还是运行时错误。外汇与贵金属行情受杠杆与跳空影响,这类时间解析仅用于辅助判断,不代表任何方向概率。
class="type">void MqlDateTimePrint(class="kw">const class="type">class="kw">datetime& array_time[]) { class=class="str">"cmt">//--- Declare a dynamic array of the class="type">MqlDateTime type class="type">MqlDateTime array_struct[]; class=class="str">"cmt">//--- Get the size of the array passed to the function class="type">int total=(class="type">int)array_time.Size(); class=class="str">"cmt">//--- If an empty array is passed, report on that and leave the function if(total==class="num">0) { PrintFormat("%s: Error. Empty array.",__FUNCTION__); class="kw">return; } class=class="str">"cmt">//--- Change the size of the class="type">MqlDateTime array to match the size of the class="type">class="kw">datetime array ResetLastError(); if(ArrayResize(array_struct,total)!=total) { PrintFormat("%s: ArrayResize() failed. Error %s",__FUNCTION__,(class="type">class="kw">string)GetLastError()); class="kw">return; } class=class="str">"cmt">//--- Convert dates from the class="type">class="kw">datetime array into the date structure in the class="type">MqlDateTime array for(class="type">int i=class="num">0;i<total;i++) { ResetLastError(); if(!TimeToStruct(array_time[i],array_struct[i])) PrintFormat("%s: [%s] TimeToStruct() failed. Error %s",__FUNCTION__,(class="type">class="kw">string)i,(class="type">class="kw">string)GetLastError()); } class=class="str">"cmt">//--- Print the filled class="type">MqlDateTime array ArrayPrint(array_struct); }