使用MQL5经济日历进行交易(第五部分):添加响应式控件和过滤按钮的增强型仪表盘·进阶篇
📘

使用MQL5经济日历进行交易(第五部分):添加响应式控件和过滤按钮的增强型仪表盘·进阶篇

第 2/3 篇

给仪表盘按钮接上点击事件

要让 MT5 图表上的仪表盘能听指令,核心是重载 OnChartEvent。我们只截取 CHARTEVENT_OBJECT_CLICK 这一种事件 ID,其余图表变动一律忽略,避免无谓开销。 取消按钮逻辑最轻:命中 "CANCEL_BTN" 就把全局 isDashboardUpdate 置 false,再调 destroy_Dashboard 清掉所有图形对象。实测点击后界面立即归零,无残留句柄。 货币与过滤器按钮走同一套路:用 ObjectGetInteger(...,OBJPROP_STATE) 读选中态,把 enableCurrencyFilter 等标识同步,再用 ShortToString 把文本切到 ✓ 或 ✗,边框染绿(启用)或红(禁用),最后 ChartRedraw 强制重绘。

MQL5 / C++
class="type">int OnChartEvent(const class="type">int id, const class="type">long &lparam, const class="type">class="kw">double &dparam, const class="type">class="kw">string &sparam)
{
   if(id==CHARTEVENT_OBJECT_CLICK) class=class="str">"cmt">// 仅处理图表对象被点击
   {
      if(sparam=="CANCEL_BTN") class=class="str">"cmt">// 判断被点对象名
      {
         isDashboardUpdate=false; class=class="str">"cmt">// 禁止后续更新
         destroy_Dashboard(); class=class="str">"cmt">// 清除仪表盘元素
      }
   }
   class="kw">return(class="num">0);
}
货币按钮组用 StringFind 确认前缀 "CURRENCY_BTNS",命中后 ObjectGetString 取币名,依 OBJPROP_STATE 决定从 curr_filter_selected 数组删或增:删时左移覆盖再 ArrayResize 截尾,增时先查重再扩尾。每次变动 ArrayPrint 打数组,调 update_dashboard_values 重算。 关键点:update_dashboard_values 改成用 &curr_filter_array 引用传参,函数内改的就是原数组,大数组下省去拷贝。外汇与贵金属行情瞬变,这类界面交互仅辅助筛选,实盘仍属高风险,参数切换不代表方向判断。 重要性过滤要维护 impact_labels(None/Low/Medium/High)、impact_filter_selected 与 imp_filter_selected 三数组。初始化时若 enableImportanceFilter 为真,ArrayFree 后全量复制默认全开,遍历设按钮态并去边框色。点击 IMPACT_LABEL 按钮时,get_importance_level 把标签转枚举,再对两数组做增删,调 update_dashboard_values(curr_filter_selected, imp_filter_selected) 双参刷新。

MQL5 / C++
class="type">int OnChartEvent(const class="type">int id, const class="type">long &lparam, const class="type">class="kw">double &dparam, const class="type">class="kw">string &sparam)
{
   if(id==CHARTEVENT_OBJECT_CLICK) class=class="str">"cmt">// 仅处理图表对象被点击
   {
      if(sparam=="CANCEL_BTN") class=class="str">"cmt">// 判断被点对象名
      {
         isDashboardUpdate=false; class=class="str">"cmt">// 禁止后续更新
         destroy_Dashboard(); class=class="str">"cmt">// 清除仪表盘元素
      }
   }
   class="kw">return(class="num">0);
}

◍ 把字符串级别翻成枚举并接上时间窗

