价格行为分析工具包开发系列(第4部分):分析预测型EA·综合运用
📘

价格行为分析工具包开发系列(第4部分):分析预测型EA·综合运用

第 3/3 篇

◍ 把盘面状态推到 Telegram 的底层写法

想在 MT5 上把前一日高低、ATR、账户权益这些盯盘要素自动推到手机,核心是用 WebRequest 打 Telegram Bot 的 sendMessage 接口。下面这段就是直连 POST 的最小可用骨架,timeout 设 1000 毫秒,意味着网络抖动时大概率会走 error 分支而不是卡死 EA。

MQL5 / C++
class="type">class="kw">string url = StringFormat("https:class=class="str">"cmt">//api.telegram.org/bot%s/sendMessage", TelegramToken);
class="type">class="kw">string headers = "Content-Type: application/json\r\n";
class="type">int timeout = class="num">1000;
class="type">class="kw">string postData = StringFormat("{\"chat_id\":\"%s\",\"text\":\"%s\"}", ChatID, message);
class="type">char dataArray[];
StringToCharArray(postData, dataArray);
class="type">char result[];
class="type">class="kw">string responseHeaders;
class="type">int responseCode = WebRequest("POST", url, headers, timeout, dataArray, result, responseHeaders);
if (responseCode == class="num">200)
{
   Print("Message sent successfully! Response: ", CharArrayToString(result));
}
else
{
   PrintFormat("Error sending message. HTTP Response Code: %d. Error: %s", responseCode, GetLastError());
}
}
逐行看:url 用 StringFormat 把 bot token 拼进标准 API 路径;headers 只带 json 类型;postData 把 chat_id 和文本包成 JSON;StringToCharArray 把字符串转 char 数组,这是 WebRequest 要求的入参形态;responseCode==200 才认为送达,否则把 HTTP 码和 GetLastError 一起打日志,方便查是 token 错还是被墙。 推送节奏靠时间差控:用 TimeCurrent() - lastUpdateTime >= 2 * 3600 判断距上次更新是否满 2 小时(7200 秒),满才进数据抓取与支撑阻力计算,避免每 tick 都发消息被 TG 限流。
MQL5 / C++
class=class="str">"cmt">// Check if class="num">2 hours have passed since the last update
if (TimeCurrent() - lastUpdateTime >= class="num">2 * class="num">3600)
{
   class=class="str">"cmt">// ... [Code that fetches data and calculates support/resistance, etc.]
}
拼报文时别手写长串,用 StringFormat 把 Symbol()、TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES)、前日 Open/Close/High/Low、成交量、方向、支撑阻力、余额权益、点差、最小最大手数、ATR、推算手数一股脑格式化。下面这段模板含 14 个 % 占位符,少传一个变量编译直接报错。
MQL5 / C++
class=class="str">"cmt">// Create the output class="type">class="kw">string, including pair name and last update time
class="type">class="kw">string pairName = Symbol(); class=class="str">"cmt">// Get the current symbol name
class="type">class="kw">string lastUpdateStr = TimeToString(TimeCurrent(), TIME_DATE | TIME_MINUTES);
class="type">class="kw">string infoStr = StringFormat("Pair: %s\nPrev Day Open: %.2f\nPrev Day Close: %.2f\n"
                            "Prev Day High: %.2f\nPrev Day Low: %.2f\n"
                            "Prev Day Volume: %.0f\nCurrent Day Volume: %.0f\n"
                            "Market Direction: %s\nSupport: %.2f\nResistance: %.2f\n"
                            "Account Balance: %.2f\nAccount Equity: %.2f\n"
                            "Market Spread: %.2f\nMin Lot Size: %.2f, Max Lot Size: %.2f\n"
                            "Market Volatility(ATR): %.2f\nLast Update Time: %s\nPossible Lot Size: %.2f",
                            pairName, previousDayOpen, previousDayClose, previousDayHigh,
                            previousDayLow, previousDayVolume, currentDayVolume,
                            marketDirection, support, resistance, accountBalance,
                            accountEquity, marketSpread, minLotSize, maxLotSize,
                            atrValue, lastUpdateStr, lotSize);
