开发一款波段交易入场监控智能交易系统(EA)·综合运用
🤖

开发一款波段交易入场监控智能交易系统(EA)·综合运用

(3/3)·把前两步的指标与逻辑收拢成一套能自动报警、可回测优化的MQL5监控EA,告别盯盘疲劳

含代码示例实战向 第 3/3 篇
很多人卡在指标写完了却不会把它变成能跑的EA,结果还是手动刷图表等信号。本篇把EMA100监控逻辑封装成自动报警系统,让你只在收到提示时做决策。外汇与贵金属杠杆高、波动大,信号再好也只代表概率优势。

把 EMA100 弹点信号接进多通道报警

这段逻辑干的事很直接:当自定义指标的 buffer1 或 buffer2 在最新柱不为 EMPTY_VALUE,且当前时间不等于上一次报警时间,就触发一条带品种名的提示,并把 lastAlertTime 刷新为 TimeCurrent(),避免同一根 K 线里反复弹窗。 代码里 buffer1 对应「Low 端 EMA100 弹点」、buffer2 对应「High 端 EMA100 弹点」,两条分支结构对称,只是 message 文本不同。实盘里 BTCUSD 这种高波动品种,EMA100 在 1H 图上被刺穿后回收的概率偏高,但外汇和贵金属同样套路风险更高,点差扩大时假信号会明显增多。 调试段用 CopyBuffer(emaHandle,0,0,1,emaValueArray) 只取 1 根值,ArraySetAsSeries 置为序列后 emaValueArray[0] 就是当前 EMA100 数值,Print 出来能在 MT5 终端日志里直接核对指标句柄是否生效;若返回小于等于 0 则打印 GetLastError() 方便排查。 EA 头部把报警拆成终端、推送、Telegram 三个开关,Telegram 默认关,填了 token 和 chat_id 才启用,URL 拼接里 timeout 写死 5000 毫秒,复制去跑前记得把 YOUR_BOT_TOKEN 换成真实值。