把用户在下拉框里选的 "Medium" 这类字符串,转成 MT5 日历函数认得的枚举值,是过滤器能跑起来的前提。内部用 for 循环扫 impact_label 数组,命中 selected_label 就返回 importance_levels 同索引的值;全扫完没命中则回落到 CALENDAR_IMPORTANCE_NONE,避免空指针式报错。 引用传递更新后的重要性数组进刷新函数,筛选器才能随界面偏好实时变。OnInit 里重构同类调用后,货币与重要性两条过滤链就接好了。 为了看清数据被砍到哪一层,全局定义了三个整型计数器:totalEvents_Considered 是过滤前的总进入量,totalEvents_Filtered 是被货币/重要性/时间剔掉的,totalEvents_Displayable 是最终能画在图表上的。进首个循环前先归零,再在循环里同步累加,到达显示上限就跳处理——这样溢出多少一眼可见。 实测一版输出里三个数分别是 11 / 24 / 539:11 是可显示上限,24 是筛完但画不下的,539 是起初纳入处理的全部新闻。外汇与贵金属事件受此过滤影响明显,杠杆环境下误筛可能漏掉波动源,属高风险配置。 时间窗用 ENUM_TIMEFRAMES 做输入:start_time 默认 PERIOD_H12 定起点,end_time 同样默认 PERIOD_H12 定终点,range_time 默认 PERIOD_H8 定跨度。编译后下拉可直接选,仪表盘随设随应。 下面这段 OnChartEvent 截取了取消与货币过滤按钮的点击响应,状态取 ObjectGetInteger 的 OBJPROP_STATE,勾选用 0x2714 对勾、取消用 0x274C 叉号,颜色随 clrLime / clrRed 切换。复制进 EA 的事件函数即可验证按钮联动。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|  OnChartEvent handler function                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void  OnChartEvent(
   const class="type">int      id,      class=class="str">"cmt">// event ID
   const class="type">long&    lparam,  class=class="str">"cmt">// class="type">long type event parameter
   const class="type">class="kw">double&  dparam,  class=class="str">"cmt">// class="type">class="kw">double type event parameter
   const class="type">class="kw">string&  sparam   class=class="str">"cmt">// class="type">class="kw">string type event parameter
){
class=class="str">"cmt">//---
}
if (id == CHARTEVENT_OBJECT_CLICK){ class=class="str">"cmt">//--- Check if the event is a click on an object

   if (sparam == CANCEL_BTN){ class=class="str">"cmt">//--- If the Cancel button is clicked
      isDashboardUpdate = false; class=class="str">"cmt">//--- Set dashboard update flag to false
      destroy_Dashboard(); class=class="str">"cmt">//--- Call the function to destroy the dashboard
   }
}
if (sparam == FILTER_CURR_BTN){ class=class="str">"cmt">//--- If the Currency filter button is clicked
   class="type">bool btn_state = ObjectGetInteger(class="num">0,sparam,OBJPROP_STATE); class=class="str">"cmt">//--- Get the button state(clicked/unclicked)
   enableCurrencyFilter = btn_state; class=class="str">"cmt">//--- Update the Currency filter flag
   Print(sparam+" STATE = "+(class="type">class="kw">string)btn_state+", FLAG = "+(class="type">class="kw">string)enableCurrencyFilter); class=class="str">"cmt">//--- Log the state
   class="type">class="kw">string filter_curr_text = enableCurrencyFilter ? ShortToString(0x2714)+"Currency" : ShortToString(0x274C)+"Currency"; class=class="str">"cmt">//--- Set button text based on state
   class="type">color filter_curr_txt_color = enableCurrencyFilter ? clrLime : clrRed; class=class="str">"cmt">//--- Set button text class="type">color based on state
   ObjectSetString(class="num">0,FILTER_CURR_BTN,OBJPROP_TEXT,filter_curr_text); class=class="str">"cmt">//--- Update the button text
   ObjectSetInteger(class="num">0,FILTER_CURR_BTN,OBJPROP_COLOR,filter_curr_txt_color); class=class="str">"cmt">//--- Update the button text class="type">color

「按钮点击后怎么改写面板状态」

在 MT5 自定义指标里,给三个过滤器按钮(货币、重要性、时间)绑定点击事件后,核心动作就是读按钮状态、改全局旗标、刷新标签文字与颜色,最后重绘图表。 以重要性过滤为例:先用 ObjectGetInteger(0,sparam,OBJPROP_STATE) 拿到按钮当前是否被按下,把值赋给 enableImportanceFilter。接着用 ShortToString(0x2714) 拼出对勾、0x274C 拼出叉号,开启时文字显绿(clrLime)、关闭时显红(clrRed),再分别用 ObjectSetString 和 ObjectSetInteger 写回按钮。 每次处理完都调 ChartRedraw(0) 让 0 号图表立即反映改动;日志里 Print 出 STATE 与 FLAG,方便你在专家日志里核对。外汇与贵金属事件过滤涉及高风险,按钮逻辑只解决显示与标记,不预示行情方向。 货币按钮走另一分支:StringFind(sparam,CURRENCY_BTNS)>=0 命中后,用 ObjectGetString 取按钮文字得到具体货币对,再读 OBJPROP_STATE;若 btn_state==false 表示用户取消了该货币的选择,后续应据此从绘制集合里剔除。

MQL5 / C++
Print("Success. Changes updated! State: "+(class="type">class="kw">string)enableCurrencyFilter); class=class="str">"cmt">//--- Log success
ChartRedraw(class="num">0); class=class="str">"cmt">//--- Redraw the chart to reflect changes
}
if (sparam == FILTER_IMP_BTN){ class=class="str">"cmt">//--- If the Importance filter button is clicked
  class="type">bool btn_state = ObjectGetInteger(class="num">0,sparam,OBJPROP_STATE); class=class="str">"cmt">//--- Get the button state
  enableImportanceFilter = btn_state; class=class="str">"cmt">//--- Update the Importance filter flag
  Print(sparam+" STATE = "+(class="type">class="kw">string)btn_state+", FLAG = "+(class="type">class="kw">string)enableImportanceFilter); class=class="str">"cmt">//--- Log the state
  class="type">class="kw">string filter_imp_text = enableImportanceFilter ? ShortToString(0x2714)+"Importance" : ShortToString(0x274C)+"Importance"; class=class="str">"cmt">//--- Set button text
  class="type">color filter_imp_txt_color = enableImportanceFilter ? clrLime : clrRed; class=class="str">"cmt">//--- Set button text class="type">color
  ObjectSetString(class="num">0,FILTER_IMP_BTN,OBJPROP_TEXT,filter_imp_text); class=class="str">"cmt">//--- Update the button text
  ObjectSetInteger(class="num">0,FILTER_IMP_BTN,OBJPROP_COLOR,filter_imp_txt_color); class=class="str">"cmt">//--- Update the button text class="type">color
  Print("Success. Changes updated! State: "+(class="type">class="kw">string)enableImportanceFilter); class=class="str">"cmt">//--- Log success
  ChartRedraw(class="num">0); class=class="str">"cmt">//--- Redraw the chart
}
if (sparam == FILTER_TIME_BTN){ class=class="str">"cmt">//--- If the Time filter button is clicked
  class="type">bool btn_state = ObjectGetInteger(class="num">0,sparam,OBJPROP_STATE); class=class="str">"cmt">//--- Get the button state
  enableTimeFilter = btn_state; class=class="str">"cmt">//--- Update the Time filter flag
  Print(sparam+" STATE = "+(class="type">class="kw">string)btn_state+", FLAG = "+(class="type">class="kw">string)enableTimeFilter); class=class="str">"cmt">//--- Log the state
  class="type">class="kw">string filter_time_text = enableTimeFilter ? ShortToString(0x2714)+"Time" : ShortToString(0x274C)+"Time"; class=class="str">"cmt">//--- Set button text
  class="type">color filter_time_txt_color = enableTimeFilter ? clrLime : clrRed; class=class="str">"cmt">//--- Set button text class="type">color
  ObjectSetString(class="num">0,FILTER_TIME_BTN,OBJPROP_TEXT,filter_time_text); class=class="str">"cmt">//--- Update the button text
  ObjectSetInteger(class="num">0,FILTER_TIME_BTN,OBJPROP_COLOR,filter_time_txt_color); class=class="str">"cmt">//--- Update the button text class="type">color
  Print("Success. Changes updated! State: "+(class="type">class="kw">string)enableTimeFilter); class=class="str">"cmt">//--- Log success
  ChartRedraw(class="num">0); class=class="str">"cmt">//--- Redraw the chart
}
if (StringFind(sparam,CURRENCY_BTNS) >= class="num">0){ class=class="str">"cmt">//--- If a Currency button is clicked
  class="type">class="kw">string selected_curr = ObjectGetString(class="num">0,sparam,OBJPROP_TEXT); class=class="str">"cmt">//--- Get the text of the clicked button
  Print("BTN NAME = ",sparam,", CURRENCY = ",selected_curr); class=class="str">"cmt">//--- Log the button name and currency
  
  class="type">bool btn_state = ObjectGetInteger(class="num">0,sparam,OBJPROP_STATE); class=class="str">"cmt">//--- Get the button state
  
  if (btn_state == false){ class=class="str">"cmt">//--- If the button is unselected

按钮状态驱动的品种过滤数组增删

这段逻辑挂在按钮事件回调里,靠 btn_state 的布尔值判断用户是取消勾选还是选中某个货币对。取消时先 Print 提示未选模式,再遍历 curr_filter_selected 数组,命中 selected_curr 就做前向覆盖移位并 ArrayResize 缩容 1,最后 break 退出。 选中分支先跑一遍重复检测:用 already_selected 标记,若目标品种已存在于数组则直接打印日志不重复添加。未重复才 ArrayResize 扩容 1,把新值塞到末位索引 ArraySize-1。 无论哪条分支,收尾都会打印 SELECTED ARRAY SIZE 与实际数组内容,调用 update_dashboard_values 刷新面板,ChartRedraw(0) 强制重绘。外汇与贵金属品种过滤涉及高杠杆风险,数组误操作可能导致面板显示与真实持仓过滤不一致,建议开 MT5 用这段在 EURUSD 按钮上断点验证数组长度变化。

MQL5 / C++
Print("BUTTON IS IN UN-SELECTED MODE.");
class=class="str">"cmt">//--- Loop to find and remove the currency from the array
for (class="type">int i = class="num">0; i < ArraySize(curr_filter_selected); i++) {
      if (curr_filter_selected[i] == selected_curr) {
            class=class="str">"cmt">//--- Shift elements to remove the selected currency
            for (class="type">int j = i; j < ArraySize(curr_filter_selected) - class="num">1; j++) {
                  curr_filter_selected[j] = curr_filter_selected[j + class="num">1];
            }
            ArrayResize(curr_filter_selected, ArraySize(curr_filter_selected) - class="num">1); class=class="str">"cmt">//--- Resize the array
            Print("Removed from selected filters: ", selected_curr); class=class="str">"cmt">//--- Log removal
            break;
      }
}
 }
 else if (btn_state == true){ class=class="str">"cmt">//--- If the button is selected
   Print("BUTTON IS IN SELECTED MODE. TAKE ACTION");
   class=class="str">"cmt">//--- Check for duplicates
   class="type">bool already_selected = false;
   for (class="type">int j = class="num">0; j < ArraySize(curr_filter_selected); j++) {
         if (curr_filter_selected[j] == selected_curr) {
               already_selected = true;
               break;
         }
   }
   class=class="str">"cmt">//--- If not already selected, add to the array
   if (!already_selected) {
         ArrayResize(curr_filter_selected, ArraySize(curr_filter_selected) + class="num">1); class=class="str">"cmt">//--- Resize array
         curr_filter_selected[ArraySize(curr_filter_selected) - class="num">1] = selected_curr; class=class="str">"cmt">//--- Add the new currency
         Print("Added to selected filters: ", selected_curr); class=class="str">"cmt">//--- Log addition
   }
   else {
         Print("Currency already selected: ", selected_curr); class=class="str">"cmt">//--- Log already selected
   }
   
 }
 Print("SELECTED ARRAY SIZE = ",ArraySize(curr_filter_selected)); class=class="str">"cmt">//--- Log the size of the selected array
 ArrayPrint(curr_filter_selected); class=class="str">"cmt">//--- Print the selected array

 update_dashboard_values(curr_filter_selected); class=class="str">"cmt">//--- Update the dashboard with the selected filters
 Print("SUCCESS. DASHBOARD UPDATED"); class=class="str">"cmt">//--- Log success

 ChartRedraw(class="num">0); class=class="str">"cmt">//--- Redraw the chart to reflect changes
}

