构建K线图趋势约束模型(第六部分):一体化集成·进阶篇
🔗

构建K线图趋势约束模型(第六部分):一体化集成·进阶篇

(2/3)·双通道通知代码各自为战,合并时隐蔽执行难确认送达,本篇拆解连贯函数整合逻辑

含代码示例 第 2/3 篇
把 Telegram 和 WhatsApp 通知各写一套程序,图表上却看不出信号是否真发出去了。隐藏命令行窗口虽不打扰操作,但漏发时你毫无察觉。把两路逻辑收进同一个 myAlert 函数,才能既跑得快又留得下痕。

「用 ShellExecuteW 把 MT5 警报推到外部聊天软件」

想在 MT5 触发信号时顺手发到 WhatsApp,核心不是 MQL5 自己联网,而是借 Windows 的 shell32.dll 起一个进程跑 Python 脚本。下面这段通过 #import 把 ShellExecuteW 引进来,参数里 hwnd 填 0、lpOperation 用 "open"、nShowCmd 用 1(普通窗口),返回码 ≤32 代表系统层调用失败。 警报本身套了一层冷却逻辑:alert_cooldown_seconds 输入项默认 60 秒,myAlert 每次进来先用 TimeCurrent() 减 last_alert_time,差值不够就直接 return,避免同一根 K 线里被刷屏。 真正发消息只在 type 为 indicator 或 info 时走分支:若 Audible_Alerts 开就 Alert() 弹窗响铃,Push_Notifications 开就 SendNotification() 推 MT5 移动端;同时拼出 whatsapp_command,把 python.exe 路径和脚本路径写死(注意原文是 C:\\Users\\Your_Computer_Name\\…\\Python312,需改成你本机实际路径),再用 cmd.exe /c 执行并 timeout 5 留 5 秒让脚本发完。 调试时 Print 会打出整条命令串,方便你直接粘到命令行手动复跑;若 whatsapp_result<=32 就说明 ShellExecuteW 没拉起 cmd,优先查路径空格转义与 Python 是否装在该目录。外汇与贵金属波动剧烈,这类外推仅作辅助提醒,信号误发或延迟都可能发生,实盘前务必在模拟盘验证通路。

MQL5 / C++
class="macro">#class="kw">import "shell32.dll"
class="type">int ShellExecuteW(class="type">int hwnd, class="type">class="kw">string lpOperation, class="type">class="kw">string lpFile, class="type">class="kw">string lpParameters, class="type">class="kw">string lpDirectory, class="type">int nShowCmd);
class="macro">#class="kw">import

