创建 MQL5-Telegram 集成 EA 交易(第 4 部分):模块化代码函数以增强可重用性·综合运用
📘

创建 MQL5-Telegram 集成 EA 交易(第 4 部分):模块化代码函数以增强可重用性·综合运用

第 3/3 篇

◍ 截图落盘后如何确认文件已生成

在 MT5 里用脚本抓图表截图,最怕的是 ChartScreenShot 调用完就以为万事大吉,实际上文件可能还在后台写盘。上面这段逻辑在关闭图表前先 Sleep(10000) 暂停 10 秒,给人眼和硬盘都留了缓冲。 紧接着用 while 循环做存在性轮询:最多等 60 次、每次 Sleep(500),也就是最长 30 秒去确认截图文件真的出现在数据目录里。若 wait_loops 耗尽仍 FileIsExist 返回 false,就打印未保存并回退 FAILED_CODE,避免后续拿空文件去发消息。 确认存在后返回 SUCCEEDED_CODE,外面再据此决定是走 INIT_FAILED 还是继续。实盘跑这段时建议把 1366x768 和 10 秒暂停当成可调参数:机器慢就加 Sleep,高清屏抓图可改分辨率,但截图尺寸越大写盘越慢,轮询上限也得跟着放。 外汇与贵金属市场波动剧烈、滑点频发,这类自动截图只作盘后复核或告警留痕,不替代任何交易决策,信号误发概率始终存在。

MQL5 / C++
  ChartScreenShot(chart_id,screenshot_name,class="num">1366,class="num">768,ALIGN_RIGHT);
  Print("OPENED CHART PAUSED FOR class="num">10 SECONDS TO TAKE SCREENSHOT.");
  Sleep(class="num">10000); class=class="str">"cmt">// sleep for class="num">10 secs to see the opened chart
  ChartClose(chart_id);
  
  class=class="str">"cmt">// Wait for class="num">30 secs to save screenshot if not yet saved
  class="type">int wait_loops = class="num">60;
  while(!FileIsExist(screenshot_name) && --wait_loops > class="num">0){
      Sleep(class="num">500);
  }
  
  if(!FileIsExist(screenshot_name)){
      Print("THE SPECIFIED SCREENSHOT DOES NOT EXIST(WAS NOT SAVED). REVERTING NOW!");
      class="kw">return (FAILED_CODE);
  }
  else if(FileIsExist(screenshot_name)){
      Print("THE CHART SCREENSHOT WAS SAVED SUCCESSFULLY TO THE DATA-BASE.");
      class="kw">return (SUCCEEDED_CODE);
  }
  class="kw">return (SUCCEEDED_CODE);
}
  getScreenshot_of_Current_Chart(SCREENSHOT_FILE_NAME);
  sendScreenShot(SCREENSHOT_FILE_NAME,TG_API_URL,botTkn,chatID,NULL);
  class="type">int get_screenshot_new_chart_result = getScreenshot_of_New_Chart(SCREENSHOT_FILE_NAME,_Symbol,_Period);
  if (get_screenshot_new_chart_result == FAILED_CODE){
      class="type">class="kw">string result_msg = "NEW CHART SCREENSHOT COULDN&class="macro">#x27;T BE SAVED. REVERT NOW.";
      Print(result_msg);
      sendSimpleMessage(result_msg,TG_API_URL,botTkn,chatID,class="num">10000);
      class="kw">return (INIT_FAILED);
  }
  else if (get_screenshot_new_chart_result == SUCCEEDED_CODE){
      class="type">class="kw">string result_msg = "SUCCESS. NEW CHART SCREENSHOT WAS SAVED. CONTINUE NOW.";
      Print(result_msg);
      sendSimpleMessage(result_msg,TG_API_URL,botTkn,chatID,class="num">10000);
      class="type">class="kw">string sending_msg = "\x2705\SCREENSHOT SENDING HAS BEEN INITIATED SUCCESSFULLY.";
      sending_msg += "\n\x270C\YOU SHOULD RECEIVE THE IMAGE FILE WITHIN class="num">10 SECONDS";
      class="type">class="kw">string encoded_sending_msg = UrlEncode(sending_msg);
      Print(encoded_sending_msg);
      sendEncodedMessage(encoded_sending_msg,TG_API_URL,botTkn,chatID,class="num">10000);
      
  }
  sendScreenShot(SCREENSHOT_FILE_NAME,TG_API_URL,botTkn,chatID,NULL);
  class=class="str">"cmt">//--- Caption
  class="type">class="kw">string CAPTION = NULL;
  CAPTION = "Screenshot of Symbol: "+Symbol()+
             " ("+EnumToString(ENUM_TIMEFRAMES(_Period))+
             ") @ Time: "+TimeToString(TimeCurrent());
  
  sendScreenShot(SCREENSHOT_FILE_NAME,TG_API_URL,botTkn,chatID,CAPTION);

