MQL5 酷宝书  财经日历(基础篇)
📘

MQL5 酷宝书 财经日历(基础篇)

第 1/3 篇

「用 MT5 自带的财经日历抓事件窗口」

MT5 终端里内置了财经日历,不用另开网页就能直接看宏观事件对盘面可能的扰动。它按时间轴排布,每条事件带发布时间和影响等级,适合在重要数据前把图表切到对应品种盯盘。 以一组真实发布记录为例:2022 年 1 月 20 日 12:55 这条日历条目,页面显示有 2 562 次浏览、26 条评论,作者标注为 Denis Kirichenko。这个浏览量级说明该类事件在交易者中关注度不低,数据公布前后贵金属与外汇直盘常出现短时波动率抬升,属于高风险的事件驱动窗口。 实操上,打开 MT5 终端底部的「日历」标签,把时间过滤调到当前交易日,就能看到类似上述条目的实时推送。建议你先挑 EUR/USD 或 XAU/USD,在日历事件前 5 分钟挂好边界挂单,验证一下滑点和高波动的触发概率。

◍ 终端里的财经日历能写进EA吗

MT5 终端和 MQL5 这几年持续迭代,市场分析相关的接口和自动化能力都在往外扩。内置的财经日历就是其中一个较新的组件,它既能人工在终端日历页翻看,也能被机器人调用。 日历本身的呈现不算死板:终端选项卡可配置筛选,网页能嵌,手机端也有独立版本。但对做算法交易的人来说,值得盯的只有一件事——它能不能被代码直接读。 本篇要做的,就是把财经日历在 MQL5 里的编程接口拆开,看清楚哪些事件字段可取、怎样在EA里订阅。

MT5 财经日历接口到底给了什么

MT5 内置的财经日历走的是一套标准 MQL5 资源接口:文档里列了 10 个可直接调用的函数,例如 CalendarCountries() 拉国家清单、CalendarValueHistoryByEvent() 取某事件的历史值、CalendarValueLast() 取最近一次发布值。它们要么返回国家 / 事件 / 数值三类属性,要么回吐历史序列,逻辑不绕,但字段细节藏坑。 底层用三个结构撑起数据模型:MqlCalendarCountry 描述国家维度,MqlCalendarEvent 装事件元数据,MqlCalendarValue 存具体数值。国家层面目前覆盖 21 个国家加上欧盟和全球事件,俄罗斯不在清单里,做卢布相关基本面的得自己另找源。 MqlCalendarValue 里 actual_value、forecast_value、prev_value、revised_prev_value 这四个字段被放大了一百万倍存储。没值的时候填的是 LONG_MIN(-9223372036854775808),有值就得除以 1000000 才拿到真实小数。结构自带两组方法:一组判字段是否存在,一组直接取值——直接取可能拿到 LONG_MIN,用 GetForecastValue() 这类方法会返回 nan,最稳的是先判存在再读。 跑 Test_empty_value.mq5 盯日本央行利率决议就能看到三种取法在日志里的差异。结构间关系是两层一对多:国家 ID 链事件,事件 ID 链数值。运行时错误码也分了组,5400 是数组太小装不下、5401 是超时、5402 是国家没匹配到,写脚本时得自己接这些错。 下面这段是 CalendarCountries() 实际吐出的前几行,能直接核对 ID 与货币符号的对应关系: [id] 0 999 European Union / EU / EUR / € [id] 1 124 Canada / CA / CAD / $ [id] 4 392 Japan / JP / JPY / ¥ 做外汇或贵金属联动分析时,这种映射错了会导致事件过滤全偏,属于高风险环节,建议先在小周期回测里验证一遍再上实盘。