class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Function to update dashboard values                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void update_dashboard_values(class="type">class="kw">string &curr_filter_array[]){

◍ 财经事件面板的币种与重要性过滤逻辑

在 MT5 自定义面板里做事件筛选,核心是先判断开关是否打开,再决定要不要把这条事件画上屏。下面这段逻辑用 enableCurrencyFilter 控制币种过滤:数组 curr_filter_array 存着你关心的货币(比如 EUR、USD、XAU),遍历比对 country.currency,命中就置 currencyMatch=true 并 break,否则直接 continue 跳到下一条。

MQL5 / C++
class=class="str">"cmt">//--- 检查事件币种是否落在过滤数组内(仅当过滤开启时)
class="type">bool currencyMatch = false;
if (enableCurrencyFilter) {
  for (class="type">int j = class="num">0; j < ArraySize(curr_filter_array); j++) {
    if (country.currency == curr_filter_array[j]) {
      currencyMatch = true;
      break;
    }
  }
  class=class="str">"cmt">//--- 未命中则跳过该事件
  if (!currencyMatch) {
    class="kw">continue;
  }
}
class=class="str">"cmt">//---
}
if (sparam == FILTER_CURR_BTN){ class=class="str">"cmt">//--- 点击币种过滤按钮
  class="type">bool btn_state = ObjectGetInteger(class="num">0,sparam,OBJPROP_STATE); class=class="str">"cmt">//--- 读取按钮状态
  enableCurrencyFilter = btn_state; class=class="str">"cmt">//--- 同步过滤标志位
  Print(sparam+" STATE = "+(class="type">class="kw">string)btn_state+", FLAG = "+(class="type">class="kw">string)enableCurrencyFilter); class=class="str">"cmt">//--- 打印日志
  class="type">class="kw">string filter_curr_text = enableCurrencyFilter ? ShortToString(0x2714)+"Currency" : ShortToString(0x274C)+"Currency"; class=class="str">"cmt">//--- 按状态写按钮文字(✔/✖)
  class="type">color filter_curr_txt_color = enableCurrencyFilter ? clrLime : clrRed; class=class="str">"cmt">//--- 开绿关红
  ObjectSetString(class="num">0,FILTER_CURR_BTN,OBJPROP_TEXT,filter_curr_text); class=class="str">"cmt">//--- 刷新文字
  ObjectSetInteger(class="num">0,FILTER_CURR_BTN,OBJPROP_COLOR,filter_curr_txt_color); class=class="str">"cmt">//--- 刷新颜色
  update_dashboard_values(curr_filter_selected); class=class="str">"cmt">//--- 重算面板数据
  Print("Success. Changes updated! State: "+(class="type">class="kw">string)enableCurrencyFilter); class=class="str">"cmt">//--- 成功日志
  ChartRedraw(class="num">0); class=class="str">"cmt">//--- 重绘图表
}
if (sparam == FILTER_IMP_BTN){ class=class="str">"cmt">//--- 点击重要性过滤按钮
  class="type">bool btn_state = ObjectGetInteger(class="num">0,sparam,OBJPROP_STATE); class=class="str">"cmt">//--- 读按钮状态
  enableImportanceFilter = btn_state; class=class="str">"cmt">//--- 同步重要性标志
  Print(sparam+" STATE = "+(class="type">class="kw">string)btn_state+", FLAG = "+(class="type">class="kw">string)enableImportanceFilter); class=class="str">"cmt">//--- 打印
  class="type">class="kw">string filter_imp_text = enableImportanceFilter ? ShortToString(0x2714)+"Importance" : ShortToString(0x274C)+"Importance"; class=class="str">"cmt">//--- 写✔/✖+Importance
  class="type">color filter_imp_txt_color = enableImportanceFilter ? clrLime : clrRed; class=class="str">"cmt">//--- 开绿关红
  ObjectSetString(class="num">0,FILTER_IMP_BTN,OBJPROP_TEXT,filter_imp_text); class=class="str">"cmt">//--- 刷文字
按钮回调里 0x2714 是勾号、0x274C 是叉号,用 ShortToString 转成面板能显示的字符;颜色用 clrLime / clrRed 直观区分开关。最后一句 ObjectSetString 只截到刷新文字,后面通常还跟着 ObjectSetInteger 改色和 ChartRedraw(0) 才会真正在图上生效。 外汇与贵金属受事件驱动跳空频繁,这类过滤只帮你少看噪音,不消除高风险;实盘前在策略测试器或 demo 上把 curr_filter_array 填好,点一下按钮看 Print 日志里的 FLAG 是否随状态翻转。

MQL5 / C++
class=class="str">"cmt">//--- Check if the event’s currency matches any in the filter array(if the filter is enabled)
   class="type">bool currencyMatch = false;
   if (enableCurrencyFilter) {
      for (class="type">int j = class="num">0; j < ArraySize(curr_filter_array); j++) {
         if (country.currency == curr_filter_array[j]) {
            currencyMatch = true;
            break;
         }
      }
      
      class=class="str">"cmt">//--- If no match found, skip to the next event
      if (!currencyMatch) {
         class="kw">continue;
      }
   }
class=class="str">"cmt">//---
}
if (sparam == FILTER_CURR_BTN){ class=class="str">"cmt">//--- If the Currency filter button is clicked
   class="type">bool btn_state = ObjectGetInteger(class="num">0,sparam,OBJPROP_STATE); class=class="str">"cmt">//--- Get the button state(clicked/unclicked)
   enableCurrencyFilter = btn_state; class=class="str">"cmt">//--- Update the Currency filter flag
   Print(sparam+" STATE = "+(class="type">class="kw">string)btn_state+", FLAG = "+(class="type">class="kw">string)enableCurrencyFilter); class=class="str">"cmt">//--- Log the state
   class="type">class="kw">string filter_curr_text = enableCurrencyFilter ? ShortToString(0x2714)+"Currency" : ShortToString(0x274C)+"Currency"; class=class="str">"cmt">//--- Set button text based on state
   class="type">color filter_curr_txt_color = enableCurrencyFilter ? clrLime : clrRed; class=class="str">"cmt">//--- Set button text class="type">color based on state
   ObjectSetString(class="num">0,FILTER_CURR_BTN,OBJPROP_TEXT,filter_curr_text); class=class="str">"cmt">//--- Update the button text
   ObjectSetInteger(class="num">0,FILTER_CURR_BTN,OBJPROP_COLOR,filter_curr_txt_color); class=class="str">"cmt">//--- Update the button text class="type">color
   update_dashboard_values(curr_filter_selected);
   Print("Success. Changes updated! State: "+(class="type">class="kw">string)enableCurrencyFilter); class=class="str">"cmt">//--- Log success
   ChartRedraw(class="num">0); class=class="str">"cmt">//--- Redraw the chart to reflect changes
}
if (sparam == FILTER_IMP_BTN){ class=class="str">"cmt">//--- If the Importance filter button is clicked
   class="type">bool btn_state = ObjectGetInteger(class="num">0,sparam,OBJPROP_STATE); class=class="str">"cmt">//--- Get the button state
   enableImportanceFilter = btn_state; class=class="str">"cmt">//--- Update the Importance filter flag
   Print(sparam+" STATE = "+(class="type">class="kw">string)btn_state+", FLAG = "+(class="type">class="kw">string)enableImportanceFilter); class=class="str">"cmt">//--- Log the state
   class="type">class="kw">string filter_imp_text = enableImportanceFilter ? ShortToString(0x2714)+"Importance" : ShortToString(0x274C)+"Importance"; class=class="str">"cmt">//--- Set button text
   class="type">color filter_imp_txt_color = enableImportanceFilter ? clrLime : clrRed; class=class="str">"cmt">//--- Set button text class="type">color
   ObjectSetString(class="num">0,FILTER_IMP_BTN,OBJPROP_TEXT,filter_imp_text); class=class="str">"cmt">//--- Update the button text

「按钮点击后怎么刷新财经事件面板」

在 MT5 自定义面板里,重要性过滤和时间过滤两个按钮的点击响应逻辑是分开写的。以时间过滤按钮为例,先用 ObjectGetInteger 读取 OBJPROP_STATE 拿到当前按钮状态,再赋给 enableTimeFilter 这个全局开关,Print 里把按钮名、状态和 flag 一起打出来方便排错。 按钮文字和颜色跟着状态走:勾选时拼 0x2714(✔)加 "Time"、文字染 clrLime,取消时换 0x274C(✘)加 "Time"、染 clrRed。ObjectSetString 改文字、ObjectSetInteger 改颜色,最后调用 update_dashboard_values 重算面板数据并 ChartRedraw 强制重绘。 重要性过滤开启时,代码先把 imp_filter_selected 和 impact_filter_selected 两个数组用 ArrayFree 清空,再 ArrayCopy 把四个级别(None/Low/Medium/High 对应 CALENDAR_IMPORTANCE_NONE 到 _HIGH)整体拷进去当默认全选。随后 for 循环按 IMPACT_LABEL+序号动态拼按钮名,把每个重要性按钮的 OBJPROP_STATE 设成 true,视觉上就是全亮。 外汇与贵金属受财经事件冲击大、滑点和跳空风险高,这类面板只帮你快速筛事件,不预示行情方向。把上面片段贴进 EA 的 OnChartEvent 分支,改 FILTER_TIME_BTN 的 0x2714/0x274C 就能换自己顺眼的标记符。

MQL5 / C++
ObjectSetInteger(class="num">0,FILTER_IMP_BTN,OBJPROP_COLOR,filter_imp_txt_color); class=class="str">"cmt">//--- Update the button text class="type">color
  update_dashboard_values(curr_filter_selected);
  Print("Success. Changes updated! State: "+(class="type">class="kw">string)enableImportanceFilter); class=class="str">"cmt">//--- Log success
  ChartRedraw(class="num">0); class=class="str">"cmt">//--- Redraw the chart
}
if (sparam == FILTER_TIME_BTN){ class=class="str">"cmt">//--- If the Time filter button is clicked
  class="type">bool btn_state = ObjectGetInteger(class="num">0,sparam,OBJPROP_STATE); class=class="str">"cmt">//--- Get the button state
  enableTimeFilter = btn_state; class=class="str">"cmt">//--- Update the Time filter flag
  Print(sparam+" STATE = "+(class="type">class="kw">string)btn_state+", FLAG = "+(class="type">class="kw">string)enableTimeFilter); class=class="str">"cmt">//--- Log the state
  class="type">class="kw">string filter_time_text = enableTimeFilter ? ShortToString(0x2714)+"Time" : ShortToString(0x274C)+"Time"; class=class="str">"cmt">//--- Set button text
  class="type">color filter_time_txt_color = enableTimeFilter ? clrLime : clrRed; class=class="str">"cmt">//--- Set button text class="type">color
  ObjectSetString(class="num">0,FILTER_TIME_BTN,OBJPROP_TEXT,filter_time_text); class=class="str">"cmt">//--- Update the button text
  ObjectSetInteger(class="num">0,FILTER_TIME_BTN,OBJPROP_COLOR,filter_time_txt_color); class=class="str">"cmt">//--- Update the button text class="type">color
  update_dashboard_values(curr_filter_selected);
  Print("Success. Changes updated! State: "+(class="type">class="kw">string)enableTimeFilter); class=class="str">"cmt">//--- Log success
  ChartRedraw(class="num">0); class=class="str">"cmt">//--- Redraw the chart
}

