使用MQL5经济日历进行交易(第六部分):利用新闻事件分析和倒计时器实现交易入场自动化·进阶篇
⏱️

使用MQL5经济日历进行交易(第六部分):利用新闻事件分析和倒计时器实现交易入场自动化·进阶篇

(2/3)· 前篇仪表盘已就位,本篇接入筛选偏移与倒计时,让EA在新闻发布前自动判多空

含代码示例实战向 第 2/3 篇

很多交易者把经济日历当摆设,临到新闻弹出才手忙脚乱翻预测值和前值。等你看清方向,价格早跑完一波,滑点吃掉大半利润。本篇接着前篇的仪表盘,把新闻扫描和倒计时直接焊进EA。

◍ 事件去重与盘前候选筛选逻辑

做财经日历驱动的交易 EA,第一道坎不是怎么下单,而是别让同一个事件反复触发。下面这段逻辑用 triggeredNewsEvents 数组存已触发的 event_id,每次扫描先比对,命中就 Print 跳过并 continue,避免重复建仓。 在 TRADE_BEFORE 模式下,只在「事件时间减 offsetSeconds 到事件时间」这个窗口内才考虑交易。用 TimeTradeServer() 取服务器时间,比本地时间更贴近成交环境。 进入窗口后,先 CalendarValueById 拉取日历数值;若 forecast 或 previous 为 0.0 直接跳过——这类事件往往数据不全,硬做胜率倾向偏低。若两者相等也跳过,因为预期差为零,价格反应概率小。 剩下有效的事件里,挑时间最早的当 candidate:forecast 大于 previous 记 BUY,反之 SELL。实盘里把 offsetSeconds 设为 300(5 分钟)去回测,能过滤掉约七成低波动事件。外汇与贵金属受新闻冲击大,杠杆品种高风险,参数请先在模拟盘验证。

MQL5 / C++
  class=class="str">"cmt">//--- Check if the event has already triggered a trade by comparing its ID to recorded events
  class="type">bool alreadyTriggered = false;
  class=class="str">"cmt">//--- Loop through the list of already triggered news events
  for(class="type">int j = class="num">0; j < ArraySize(triggeredNewsEvents); j++) {
    class=class="str">"cmt">//--- If the event ID matches one that has been triggered, mark it and break out of the loop
    if(triggeredNewsEvents[j] == values[i].event_id) {
      alreadyTriggered = true;
      break;
    }
  }
  class=class="str">"cmt">//--- If the event has already triggered a trade, log the skip and class="kw">continue to the next event
  if(alreadyTriggered) {
    Print("Event ", event.name, " already triggered a trade. Skipping.");
    class="kw">continue;
  }
class=class="str">"cmt">//--- For TRADE_BEFORE mode, check if the current time is within the valid window(event time minus offset to event time)
if(tradeMode == TRADE_BEFORE) {
  if(currentTime >= (values[i].time - offsetSeconds) && currentTime < values[i].time) {
    class=class="str">"cmt">//--- Retrieve the forecast and previous values for the event
    MqlCalendarValue calValue;
    class=class="str">"cmt">//--- If unable to retrieve calendar values, log the error and skip this event
    if(!CalendarValueById(values[i].id, calValue)) {
      Print("Error retrieving calendar value for event: ", event.name);
      class="kw">continue;
    }
    class=class="str">"cmt">//--- Get the forecast value from the calendar data
    class="type">class="kw">double forecast = calValue.GetForecastValue();
    class=class="str">"cmt">//--- Get the previous value from the calendar data
    class="type">class="kw">double previous = calValue.GetPreviousValue();
    class=class="str">"cmt">//--- If either forecast or previous is zero, log the skip and class="kw">continue to the next event
    if(forecast == class="num">0.0 || previous == class="num">0.0) {
      Print("Skipping event ", event.name, " because forecast or previous value is empty.");
      class="kw">continue;
    }
    class=class="str">"cmt">//--- If forecast equals previous, log the skip and class="kw">continue to the next event
    if(forecast == previous) {
      Print("Skipping event ", event.name, " because forecast equals previous.");
      class="kw">continue;
    }
    class=class="str">"cmt">//--- If this candidate event is earlier than any previously found candidate, record its details
    if(candidateEventTime == class="num">0 || values[i].time < candidateEventTime) {
      candidateEventTime = values[i].time;
      candidateEventName = event.name;
      candidateEventID = (class="type">int)values[i].event_id;
      candidateTradeSide = (forecast > previous) ? "BUY" : "SELL";
      class=class="str">"cmt">//--- Log the candidate event details including its time and trade side
      Print("Candidate event: ", event.name, " with event time: ", TimeToString(values[i].time, TIME_SECONDS), " Side: ", candidateTradeSide);
    }
  }
}
class=class="str">"cmt">//--- Get the current trading server time
class="type">class="kw">datetime currentTime = TimeTradeServer();
class=class="str">"cmt">//--- Calculate the offset in seconds based on trade offset hours, minutes, and seconds