MQL5 / C++
[id]         [name] [code] [currency] [currency_symbol]     [url_name] [reserved]
[ class="num">0]   class="num">999 "European Union" "EU"  "EUR"      "€"                "european-union"       ...
[ class="num">1]   class="num">124 "Canada"         "CA"  "CAD"      "$"                "canada"               ...
[ class="num">2]    class="num">36 "Australia"      "AU"  "AUD"      "$"                "australia"            ...
[ class="num">3]   class="num">554 "New Zealand"    "NZ"  "NZD"      "$"                "new-zealand"          ...
[ class="num">4]   class="num">392 "Japan"          "JP"  "JPY"      "¥"                "japan"                ...
[ class="num">5]   class="num">156 "China"          "CN"  "CNY"      "¥"                "china"                ...
[ class="num">6]   class="num">276 "Germany"        "DE"  "EUR"      "€"                "germany"              ...
[ class="num">7]   class="num">250 "France"         "FR"  "EUR"      "€"                "france"               ...

「国家与货币代码的底层映射表」

在 MT5 的底层数据结构中,经济体与货币并非靠名称字符串硬匹配,而是用一组固定字段做映射:数字 ID、国家名、双字母国家码、ISO 货币码、货币符号、以及小写连字符形式的检索键。 上面这段原始记录展示了 12 个具体条目,从 Italy 的 ID 380 到 Switzerland 的 ID 756,中间还插了一条 ID 为 0 的 Worldwide 虚拟项,其货币码被标为 ALL、符号留空。 注意 Singapore 的货币符号字段写的是 "R$",与 Brazil 的 "R$" 撞车,而 South Africa 用的是单字符 "R"——如果你在 EA 里用符号反查国家,就会踩到歧义坑。 开 MT5 后,可把这些条目直接塞进一个结构体数组做枚举,用数字 ID 做主键比用字符串可靠得多;外汇与贵金属杠杆交易高风险,任何映射错误都可能让订单发往错误标的。

MQL5 / C++
[ class="num">8]   class="num">380 "Italy"            "IT"   "EUR"    "€"                  "italy"              ...
[ class="num">9]    class="num">76 "Brazil"           "BR"   "BRL"    "R$"                 "brazil"             ...
[class="num">10]   class="num">344 "Hong Kong"        "HK"   "HKD"    "HK$"                "hong-kong"          ...
[class="num">11]   class="num">702 "Singapore"        "SG"   "SGD"    "R$"                 "singapore"          ...
[class="num">12]   class="num">484 "Mexico"           "MX"   "MXN"    "Mex$"               "mexico"             ...
[class="num">13]   class="num">710 "South Africa"     "ZA"   "ZAR"    "R"                  "south-africa"       ...
[class="num">14]   class="num">356 "India"            "IN"   "INR"    "₹"                  "india"              ...
[class="num">15]   class="num">578 "Norway"           "NO"   "NOK"    "Kr"                 "norway"             ...
[class="num">16]    class="num">0 "Worldwide"         "WW"   "ALL"    ""                   "worldwide"          ...
[class="num">17]   class="num">840 "United States"    "US"   "USD"    "$"                  "united-states"      ...
[class="num">18]   class="num">826 "United Kingdom"   "GB"   "GBP"    "£"                  "united-kingdom"     ...
[class="num">19]   class="num">756 "Switzerland"      "CH"   "CHF"    "₣"                  "switzerland"        ...

◍ 经济日历事件值的取值与校验