把信号确认接进模块化函数跑通

把 EA 逻辑拆成可复用函数后,下一步是在真实行情里验证它们能否协同:信号触发时自动发 Telegram 消息、截当前图表。我们在 1 分钟周期上挂机等待,首根确认的是卖出设置,终端日志记下了信号,持仓数据与截图同步推到了 TG 群。 随后看涨交叉出现,EA 平掉卖仓开买仓,并把买仓的价位、时间、手数、SL/TP 通过同一套函数发出。实测两种方向信号均完成 MQL5→Telegram 的传递,说明模块化桥接既可靠也有扩展余地。 外汇与贵金属杠杆高、滑点随机,这类自动推送只解决通知与留痕,不替代风控。建议读者把下面买仓代码片段直接塞进自己 EA 的信号块,用 MT5 编译后开 1 分钟图验证截图与 emoji 是否正常出海。 代码里 0xF4B0 是钱袋 emoji 的 UTF-16,ShortToString 转成字符串拼进消息;sendEncodedMessage 最后一个入参 10000 是 WebRequest 超时毫秒数,网络差时可调大。若 getScreenshot_of_Current_Chart 返回 FAILED_CODE,会发告警并 return,避免带着缺截图的状态继续跑。

MQL5 / C++
    class=class="str">"cmt">// BUY POSITION OPENED. GET READY TO SEND MESSAGE TO TELEGRAM
    Print("BUY POSITION OPENED. SEND MESSAGE TO TELEGRAM NOW.");
    
    class=class="str">"cmt">//class="type">char data[];  // Array to hold data to be sent in the web request(empty in this case)
    class=class="str">"cmt">//class="type">char res[];   // Array to hold the response data from the web request
    class=class="str">"cmt">//class="type">class="kw">string resHeaders;   // String to hold the response headers from the web request
    
    
    class="type">class="kw">ushort MONEYBAG = 0xF4B0;
    class="type">class="kw">string MONEYBAG_Emoji_code = ShortToString(MONEYBAG);
    class="type">class="kw">string msg =  "\xF680 Opened Buy Position."
                 +"\n===================="
                 +"\n"+MONEYBAG_Emoji_code+"Price = "+DoubleToString(openPrice,_Digits)
                 +"\n\xF412\Time = "+TimeToString(iTime(_Symbol,_Period,class="num">0),TIME_SECONDS)
                 +"\n\xF551\Time Current = "+TimeToString(TimeCurrent(),TIME_SECONDS)
                 +"\n\xF525 Lotsize = "+DoubleToString(lotSize,class="num">2)
                 +"\n\x274E\Stop loss = "+DoubleToString(stopLoss,_Digits)
                 +"\n\x2705\Take Profit = "+DoubleToString(takeProfit,_Digits)
                 +"\n_________________________"
                 +"\n\xF5FD\Time Local = "+TimeToString(TimeLocal(),TIME_DATE)
                 +" @ "+TimeToString(TimeLocal(),TIME_SECONDS)
                 ;
    class="type">class="kw">string encloded_msg = UrlEncode(msg);
    msg = encloded_msg;
    
    sendEncodedMessage(msg,TG_API_URL,botTkn,chatID,class="num">10000);
    
    class="type">int get_screenshot_current_chart_result = getScreenshot_of_Current_Chart(SCREENSHOT_FILE_NAME);
    if (get_screenshot_current_chart_result == FAILED_CODE){
       class="type">class="kw">string result_msg = "CURRENT CHART SCREENSHOT COULDN&class="macro">#x27;T BE SAVED. REVERT NOW.";
       Print(result_msg);
       sendSimpleMessage(result_msg,TG_API_URL,botTkn,chatID,class="num">10000);
       class="kw">return;
    }

「做空成交后把单子推到 Telegram」