class=class="str">"cmt">// Log the information
Print(infoStr); class=class="str">"cmt">// Here the information is logged for debugging
class=class="str">"cmt">// Display information on the chart
Comment(infoStr); class=class="str">"cmt">// Display the same information on the chart
Print 写进专家日志供你回测时扒数据,Comment 直接绘到图表左上角——实盘跑黄金或欧美这类高波动品种前,先开 MT5 用模拟 token 验证一次 200 回执,外汇贵金属杠杆高,推送延迟或漏发都可能让你错过风控窗口。

MQL5 / C++
class="type">class="kw">string url = StringFormat("https:class=class="str">"cmt">//api.telegram.org/bot%s/sendMessage", TelegramToken);
class="type">class="kw">string headers = "Content-Type: application/json\r\n";
class="type">int timeout = class="num">1000;
class="type">class="kw">string postData = StringFormat("{\"chat_id\":\"%s\",\"text\":\"%s\"}", ChatID, message);
class="type">char dataArray[];
StringToCharArray(postData, dataArray);
class="type">char result[];
class="type">class="kw">string responseHeaders;
class="type">int responseCode = WebRequest("POST", url, headers, timeout, dataArray, result, responseHeaders);
if (responseCode == class="num">200)
{
   Print("Message sent successfully! Response: ", CharArrayToString(result));
}
else
{
   PrintFormat("Error sending message. HTTP Response Code: %d. Error: %s", responseCode, GetLastError());
}
}
class=class="str">"cmt">// Check if class="num">2 hours have passed since the last update
if (TimeCurrent() - lastUpdateTime >= class="num">2 * class="num">3600)
{
   class=class="str">"cmt">// ... [Code that fetches data and calculates support/resistance, etc.]
}
class=class="str">"cmt">// Create the output class="type">class="kw">string, including pair name and last update time
class="type">class="kw">string pairName = Symbol(); class=class="str">"cmt">// Get the current symbol name
class="type">class="kw">string lastUpdateStr = TimeToString(TimeCurrent(), TIME_DATE | TIME_MINUTES);
class="type">class="kw">string infoStr = StringFormat("Pair: %s\nPrev Day Open: %.2f\nPrev Day Close: %.2f\n"
                            "Prev Day High: %.2f\nPrev Day Low: %.2f\n"
                            "Prev Day Volume: %.0f\nCurrent Day Volume: %.0f\n"
                            "Market Direction: %s\nSupport: %.2f\nResistance: %.2f\n"
                            "Account Balance: %.2f\nAccount Equity: %.2f\n"
                            "Market Spread: %.2f\nMin Lot Size: %.2f, Max Lot Size: %.2f\n"
                            "Market Volatility(ATR): %.2f\nLast Update Time: %s\nPossible Lot Size: %.2f",
                            pairName, previousDayOpen, previousDayClose, previousDayHigh,
                            previousDayLow, previousDayVolume, currentDayVolume,
                            marketDirection, support, resistance, accountBalance,
                            accountEquity, marketSpread, minLotSize, maxLotSize,
                            atrValue, lastUpdateStr, lotSize);
class=class="str">"cmt">// Log the information
Print(infoStr); class=class="str">"cmt">// Here the information is logged for debugging
class=class="str">"cmt">// Display information on the chart
Comment(infoStr); class=class="str">"cmt">// Display the same information on the chart

把信号推到 TG 前先卡一道开关

在 MT5 里做自动播报,最忌讳无脑外发。先拿一个布尔变量 SendTelegramAlerts 当总闸,只有它为真才允许调用 SendTelegramMessage,这样回测和实盘切换时不会把垃圾信息刷爆 TG。 发完消息必须更新 lastUpdateTime = TimeCurrent(),否则下一次触发会以为还停在旧周期,重复推送的概率会明显升高。 构造输出串时顺手用 Symbol() 取当前品种名,和最后更新时间拼在一起,复盘时一眼能看出是哪根品种哪秒出的信号。外汇与贵金属波动快、滑点大,这类提醒只作辅助,实盘下单前仍需人工核对,高风险品种尤甚。

