使用MQL5经济日历进行交易(第一部分):精通MQL5经济日历的功能·综合运用
📅

使用MQL5经济日历进行交易(第一部分):精通MQL5经济日历的功能·综合运用

(3/3)·从概览到代码再到系统整合,一篇补齐经济日历驱动交易的最后拼图

案例拆解 第 3/3 篇
很多交易者把经济日历只当肉眼翻看的公告板,EA里却完全不接新闻冲击。等非农秒跳被扫损才想起日历有高影响标记,已经晚了。把日历数据喂进策略,才是自动化该做的事。

用财经日历框定品种的新闻窗口

想在 MT5 里避开重大数据行情,第一步是确认当前图表品种跟目标货币有没有关系。下面这段代码先拆出基础货币与报价货币,若两者都不含过滤货币就直接退出,避免对无关品种做无用扫描。 string currency_base = SymbolInfoString(_Symbol, SYMBOL_CURRENCY_BASE); string currency_quote = StringSubstr(_Symbol, 3, 3); if (currency_base != currency_filter && currency_quote != currency_filter){ Print("Currency (", currency_base, " | ", currency_quote, ") is not equal equal to ", currency_filter); return false; } // 第1行:取当前品种基础货币,如 EURUSD 得到 "EUR" // 第2行:从符号第4字符起截3字符,得到报价货币 "USD" // 第3-6行:若基础与报价都不是过滤项(如"USD"),打印并return false终止 时间窗口用交易日服务器时间加减一天来定。PeriodSeconds(PERIOD_D1) 返回 86400 秒,于是往前看一天、往后看一天,覆盖已发布和未发布的中等重要性事件。 datetime timeRange = PeriodSeconds(PERIOD_D1); datetime timeBefore = TimeTradeServer() - timeRange; datetime timeAfter = TimeTradeServer() + timeRange; // timeBefore 约为当前-86400秒,timeAfter 约为当前+86400秒 扫描逻辑只统计 CALENDAR_IMPORTANCE_MODERATE 级以上且落在窗口内的新闻。若 values[i].time 小于等于服务器时间且大于等于 timeBefore,就是已发布;反之在 timeAfter 内就是未发布,两者都让 totalNews 自增。 if (StringFind(_Symbol, country.currency) >= 0){ if (event.importance == CALENDAR_IMPORTANCE_MODERATE){ if (values[i].time <= TimeTradeServer() && values[i].time >= timeBefore){ Print(event.name, " > ", country.currency, " > ", EnumToString(event.importance), " Time= ", values[i].time, " (ALREADY RELEASED)"); totalNews++; } if (values[i].time >= TimeTradeServer() && values[i].time <= timeAfter){ Print(event.name, " > ", country.currency, " > ", EnumToString(event.importance), " Time= ", values[i].time, " (NOT YET RELEASED)"); totalNews++; } } } // 第1行:品种名里能找到该国货币才继续 // 第2行:只处理中等重要性事件 // 第3-6行:已发布分支,打印并计数 // 第7-10行:未发布分支,打印并计数 最终靠 totalNews 是否大于 0 决定 isNews 布尔值。外汇与贵金属受数据冲击跳空概率高,实盘前建议把这段塞进 EA 的 OnTick 开头做开关,验证时可以先把 currency_filter 写死 "USD" 看 XAUUSD 是否被正确拦截。