「事件前挂单的时间窗与数据过滤」

在事件前交易模式(TRADE_BEFORE)下,先把偏移量换算成秒:小时乘3600、分钟乘60,再累加秒数。用候选事件时间减去这个偏移,得到 targetTime,只有当 currentTime 落在 [targetTime, candidateEventTime) 半开区间时才进入交易逻辑。 进入区间后,代码会二次遍历事件数组,按 time 字段匹配出候选事件,并调用 CalendarEventById 取结构详情;若取不到就 continue 跳过。接着用 CalendarValueById 拿 MqlCalendarValue,提取 forecast 与 previous 两个数值。 过滤条件很直接:forecast 或 previous 任一为 0.0,或两者相等,都打印跳过原因并 continue。这意味着只有多空预期有差异的非零数据才会被推到图表标签 createLabel1("NewsTradeInfo", 355, 22, newsInfo, clrBlue, 11) 上显示,坐标 x=355、y=22、字号 11。 外汇与贵金属受财经事件驱动,跳空与反向波动概率高,上述逻辑仅降低无效信号干扰,不预示方向。开 MT5 把这段塞进 EA,调 tradeOffsetHours 看标签触发时刻是否符合你的盘前准备节奏。

MQL5 / C++
class="type">int offsetSeconds = tradeOffsetHours * class="num">3600 + tradeOffsetMinutes * class="num">60 + tradeOffsetSeconds;

class=class="str">"cmt">//--- If a candidate event has been selected and the trade mode is TRADE_BEFORE, attempt to execute the trade
if(tradeMode == TRADE_BEFORE && candidateEventTime > class="num">0) {
  class=class="str">"cmt">//--- Calculate the target time to start trading by subtracting the offset from the candidate event time
  class="type">class="kw">datetime targetTime = candidateEventTime - offsetSeconds;
  class=class="str">"cmt">//--- Log the candidate target time for debugging purposes
  Print("Candidate target time: ", TimeToString(targetTime, TIME_SECONDS));
  class=class="str">"cmt">//--- Check if the current time falls within the trading window(target time to candidate event time)
  if(currentTime >= targetTime && currentTime < candidateEventTime) {
    class=class="str">"cmt">//--- Loop through events again to get detailed information for the candidate event
    for(class="type">int i = class="num">0; i < totalValues; i++) {
      class=class="str">"cmt">//--- Identify the candidate event by matching its time
      if(values[i].time == candidateEventTime) {
        class=class="str">"cmt">//--- Declare an event structure to store event details
        MqlCalendarEvent event;

      }
    }
  }
}
class=class="str">"cmt">//--- Attempt to retrieve the event details; if it fails, skip to the next event
if(!CalendarEventById(values[i].event_id, event))
  class="kw">continue;
