利用 MQL5 经济日历进行交易(第四部分):在仪表盘中实现实时新闻更新(基础篇)
📘

利用 MQL5 经济日历进行交易(第四部分):在仪表盘中实现实时新闻更新(基础篇)

第 1/3 篇

把经济日历搬进 MT5 仪表盘

MT5 内置的经济日历接口能直接在图表或自定义面板里拉取宏观事件,省去切网页看新闻的麻烦。2025 年 8 月 19 日发布的这套实现思路,核心是用 MQL5 的 CEventInfo 相关类订阅日历流,再把事件标题、影响星级、公布值写进自建仪表盘。 外汇与贵金属对 CPI、非农、利率决议这类事件反应剧烈,属于高风险品种;事件窗口前后点差扩张和滑点概率明显上升,实盘前务必在策略测试器或模拟盘验证刷新逻辑。 下面这段是原文给出的日历事件抓取骨架,去掉了界面绘制部分,只留数据订阅与读取:

MQL5 / C++
CEconomicCalendar calendar;
if(calendar.Open())
{
   CEventInfo event;
   while(calendar.GetNextEvent(event))
   {
      class="type">class="kw">string name = event.Name();
      class="type">int impact = event.Impact();
      class="type">class="kw">datetime time = event.Time();
   }
}

「给经济日历仪表盘接上实时刷新」

上一篇文章里我们搭好了一个 MQL5 经济日历面板,能按货币、重要性和时间筛新闻,但数据是一次性的。这一节要补的缺口是:让面板自己持续拉新数据,不再靠手动重开脚本。 实时更新的核心价值在于,MT5 终端里的日历不再是一张静态截图。宏观新闻往往在分钟级别改变盘面波动概率,外汇与贵金属杠杆高、跳空风险大,迟到的事件提示可能直接放大止损被扫的概率。 本节的落地范围很明确:在已有筛选逻辑之上,嵌入定时轮询机制,把新到的关键事件推到面板。做完这一步,仪表盘从「查历史」变成「盯实时」,交易决策响应窗口会明显缩短。

◍ 用双数组差分让新闻面板跟着tick走

实时刷新经济事件面板,核心不是反复读日历,而是「当前数组」与「先前数组」的差分。MT5 里用两个 string 数组分别承接本次与上次报价周期的事件名,只在二者不一致时才重绘对象,能省掉大量无谓的 GUI 创建开销。 初始化时先 ArrayFree 清空 current_eventNames_data,再用 ArrayResize 把长度加 1,把新事件名写进末位索引。随后 Print + ArrayPrint 打出大小与内容,ArrayCopy 把当前数组整份拷进 previous_eventNames_data,作为下一 tick 的比对基准。这两步在 OnInit 里做一遍,拿到「初始事件」。 每个 tick 调 update_dashboard_values:重新拉日历、按货币/重要性/时间窗过滤、动态塞进 current_eventNames_data。之后用 bool isChangeInStringArrays 比大小再比逐元素 StringCompare,任一处不同就返回 true。实测日志会出现「事件更新 / 仪表盘更新」的连续打印,说明变化被捕获。 检测到变化后先 ObjectsDeleteAll 清掉前缀为 DATA_HOLDERS 与 ARRAY_NEWS 的旧对象,ArrayFree 释放 current 内存,再走一遍「拷贝进 previous」的流程。这样面板始终只反映最新事件,且 previous 数组留作下次差分——外汇与贵金属受新闻跳空影响大,这种高频比对能帮你更快察觉日历变动,但新闻市况流动性骤降,实操仍属高风险。

MQL5 / C++
class="type">class="kw">string current_eventNames_data[];
class="type">class="kw">string previous_eventNames_data[];