class=class="str">"cmt">//--- Define labels for impact levels and size of impact display areas
class="type">class="kw">string impact_labels[] = {"None","Low","Medium","High"};
class="type">class="kw">string impact_filter_selected[];
class=class="str">"cmt">// Define the levels of importance to filter(low, moderate, high)
ENUM_CALENDAR_EVENT_IMPORTANCE allowed_importance_levels[] = {CALENDAR_IMPORTANCE_NONE,CALENDAR_IMPORTANCE_LOW, CALENDAR_IMPORTANCE_MODERATE, CALENDAR_IMPORTANCE_HIGH};
ENUM_CALENDAR_EVENT_IMPORTANCE imp_filter_selected[];

if (enableImportanceFilter == true) {
  ArrayFree(imp_filter_selected); class=class="str">"cmt">//--- Clear the existing selections in the importance filter array
  ArrayCopy(imp_filter_selected, allowed_importance_levels); class=class="str">"cmt">//--- Copy all allowed importance levels as class="kw">default selections
  ArrayFree(impact_filter_selected);
  ArrayCopy(impact_filter_selected, impact_labels);
  Print("IMPORTANCE FILTER ENABLED"); class=class="str">"cmt">//--- Log that importance filter is enabled
  ArrayPrint(imp_filter_selected); class=class="str">"cmt">//--- Print the current selection of importance levels
  ArrayPrint(impact_filter_selected);

  class=class="str">"cmt">// Loop through the importance levels and set their buttons to "selected" state
  for (class="type">int i = class="num">0; i < ArraySize(imp_filter_selected); i++) {
    class="type">class="kw">string btn_name = IMPACT_LABEL+IntegerToString(i); class=class="str">"cmt">//--- Dynamically name the button for each importance level
    ObjectSetInteger(class="num">0, btn_name, OBJPROP_STATE, true); class=class="str">"cmt">//--- Set the button state to "clicked" (selected)

常见问题

多半是按钮的点击事件没和过滤枚举绑定,检查点击回调里是否把字符串级别转成了枚举并写入了过滤数组。
在币种过滤逻辑里维护一个币种数组,按钮点击时往里增删对应代号,再触发面板重绘即可。
小布可以替你跑这套按钮状态驱动的过滤逻辑,打开对应品种页就能直接看已过滤的事件面板,不用自己写回调。
是的,点击改写面板状态后必须显式调用重绘或数据重载,否则界面还停在旧数组上。
字符串比对受大小写和空格干扰,翻成枚举再接时间窗和过滤数组,逻辑更稳也更好维护。