从基础到中级:定义(二)·综合运用
📘

从基础到中级:定义(二)·综合运用

第 3/3 篇

「用宏把时间戳拆成可读的时分秒」

MT5 里 datetime 本质是从 1970-01-01 起算的秒数,直接打印虽然能看,但要做成分段显示就得自己拆。下面这组宏把秒级时间戳按 86400、3600、60 的整数倍切开,分别拿到日期、小时、分钟和秒。 宏 macro_GetDate 用 A - (A % 86400) 直接抹掉当天秒数剩日期;macro_GetHour 先取 % 86400 去掉日期部分,再减 % 3600 去掉小时以下,除以 3600 得小时数。分钟和秒同理,macro_GetMin 里除以 60 把秒转成整分。 实际验证时,把 datetime dt = D'2024.08.15 12:30:27' 丢进 OnStart,配合 PrintX 宏打印,能看到 12 点 30 分 27 秒被准确拆出。外汇和贵金属行情里时间对齐很关键,这类拆解在跨时区回测时可能帮你少踩坑,但杠杆品种波动剧烈,高风险始终在。 别在递归里顺手调时间宏 斐波那契递归函数 Fibonacci_Recursive 自身不带时间逻辑,若你把它和 macro_GetHour 之类混用在同一个打印流,调用栈一深就难定位是哪一层输出了时间。建议时间拆解单独成块,递归只管数列。

MQL5 / C++
class="macro">#define macro_GetDate(A)      (A - (A % class="num">86400))
class="macro">#define macro_GetTime(A)      (A % class="num">86400)
class=class="str">"cmt">//+----------------+
class="macro">#define macro_GetSec(A)       (A - (A - (A % class="num">60)))
class="macro">#define macro_GetMin(A)       (class="type">int)((A - (A - ((A % class="num">3600) - (A % class="num">60)))) / class="num">60)
class="macro">#define macro_GetHour(A)      (class="type">int)((A - (A - ((A % class="num">86400) - (A % class="num">3600)))) / class="num">3600)
class=class="str">"cmt">//+----------------+
class="macro">#define PrintX(X)             Print(class="macro">#X, " => ", X);

class="type">uint Fibonacci_Recursive(class="type">uint arg = class="num">1)
{
   if (arg <= class="num">1)
      class="kw">return arg;
   class="kw">return Fibonacci_Recursive(arg - class="num">1) + Fibonacci_Recursive(arg - class="num">2);
}

class="type">void OnStart(class="type">void)
{
   class="type">class="kw">datetime dt = D&class="macro">#x27;class="num">2024.08.class="num">15 class="num">12:class="num">30:class="num">27&class="macro">#x27;;
   class="type">ulong v;
   Print("Date And Time: ", dt);
}

把 datetime 拆成日期时间分秒的十六进制验证

在 MT5 里 datetime 本质是从 1970-01-01 起算的秒数,直接 Print 出来是十进制整数,肉眼难对应到日历时间。上面这段把同一个 dt 分别喂给 macro_GetDate、macro_GetTime、macro_GetSec、macro_GetMin、macro_GetHour,再强制转回 datetime 打印十六进制与十进制,等于把时间结构体各字段单独拎出来看底层值。 以 2024-01-01 00:00:00 为例,macro_GetDate 返回的 datetime 十六进制约为 0x65910000,十进制约 1704067200,而 macro_GetTime 同刻会回到 0x0;若 dt 带 13:45:30,macro_GetHour 对应值十六进制约 0x35E0(十进制 13776 秒 = 3.826 小时偏移)。这种打印能帮你确认宏定义是否真的只掩码了对应字节。 实盘外汇与贵金属波动受杠杆与跳空影响,这类底层时间解析仅用于排查 EA 逻辑错误,不涉及任何方向判断;直接在 MT5 策略测试器里跑这段,改 dt 赋值就能对照自己服务器的时区偏移。

MQL5 / C++
class="num">12.    Print("0x", ValueToString(dt, FORMAT_HEX));
class="num">13.    PrintX((class="type">class="kw">datetime)(v = macro_GetDate(dt)));
class="num">14.    Print("0x", ValueToString(v, FORMAT_HEX), " :: ", ValueToString(v, FORMAT_DECIMAL));
class="num">15.    PrintX((class="type">class="kw">datetime)(v = macro_GetTime(dt)));
class="num">16.    Print("0x", ValueToString(v, FORMAT_HEX), " :: ", ValueToString(v, FORMAT_DECIMAL));
class="num">17.    PrintX((class="type">class="kw">datetime)(v = macro_GetSec(dt)));
class="num">18.    Print("0x", ValueToString(v, FORMAT_HEX), " :: ", ValueToString(v, FORMAT_DECIMAL));
class="num">19.    PrintX((class="type">class="kw">datetime)(v = macro_GetMin(dt)));
class="num">20.    Print("0x", ValueToString(v, FORMAT_HEX), " :: ", ValueToString(v, FORMAT_DECIMAL));
class="num">21.    PrintX((class="type">class="kw">datetime)(v = macro_GetHour(dt)));
class="num">22.    Print("0x", ValueToString(v, FORMAT_HEX), " :: ", ValueToString(v, FORMAT_DECIMAL));
class="num">23. }

◍ 别急着下结论

宏在 MQL5 里常被误用,也常被完全无视,根子在于多数人对它的存在理由和适用边界没概念。从正确路径起步、先把工具为什么存在弄透,比急着写复杂逻辑更重要;那些曾觉得啃不动的功能,往往只是缺了这一步认知。 写代码这件事没有天生的门外汉,只有还没撞上自己节奏的人。把本文说的宏处理思路在 MT5 里建个空 EA 实测一遍,你会看到不少原先认为做不到的封装方式其实顺手就能落地。 外汇与贵金属波动剧烈、杠杆风险高,任何编码便利都只是降低试错成本,不替你兜底盈亏。方向找对了,剩下的只是时间和练习。

常见问题

用宏把时间戳按位拆出时、分、秒字段,再拼成字符串显示,比直接看原始数字直观得多。
先确认拆位顺序和字节长度,用十六进制逐段验证日期与时间分量,对不上多半是高低位弄反了。
可以,小布能按你给的宏逻辑自动解析品种时间字段并标出异常,你只管看结论就行。
不能急下定论,先排除数据延迟或拆算误差,再结合价格行为确认,否则容易误杀。
系统自带通常够用,只有做跨周期对齐或自研指标时才值得手写,避免无谓重复劳动。