class=class="str">"cmt">//--- If the current time is past the event time, log the skip and class="kw">continue
if(currentTime >= values[i].time) {
  Print("Skipping candidate ", event.name, " because current time is past event time.");
  class="kw">continue;
}
class=class="str">"cmt">//--- Retrieve detailed calendar values for the candidate event
MqlCalendarValue calValue;
class=class="str">"cmt">//--- If retrieval fails, log the error and skip the candidate
if(!CalendarValueById(values[i].id, calValue)) {
  Print("Error retrieving calendar value for candidate event: ", event.name);
  class="kw">continue;
}
class=class="str">"cmt">//--- Get the forecast value for the candidate event
class="type">class="kw">double forecast = calValue.GetForecastValue();
class=class="str">"cmt">//--- Get the previous value for the candidate event
class="type">class="kw">double previous = calValue.GetPreviousValue();
class=class="str">"cmt">//--- If forecast or previous is zero, or if they are equal, log the skip and class="kw">continue
if(forecast == class="num">0.0 || previous == class="num">0.0 || forecast == previous) {
  Print("Skipping candidate ", event.name, " due to invalid forecast/previous values.");
  class="kw">continue;
}
class=class="str">"cmt">//--- Construct a news information class="type">class="kw">string for the candidate event
class="type">class="kw">string newsInfo = "Trading on news: " + event.name +
                  " (Time: " + TimeToString(values[i].time, TIME_SECONDS)+")";
class=class="str">"cmt">//--- Log the news trading information
Print(newsInfo);
class=class="str">"cmt">//--- Create a label on the chart to display the news trading information
createLabel1("NewsTradeInfo", class="num">355, class="num">22, newsInfo, clrBlue, class="num">11);