class="type">class="kw">datetime last_alert_time;
input class="type">int alert_cooldown_seconds = class="num">60; class=class="str">"cmt">// Cooldown period in seconds
class="type">void myAlert(class="type">class="kw">string type, class="type">class="kw">string message) {
   class="type">class="kw">datetime current_time = TimeCurrent();
   if (current_time - last_alert_time < alert_cooldown_seconds) {
      class=class="str">"cmt">// Skip alert if within cooldown period
      class="kw">return;
   }
   last_alert_time = current_time;
   class="type">class="kw">string full_message = type + " | Trend Constraint V1.class="num">06 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message;
   if (type == "print") {
      Print(message);
   } else if (type == "error") {
      Print(type + " | Trend Constraint V1.class="num">06 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message);
   } else if (type == "order") {
      class=class="str">"cmt">// Add order alert handling if needed
   } else if (type == "modify") {
      class=class="str">"cmt">// Add modify alert handling if needed
   } else if (type == "indicator" || type == "info") {
      if (Audible_Alerts) {
         Alert(full_message);
      }
      if (Push_Notifications) {
         SendNotification(full_message);
      }
      class=class="str">"cmt">// Send to WhatsApp
      class="type">class="kw">string python_path = "C:\\Users\\Your_Computer_Name\\AppData\\Local\\Programs\\Python\\Python312\\python.exe";
      class="type">class="kw">string whatsapp_script_path = "C:\\Users\\Your_Computer_Name\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_whatsapp_message.py";
      class="type">class="kw">string whatsapp_command = python_path + " \"" + whatsapp_script_path + "\" \"" + full_message + "\"";
      
      class=class="str">"cmt">// Debugging: Print the command being executed for WhatsApp
      Print("Executing command to send WhatsApp message: ", whatsapp_command);
      class=class="str">"cmt">// Use cmd.exe to execute the command and then wait for class="num">5 seconds
      class="type">class="kw">string final_whatsapp_command = "/c " + whatsapp_command + " && timeout class="num">5";
      class="type">int whatsapp_result = ShellExecuteW(class="num">0, "open", "cmd.exe", final_whatsapp_command, NULL, class="num">1);
      if (whatsapp_result <= class="num">32) {

◍ 把信号推到 WhatsApp 与 Telegram 的桥接细节

在 MT5 的 EA 或脚本里调用外部 Python 发消息,核心是用 ShellExecuteW 拉起 cmd.exe 再跑 python 脚本。下面这段片段先处理 WhatsApp 失败分支:拿 GetLastError 码打印出来,成功则回显 result code,方便你当场判断是权限问题还是路径错。 Telegram 部分把 python 完整路径和脚本路径拼进命令字符串,注意 C:\\Users\\Your_Computer_Name\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\ 这类路径必须换成你本机真实用户名,否则 ShellExecuteW 返回 ≤32 直接进失败分支。 调试时在日志里打印最终 command 非常关键——曾有人在 cmd 里手动跑 python send_telegram_message.py "Trend Constraint V1.07 testing" 得到 Message sent successfully!,但 EA 里静默失败,差异就在转义引号与 && timeout 5 的有无。 冷却逻辑用 TimeCurrent 减 last_alert_time 判断是否小于 alert_cooldown_seconds,未过冷却直接 return,避免一秒触发几十条消息把号限流。外汇与贵金属信号推送本身不杠杆风险,但策略误报会带来高频干扰,实盘前先在 demo 账户验证推送链路。

MQL5 / C++
class="type">int error_code = GetLastError();
Print("Failed to execute WhatsApp Python script. Error code: ", error_code);
} else {
Print("Successfully executed WhatsApp Python script. Result code: ", whatsapp_result);
}
class=class="str">"cmt">// Send to Telegram
class="type">class="kw">string telegram_script_path = "C:\\Users\\Your_Computer_Name\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_telegram_message.py";
class="type">class="kw">string telegram_command = python_path + " \"" + telegram_script_path + "\" \"" + full_message + "\"";

class=class="str">"cmt">// Debugging: Print the command being executed for Telegram
Print("Executing command to send Telegram message: ", telegram_command);
class=class="str">"cmt">// Use cmd.exe to execute the command and then wait for class="num">5 seconds
class="type">class="kw">string final_telegram_command = "/c " + telegram_command + " && timeout class="num">5";
class="type">int telegram_result = ShellExecuteW(class="num">0, "open", "cmd.exe", final_telegram_command, NULL, class="num">1);
if (telegram_result <= class="num">32) {
class="type">int error_code = GetLastError();
Print("Failed to execute Telegram Python script. Error code: ", error_code);
} else {
Print("Successfully executed Telegram Python script. Result code: ", telegram_result);
}
}
}
class="type">class="kw">datetime current_time = TimeCurrent();
if (current_time - last_alert_time < alert_cooldown_seconds) {
class=class="str">"cmt">// Skip alert if within cooldown period
class="kw">return;
}
last_alert_time = current_time;

指标缓冲区与参数声明的底层结构

这套自定义指标一口气挂了 6 个绘图缓冲区和 6 个 indicator_plots,意味着 MT5 子窗口里能同时渲染箭头与线段两类信号。前 4 个 plot 是 DRAW_ARROW:买/卖主信号线宽 5、反转信号线宽 2,颜色分别用 0xFF3C00(橙红买)、0x0000FF(蓝卖)、0xE8351A(深红买反转)、0x1A1AE8(深蓝卖反转)做了区分。 后两个 plot 是 DRAW_LINE,宽度均为 2,橙黄 0xFFAA00 标买区、纯蓝 0x0000FF 标卖区,和箭头形成双层视觉确认。宏 PLOT_MAXIMUM_BARS_BACK 设 5000、OMIT_OLDEST_BARS 设 50,实际回看深度控制在最近 5000 根、计算时跳过最老 50 根,避免历史边界噪声。 输入参数里 RSI 超卖 30 / 超买 70 是经典阈值,慢 MA 200、快 MA 100 两线金叉死叉作为趋势过滤。Audible_Alerts 与 Push_Notifications 默认开,新信号会触发终端响铃和手机推送——外汇与贵金属波动剧烈,信号仅作概率参考,实盘须自担高风险。 代码里声明了 RSI_handle 及 7 组 MA_handle(MA~MA7),说明指标内部叠加了多周期均线阵列,并非单线判断。ShellExecuteW 从 shell32.dll 导入,预留了调外部程序的能力,开 MT5 把这段贴进 MQEditor 可直接编译看缓冲分配是否报错。

MQL5 / C++
class="macro">#class="kw">property indicator_buffers class="num">6
class="macro">#class="kw">property indicator_plots class="num">6
class="macro">#class="kw">property indicator_type1 DRAW_ARROW
class="macro">#class="kw">property indicator_width1 class="num">5
class="macro">#class="kw">property indicator_color1 0xFF3C00
class="macro">#class="kw">property indicator_label1 "Buy"
class="macro">#class="kw">property indicator_type2 DRAW_ARROW
class="macro">#class="kw">property indicator_width2 class="num">5
class="macro">#class="kw">property indicator_color2 0x0000FF
class="macro">#class="kw">property indicator_label2 "Sell"
class="macro">#class="kw">property indicator_type3 DRAW_ARROW
class="macro">#class="kw">property indicator_width3 class="num">2
class="macro">#class="kw">property indicator_color3 0xE8351A
class="macro">#class="kw">property indicator_label3 "Buy Reversal"
class="macro">#class="kw">property indicator_type4 DRAW_ARROW
class="macro">#class="kw">property indicator_width4 class="num">2
class="macro">#class="kw">property indicator_color4 0x1A1AE8
class="macro">#class="kw">property indicator_label4 "Sell Reversal"
class="macro">#class="kw">property indicator_type5 DRAW_LINE
class="macro">#class="kw">property indicator_style5 STYLE_SOLID
class="macro">#class="kw">property indicator_width5 class="num">2
class="macro">#class="kw">property indicator_color5 0xFFAA00
class="macro">#class="kw">property indicator_label5 "Buy"
class="macro">#class="kw">property indicator_type6 DRAW_LINE
class="macro">#class="kw">property indicator_style6 STYLE_SOLID
class="macro">#class="kw">property indicator_width6 class="num">2
class="macro">#class="kw">property indicator_color6 0x0000FF
class="macro">#class="kw">property indicator_label6 "Sell"
class="macro">#define PLOT_MAXIMUM_BARS_BACK class="num">5000
class="macro">#define OMIT_OLDEST_BARS class="num">50
class=class="str">"cmt">//--- indicator buffers
class="type">class="kw">double Buffer1[];
class="type">class="kw">double Buffer2[];
class="type">class="kw">double Buffer3[];
class="type">class="kw">double Buffer4[];
class="type">class="kw">double Buffer5[];
class="type">class="kw">double Buffer6[];
input class="type">class="kw">double Oversold = class="num">30;
input class="type">class="kw">double Overbought = class="num">70;
input class="type">int Slow_MA_period = class="num">200;
input class="type">int Fast_MA_period = class="num">100;
class="type">class="kw">datetime time_alert; class=class="str">"cmt">//used when sending alert
input class="type">bool Audible_Alerts = true;
input class="type">bool Push_Notifications = true;
class="type">class="kw">double myPoint; class=class="str">"cmt">//initialized in OnInit
class="type">int RSI_handle;
class="type">class="kw">double RSI[];
class="type">class="kw">double Open[];
class="type">class="kw">double Close[];
class="type">int MA_handle;
class="type">class="kw">double MA[];
class="type">int MA_handle2;
class="type">class="kw">double MA2[];
class="type">int MA_handle3;
class="type">class="kw">double MA3[];
class="type">int MA_handle4;
class="type">class="kw">double MA4[];
class="type">class="kw">double Low[];
class="type">class="kw">double High[];
class="type">int MA_handle5;
class="type">class="kw">double MA5[];
class="type">int MA_handle6;
class="type">class="kw">double MA6[];
class="type">int MA_handle7;
class="type">class="kw">double MA7[];
class=class="str">"cmt">//--- ShellExecuteW declaration ----------------------------------------------
class="macro">#class="kw">import "shell32.dll"

「给 EA 警报加上冷却与 WhatsApp 转发」

在 MT5 里跑趋势约束类 EA,最烦的是同一条信号在几秒内刷出十几条报警。下面这段代码用全局变量 last_alert_time 配合输入参数 alert_cooldown_seconds(默认 60 秒),把重复报警压住:距上次报警不足 60 秒的直接 return,读者可以把 60 改成 5 或 300 来适配自己的盯盘节奏。 myAlert() 函数按 type 分流:print 只写日志,error 带前缀写日志,indicator/info 类才触发 Alert() 弹窗和 SendNotification() 推送。若想让小布类工具替你跑这套,可把 Audible_Alerts、Push_Notifications 两个开关接进输入变量,避免硬改代码。 真正有意思的是 WhatsApp 分支:它拼出 python.exe 调用本地 send_whatsapp_message.py 的命令,再用 ShellExecuteW 拉起 cmd.exe 执行,并追加 && timeout 5 留 5 秒让脚本发完。ShellExecuteW 返回值 ≤32 表示 shell 调用失败(微软约定),EA 里应补一行 Print 报这个码,方便查路径错。路径里的 Your_Computer 必须换成你机子的实际用户名,否则 cmd 根本起不来。 外汇与贵金属杠杆高、滑点大,任何报警转发都只是辅助,信号错判可能造成实亏,上线前务必在策略测试器用历史数据跑通整条链路。

MQL5 / C++
class="type">int ShellExecuteW(class="type">int hwnd, class="type">class="kw">string lpOperation, class="type">class="kw">string lpFile, class="type">class="kw">string lpParameters, class="type">class="kw">string lpDirectory, class="type">int nShowCmd);
class="macro">#class="kw">import
class=class="str">"cmt">//--- global variables ------------------------------------------------------
class="type">class="kw">datetime last_alert_time;
input class="type">int alert_cooldown_seconds = class="num">60; class=class="str">"cmt">// Cooldown period in seconds
class=class="str">"cmt">//--- myAlert function ------------------------------------------------------
class="type">void myAlert(class="type">class="kw">string type, class="type">class="kw">string message) {
    class="type">class="kw">datetime current_time = TimeCurrent();
    if (current_time - last_alert_time < alert_cooldown_seconds) {
        class=class="str">"cmt">// Skip alert if within cooldown period
        class="kw">return;
    }
    last_alert_time = current_time;
    class="type">class="kw">string full_message = type + " | Trend Constraint V1.class="num">07 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message;
    if (type == "print") {
        Print(message);
    } else if (type == "error") {
        Print(type + " | Trend Constraint V1.class="num">07 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message);
    } else if (type == "order") {
        class=class="str">"cmt">// Add order alert handling if needed
    } else if (type == "modify") {
        class=class="str">"cmt">// Add modify alert handling if needed
    } else if (type == "indicator" || type == "info") {
        if (Audible_Alerts) {
            Alert(full_message);
        }
        if (Push_Notifications) {
            SendNotification(full_message);
        }
        class=class="str">"cmt">// Send to WhatsApp //Replace your_computer_name with the your actual computer name. //Make sure the path to your python and scripts is correct.
        class="type">class="kw">string python_path = "C:\\Users\\Your_Computer\\AppData\\Local\\Programs\\Python\\Python312\\python.exe";
        class="type">class="kw">string whatsapp_script_path = "C:\\Users\\Your_computer_name\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_whatsapp_message.py";
        class="type">class="kw">string whatsapp_command = python_path + " \"" + whatsapp_script_path + "\" \"" + full_message + "\"";
        
        class=class="str">"cmt">// Debugging: Print the command being executed for WhatsApp
        Print("Executing command to send WhatsApp message: ", whatsapp_command);
        class=class="str">"cmt">// Use cmd.exe to execute the command and then wait for class="num">5 seconds
        class="type">class="kw">string final_whatsapp_command = "/c " + whatsapp_command + " && timeout class="num">5";
        class="type">int whatsapp_result = ShellExecuteW(class="num">0, "open", "cmd.exe", final_whatsapp_command, NULL, class="num">1);
        if (whatsapp_result <= class="num">32) {

◍ 用 ShellExecuteW 外发信号并初始化箭头缓冲

这段逻辑把 MT5 指标算出的信号通过系统命令行甩给外部 Python 脚本,分别推到 WhatsApp 和 Telegram。ShellExecuteW 返回值若 ≤32 代表调用失败,此时用 GetLastError 拿系统错误码打印,便于在 MT5 专家日志里定位是路径问题还是权限问题。 Telegram 部分拼出的命令会先走 cmd.exe 的 /c 参数,末尾加 && timeout 5,意思是脚本跑完强制等 5 秒。这个等待在频繁触发的行情里可能拖慢主线程,若你用更高频率的 M1 周期,建议把 5 秒改短或改成异步。 OnInit 里给三个缓冲分别绑定箭头样式:Buffer1 用 241(向上箭头),Buffer2 用 242(向下箭头),Buffer3 留作第三状态。PLOT_DRAW_BEGIN 用 MathMax 卡住老 K 线,避免历史太长的回测把图形画到不可信区域。外汇与贵金属波动剧烈,这类外部通讯若失败可能漏发信号,实盘前务必在模拟盘验证脚本路径与返回值。

MQL5 / C++
class="type">int error_code = GetLastError();
Print("Failed to execute WhatsApp Python script. Error code: ", error_code);
} else {
Print("Successfully executed WhatsApp Python script. Result code: ", whatsapp_result);
}
class=class="str">"cmt">// Send to Telegram
class="type">class="kw">string telegram_script_path = "C:\\Users\\protech\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_telegram_message.py";
class="type">class="kw">string telegram_command = python_path + " \"" + telegram_script_path + "\" \"" + full_message + "\"";

class=class="str">"cmt">// Debugging: Print the command being executed for Telegram
Print("Executing command to send Telegram message: ", telegram_command);
class=class="str">"cmt">// Use cmd.exe to execute the command and then wait for class="num">5 seconds
class="type">class="kw">string final_telegram_command = "/c " + telegram_command + " && timeout class="num">5";
class="type">int telegram_result = ShellExecuteW(class="num">0, "open", "cmd.exe", final_telegram_command, NULL, class="num">1);
if (telegram_result <= class="num">32) {
class="type">int error_code = GetLastError();
Print("Failed to execute Telegram Python script. Error code: ", error_code);
} else {
Print("Successfully executed Telegram Python script. Result code: ", telegram_result);
}
}
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Custom indicator initialization function                         |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
  SetIndexBuffer(class="num">0, Buffer1);
  PlotIndexSetDouble(class="num">0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
  PlotIndexSetInteger(class="num">0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+class="num">1, OMIT_OLDEST_BARS+class="num">1));
  PlotIndexSetInteger(class="num">0, PLOT_ARROW, class="num">241);
  SetIndexBuffer(class="num">1, Buffer2);
  PlotIndexSetDouble(class="num">1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
  PlotIndexSetInteger(class="num">1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+class="num">1, OMIT_OLDEST_BARS+class="num">1));
  PlotIndexSetInteger(class="num">1, PLOT_ARROW, class="num">242);
  SetIndexBuffer(class="num">2, Buffer3);
  PlotIndexSetDouble(class="num">2, PLOT_EMPTY_VALUE, EMPTY_VALUE);

信号箭头与指标句柄的初始化落点

指标绘图缓冲的收尾绑定里,第 2、3、4、5 号绘图索引分别用 PlotIndexSetInteger 设了 PLOT_DRAW_BEGIN,取值是 Bars(Symbol(),PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1 与 OMIT_OLDEST_BARS+1 的较大者,箭头代码 236、238 分别对应两套买卖标记;空值统一交给 EMPTY_VALUE,避免旧数据在图表上留噪点。 启动阶段直接调 myAlert 发一条订阅确认文案,并顺手算 myPoint:当 Digits() 是 5 或 3 时,Point() 乘 10 修正点位精度,否则用原始 Point(),这一步决定了后面挂单距离和箭头偏移是否画歪。 RSI 用 iRSI(NULL,PERIOD_CURRENT,14,PRICE_CLOSE) 拿句柄,7 周期 SMMA 与 400 周期 SMA 分别由 iMA 生成;任一 handle 小于 0 就 Print 出错信息并 return(INIT_FAILED),MT5 终端里能看到具体 GetLastError 码,外汇与贵金属品种波动大,句柄创建失败往往和离线历史不足有关,开图前先加载够 K 线再拖指标更稳。

MQL5 / C++
PlotIndexSetInteger(class="num">2, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(),PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+class="num">1, OMIT_OLDEST_BARS+class="num">1));
PlotIndexSetInteger(class="num">2, PLOT_ARROW, class="num">236);
SetIndexBuffer(class="num">3, Buffer4);
PlotIndexSetDouble(class="num">3, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetInteger(class="num">3, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(),PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+class="num">1, OMIT_OLDEST_BARS+class="num">1));
PlotIndexSetInteger(class="num">3, PLOT_ARROW, class="num">238);
SetIndexBuffer(class="num">4, Buffer5);
PlotIndexSetDouble(class="num">4, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetInteger(class="num">4, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(),PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+class="num">1, OMIT_OLDEST_BARS+class="num">1));
SetIndexBuffer(class="num">5, Buffer6);
PlotIndexSetDouble(class="num">5, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetInteger(class="num">5, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(),PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+class="num">1, OMIT_OLDEST_BARS+class="num">1));
class=class="str">"cmt">// Send test message on launch
myAlert("info", "Thank you for subscribing. You shall be receiving Trend Constraint signal alerts via Whatsapp.");
class=class="str">"cmt">//initialize myPoint
myPoint = Point();
if(Digits() == class="num">5 || Digits() == class="num">3)
  {
   myPoint *= class="num">10;
  }
RSI_handle = iRSI(NULL, PERIOD_CURRENT, class="num">14, PRICE_CLOSE);
if(RSI_handle < class="num">0)
  {
   Print("The creation of iRSI has failed: RSI_handle=", INVALID_HANDLE);
   Print("Runtime error = ", GetLastError());
   class="kw">return(INIT_FAILED);
  }

MA_handle = iMA(NULL, PERIOD_CURRENT, class="num">7, class="num">0, MODE_SMMA, PRICE_CLOSE);
if(MA_handle < class="num">0)
  {
   Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE);
   Print("Runtime error = ", GetLastError());
   class="kw">return(INIT_FAILED);
  }

MA_handle2 = iMA(NULL, PERIOD_CURRENT, class="num">400, class="num">0, MODE_SMA, PRICE_CLOSE);
if(MA_handle2 < class="num">0)
  {
   Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE);
   Print("Runtime error = ", GetLastError());
让小布替你跑这套双通道播报
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到信号送达注释与日志,把重复劳动交给小布,你专注决策。

常见问题

两个代码段都用到 ShellExecuteW 与冷却期变量,提到顶部可避免重复声明、减少冲突,也方便在单一函数内统一调度执行逻辑。
小布盯盘的品种页已内置多通道信号注释与日志追踪,无需自己拼 MQL5 代码即可看到每次广播是否成功,贵金属与外汇波动快、杠杆高,请自行评估风险。
保留原有冷却期变量与判断分支,在扩展后的函数里对 WhatsApp 和 Telegram 共用同一冷却计时,任一路触发后即锁定时长。
本篇倾向在图表窗口为每次成功广播添加注释,或打印到平台日志;这样即使窗口隐藏,也能事后回溯投递状态。
具有一致效果的全局声明、冷却逻辑与执行封装被保留,功能不同的发送命令则并入同一函数分支,以确保最优且连贯。