MT4交易订单推送Telegram代码报错求助
MT4交易信息推送Telegram的MQL4代码错误排查与修复
问题描述
编写了一段MQL4代码,用于将MT4的交易订单、订单修改及平仓信息推送至Telegram,但在MetaEditor中持续报错。需要实现:
- 下单时推送含交易详情+截图的消息
- 订单更新时推送修改通知
- 平仓时推送平仓信息
代码中的核心错误点
- WebRequest参数问题:
- 发送消息时
text参数未做URL编码,特殊字符会导致请求失败 - 发送截图用
POST请求时,参数格式错误——Telegram的sendPhoto接口需要用multipart/form-data格式上传文件,不能直接拼接参数 - 未初始化的
char post[]数组传递给WebRequest,会引发内存异常
- 发送消息时
- 事件逻辑混乱:
OnTrade/OnTradeModification/OnTradeClose是MT4内置事件函数,不需要在start()中手动调用,手动调用会导致重复触发- 遍历所有订单会重复推送历史订单,而非仅触发事件的目标订单
- 截图路径错误:
WindowScreenShot默认保存到MT4的MQL4\Files目录,但直接传文件名给接口时,WebRequest无法正确读取文件;且未处理截图失败的情况 - 冗余库引用:
WinUser32.mqh、stderror.mqh在代码中未使用,可移除
修正后的代码
// Include necessary libraries #include <stdlib.mqh> // 配置Telegram机器人信息 string botToken = "7241390163:AAF_2395NQiPGXbWsXEI5a9nMvn_OccCCZQ"; string chatID = "1233229081"; // URL编码函数,处理特殊字符避免请求失败 string URLEncode(string text) { string encoded = ""; for(int i=0; i<StringLen(text); i++) { char c = StringGetChar(text, i); if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.' || c == '~') { encoded += c; } else { encoded += "%" + IntegerToString(c, 16); } } return encoded; } // 发送文本消息到Telegram void SendTelegramMessage(string message) { string encodedText = URLEncode(message); string url = "https://api.telegram.org/bot" + botToken + "/sendMessage?chat_id=" + chatID + "&text=" + encodedText; int timeout = 5000; char post[] = ""; // 初始化空数组避免内存问题 int res = WebRequest("GET", url, "", 0, post, timeout); if(res != 200) { Print("发送消息错误: ", GetLastError()); } } // 发送截图到Telegram(采用multipart/form-data格式) void SendTelegramScreenshot(string filePath) { string boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"; string url = "https://api.telegram.org/bot" + botToken + "/sendPhoto"; int timeout = 10000; // 构建请求头和表单数据 string postData = "--" + boundary + "\r\n"; postData += "Content-Disposition: form-data; name=\"chat_id\"\r\n\r\n"; postData += chatID + "\r\n"; postData += "--" + boundary + "\r\n"; postData += "Content-Disposition: form-data; name=\"photo\"; filename=\"" + StringSubstr(filePath, StringFind(filePath, "\\")+1) + "\"\r\n"; postData += "Content-Type: image/png\r\n\r\n"; // 读取本地截图文件 int fileHandle = FileOpen(filePath, FILE_BIN | FILE_READ); if(fileHandle == INVALID_HANDLE) { Print("打开截图文件失败: ", GetLastError()); return; } int fileSize = FileSize(fileHandle); char fileData[]; ArrayResize(fileData, fileSize); FileReadArray(fileHandle, fileData, 0, fileSize); FileClose(fileHandle); // 拼接完整请求体 char post[]; int postLen = StringLen(postData); ArrayResize(post, postLen + fileSize + StringLen("\r\n--" + boundary + "--\r\n")); StringToCharArray(postData, post, 0, postLen); ArrayCopy(post, fileData, postLen, 0, fileSize); StringToCharArray("\r\n--" + boundary + "--\r\n", post, postLen + fileSize); string headers = "Content-Type: multipart/form-data; boundary=" + boundary; int res = WebRequest("POST", url, headers, 0, post, timeout); if(res != 200) { Print("发送截图错误: ", GetLastError()); } } // 捕获MT4窗口截图,返回绝对路径 bool CaptureScreenshot(string &filePath) { // 保存到MT4的Files目录,生成唯一文件名 filePath = TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL4\\Files\\screenshot_" + IntegerToString(GetTickCount()) + ".png"; bool success = WindowScreenShot(0, 0, 800, 600, filePath); if(!success) { Print("截图失败: ", GetLastError()); } return success; } // 新订单创建事件:仅推送刚创建的订单 void OnTrade() { if(OrderSelect(OrdersTotal()-1, SELECT_BY_POS, MODE_TRADES)) { string message = "订单创建通知:\n"; message += "订单ID: " + IntegerToString(OrderTicket()) + "\n"; message += "方向: " + (OrderType() == OP_BUY ? "做多" : "做空") + "\n"; message += "品种: " + OrderSymbol() + "\n"; message += "开仓价: " + DoubleToString(OrderOpenPrice(), Digits) + "\n"; message += "止损: " + (OrderStopLoss() > 0 ? DoubleToString(OrderStopLoss(), Digits) : "无") + "\n"; message += "止盈: " + (OrderTakeProfit() > 0 ? DoubleToString(OrderTakeProfit(), Digits) : "无"); SendTelegramMessage(message); string screenshotPath; if(CaptureScreenshot(screenshotPath)) { SendTelegramScreenshot(screenshotPath); FileDelete(screenshotPath); // 发送后删除本地文件 } } } // 订单修改事件:推送修改后的订单信息 void OnTradeModification() { if(OrderSelect(OrderTicket(), SELECT_BY_TICKET, MODE_TRADES)) { string message = "订单修改通知:\n"; message += "订单ID: " + IntegerToString(OrderTicket()) + "\n"; message += "方向: " + (OrderType() == OP_BUY ? "做多" : "做空") + "\n"; message += "品种: " + OrderSymbol() + "\n"; message += "开仓价: " + DoubleToString(OrderOpenPrice(), Digits) + "\n"; message += "新止损: " + (OrderStopLoss() > 0 ? DoubleToString(OrderStopLoss(), Digits) : "无") + "\n"; message += "新止盈: " + (OrderTakeProfit() > 0 ? DoubleToString(OrderTakeProfit(), Digits) : "无"); SendTelegramMessage(message); string screenshotPath; if(CaptureScreenshot(screenshotPath)) { SendTelegramScreenshot(screenshotPath); FileDelete(screenshotPath); } } } // 订单平仓事件:推送平仓信息 void OnTradeClose() { if(OrderSelect(OrdersHistoryTotal()-1, SELECT_BY_POS, MODE_HISTORY)) { string message = "订单平仓通知:\n"; message += "订单ID: " + IntegerToString(OrderTicket()) + "\n"; message += "方向: " + (OrderType() == OP_BUY ? "做多" : "做空") + "\n"; message += "品种: " + OrderSymbol() + "\n"; message += "平仓价: " + DoubleToString(OrderClosePrice(), Digits) + "\n"; message += "盈亏: " + DoubleToString(OrderProfit(), 2) + " " + AccountCurrency(); SendTelegramMessage(message); string screenshotPath; if(CaptureScreenshot(screenshotPath)) { SendTelegramScreenshot(screenshotPath); FileDelete(screenshotPath); } } } // 注意:移除了start()函数,MT4会自动触发OnTrade等内置事件
额外注意事项
- MT4权限设置:在MT4的
工具->选项->EA交易中,勾选允许WebRequest用于下列URL,并添加https://api.telegram.org - Bot权限:确保Telegram机器人已加入目标聊天,且拥有发送消息和图片的权限
- 日志排查:通过MT4的
工具->专家日志查看具体错误信息,辅助定位问题
内容的提问来源于stack exchange,提问作者Under IT Guy
相关产品推荐
相关产品推荐