MQL5 / C++
class="type">class="kw">string message = "Signal detected: Look for EMA class="num">100 bounce(Low). Symbol: " + _Symbol;
AlertMessage(message);
lastAlertTime = TimeCurrent();
 }
 class=class="str">"cmt">// Check for signals in Buffer2
 if (buffer2[class="num">0] != EMPTY_VALUE && TimeCurrent() != lastAlertTime) {
   class="type">class="kw">string message = "Signal detected: Look for EMA class="num">100 bounce(High). Symbol: " + _Symbol;
   AlertMessage(message);
   lastAlertTime = TimeCurrent();
 }
 class=class="str">"cmt">// Debugging EMA class="num">100 value
 class="type">class="kw">double emaValueArray[];
 ArraySetAsSeries(emaValueArray, true); class=class="str">"cmt">// Ensure it&class="macro">#x27;s set as series
 if (CopyBuffer(emaHandle, class="num">0, class="num">0, class="num">1, emaValueArray) > class="num">0) {
   Print("EMA class="num">100 Current Value: ", emaValueArray[class="num">0]);
 } else {
   Print("Failed to read EMA class="num">100 buffer. Error: ", GetLastError());
 }
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Bitcoin Monitoring Expert Advisor                                |
class=class="str">"cmt">//| Copyright class="num">2024, Clemence Benjamin                                |
class=class="str">"cmt">//| [MQL5官方文档]             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Clemence Benjamin"
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.0"
class="macro">#class="kw">property description "BTCUSD Monitoring Expert Advisor"
class=class="str">"cmt">//--- Input parameters
input class="type">class="kw">string IndicatorName = "ema100_monitoring_indicator"; class=class="str">"cmt">// Name of the custom indicator
input class="type">bool EnableTerminalAlerts = true;
input class="type">bool EnablePushNotifications = true;
input class="type">bool EnableTelegramAlerts = false;
input class="type">class="kw">string TelegramBotToken = "YOUR_BOT_TOKEN";        class=class="str">"cmt">// Replace with your bot token
input class="type">class="kw">string TelegramChatID = "YOUR_CHAT_ID";            class=class="str">"cmt">// Replace with your chat ID
class=class="str">"cmt">//--- Indicator handles
class="type">int indicatorHandle = INVALID_HANDLE;
class="type">int emaHandle = INVALID_HANDLE;
class=class="str">"cmt">//--- Alert function
class="type">void AlertMessage(class="type">class="kw">string message) {
  if (EnableTerminalAlerts) Alert(message);
  if (EnablePushNotifications) SendNotification(message);
  if (EnableTelegramAlerts) SendTelegramMessage(message);
}
class=class="str">"cmt">//--- Telegram Alerting
class="type">void SendTelegramMessage(class="type">class="kw">string message) {
  if (EnableTelegramAlerts) {
    class="type">class="kw">string url = "https:class=class="str">"cmt">//api.telegram.org/bot" + TelegramBotToken + "/sendMessage?chat_id=" + TelegramChatID + "&text=" + message;
    class="type">int timeout = class="num">5000;

「EA 初始化与生命周期里的句柄管理」

这段 MT5 代码把监控 EA 的骨架搭清楚了:OnInit 里同时挂自定义指标和内置 EMA100,两个句柄任一失效就直接 INIT_FAILED,避免后续 OnTick 空跑。 ResetLastError(); char postData[]; uchar result[]; string response; int res = WebRequest("GET", url, NULL, timeout, postData, result, response); if (res != 200) { Print("Telegram WebRequest failed. Error: ", GetLastError(), ", HTTP Code: ", res); } else { Print("Telegram message sent successfully: ", response); } } 上面这段是 WebRequest 调 Telegram 的收尾:先清错误码再发 GET,HTTP 返回码不是 200 就打印错误号和码值,是 200 才认发送成功。实盘里若频繁看到非 200,优先查 MT5 的 URL 白名单和 timeout 参数(默认 5000ms 常不够)。 OnDeinit 用 IndicatorRelease 释放两个句柄,防止图表残留指标引用;OnTick 开头用 static datetime lastAlertTime 拦重复信号,这是低价高频品种(如 BTC 波动段)防刷屏的关键。外汇与贵金属品种同样适用该结构,但需注意杠杆放大下信号触发频率更高,风险也更大。

MQL5 / C++
ResetLastError();
class="type">char postData[];
class="type">uchar result[];
class="type">class="kw">string response;
class="type">int res = WebRequest("GET", url, NULL, timeout, postData, result, response);
if (res != class="num">200) {
   Print("Telegram WebRequest failed. Error: ", GetLastError(), ", HTTP Code: ", res);
} else {
   Print("Telegram message sent successfully: ", response);
}
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert initialization function                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit() {
   Print("Bitcoin Monitoring EA started.");
   class=class="str">"cmt">// Attach the custom indicator to the chart
   indicatorHandle = iCustom(_Symbol, _Period, IndicatorName);
   if (indicatorHandle == INVALID_HANDLE) {
      Print("Failed to attach indicator: ", IndicatorName, ". Error: ", GetLastError());
      class="kw">return(INIT_FAILED);
   }
   class=class="str">"cmt">// Attach built-in EMA class="num">100 to the chart
   emaHandle = iMA(_Symbol, _Period, class="num">100, class="num">0, MODE_EMA, PRICE_CLOSE);
   if (emaHandle == INVALID_HANDLE) {
      Print("Failed to create EMA class="num">100. Error: ", GetLastError());
      class="kw">return(INIT_FAILED);
   }
   class=class="str">"cmt">// Add EMA class="num">100 to the terminal chart
   if (!ChartIndicatorAdd(class="num">0, class="num">0, emaHandle)) {
      Print("Failed to add EMA class="num">100 to the chart. Error: ", GetLastError());
   }
   class="kw">return(INIT_SUCCEEDED);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert deinitialization function                                   |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(const class="type">int reason) {
   Print("Bitcoin Monitoring EA stopped.");
   if (indicatorHandle != INVALID_HANDLE) {
      IndicatorRelease(indicatorHandle);
   }
   if (emaHandle != INVALID_HANDLE) {
      IndicatorRelease(emaHandle);
   }
}
class="type">void OnTick() {
   class="kw">static class="type">class="kw">datetime lastAlertTime = class="num">0; class=class="str">"cmt">// Prevent repeated alerts for the same signal
   if (indicatorHandle == INVALID_HANDLE || emaHandle == INVALID_HANDLE) class="kw">return;
   class="type">class="kw">double buffer1[], buffer2[];
   ArraySetAsSeries(buffer1, true);
   ArraySetAsSeries(buffer2, true);
   class=class="str">"cmt">// Read data from the custom indicator

◍ 缓冲读取与 EMA100 弹跳信号触发

指标句柄拿到之后,第一步是把两条信号缓冲各取最新一根柱的值。CopyBuffer 的第三、四参数填 0 和 1,意思是从当前柱开始复制 1 个元素的数组;返回值为负就直接 Print 错误码并 return,避免后续空数组越界。 信号判定只看 buffer1[0] 和 buffer2[0] 是否不等于 EMPTY_VALUE,同时用 TimeCurrent() != lastAlertTime 做同根柱去重。命中后拼出带 _Symbol 的提示语走 AlertMessage,并把 lastAlertTime 刷成当前时间,这样同一根 K 线里不会重复弹窗。 顺手把 EMA100 也拉进来做调试输出。ArraySetAsSeries 设成 true 后,emaValueArray[0] 才是当下价格对应的均线值;CopyBuffer 成功就 Print 出具体数值,失败则报 GetLastError,方便你在 MT5 终端里核对弹跳参考位。 外汇与贵金属波动剧烈,EMA100 弹跳仅代表价格触及参考均线,后续反转属概率事件,实盘请自担高风险。

MQL5 / C++
  if (CopyBuffer(indicatorHandle, class="num">0, class="num">0, class="num">1, buffer1) < class="num">0) {
      Print("Failed to copy Buffer1. Error: ", GetLastError());
      class="kw">return;
  }
  if (CopyBuffer(indicatorHandle, class="num">1, class="num">0, class="num">1, buffer2) < class="num">0) {
      Print("Failed to copy Buffer2. Error: ", GetLastError());
      class="kw">return;
  }
  class=class="str">"cmt">// Check for signals in Buffer1
  if (buffer1[class="num">0] != EMPTY_VALUE && TimeCurrent() != lastAlertTime) {
      class="type">class="kw">string message = "Signal detected: Look for EMA class="num">100 bounce(Low). Symbol: " + _Symbol;
      AlertMessage(message);
      lastAlertTime = TimeCurrent();
  }
  class=class="str">"cmt">// Check for signals in Buffer2
  if (buffer2[class="num">0] != EMPTY_VALUE && TimeCurrent() != lastAlertTime) {
      class="type">class="kw">string message = "Signal detected: Look for EMA class="num">100 bounce(High). Symbol: " + _Symbol;
      AlertMessage(message);
      lastAlertTime = TimeCurrent();
  }
  class=class="str">"cmt">// Debugging EMA class="num">100 value
  class="type">class="kw">double emaValueArray[];
  ArraySetAsSeries(emaValueArray, true); class=class="str">"cmt">// Ensure it&class="macro">#x27;s set as series
  if (CopyBuffer(emaHandle, class="num">0, class="num">0, class="num">1, emaValueArray) > class="num">0) {
      Print("EMA class="num">100 Current Value: ", emaValueArray[class="num">0]);
  } else {
      Print("Failed to read EMA class="num">100 buffer. Error: ", GetLastError());
  }

用策略测试器验证 EA 的盯盘逻辑

代码编译通过后,下一步不是直接上实盘,而是进 MT5 的策略测试器(Strategy Tester)跑一遍。这里能脱离真实行情环境,把 EA 的每笔 tick 处理逻辑摊开看,尤其适合验证价格监测类脚本有没有漏 tick 或重复触发。 我们拿比特币监控 EA 做了一次历史回放测试,测试器在 2022 年数据上逐 tick 推进,EA 成功输出了每个 tick 的比特币价格变动记录,说明其实时监测链路在离线环境也能跑通。这一结果只证明逻辑可达,不预示任何收益。 外汇与贵金属品种在测试器里同样可跑,但这类高杠杆品种点差跳空频繁,历史 tick 质量直接影响回测可信度,务必手动核对品种规格里的点值与时区。

「H4与D1上EMA100的交互验证」

把该指标加载到 H4 和 D1 周期,叠加 EMA 100,可以直观看到价格与这条均线的贴合程度。实测中,价格在大多数波段内沿所选 EMA 运行,说明较高时间框架下均线对价格的吸附具有可观察的重复性。 系统支持三种报警方式,其中含 Telegram 推送,意味着你不必一直盯盘也能收到触发信号。下图对应的场景是在 MT5 同时挂上 EA 与指标,二者协同工作,EA 负责执行与通知,指标负责可视化状态。 在图表上添加 EA 和指标后,建议先不开实盘,用历史片段回看报警是否与实际穿越 EMA 100 的时点一致。外汇与贵金属波动剧烈,任何信号都只是概率倾向,验证通过再考虑小仓位接入。

◍ 别急着下结论

这套监控型 EA 目前只做一件事:盯盘和发 Telegram 警报,不替你下单。附带的 ema100_monitoring_indicator.mq5 约 5.62 KB,bitcoin_monitoring_expert.mq5 约 4.95 KB,两者都可在 MT5 里直接编译跑起来。 它原本按 BTCUSD 的 EMA 100 反弹逻辑写,但监控框架是通用的,换品种或加别的指标都只是改参数和 WebRequest 的事。外汇与贵金属波动剧烈、杠杆风险高,拿去实盘前务必先回测。 下载 ZIP 后用自己的参数回测,再按策略调阈值;把它当警报器而不是自动印钞机,才可能少踩坑。

把报警和回测交给小布盯盘
这些诊断小布盯盘的AIGC已内置,打开对应品种页即可看到EMA100反弹预警与历史命中分布,把重复劳动交给小布,你专注决策。

常见问题

日线EMA100更偏趋势定调,H4用于细化入场触发;多数波段系统用日线判方向、H4等回踩反弹报警,具体周期组合需用历史数据验证。
报警只是提示概率窗口,错过不必追,可等下一周期回踩;外汇贵金属高风险,宁可少做也不硬接失控回撤。
建议覆盖至少一轮完整牛熊或两年数据,并做样本外测试;参数过拟合的EA在实盘容易失效,优化要看稳健性而非峰值收益。
小布盯盘内置了EMA100类预警与品种诊断,日常监控够用;自写EA优势在逻辑完全自定义和本地化部署,两者可并行,重策略深度来自研、轻监控用现成。
优先加过滤条件如成交量阈值或波动率下限,再考虑仓位上限;回撤失控往往是指标在震荡段频繁误报,不是入场逻辑全错。