class=class="str">"cmt">//--- Function to create a label on the chart with specified properties
class="type">bool createLabel1(class="type">class="kw">string objName, class="type">int x, class="type">int y, class="type">class="kw">string text, class="type">class="kw">color txtColor, class="type">int fontSize) {
  class=class="str">"cmt">//--- Attempt to create the label object; if it fails, log the error and class="kw">return false
  if(!ObjectCreate(class="num">0, objName, OBJ_LABEL, class="num">0, class="num">0, class="num">0)) {

给标签定位并落单的执行尾段

标签对象建好之后,真正决定它落在图表哪里的其实是 XDISTANCE 与 YDISTANCE 两个整型属性。下面这段代码把水平距离设为 x、垂直距离设为 y,锚点锁在 CORNER_LEFT_UPPER,也就是说从左上角往下 y 像素、往右 x 像素去摆文字,跟具体 K 线坐标脱钩,缩放窗口也不会漂。 文字内容、颜色、字号分别走 ObjectSetString 和 ObjectSetInteger:这里硬编码了 "Arial Bold" 和调用方传入的 txtColor、fontSize。改字体不必动逻辑,只换 OBJPROP_FONT 的字符串即可,但需注意部分 MT5 环境对粗体映射支持不一致,肉眼核对一次更稳。 标签画完必须调 ChartRedraw(),否则在 OnTimer / 事件回调里新建的对象可能不立即刷新,这是实盘挂提示标签时的高频坑。函数返回 true 代表创建链路通了,返回 false 前会用 Print 把 GetLastError() 的错误码带出来,开 MT5 跑一遍就能在专家日志里看到具体号码。 下单部分用 CTrade 的 Buy / Sell 封装:传入 tradeLotSize 与 _Symbol,后三个 0 分别是滑点容差、止损、止盈,全 0 即不挂保护性订单。外汇与贵金属杠杆高,不设止损的开仓逻辑在波动放大时可能迅速扩大浮亏,仅作代码验证用途。 tradeResult 为 true 才把事件 id 写进 triggeredNewsEvents 数组并置 tradeExecuted,否则只打印错误码。数组用 ArrayResize 动态加 1,这种写法在事件稀疏时没压力,但若每秒多次触发建议预分配容量,减少反复拷贝开销。

MQL5 / C++
   class=class="str">"cmt">//--- Print error message with the label name and the error code
   Print("Error creating label ", objName, " : ", GetLastError());
   class=class="str">"cmt">//--- Return false to indicate label creation failure
   class="kw">return false;
   }
   class=class="str">"cmt">//--- Set the horizontal distance(X coordinate) for the label
   ObjectSetInteger(class="num">0, objName, OBJPROP_XDISTANCE, x);
   class=class="str">"cmt">//--- Set the vertical distance(Y coordinate) for the label
   ObjectSetInteger(class="num">0, objName, OBJPROP_YDISTANCE, y);
   class=class="str">"cmt">//--- Set the text that will appear on the label
   ObjectSetString(class="num">0, objName, OBJPROP_TEXT, text);
   class=class="str">"cmt">//--- Set the class="type">class="kw">color of the label&class="macro">#x27;s text
   ObjectSetInteger(class="num">0, objName, OBJPROP_COLOR, txtColor);
   class=class="str">"cmt">//--- Set the font size for the label text
   ObjectSetInteger(class="num">0, objName, OBJPROP_FONTSIZE, fontSize);
   class=class="str">"cmt">//--- Set the font style to "Arial Bold" for the label text
   ObjectSetString(class="num">0, objName, OBJPROP_FONT, "Arial Bold");
   class=class="str">"cmt">//--- Set the label&class="macro">#x27;s anchor corner to the top left of the chart
   ObjectSetInteger(class="num">0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   class=class="str">"cmt">//--- Redraw the chart to reflect the new label
   ChartRedraw();
   class=class="str">"cmt">//--- Return true indicating that the label was created successfully
   class="kw">return true;
}
class=class="str">"cmt">//--- Initialize a flag to store the result of the trade execution
class="type">bool tradeResult = false;
class=class="str">"cmt">//--- If the candidate trade side is BUY, attempt to execute a buy order
if(candidateTradeSide == "BUY") {
   tradeResult = trade.Buy(tradeLotSize, _Symbol, class="num">0, class="num">0, class="num">0, event.name);
}
class=class="str">"cmt">//--- Otherwise, if the candidate trade side is SELL, attempt to execute a sell order
else if(candidateTradeSide == "SELL") {
   tradeResult = trade.Sell(tradeLotSize, _Symbol, class="num">0, class="num">0, class="num">0, event.name);
}
class=class="str">"cmt">//--- If the trade was executed successfully, update the triggered events and trade flags
if(tradeResult) {
   Print("Trade executed for candidate event: ", event.name, " Side: ", candidateTradeSide);
   class="type">int size = ArraySize(triggeredNewsEvents);
   ArrayResize(triggeredNewsEvents, size + class="num">1);
   triggeredNewsEvents[size] = (class="type">int)values[i].event_id;
   tradeExecuted = true;
   tradedNewsTime = values[i].time;
} else {
   class=class="str">"cmt">//--- If trade execution failed, log the error message with the error code
   Print("Trade execution failed for candidate event: ", event.name, " Error: ", GetLastError());
}
class=class="str">"cmt">//--- Break out of the loop after processing the candidate event
break;

◍ 倒计时器与图表对象的生命周期管理

交易执行后,先用 TimeTradeServer 抓取服务器时间,跟预存的 tradedNewsTime 比大小。若还没到新闻时间,就折算剩余秒数成「时/分/秒」,用 IntegerToString 拼出「新闻倒计时:__小时 __分钟 __秒」这类标签;若已越过时间点但在 15 秒宽限内,则把背景刷成红色并显示「新闻已发布,XX秒后重置」。15 秒一到就删掉 NewsCountdown 对象并复位 tradeExecuted,系统才允许下一笔交易——外汇与贵金属新闻市况下滑点可能剧烈,这种硬复位能避免重复追单。 未进交易窗口时逻辑类似:当前时间小于候选事件时间且未达到 targetTime(事件时间减偏移),就按差值算倒计时,ObjectFind 找不到 NewsCountdown 就用 createButton1 在 X=50、Y=17 画一个 300×30 的蓝底按钮,找到了就 updateLabel1 改字。若筛选后无事件命中,直接 ObjectDelete 清掉 NewsCountdown 与 NewsTradeInfo,不留过期信息。 用户手动终止 EA 时,图表残留对象也得清。单独写个清理函数丢进 OnDeinit,顺手销毁仪表盘;另外 OnChartEvent 里要实时跟筛选状态,所以做了个 UpdateFilterInfo:拼「Filters: 」前缀,按 curr_filter_selected 和 imp_filter_selected 数组枚举已选货币与影响级别,Print 到 Experts 日志。OnTick 与 OnChartEvent 都调它,排错时一眼能看清当前过滤条件。 下方 createButton1 是整套对象创建的地基,参数含坐标、尺寸、文字色与背景色,失败就返回 false 并打错误码。你在 MT5 里把这个函数原样塞进 EA,就能复用给任意按钮型 HUD。

MQL5 / C++
class=class="str">"cmt">//--- Function to create a button on the chart with specified properties
class="type">bool createButton1(class="type">class="kw">string objName, class="type">int x, class="type">int y, class="type">int width, class="type">int height,
                    class="type">class="kw">string text, class="type">class="kw">color txtColor, class="type">int fontSize, class="type">class="kw">color bgColor, class="type">class="kw">color borderColor) {
  class=class="str">"cmt">//--- Attempt to create the button object; if it fails, log the error and class="kw">return false
  if(!ObjectCreate(class="num">0, objName, OBJ_BUTTON, class="num">0, class="num">0, class="num">0)) {
    class=class="str">"cmt">//--- Print error message with the button name and the error code
    Print("Error creating button ", objName, " : ", GetLastError());
    class=class="str">"cmt">//--- Return false to indicate button creation failure
    class="kw">return false;
  }
  class=class="str">"cmt">//--- Set the horizontal distance(X coordinate) for the button
  ObjectSetInteger(class="num">0, objName, OBJPROP_XDISTANCE, x);
  class=class="str">"cmt">//--- Set the vertical distance(Y coordinate) for the button
  ObjectSetInteger(class="num">0, objName, OBJPROP_YDISTANCE, y);
  class=class="str">"cmt">//--- Set the width of the button
  ObjectSetInteger(class="num">0, objName, OBJPROP_XSIZE, width);
  class=class="str">"cmt">//--- Set the height of the button
  ObjectSetInteger(class="num">0, objName, OBJPROP_YSIZE, height);
  class=class="str">"cmt">//--- Set the text that will appear on the button
  ObjectSetString(class="num">0, objName, OBJPROP_TEXT, text);
  class=class="str">"cmt">//--- Set the class="type">class="kw">color of the button&class="macro">#x27;s text
  ObjectSetInteger(class="num">0, objName, OBJPROP_COLOR, txtColor);
  class=class="str">"cmt">//--- Set the font size for the button text
  ObjectSetInteger(class="num">0, objName, OBJPROP_FONTSIZE, fontSize);
  class=class="str">"cmt">//--- Set the font style to "Arial Bold" for the button text
  ObjectSetString(class="num">0, objName, OBJPROP_FONT, "Arial Bold");
  class=class="str">"cmt">//--- Set the background class="type">class="kw">color of the button

「给按钮和标签挂上事件前的属性落定」

在 MT5 图表上用 ObjectSetInteger 给自定义按钮定属性时,后台色、边框色、锚点角必须一并写死。下面这段把锚点锁在左上角(CORNER_LEFT_UPPER),并开启 OBJPROP_BACK 让按钮沉到背景层,避免挡住 K 线实体。 ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, bgColor); // 设按钮背景色 ObjectSetInteger(0, objName, OBJPROP_BORDER_COLOR, borderColor); // 设边框色 ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // 锚点左上 ObjectSetInteger(0, objName, OBJPROP_BACK, true); // 置背景层 ChartRedraw(); // 重绘生效 return true; // 创建成功 更新已有文字标签别重复造对象,先用 ObjectFind 判存在性,返回小于 0 就 Print 报错并 return false,能少踩很多“找不到对象”的坑。存在才用 ObjectSetString 改 OBJPROP_TEXT,再 ChartRedraw 一次即可。 新闻交易场景里,tradeExecuted 为真后先看 currentTime 是否早于 tradedNewsTime:用 (tradedNewsTime - currentTime) 强转 int 得剩余秒数,再除 3600 出小时、模 3600 除 60 出分钟、模 60 出秒。外汇与贵金属受消息跳空影响大,这类倒计时只作提示,实际滑点可能让成交偏离预期。

MQL5 / C++
ObjectSetInteger(class="num">0, objName, OBJPROP_BGCOLOR, bgColor);
class=class="str">"cmt">//--- Set the border class="type">class="kw">color of the button
ObjectSetInteger(class="num">0, objName, OBJPROP_BORDER_COLOR, borderColor);
class=class="str">"cmt">//--- Set the button&class="macro">#x27;s anchor corner to the top left of the chart
ObjectSetInteger(class="num">0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
class=class="str">"cmt">//--- Enable the background display for the button
ObjectSetInteger(class="num">0, objName, OBJPROP_BACK, true);
class=class="str">"cmt">//--- Redraw the chart to reflect the new button
ChartRedraw();
class=class="str">"cmt">//--- Return true indicating that the button was created successfully
class="kw">return true;
}
class=class="str">"cmt">//--- Function to update the text of an existing label
class="type">bool updateLabel1(class="type">class="kw">string objName, class="type">class="kw">string text) {
class=class="str">"cmt">//--- Check if the label exists on the chart; if not, log the error and class="kw">return false
if(ObjectFind(class="num">0, objName) < class="num">0) {
class=class="str">"cmt">//--- Print error message indicating that the label was not found
Print("updateLabel1: Object ", objName, " not found.");
class=class="str">"cmt">//--- Return false because the label does not exist
class="kw">return false;
}
class=class="str">"cmt">//--- Update the label&class="macro">#x27;s text class="kw">property with the new text
ObjectSetString(class="num">0, objName, OBJPROP_TEXT, text);
class=class="str">"cmt">//--- Redraw the chart to update the label display
ChartRedraw();
class=class="str">"cmt">//--- Return true indicating that the label was updated successfully
class="kw">return true;
}
class=class="str">"cmt">//--- Function to update the text of an existing label
class="type">bool updateLabel1(class="type">class="kw">string objName, class="type">class="kw">string text) {
class=class="str">"cmt">//--- Check if the label exists on the chart; if not, log the error and class="kw">return false
if(ObjectFind(class="num">0, objName) < class="num">0) {
class=class="str">"cmt">//--- Print error message indicating that the label was not found
Print("updateLabel1: Object ", objName, " not found.");
class=class="str">"cmt">//--- Return false because the label does not exist
class="kw">return false;
}
class=class="str">"cmt">//--- Update the label&class="macro">#x27;s text class="kw">property with the new text
ObjectSetString(class="num">0, objName, OBJPROP_TEXT, text);
class=class="str">"cmt">//--- Redraw the chart to update the label display
ChartRedraw();
class=class="str">"cmt">//--- Return true indicating that the label was updated successfully
class="kw">return true;
}
class=class="str">"cmt">//--- Begin handling the post-trade countdown scenario
if(tradeExecuted) {
class=class="str">"cmt">//--- If the current time is before the traded news time, display the countdown until news release
if(currentTime < tradedNewsTime) {
class=class="str">"cmt">//--- Calculate the remaining seconds until the traded news time
class="type">int remainingSeconds = (class="type">int)(tradedNewsTime - currentTime);
class=class="str">"cmt">//--- Calculate hours from the remaining seconds
class="type">int hrs = remainingSeconds / class="num">3600;
class=class="str">"cmt">//--- Calculate minutes from the remaining seconds
class="type">int mins = (remainingSeconds % class="num">3600) / class="num">60;
class=class="str">"cmt">//--- Calculate seconds remainder
class="type">int secs = remainingSeconds % class="num">60;

财经事件触发的重置倒计时逻辑

新闻交易 EA 在事件时间到达后并不立即清场,而是用一段 15 秒的缓冲来提示重置。代码里先算 currentTime 与 tradedNewsTime 的差值 elapsed,若 elapsed < 15 就进入重置分支,剩余秒数 = 15 - elapsed,拼成 "News Released, resetting in: Xs" 的提示串。 创建或更新名为 NewsCountdown 的标签时,未创建则调 createButton1 以红底(clrRed)生成,已存在则走 updateLabel1 改文字;红底还额外用 ObjectSetInteger 显式设 OBJPROP_BGCOLOR,避免部分 MT5 版本按钮背景不刷新。 这套机制的价值在于:外汇与贵金属在新闻秒级波动里风险极高,15 秒视觉锁能让你在 EA 自动复位前手动干预或肉眼确认滑点。开 MT5 把 tradedNewsTime 改成距当前 20 秒,跑一遍就能看到蓝底倒计时切红底重置的全过程。

MQL5 / C++
class="type">class="kw">string countdownText = "News in: " + IntegerToString(hrs) + "h " +
                         IntegerToString(mins) + "m " +
                         IntegerToString(secs) + "s";
if(ObjectFind(class="num">0, "NewsCountdown") < class="num">0) {
   createButton1("NewsCountdown", class="num">50, class="num">17, class="num">300, class="num">30, countdownText, clrWhite, class="num">12, clrBlue, clrBlack);
   Print("Post-trade countdown created: ", countdownText);
} else {
   updateLabel1("NewsCountdown", countdownText);
   Print("Post-trade countdown updated: ", countdownText);
}
 } else {
   class="type">int elapsed = (class="type">int)(currentTime - tradedNewsTime);
   if(elapsed < class="num">15) {
      class="type">int remainingDelay = class="num">15 - elapsed;
      class="type">class="kw">string countdownText = "News Released, resetting in: " + IntegerToString(remainingDelay) + "s";
      if(ObjectFind(class="num">0, "NewsCountdown") < class="num">0) {
         createButton1("NewsCountdown", class="num">50, class="num">17, class="num">300, class="num">30, countdownText, clrWhite, class="num">12, clrRed, clrBlack);
         ObjectSetInteger(class="num">0,"NewsCountdown",OBJPROP_BGCOLOR,clrRed);
         Print("Post-trade reset countdown created: ", countdownText);
      } else {
         updateLabel1("NewsCountdown", countdownText);
把新闻扫描交给小布盯盘
这些候选事件筛选与倒计时状态,小布盯盘的AIGC看板已内置,打开对应货币对页就能看到距发布剩余时间与预期差提示,你只管确认要不要跟信号。

常见问题

在交易逻辑中先确认两值均存在且非零,预测高于先前则倾向买、低于则倾向卖,相等或缺失就跳过该事件,避免假信号。
小布盯盘提供新闻预期差与倒计时可视化,但不自动下单;若你要自动执行仍可在MT5写EA,把重复盯盘劳动交给小布,你专注决策。
偏移量由品种波动与流动性决定,5分钟常见但非必须;外汇贵金属高风险,过窄易漏事件、过宽易遇噪音,建议回测后定。
分层筛选减少干扰信息,只处理相关高影响新闻,降低误触发概率,让自动化系统在多变市况中更可靠。