ArrayResize(current_eventNames_data,ArraySize(current_eventNames_data)+class="num">1);
current_eventNames_data[ArraySize(current_eventNames_data)-class="num">1] = event.name;
ArrayFree(current_eventNames_data);
Print("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data));
ArrayPrint(current_eventNames_data);
Print("PREVIOUS EVENT NAMES DATA SIZE(Before) = ",ArraySize(previous_eventNames_data));
ArrayCopy(previous_eventNames_data,current_eventNames_data);
Print("PREVIOUS EVENT NAMES DATA SIZE(After) = ",ArraySize(previous_eventNames_data));
ArrayPrint(previous_eventNames_data);

class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert initialization function                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit(){

把财经事件塞进数组并落盘到上一轮

这段逻辑干的事很直接:先释放上一帧的 current_eventNames_data,再按 valuesTotal 条日历事件、array_calendar 列宽去拼 news_data。每一行都带日期、分钟级时间、货币对所属国代码,以及用 0x25CF 实心圆点标记的重要度符号。 重要度配色是硬规则:低影响给 clrYellow,中等给 clrOrange,高影响给 clrRed,对应 CALENDAR_IMPORTANCE_LOW / MODERATE / HIGH 三个枚举。实际、预测、前值都用 DoubleToString(...,3) 锁死三位小数,避免 MT5 终端里浮点显示漂移。 每跑完一个事件就把 event.name 追进 current_eventNames_data,ArrayResize 每次只加 1,属于典型的小步扩容。循环结束用 Print + ArrayPrint 把当前与 previous 两个数组的尺寸和內容打到日志,再用 ArrayCopy 把当前帧整体覆盖给上一帧。 开 MT5 按 F4 贴这段代码,跑完看 Experts 标签:若 PREVIOUS EVENT NAMES DATA SIZE (After) 与 CURRENT 一致,说明帧间传递没漏事件;外汇与贵金属受此日历驱动跳空概率高,验证时务必用模拟盘。

MQL5 / C++
ArrayFree(current_eventNames_data);

class=class="str">"cmt">//--- Loop through each calendar value up to the maximum defined total
for (class="type">int i = class="num">0; i < valuesTotal; i++){

   class=class="str">"cmt">//---
   class=class="str">"cmt">//--- Loop through calendar data columns
   for (class="type">int k=class="num">0; k<ArraySize(array_calendar); k++){
      class=class="str">"cmt">//---
      class=class="str">"cmt">//--- Prepare news data array with time, country, and other event details
      class="type">class="kw">string news_data[ArraySize(array_calendar)];
      news_data[class="num">0] = TimeToString(values[i].time,TIME_DATE); class=class="str">"cmt">//--- Event date
      news_data[class="num">1] = TimeToString(values[i].time,TIME_MINUTES); class=class="str">"cmt">//--- Event time
      news_data[class="num">2] = country.currency; class=class="str">"cmt">//--- Event country currency

      class=class="str">"cmt">//--- Determine importance class="type">class="kw">color based on event impact
      class="type">class="kw">color importance_color = clrBlack;
      if (event.importance == CALENDAR_IMPORTANCE_LOW){importance_color=clrYellow;}
      else if (event.importance == CALENDAR_IMPORTANCE_MODERATE){importance_color=clrOrange;}
      else if (event.importance == CALENDAR_IMPORTANCE_HIGH){importance_color=clrRed;}

      class=class="str">"cmt">//--- Set importance symbol for the event
      news_data[class="num">3] = ShortToString(0x25CF);

      class=class="str">"cmt">//--- Set event name in the data array
      news_data[class="num">4] = event.name;

      class=class="str">"cmt">//--- Populate actual, forecast, and previous values in the news data array
      news_data[class="num">5] = DoubleToString(value.GetActualValue(),class="num">3);
      news_data[class="num">6] = DoubleToString(value.GetForecastValue(),class="num">3);
      news_data[class="num">7] = DoubleToString(value.GetPreviousValue(),class="num">3);
      class=class="str">"cmt">//---
   }

   ArrayResize(current_eventNames_data,ArraySize(current_eventNames_data)+class="num">1);
   current_eventNames_data[ArraySize(current_eventNames_data)-class="num">1] = event.name;

}
Print("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data));
ArrayPrint(current_eventNames_data);
Print("PREVIOUS EVENT NAMES DATA SIZE(Before) = ",ArraySize(previous_eventNames_data));
ArrayCopy(previous_eventNames_data,current_eventNames_data);
Print("PREVIOUS EVENT NAMES DATA SIZE(After) = ",ArraySize(previous_eventNames_data));
ArrayPrint(previous_eventNames_data);

常见问题

用 MQL5 把经济日历数据读进 EA,在图表上画一个自定义仪表盘面板,事件和前值预测就能常驻盘面。
多数基础版只初始化时拉一次数据;需要给面板挂上 OnTick 或定时器,用双数组存上轮和本轮做差分才刷得动。
可以,小布盯盘的 AIGC 已内置实时新闻诊断,打开对应品种页就能看到事件更新和冲击提示,不用自己写面板。
每轮把新抓的事件 ID 存进数组 A,和上轮数组 B 比对,B 里没有的 ID 就是新增,标红推到面板最上面即可。
不行,不落盘就无法做差分,面板分不清新旧;落盘后用当前数组减上一轮数组才能只推增量、省资源。