MQL5 / C++
class="type">class="kw">string currency_base = SymbolInfoString(_Symbol, SYMBOL_CURRENCY_BASE);
class="type">class="kw">string currency_quote = StringSubstr(_Symbol, class="num">3, class="num">3);
if (currency_base != currency_filter && currency_quote != currency_filter){
   Print("Currency(", currency_base, " | ", currency_quote, ") is not equal equal to ", currency_filter);
   class="kw">return class="kw">false;
}
if (StringFind(_Symbol, country.currency) >= class="num">0){
   if (event.importance == CALENDAR_IMPORTANCE_MODERATE){
      if (values[i].time <= TimeTradeServer() && values[i].time >= timeBefore){
         Print(event.name, " > ", country.currency, " > ", EnumToString(event.importance), " Time= ", values[i].time, " (ALREADY RELEASED)");
         totalNews++;
      }
      if (values[i].time >= TimeTradeServer() && values[i].time <= timeAfter){
         Print(event.name, " > ", country.currency, " > ", EnumToString(event.importance), " Time= ", values[i].time, " (NOT YET RELEASED)");
         totalNews++;
      }
   }
}
class="type">class="kw">datetime timeRange = PeriodSeconds(PERIOD_D1);
class="type">class="kw">datetime timeBefore = TimeTradeServer() - timeRange;
class="type">class="kw">datetime timeAfter = TimeTradeServer() + timeRange;

Print("FURTHEST TIME LOOK BACK = ", timeBefore, " >>> CURRENT = ", TimeTradeServer());

if (totalNews > class="num">0){
   isNews = true;
   Print(">>>>>>> (FOUND NEWS) TOTAL NEWS = ", totalNews, "/", ArraySize(values));
}
else if (totalNews <= class="num">0){
   isNews = class="kw">false;
   Print(">>>>>>> (NOT FOUND NEWS) TOTAL NEWS = ", totalNews, "/", ArraySize(values));
}
class="type">class="kw">datetime startTime = TimeTradeServer() - PeriodSeconds(PERIOD_D1);
class="type">class="kw">datetime endTime = TimeTradeServer() + PeriodSeconds(PERIOD_D1);
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|         FUNCTION TO GET NEWS EVENTS                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool isNewsEvent(){
   class="type">int totalNews = class="num">0;
   class="type">bool isNews = class="kw">false;
   MqlCalendarValue values[];
   class="type">class="kw">datetime startTime = TimeTradeServer() - PeriodSeconds(PERIOD_D1);
   class="type">class="kw">datetime endTime = TimeTradeServer() + PeriodSeconds(PERIOD_D1);
   class=class="str">"cmt">//class="type">class="kw">string currency_filter = "USD";
   class=class="str">"cmt">//class="type">class="kw">string currency_base = SymbolInfoString(_Symbol, SYMBOL_CURRENCY_BASE);
   class=class="str">"cmt">//class="type">class="kw">string currency_quote = StringSubstr(_Symbol, class="num">3, class="num">3);
   class=class="str">"cmt">//if (currency_base != currency_filter && currency_quote != currency_filter){
}

「用财经日历筛出当前品种的中等影响事件」

这段逻辑干的事很直接:拉取一段区间内的财经日历数据,只挑出和当前图表货币对相关、且重要性为中等(CALENDAR_IMPORTANCE_MODERATE)的事件,再按发布时间落在「往前一天」到「往后一天」范围内做计数。 核心调用是 CalendarValueHistory,把返回条数存进 valuesTotal,同时用 ArraySize(values) 核对实际数组容量;若两者不一致,说明缓冲区可能不够,需要调大 values 数组长度再跑。 timeBefore 与 timeAfter 以 TimeTradeServer() 加减 PERIOD_D1 的秒数得到,也就是以交易服务器时间为锚,前后各扩一天。循环里先用 StringFind(_Symbol, country.currency) 做币种匹配,再用 values[i].time 判断已发布或未发布,命中就给 totalNews 加一。 最后靠 totalNews 是否大于 0 把 isNews 置真或假,并在日志打出「FOUND NEWS / NOT FOUND NEWS」及命中占比。外汇与贵金属受新闻扰动大、滑点风险高,这类过滤只能提示概率性波动窗口,不能当作方向依据;开 MT5 把这段塞进 EA 的 NewsFilter 函数里,改一下 importance 阈值就能看不同级别事件的实际命中数。