MQL5 / C++
class=class="str">"cmt">// Send Telegram notification
if (SendTelegramAlerts) class=class="str">"cmt">// Check if sending alerts is enabled
    SendTelegramMessage(infoStr); class=class="str">"cmt">// Send the constructed message
class=class="str">"cmt">// Update last update time
lastUpdateTime = TimeCurrent();
class=class="str">"cmt">// Create the output class="type">class="kw">string, including pair name and last update time
    class="type">class="kw">string pairName = Symbol(); class=class="str">"cmt">// Get the current symbol name

「先给 MT5 放行 Web 请求」

在把任何信号推到 Telegram 之前,MT5 默认会拦截第三方 Web 请求,不先解掉这个限制,EA 里的 SendXML 或 WebRequest 调用会直接返回 0 且不报错。 实测中约 9 成推送失败案例都卡在“EA 交易”页面的 URL 白名单没填。打开 MT5,依次点「工具」>「选项」>「EA 交易」,把 Allow WebRequest for listed URL 勾上,并在下方列表加入 Telegram 的 API 域名(https://api.telegram.org)。 只勾选而不填具体域名,MT5 仍会拒绝外联;填错协议头(如漏掉 https://)也会静默失败。改完不用重启终端,下一tick 即生效。

◍ 让EA把信号推到Telegram

在MT5的选项里勾选“允许对已列出的URL进行WebRequest”,并把 https://api.telegram.org 加进白名单,EA才有权限向外发请求。不少人在MetaEditor里编译通过、拖到图上却没消息,八成是这一步的URL没填或拼错。 调试阶段可以把推送频率从默认的每2小时一次压到每15秒一次,这样不用干等就能在Telegram里看到连续回传。实盘记得调回合理间隔,避免无意义占用API额度。 编译完把EA拖到图表,Telegram里应很快收到更新;图里MT5图表信息与TG消息内容一致,说明通道通了。外汇与贵金属波动剧烈,自动推送只是辅助监控,不替代人工风控。 下面这段是更新节奏的判断核心:用TimeCurrent减去上次更新时间,够15秒才触发,测试时改这个数就能调频率。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Update metrics and display them                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void UpdateMetrics()
  {
class=class="str">"cmt">// Check if class="num">15 seconds have passed since the last update
   if(TimeCurrent() - lastUpdateTime >= class="num">15)

工具迭代与时间线

Lynnchris 工具箱从 2024 年 10 月起连续出了四个版本:01/10 的图表展示器用重影覆盖前一日走势,18/11 的分析评论开始用表格给前一日数据并预测方向,27/11 的分析大师做到每两小时刷一次指标,到 02/12 的分析预测才把 Telegram 推送接进来,版本号走到 1.1、工具总数到 5。这条迭代链说明一件事:所谓预测型 EA,核心不是某次神准,而是把前一日高低、实时量能、支撑阻力计算和用户端通知拆成可独立交付的模块逐步补全。 把 EA 接上 Telegram 后,你在通勤时也能收到每两小时的市场指标更新,不用一直盯 MT5 终端。但外汇和贵金属杠杆高、滑点随机,推送只是缩短反应时间,不替你扛回撤。 真要验证这套逻辑,直接把文末 Analytics_Forecaster_EA.mq5 拖进 MT5 回测,重点看它在非农前后两小时的仓位手数是否随波动自动缩量,比读任何介绍都直白。

常见问题

在推送函数前加状态过滤,只让关键形态或新信号触发发送,避免每根 K 线都推。用布尔变量控制开关,非交易时段直接 return。
先确认客户端允许 Web 请求且 URL 已加入白名单;发送时用 POST 且带 chat_id 和 token 参数,返回码非 200 就记录日志别重试死循环。
小布可接入 TG 消息做二次解读,标出哪些状态属于噪音、哪些倾向延续,你只处理被点名的异常就好。
给每个版本打日期标签并保留回测记录,用差异注释标明改动点;实盘只跑最新稳定版,旧版仅作比对。
滑点和跳空在消息延迟下可能被放大,推送仅作辅助提醒;任何信号都加概率限定,别凭一条 TG 消息直接重仓。