创建 MQL5-Telegram 集成 EA 交易 (第 3 部分):将带有标题的图表截图从 MQL5 发送到 Telegram(基础篇)
📘

创建 MQL5-Telegram 集成 EA 交易 (第 3 部分):将带有标题的图表截图从 MQL5 发送到 Telegram(基础篇)

第 1/3 篇

◍ 把带标题的图表截图推到 Telegram

在 MQL5 里做图表截图并外发,核心不是画图本身,而是用 ChartScreenShot 把当前画面落盘,再交给 WinAPICFile 读成字节流推到 Telegram 的 bot 接口。 原文作者 Allan Munene Mutiiria 于 2025 年 5 月 8 日发布该系列第 3 篇,发布 4 天内累计阅读 772、评论 18,说明这类「EA 自动发图」需求在 MT5 用户里并不小众。 截图时建议显式传入标题参数(例如在图表上用 Comment()TextSetString 写一段标注),否则推到手机上的图没有上下文,复盘时很难对应当时信号。外汇与贵金属杠杆高、滑点大,任何自动推送只作辅助记录,不构成交易依据。

为什么要把图表截图塞进信号里

上一系列我们验证了用 MQL5 把交易信号文本推到 Telegram 的可行性,但纯文字对价格行为交易者不够用——你收到「孕线突破」四个字,仍要在 MT5 里自己翻图确认形态位置。 本篇要做的是把图表截图随信号一起发过去:不是描述设置,而是直接把设置画给你看。这就要求先把 MT5 终端里的图像数据转成能塞进 HTTPS 请求的格式,否则 Telegram 机器人根本不认。 全文拆成四块推进:先讲图像编码与 HTTPS 传输的底层的概念,再落进 MQL5 具体实现,接着实机测试已写好的程序,最后产出一个能同时推送截图、信号说明和下单信息的 EA。 节奏上,第一部分偏原理,第二部分偏代码,第三部分你在自己终端跑一遍就能验证,第四部分直接拿到可用 EA。外汇与贵金属波动剧烈,任何信号推送都只是辅助,截图也不能替你扛回撤。

「把图像塞进文本协议:Base64 与 HTTPS 的实操分工」

在 MT5 外接 Telegram 这类消息 API 时,直接抛二进制图像文件基本跑不通——字节流太长且文本协议不认。折中办法是先做 Base64 编码:把图像原始字节逐字节读出来,映射到 64 字符集合(A–Z、a–z、0–9、+ 和 /)生成纯文本串,这样图像就能当作命令 payload 的一部分走 HTTP 类通道。 编码完只是能发,不等于安全。HTTPS 在 HTTP 明文之上套了 SSL/TLS 加密,客户端与服务端之间的字节流被加密,第三方截获也解不出原图或信号内容。对外汇、贵金属这类高波动品种,信号图若走明文 HTTP,被嗅探后存在被抢跑或反手操纵的概率,账户面临非对称风险。 一个可验证落点:开 MT5 用 WebRequest 往 Telegram Bot API 推图,先本地把截图 Buffer 做 Base64,再 POST 到 https 接口;若去掉 HTTPS 改 http,部分节点会直接拒绝或明文暴露 token。想验证就抓一次包看二者差异。

◍ EA 初始化时把图表截下来并读进数组

MT5 里做图像中继,第一步是在 EA 的 OnInit 里把当前图表截成文件。用 #define 定一个 SCREENSHOT_FILE_NAME 常量(比如 "Our Chart ScreenShot.jpg"),后面加载、保存、发送都引用它,改格式只动这一处。JPG 是有损压缩、体积小的方案;换 PNG 只需改后缀和常量,文件会落在终端 Files 目录。 截之前先 FileIsExist 查重,有旧图就 FileDelete 清掉,再 ChartRedraw 刷一次最新可视状态,避免新图覆盖旧图造成状态混淆。清完用 ChartScreenShot(0, SCREENSHOT_FILE_NAME, 1366, 768, ALIGN_RIGHT) 抓图:0 是当前图表 ID,1366×768 是像素尺寸,ALIGN_RIGHT 控制对齐。 截图写盘可能延迟,所以用 while 循环等文件落盘:wait_loops 初值 60,每次睡 500 毫秒,最长等 30 秒;循环里递减计数器防死循环。超时仍 FileIsExist 为假就 Print "指定的屏幕截图不存在(未保存)。立即恢复!" 并返回 INIT_FAILED,因为后续逻辑全依赖这张图。 图存好后用 FileOpen(name, FILE_READ|FILE_BIN) 以二进制读句柄打开,失败同样回 INIT_FAILED。句柄有效就用 FileSize 取字节数,实测一张 1366×768 的 JPG 约 320894 字节;再 ArrayResize 一个 uchar 数组,FileReadArray 把内容整段读进去,随后 FileClose 释放句柄。 二进制不能直接走 HTTP,要 CryptEncode(CRYPT_BASE64, photoArr_Data, key, base64) 转 ASCII。转完 ArraySize(base64) 若 >0 即成功,原 320894 字节会变成约 427860 字节——这就是 Base64 膨胀。下一步只取前 1024 字节进 temporaryArr 零初始化数组做分段处理。