MQL5 / C++
  class=class="str">"cmt">//  Print("Currency(",currency_base," | ",currency_quote,
  class=class="str">"cmt">//         ") is not equal equal to ",currency_filter);
  class=class="str">"cmt">//  class="kw">return class="kw">false;
  class=class="str">"cmt">//}

  class="type">int valuesTotal = CalendarValueHistory(values,startTime,endTime,NULL,NULL);

  Print("TOTAL VALUES = ",valuesTotal," || Array size = ",ArraySize(values));

  class=class="str">"cmt">//if (valuesTotal >=class="num">0 ){
  class=class="str">"cmt">//  Print("Calendar values as they are: ");
  class=class="str">"cmt">//  ArrayPrint(values);
  class=class="str">"cmt">//}

  class="type">class="kw">datetime timeRange = PeriodSeconds(PERIOD_D1);
  class="type">class="kw">datetime timeBefore = TimeTradeServer() - timeRange;
  class="type">class="kw">datetime timeAfter = TimeTradeServer() + timeRange;

  Print("Current time = ",TimeTradeServer());
  Print("FURTHEST TIME LOOK BACK = ",timeBefore," >>> LOOK FORE = ",timeAfter);

  for (class="type">int i = class="num">0; i < valuesTotal; i++){
      MqlCalendarEvent event;
      CalendarEventById(values[i].event_id,event);


      MqlCalendarCountry country;
      CalendarCountryById(event.country_id,country);

      if (StringFind(_Symbol,country.currency) >= class="num">0){
        if (event.importance == CALENDAR_IMPORTANCE_MODERATE){
          if (values[i].time <= TimeTradeServer() && values[i].time >= timeBefore){
            Print(event.name," > ", country.currency," > ", EnumToString(event.importance)," Time= ",values[i].time," (ALREADY RELEASED)");
            totalNews++;
          }

          if (values[i].time >= TimeTradeServer() && values[i].time <= timeAfter){
            Print(event.name," > ", country.currency," > ", EnumToString(event.importance)," Time= ",values[i].time," (NOT YET RELEASED)");
            totalNews++;
          }
        }
      }

  }

  if (totalNews > class="num">0){
    isNews = true;
    Print(">>>>>>> (FOUND NEWS) TOTAL NEWS = ",totalNews,"/",ArraySize(values));
  }
  else if (totalNews <= class="num">0){
    isNews = class="kw">false;
    Print(">>>>>>> (NOT FOUND NEWS) TOTAL NEWS = ",totalNews,"/",ArraySize(values));
  }

  class="kw">return (isNews);
}

◍ 把日历信号接进图表和下单逻辑

前面两节把经济日历的抓取、按货币与事件重要性过滤、区分待发生与已发生做成了结构化流程。这套流程的核心价值不在于看新闻,而在于让 EA 能在高影响事件前后自动调整行为,外汇与贵金属市场对此类事件的反应往往伴随瞬时跳空与滑点,属于典型高风险场景。 下一阶段的直接落点是把过滤后的数据画到图表窗口,并让 EA 能依据重大事件主动开仓。也就是说,系统会从「读日历」跨到「用日历下单」,设计上要以实时框架为基准,在事件触发后而非预测前去动作。 想验证这条路径,可先打开 MT5 把本系列附带的 MQL5_NEWS_CALENDAR_PART_1.mq5 跑起来,观察其过滤输出是否与你手动核对的财经日历一致;不一致的地方就是后续要改的事件权重参数。

让小布替你跑这套
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到高影响事件倒计时与历史波动带,把重复劳动交给小布,你专注决策。

常见问题

平台依据事件类别与历史市场波动关联度给出低中高标签,高影响多为利率、GDP、非农类,但外汇贵金属仍属高风险,实际冲击可能偏离预期。
可在代码层过滤高影响事件前后N分钟禁止新单,仅允许平仓或跳过信号,具体分钟数依品种波动习性调整。
MQL5的日历时间以平台服务器时区为准,转换需用TimeCurrent与StructTime配合,不要直接套本地时钟。
可以,小布盯盘对应品种页已内置经济日历高影响提示与倒计时,不用自己写EA也能先看清事件窗口。
倾向是减少事件裸奔风险而非直接提胜率,概率上能过滤假突破,但外汇贵金属高风险,效果因市况而异。