当图表截图接口返回 SUCCEEDED_CODE,程序先往 MT5 日志打印成功信息,并通过 sendSimpleMessage 以 10000 毫秒超时把状态发到 Telegram。随后拼接带 ✅ 与 ✌ emoji 的发送提示,UrlEncode 编码后再次调用 sendEncodedMessage,提示图片大概率在 10 秒内到达。 截图发送前会动态拼 CAPTION:用 Symbol() 取品种名、EnumToString(_Period) 取周期、TimeToString(TimeCurrent()) 取服务器时间,例如「Screenshot of Symbol: XAUUSD (PERIOD_M15) @ Time: 2024.05.21 13:45:30」。这条 caption 随 sendScreenShot 一起把 PNG 推到频道。 空单真正开出后,代码用 0xF4B0(💰)转成 MONEYBAG_Emoji_code,再拼一段含 🚀/🌒/🕑/🥥/❎/✅ 等符号的 msg:列明成交价 openPrice(按 _Digits 精度)、当前 K 线时间 iTime(_Symbol,_Period,0)、本地时间 TimeLocal()、手数 lotSize(2 位小数)、止损止盈按 _Digits 显示。外汇与贵金属杠杆高,这类自动推送只是降低盯盘成本,不预示任何方向胜率。 把这段逻辑直接塞进你的 EA 成交回调里,开 MT5 跑一单模拟空单,就能在 TG 收到带品种周期和时间戳的成交通知;若 10 秒没图,优先查 SCREENSHOT_FILE_NAME 路径权限而非网络。

MQL5 / C++
else if (get_screenshot_current_chart_result == SUCCEEDED_CODE){
      class="type">class="kw">string result_msg = "SUCCESS. CURRENT CHART SCREENSHOT WAS SAVED. CONTINUE NOW.";
      Print(result_msg);
      sendSimpleMessage(result_msg,TG_API_URL,botTkn,chatID,class="num">10000);
      class="type">class="kw">string sending_msg = "\x2705\SCREENSHOT SENDING HAS BEEN INITIATED SUCCESSFULLY.";
      sending_msg += "\n\x270C\YOU SHOULD RECEIVE THE IMAGE FILE WITHIN class="num">10 SECONDS";
      class="type">class="kw">string encoded_sending_msg = UrlEncode(sending_msg);
      Print(encoded_sending_msg);
      sendEncodedMessage(encoded_sending_msg,TG_API_URL,botTkn,chatID,class="num">10000);
      
      }
      
      class=class="str">"cmt">//--- Caption
      class="type">class="kw">string CAPTION = NULL;
      CAPTION = "Screenshot of Symbol: "+Symbol()+
                  " ("+EnumToString(ENUM_TIMEFRAMES(_Period))+
                  ") @ Time: "+TimeToString(TimeCurrent());
      
      sendScreenShot(SCREENSHOT_FILE_NAME,TG_API_URL,botTkn,chatID,CAPTION);
      class=class="str">"cmt">// SELL POSITION OPENED. GET READY TO SEND MESSAGE TO TELEGRAM
      Print("SELL POSITION OPENED. SEND MESSAGE TO TELEGRAM NOW.");
      
      class=class="str">"cmt">//class="type">char data[];    // Array to hold data to be sent in the web request(empty in this case)
      class=class="str">"cmt">//class="type">char res[];    // Array to hold the response data from the web request
      class=class="str">"cmt">//class="type">class="kw">string resHeaders;    // String to hold the response headers from the web request
      
      class="type">class="kw">ushort MONEYBAG = 0xF4B0;
      class="type">class="kw">string MONEYBAG_Emoji_code = ShortToString(MONEYBAG);
      class="type">class="kw">string msg =  "\xF680 Opened Sell Position."
                  +"\n===================="
                  +"\n"+MONEYBAG_Emoji_code+"Price = "+DoubleToString(openPrice,_Digits)
                  +"\n\xF412\Time = "+TimeToString(iTime(_Symbol,_Period,class="num">0),TIME_SECONDS)
                  +"\n\xF551\Time Current = "+TimeToString(TimeCurrent(),TIME_SECONDS)
                  +"\n\xF525 Lotsize = "+DoubleToString(lotSize,class="num">2)
                  +"\n\x274E\Stop loss = "+DoubleToString(stopLoss,_Digits)
                  +"\n\x2705\Take Profit = "+DoubleToString(takeProfit,_Digits)
                  +"\n_________________________"
                  +"\n\xF5FD\Time Local = "+TimeToString(TimeLocal(),TIME_DATE)
                  +" @ "+TimeToString(TimeLocal(),TIME_SECONDS)
                  ;

◍ 把当前图表截图推到 Telegram 的收尾逻辑

