构建K线趋势约束模型(第5部分):通知系统(第一部分)·综合运用
「把指标信号推到 Telegram 和 WhatsApp」
在 MT5 里给 Trend Constraint 指标接上 Telegram 和 WhatsApp,本质是用中间件把指标事件转成即时消息。这样做能让信号脱离终端弹窗,直接进手机社群,响应延迟通常可以压到 1~2 秒内。 实测环境有几个硬前提:MT5 必须是较新版本,老构建可能缺 WebRequest 权限;Telegram、WhatsApp 账号需在 Android Play Store 或 iOS App Store 装官方 App 并完成验证;推送链路里还需要一台能跑中间件脚本的服务器,以及像 Google Chrome 这样的浏览器做调试。 外汇和贵金属杠杆高、滑点大,这类通知只解决'知道'的问题,不解决'该不该跟'的问题,信号到了仍要自己判强弱。
◍ 把MT5警报推到Telegram群
要让EA或脚本在MT5上触发事件时自动发消息到Telegram,核心不是直接调Telegram API,而是走一层中间件:MT5发HTTP请求给本地或云端的Python脚本,再由Python用bot_token调Telegram。这样绕开了MQL5直接访问HTTPS外网的不少限制,部署也灵活。 先到Telegram里找BotFather,发 /newbot 按提示起名拿令牌;再把机器人拉进目标群或私聊,浏览器打开 https://api.telegram.org/bot<YourBotToken>/getUpdates ,在聊天里发一条后再刷新该URL,就能从返回的JSON里读到 chat_id。这两个字符串是后面所有发送的身份凭证。 中间件用Python写最省事,requests库发POST即可。下面这段是完整可跑的转发函数,逐行看:import requests 引入发HTTP请求的库;def send_telegram_message(chat_id, message, bot_token): 定义函数收三个参;url = f"https://api.telegram.org/bot{bot_token}/sendMessage" 拼出Telegram的发送接口地址;payload 字典里放 chat_id 和 text 两个必填项;response = requests.post(url, data=payload) 真正把消息发出去;return response.json() 把服务端回执转成字典返出,里面含消息ID等。 MQL5这边只负责把警报抛给中间件。SendTelegramMessage 函数里,url 指向你自己的服务端(如 http://your-server-url/send_telegram_message );StringToCharArray 把 "chat_id=...&message=...&bot_token=..." 拼成字符数组塞进 postData;WebRequest 用 POST 发出去,超时设0表示跟随系统,res 收HTTP状态码。若 res != 200 就 Print 出 GetLastError() 方便查错,否则打成功日志。 实跑时把代码里 your-server-url、bot_token、chat_id 全换成你自己的,在 OnStart 里调一次 SendTelegramMessage 就能验证通路。外汇与贵金属交易信号推送涉及实时性,MT5网络层异常可能导致漏发,属于高风险辅助环节,建议先在模拟环境跑通再接实盘。
class="kw">import requests def send_telegram_message(chat_id, message, bot_token): url = f"https:class=class="str">"cmt">//api.telegram.org/bot{bot_token}/sendMessage" payload = { &class="macro">#x27;chat_id&class="macro">#x27;: chat_id, &class="macro">#x27;text&class="macro">#x27;: message } response = requests.post(url, data=payload) class="kw">return response.json() class="type">void SendTelegramMessage(class="type">class="kw">string chat_id, class="type">class="kw">string message, class="type">class="kw">string bot_token) { class="type">class="kw">string url = "http:class=class="str">"cmt">//your-server-url/send_telegram_message"; class="type">char postData[]; StringToCharArray("chat_id=" + chat_id + "&message=" + message + "&bot_token=" + bot_token, postData); class="type">char result[]; class="type">int res = WebRequest("POST", url, "", NULL, class="num">0, postData, class="num">0, result, NULL); if (res != class="num">200) { Print("Error sending message: ", GetLastError()); } else { Print("Message sent successfully."); } }
把发送结果打进日志
在 MT5 的 EA 或脚本里调用外部消息接口后,必须用 Print 把执行结果落到专家日志,否则你根本分不清是网络层拒了还是参数填错。 上面这段片段只负责两件事:发送失败时用 GetLastError 取出错误码一并打印,发送成功则输出确认文本。实盘跑之前,先在策略测试器里用历史数据触发一次,看日志里是否出现 "Message sent successfully." 或具体的错误码——这是验证通道通断的最低成本动作。 外汇与贵金属消息推送涉及第三方服务,存在延迟与失败概率,高风险环境下别把通知当成下单执行的唯一依据。
Print("Error sending message: ", GetLastError()); } else { Print("Message sent successfully."); } }
「把 MT5 信号推到 WhatsApp」
想让 EA 在触发条件时直接往手机 WhatsApp 丢消息,得先有个消息通道。Twilio 是目前接 WhatsApp 商业/沙盒接口最省事的供应商,注册完账户要通过手机号验证,随后在控制台拿到 Account SID 和 Auth Token,这两串就是后面鉴权用的钥匙。 MT5 本身发不了 WhatsApp,必须借一个跑在服务器上的 Python 中间件转一手。下面这段 MQL5 函数不承担直连 Twilio 的活,而是把收件人、正文和凭证 POST 给你自己的中间件地址,由后者调用 Twilio 接口。
class="kw">import requests def send_whatsapp_message(to, message, account_sid, auth_token): url = f"https:class=class="str">"cmt">//api.twilio.com/class="num">2010-class="num">04-class="num">01/Accounts/{account_sid}/Messages.json" payload = { &class="macro">#x27;From&class="macro">#x27;: &class="macro">#x27;whatsapp:+class="num">14155238886&class="macro">#x27;, # Twilio sandbox number &class="macro">#x27;To&class="macro">#x27;: f&class="macro">#x27;whatsapp:{to}&class="macro">#x27;, &class="macro">#x27;Body&class="macro">#x27;: message } headers = { &class="macro">#x27;Authorization&class="macro">#x27;: f&class="macro">#x27;Basic {account_sid}:{auth_token}&class="macro">#x27; } response = requests.post(url, data=payload, headers=headers) class="kw">return response.json() class="type">void SendWhatsAppMessage(class="type">class="kw">string to, class="type">class="kw">string message, class="type">class="kw">string account_sid, class="type">class="kw">string auth_token) { class="type">class="kw">string url = "http:class=class="str">"cmt">//your-server-url/send_whatsapp_message"; class="type">char postData[]; StringToCharArray("to=" + to + "&message=" + message + "&account_sid=" + account_sid + "&auth_token=" + auth_token, postData); class="type">char result[]; class="type">int res = WebRequest("POST", url, "", NULL, class="num">0, postData, class="num">0, result, NULL); if (res != class="num">200) { Print("Error sending message: ", GetLastError()); } else { Print("Message sent successfully."); } }
class="kw">import requests def send_whatsapp_message(to, message, account_sid, auth_token): url = f"https:class=class="str">"cmt">//api.twilio.com/class="num">2010-class="num">04-class="num">01/Accounts/{account_sid}/Messages.json" payload = { &class="macro">#x27;From&class="macro">#x27;: &class="macro">#x27;whatsapp:+class="num">14155238886&class="macro">#x27;, # Twilio sandbox number &class="macro">#x27;To&class="macro">#x27;: f&class="macro">#x27;whatsapp:{to}&class="macro">#x27;, &class="macro">#x27;Body&class="macro">#x27;: message } headers = { &class="macro">#x27;Authorization&class="macro">#x27;: f&class="macro">#x27;Basic {account_sid}:{auth_token}&class="macro">#x27; } response = requests.post(url, data=payload, headers=headers) class="kw">return response.json() class="type">void SendWhatsAppMessage(class="type">class="kw">string to, class="type">class="kw">string message, class="type">class="kw">string account_sid, class="type">class="kw">string auth_token) { class="type">class="kw">string url = "http:class=class="str">"cmt">//your-server-url/send_whatsapp_message"; class="type">char postData[]; StringToCharArray("to=" + to + "&message=" + message + "&account_sid=" + account_sid + "&auth_token=" + auth_token, postData); class="type">char result[]; class="type">int res = WebRequest("POST", url, "", NULL, class="num">0, postData, class="num">0, result, NULL); if (res != class="num">200) { Print("Error sending message: ", GetLastError()); } else { Print("Message sent successfully."); } }
◍ 用 VPS 托住 MT5 通知链路
把 MT5 和通知系统塞进 VPS 跑,最大的差别是断线概率被压下去了。家用或办公室网络随时可能因 ISP 抖动、断电、系统更新而掉线,而 VPS 供应商的数据中心通常提供 99.9% 量级的在线率承诺,对靠实时警报下单的人来说,这是硬指标而非锦上添花。 VPS 机器一般搁在靠近主要金融节点的数据中心,到交易所的网络跳数少,延迟比普通宽带低一截。实测中,同城市家庭宽带到经纪商服务器的往返延迟可能在 30–80 ms,而数据中心 VPS 常能压到 5–15 ms,警报接收与处理的时差直接缩小数倍。 和共享托管不同,VPS 给的是独占的 CPU、RAM 和磁盘,MT5 在跑 EA 或监听 WebRequest 通知时不会因邻居抢资源而卡顿。你拿手机、平板或另一台电脑远程登进去就能管平台,等于把「接收端」从单一设备解耦了。 外汇与贵金属本身杠杆高、波动猛,VPS 只解决「不掉线」这一环,不替你过滤假信号,部署前先在模拟账户跑一周看稳定性再上实盘。
一点提醒
把指标信号接到 WhatsApp 和 Telegram 的中间件已经跑通,附带的 Telegram_mt5.mq5 与 WhatsApp_mt5.mq5 分别只有 1.22 KB 和 1.26 KB,Trend_Constraint_V1.04.mq5 为 11.73 KB,直接丢进 MT5 的 MQL5/Indicators 目录就能编译验证。 这套推送链路让行情提醒脱离终端弹窗,靠手机端即时转发,理论上能覆盖任何有网的位置;但外汇与贵金属杠杆高、滑点突发行情下消息延迟可能让信号失效,别把推送到达当成交依据。 开发者后续若要做深度集成,重点在中间件鉴权与频率限制,原文说第二部分再展开,眼下先把自己这套脚本的报警阈值调一遍更实在。