把图表截图推到 TG 聊天的完整链路

前面把 Base64 前 1024 字节搬进临时数组并清零后,下一步是用 MQL5 内置的 CryptEncode 算 MD5。MD5 产出 128 位摘要,在代码里表现为 16 个 uchar 元素;我们用 ArraySize 确认 md5 数组非空,再逐字节以 %02X 格式化拼成 32 位十六进制串,并截断到 16 位当作 multipart/form-data 的边界。 边界串拼好后,DATA 数组开始叠请求体:先写「--HexaDecimal_Hash」分隔符,再写 Content-Disposition 标头把 chart_id 表单字段塞进去,换行收尾。图片部分同理,用 ArrayAdd(DATA,"--"+HexaDecimal_Hash+"\r\n") 起头,跟一段 name="photo" filename="Upload_ScreenShot.jpg" 的标头,再把 base64 后的 photoArr_Data 二进制流接上,末行补「--HexaDecimal_Hash--\r\n」封口。 两个重载的 ArrayAdd 是手工拼字节流的关键:一个吃 uchar 数组,先 ArraySize 探长度、空就回退,否则 ArrayResize 目标数组再拷贝;另一个吃 string,按字符取 UTF-8 码点追进 uchar 数组。跑完用 CharArrayToString(DATA,0,WHOLE_ARRAY,CP_UTF8) 转回字符串,Print 出来就能核对请求体。 HEADERS 只需写死 Content-Type: multipart/form-data; boundary= 加那个 16 位哈希。WebRequest 用最新参数把 URL、HEADERS、DATA 发出去,MT5 日志返回 200 时,TG 聊天里就收到图了——但最初只是空截图。 想带说明就给 CAPTION 赋值(品种+周期+TimeCurrent),长度大于 0 就按 chart_id 同样套路追加一个表单字段。要截别的图,用 ChartOpen(_Symbol,_Period) 拿 chart_id,循环最多 60 次等 SeriesInfoInteger(...,SERIES_SYNCHRONIZED) 为真,ChartRedraw 后改背景色、关网格,ChartScreenShot 完事立刻 ChartClose;编译后延迟 10 秒能肉眼看到图表闪一下再关。外汇/贵金属图表推送仅作技术验证,实盘终端自动化有断网与 API 限额风险。

MQL5 / C++
class="type">class="kw">string HexaDecimal_Hash="";
for(class="type">int i=class="num">0;i<ArraySize(md5);i++)
   HexaDecimal_Hash+=StringFormat("%02X",md5[i]);
HexaDecimal_Hash=StringSubstr(HexaDecimal_Hash,class="num">0,class="num">16);

ArrayAdd(DATA,"--"+HexaDecimal_Hash+"\r\n");
ArrayAdd(DATA,"Content-Disposition: form-data; name=\"chart_id\"\r\n\r\n");
ArrayAdd(DATA,chartID);
ArrayAdd(DATA,"\r\n");

ArrayAdd(DATA,"--"+HexaDecimal_Hash+"\r\n");
ArrayAdd(DATA,"Content-Disposition: form-data; name=\"photo\"; filename=\"Upload_ScreenShot.jpg\"\r\n\r\n");
ArrayAdd(DATA,photoArr_Data);
ArrayAdd(DATA,"\r\n");
ArrayAdd(DATA,"--"+HexaDecimal_Hash+"--\r\n");

class="type">class="kw">string HEADERS="Content-Type: multipart/form-data; boundary="+HexaDecimal_Hash;
class="type">int chart_id=ChartOpen(_Symbol,_Period);
for(class="type">int k=class="num">0;k<class="num">60;k++)
   if(SeriesInfoInteger(_Symbol,_Period,SERIES_SYNCHRONIZED)) break;
ChartRedraw(chart_id);
ChartSetInteger(chart_id,CHART_COLOR_BACKGROUND,clrBlack);
ChartSetInteger(chart_id,CHART_SHOW_GRID,class="kw">false);
ChartScreenShot(chart_id,"shot.bmp",class="num">500,class="num">300);
ChartClose(chart_id);

常见问题

先在EA初始化时用ChartScreenShot把图表存成文件,再用FileOpen读进字节数组,最后通过Telegram Bot API的sendPhoto接口推送即可。
截图能保留K线形态、指标位置和手绘标注,接收方不用开终端就能快速判断信号上下文,减少误读。
可以,小布盯盘的AIGC已内置品种页诊断与快照,打开对应品种页即可把异动图表一键转发到你的聊天工具,不用自己写EA。
Base64适合把小图塞进sendMessage的caption里走纯文本协议;大图或清晰图表建议用multipart/form-data走HTTPS直传sendPhoto,更稳更快。
在ChartScreenShot调用前先用Comment或物件画出标题与标注,截图瞬间即固化当前图表状态,之后读数组推送就不会错位。