这段片段处理的是信号触发后最末一步:先把待发文本做 URL 编码,再调用 sendEncodedMessage 发往 Telegram,超时参数写死为 10000 毫秒(10 秒)。 紧接着调用 getScreenshot_of_Current_Chart 对当前图表截图,返回码若为 FAILED_CODE,就向终端打印并推送「CURRENT CHART SCREENSHOT COULDN'T BE SAVED. REVERT NOW.」后直接 return,不再继续发图。 成功分支里除打印与推送成功提示外,还拼了一段带 ✅ 与 ✌ 符号的发送中提示,并再次 URL 编码后发出;提示文案里明确写了「YOU SHOULD RECEIVE THE IMAGE FILE WITHIN 10 SECONDS」,也就是预期 10 秒内收到图。 最后组装 CAPTION,用 Symbol()、_Period 的周期枚举和 TimeCurrent() 拼出「Screenshot of Symbol: XXX (PERIOD_XXX) @ Time: XXX」,交给 sendScreenShot 把本地文件连说明一起发走。想在 MT5 里验证,只需把 SCREENSHOT_FILE_NAME 和 bot 参数接好,触发一次就能看手机是否 10 秒内弹图。

MQL5 / C++
class="type">class="kw">string encloded_msg = UrlEncode(msg);
msg = encloded_msg;

sendEncodedMessage(msg,TG_API_URL,botTkn,chatID,class="num">10000);

class="type">int get_screenshot_current_chart_result = getScreenshot_of_Current_Chart(SCREENSHOT_FILE_NAME);
if (get_screenshot_current_chart_result == FAILED_CODE){
    class="type">class="kw">string result_msg = "CURRENT CHART SCREENSHOT COULDN&class="macro">#x27;T BE SAVED. REVERT NOW.";
    Print(result_msg);
    sendSimpleMessage(result_msg,TG_API_URL,botTkn,chatID,class="num">10000);
    class="kw">return;
}
else if (get_screenshot_current_chart_result == SUCCEEDED_CODE){
    class="type">class="kw">string result_msg = "SUCCESS. CURRENT CHART SCREENSHOT WAS SAVED. CONTINUE NOW.";
    Print(result_msg);
    sendSimpleMessage(result_msg,TG_API_URL,botTkn,chatID,class="num">10000);
    class="type">class="kw">string sending_msg = "\x2705\SCREENSHOT SENDING HAS BEEN INITIATED SUCCESSFULLY.";
    sending_msg += "\n\x270C\YOU SHOULD RECEIVE THE IMAGE FILE WITHIN class="num">10 SECONDS";
    class="type">class="kw">string encoded_sending_msg = UrlEncode(sending_msg);
    Print(encoded_sending_msg);
    sendEncodedMessage(encoded_sending_msg,TG_API_URL,botTkn,chatID,class="num">10000);
    
}

class=class="str">"cmt">//--- Caption
class="type">class="kw">string CAPTION = NULL;
CAPTION = "Screenshot of Symbol: "+Symbol()+
          " ("+EnumToString(ENUM_TIMEFRAMES(_Period))+
          ") @ Time: "+TimeToString(TimeCurrent());

sendScreenShot(SCREENSHOT_FILE_NAME,TG_API_URL,botTkn,chatID,CAPTION);

把消息推送做成可插拔模块之后

这套把 MT5 和 Telegram 打通的思路,核心落在模块化函数上:发文本、发图表截图各自独立封装,EA 主逻辑只管调接口,不纠缠网络细节。实测下来,这种拆法让策略端改一处通知逻辑、不影响下单与风控,维护成本明显低于把 HTTP 请求写死在 OnTick 里。 下一篇会反向打通——Telegram 发指令回控 MT5,比如远程要一张实时持仓图或账户快照。外汇与贵金属杠杆高、滑点突变频繁,这类远程指令若没做鉴权,可能把账号暴露在误操作风险里,接之前先想清楚白名单。 随文给的 TELEGRAM_MQL5_MULTIDIMENSIONAL_PART4.mq5 约 104.6 KB,评论区已有人反馈「文字能发、截图发不出」,说明多部分表单上传在部分券商服务器上会被拦。拿回去先在本机测通截图通道,再上实盘环境,别默认它开箱即用。

常见问题

在截图函数返回后立刻用 FileIsExist 检查文件名,并打印绝对路径到日志;若返回 false 就中止后续推送,避免发空图。
在成交回调里调用已封装的 SendTradeAlert 模块,传入方向=空、symbol、open price、sl,由模块拼文本并推送到预设 chat_id。
可以。小布能读取你转发的 Telegram 信号并做 AIGC 摘要与风险标注,你只要在品种页开启提醒,不用自己逐条看消息。
不用。只改模块内部的渠道实现,对外暴露的 PushMessage(text) 接口不变,业务函数无感切换。
确保在 ChartScreenShot 完成且文件关闭后再调发送,并指定完整图表宽高参数,而非用默认可视区域。