MqlCalendarValue 结构体提供了成对的存在判断与取值方法:HasActualValue / GetActualValue、HasForecastValue / GetForecastValue、HasPreviousValue / GetPreviousValue、HasRevisedValue / GetRevisedValue。判断类方法返回布尔值,取值类方法在未设置对应字段时返回 double 类型的 nan,而不是 0,这一点在写过滤逻辑时容易踩坑。 日历国家列表中可以看到索引 20 为韩国(代码 KR、货币 KRW、符号 ₩),索引 21 为西班牙(ES、EUR、€),索引 22 为瑞典(SE、SEK、Kr),说明底层枚举是按数字 id 连续排布的,做本地化映射时直接读数组下标即可。 下方示例拉取了 2021 年 9 月 22 日日本央行利率决议(event_id = 392060022)当天的日历值。先用 CalendarValueHistoryByEvent 按日切片取回 values[],再用 union LongDouble 把同一段内存分别当 long 和 double 来解释,对比 forecast_value 字段直读与 GetForecastValue() 方法读出的差异。 HasForecastValue() 返回 false 时,GetForecastValue() 必为 nan;实盘里若拿这个值去算偏离度,必须先过存在性判断,否则 nan 参与运算会静默污染后续信号。外汇与贵金属受央行决议驱动波动剧烈,这类数据缺口不处理,策略可能在高风险事件窗直接失真。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| LongDouble                                                          |
class=class="str">"cmt">//+------------------------------------------------------------------+
union LongDouble
  {
   class="type">long   long_value;
   class="type">class="kw">double double_value;
  };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Script program start function                                       |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart()
  {
class=class="str">"cmt">//--- Bank of Japan(BoJ) Interest Rate Decision on class="num">22 Sep class="num">2021 class="num">02:class="num">47 GMT
   class="type">class="kw">ulong event_id = class="num">392060022; class=class="str">"cmt">// "boj-interest-rate-decision"
   MqlCalendarValue values[];
   class="type">class="kw">datetime date_from, date_to;
   date_from = D&class="macro">#x27;class="num">22.09.class="num">2021&class="macro">#x27;;
   date_to = date_from + PeriodSeconds(PERIOD_D1);
   if(::CalendarValueHistoryByEvent(event_id, values, date_from, date_to))
     {
      LongDouble forecast_val;
      class=class="str">"cmt">//--- class="num">1) "forecast_value" field
      forecast_val.long_value = values[class="num">0].forecast_value;
      ::PrintFormat("\"forecast_value\" field: %I64d", forecast_val.long_value);
      class=class="str">"cmt">//--- class="num">2) MqlCalendarValue::GetForecastValue()
      forecast_val.double_value = values[class="num">0].GetForecastValue();
      ::PrintFormat("MqlCalendarValue::GetForecastValue(): %g", forecast_val.double_value);
      class=class="str">"cmt">//--- class="num">3) MqlCalendarValue::HasForecastValue()
      if(!values[class="num">0].HasForecastValue())

空值字段在日志里长什么样

跑完那段测试脚本,MT5 日志会直接把日历事件里没填的预测值暴露出来。USDCAD H1 品种下,forecast_value 字段打印为 -9223372036854775808,这正是 MQL5 用 long 类型空值占位的表现,不是真实报价。 紧接着 GetForecastValue() 返回 nan,HasForecastValue() 返回 false,说明接口层已经识别该字段无效。做事件驱动策略时,若不清掉这类空值,拿 nan 去算偏离度会直接污染信号。 外汇与贵金属受数据市冲击大、杠杆高,用日历值前务必先判 HasForecastValue(),否则在重大数据空窗期可能触发误判交易。

MQL5 / C++
   ::PrintFormat("MqlCalendarValue::HasForecastValue(): %s", (class="type">class="kw">string)false);
  }
 }
class=class="str">"cmt">//+------------------------------------------------------------------+
GR      class="num">0     class="num">21:class="num">23:class="num">36.076    Test_empty_value(USDCAD,H1)      "forecast_value" field: -class="num">9223372036854775808
LH      class="num">0     class="num">21:class="num">23:class="num">36.080    Test_empty_value(USDCAD,H1)      MqlCalendarValue::GetForecastValue(): nan
HM      class="num">0     class="num">21:class="num">23:class="num">36.080    Test_empty_value(USDCAD,H1)      MqlCalendarValue::HasForecastValue(): false

常见问题

可以。打开终端的财经日历面板,按时间排序就能看到非农等事件的精确释放时刻,提前几分钟减仓或挂单避雷。
接口主要给国家代码、货币代码、事件名称、公布值、前值、预期值及时间。用这些字段可做事件前后的仓位限制。
小布会在对应品种页内置财经事件提示,打开就能看到当日高影响事件与释放时间,不用自己翻日历面板。
不是完全一一对应。GB代表英国但货币是GBP,部分国家共用货币,查底层映射表才能写对过滤逻辑。
空值代表该事件未公布或暂缺数据,不是接口故障。日志里空字段应做跳过处理,避免误判数值为零。