
创建 MQL5-Telegram 集成 EA 交易 (第一部分):从 MQL5 发送消息到 Telegram
概述
本文将遵循 Telegram 与 MetaTrader 5 集成的进程。我们打算通过使用 MetaQuotes Language 5 (MQL5) 编程语言编写自定义 EA 交易来实现这一目标。我们的主要任务是编写一个实时运行的交易助手,并通过 Telegram 上的聊天让我们随时了解最新情况。我们将构建的 Telegram 机器人将充当更新服务器,向我们发送有用的信息,帮助我们做出重要的交易决策。
为了实现这一目标,我们将建立 Telegram 机器人并调整我们的 EA 以与 Telegram 的应用程序编程接口(API) 进行通信。我们将首先设置 BotFather ,它是一个可以帮助您创建新机器人并管理现有机器人的 Telegram 机器人。使用“BotFather”,我们将创建一个新的机器人并有机会为其命名。我们还将获得一个重要信息 - 令牌 - 我们将使用它从应用程序编程接口(API)识别并访问我们的机器人。之后,我们将获得聊天ID,并使用这两个项目访问 API 并使其工作。
因此,在本文中,我们将提供一个全面的编码教程。我们将向您展示如何编写和实现一个 EA 交易,以在 MetaTrader 5 和 Telegram 之间建立双向链接。我们不仅会解释“如何”,还会解释“为什么”,以便您了解集成的技术和实践两个方面。我们还将讨论在设置和操作过程中可能出现的潜在错误,主要是为了帮助您避免这些错误,但也要确保您知道如何处理这些错误,即使我们尽最大努力预见和预防这些错误。
为了轻松地将内容分成小块,我们将把这个过程分解为以下子主题:
- MQL5 与 Telegram 集成简介
- 设置 Telegram 机器人
- 配置 MetaTrader 5 用于与 Telegram 通信
- MQL5 中的实现
- 测试集成
- 结论
读完本文后,您应该对如何实现 MetaTrader 5 和 Telegram 之间的集成自动通信,并以可运行的 EA 作为最终产品有扎实的理解。
MQL5 与 Telegram 集成简介
- 本系列文章的概述和目标:
本系列文章旨在使您在 MetaTrader 5 平台上的交易与在 Telegram 应用程序上的即时通信之间完成闭环。在本系列结束时,您将拥有一个 MQL5 中的可运行的 EA 交易,它可以发送和接收消息,甚至通过您的交易平台和 Telegram 帐户传递图像。本系列的每一部分都以上一部分为基础,增强了 EA 的功能和您可以使用的整体交易系统。
- Telegram 与 MQL5 集成的好处:
将 Telegram 与 MQL5 集成有几个优点。首先,它提供发送即时通知的功能。如果您已经设置了 EA 交易来使用 MQL5 进行交易,您可以对其进行编程,使其通过 Telegram 向您发送提醒信息。这很有效,因为您可以配置您的交易算法,使您收到的提醒只是很好的新交易机会,或是有关未平仓头寸的重要更新。通过 Telegram 与交易算法进行通信的另一种主要途径是使用 Telegram 机器人。在编写服务以向您发送提醒和/或允许有限但安全的交易敏感数据传输时,机器人提供了一些明显的优势。此外,您可以共享各种与交易相关的媒体,如图表或截图,与机器人协同工作,使您的交易算法更好地为您服务。从技术上讲,机器人在用户和服务器之间中继通信。以下是按时间顺序排列的详细过程示意图:
- 与现代交易的相关性:
当今的交易世界要求参与者具有快速的适应能力;这是一个盈亏问题。必然地,我们交易员已经找到了自动化策略的方法 — 以便能够与市场保持联系,但又不受办公桌的束缚。实现这一目标的最新方法之一是使用功能强大的编程语言 MQL5 和 Telegram,Telegram 是一款即时通讯应用程序,几乎可以作为定制的交易仪表板来执行。此代理交易电报设置涵盖了包含在任何电报中的必要基础,用于通知用户他们可能管理的任何帐户的相关事件。无论您是否有团队,Telegram 的点对点更新功能都使该应用程序成为交易者工具包中的合法候选者。
- 为系列文章设定基础:
理解集成的基本概念和基本工具至关重要。我们将从基础开始:创建一个 Telegram 机器人并配置 MQL5 以通过它发送消息。这一步是最基本的,它为我们在未来的版本中构建更先进、更复杂、更有用的功能奠定了基础。在第一部分结束时,我们将拥有一个基本但功能齐全的系统,能够将文本消息从我们的 EA 发送到 Telegram。这个基础不仅会给你实用技能,还会为你未来更复杂的任务做好准备,例如发送图像和处理 MQL5 与 Telegram 之间的双向通信。最后,我们将得到如下的集成:
这将作为其他部分的基本基础。
设置 Telegram 机器人
将 Telegram 连接到 MetaTrader 5 的第一步是创建一个 Telegram 机器人。该机器人将作为 Telegram 和 MetaTrader 5 之间发送和接收消息的中介。使用 BotFather,我们将创建一个新的机器人程序,为其配置必要的权限,然后获得允许与我们的机器人程序通信的 API 令牌。
要创建机器人,首先打开 Telegram 应用程序并搜索“BotFather”,这是一个特殊的机器人,您可以用它来创建和管理其他机器人。由于可能有许多名称几乎相似的词,因此请确保输入如图所示的词。
您开始与 BotFather 聊天并使用命令“/newbot”创建一个新的机器人。然后,BotFather 会提示您输入机器人的名称和用户名。在那之后,您将获得一个唯一的 API 令牌。这是一件大事,因为它允许您的应用程序与 Telegram 的服务器进行身份验证,并以服务器知道合法的方式与它们进行交互。为了说明所进行的过程,我们使用了如下所示的 GIF 图像演示,以确保您获得正确的步骤。
设置机器人:获取 API 令牌后,我们必须设置机器人来满足我们的需求。我们可以对其进行编程,使用 BotFather 的“/setcommands”命令识别并响应命令。要打开机器人,您可以使用其名称进行搜索,或者单击“BotFather”提供的第一个链接,如下所示:
我们还可以为机器人提供更加友好的用户界面。添加资料、描述和图片会使其更具吸引力,但这是可选步骤。配置机器人的下一步是确保它能够根据我们的要求处理实际的消息传递。
获取聊天 ID:要从我们的机器人向特定的聊天或群组发送直接消息,我们需要获取聊天 ID。我们可以通过向我们的机器人发送消息,然后使用 Telegram API“getUpdates”方法提取聊天 ID 来实现这一点。如果我们想让我们的机器人向其所有者以外的任何地方发送消息,我们需要这个 ID。如果我们希望机器人向群组或频道发送消息,我们可以先将机器人添加到群组中,然后使用相同的方法获取聊天 ID。为了获取聊天 ID,我们使用以下代码片段。只需复制,并用您的机器人令牌替换代码中的机器人令牌,然后在浏览器上运行它。
//CHAT ID = https://api.telegram.org/bot{BOT TOKEN}/getUpdates //https://api.telegram.org/bot7456439661:AAELUurPxI1jloZZl3Rt-zWHRDEvBk2venc/getUpdates
以下是我们得到的结果:
您可以看到,我们的结果不包含任何消息更新,即使我们返回 true,表示提供的所有内容都是正确的。如果你在链接中输入了不正确的内容,你将收到一个错误的网络请求,并得到如下错误的返回:
{"ok":false,"error_code":404,"description":"Not Found"}
在我们的例子中,我们返回 true,但我们的结构是空的。这是因为我们需要向机器人发送一条消息,以便进行更新。在我们的例子中,我们发送一个启动“/start”命令。
一旦我们发送消息并再次刷新链接,我们就可以获得更新。这里,值得注意的是,消息仅在 Telegram 服务器上存储 24 个小时,之后会被丢弃。因此,如果您使用此方法获取聊天 ID,请确保消息在处理前 24 小时内发送。以下是我们所得到的:
我们得到了更新,但演示结构非常简单,没有吸引力。要实现更易读的格式,只需选中“Pretty-Print”框,您应该就能得到以下结构。
{ "ok": true, "result": [ { "update_id": 794283176, "message": { "message_id": 1, "from": { "id": [YOUR ID], "is_bot": false, "first_name": "Forex Algo-Trader", "username": "Forex_Algo_Trader", "language_code": "en" }, "chat": { "id": [YOUR ID], "first_name": "Forex Algo-Trader", "username": "Forex_Algo_Trader", "type": "private" }, "date": 1722368989, "text": "/start", "entities": [ { "offset": 0, "length": 6, "type": "bot_command" } ] } } ] }
我们的聊天ID是 “chat id” 列下的那个。到目前为止,有了机器人令牌和聊天 ID,我们就可以创建一个程序,将消息从 MQL5 发送到我们创建的 Telegram 机器人。
配置 MetaTrader 5 用于与 Telegram 通信
为了确保我们的 MetaTrader 5 平台可以与 Telegram 通信,我们需要将 Telegram API URL 添加到 MetaTrader 5 中允许的 URL 列表中。我们首先打开 MetaTrader 5 并导航到 “工具” 菜单。从那里,我们选择“选项”,或者可以通过按 “CTRL + O” 来打开。
一旦“选项”窗口弹出,导航至“EA 交易”选项卡。在这里,我们选中“允许列出的 URL 的 WebRequest”框,并将 URL “https://api.telegram.org” 添加到列表中。这一步至关重要,因为它授予我们的 EA 交易向 Telegram API 发送 HTTP 请求所需的权限,使其能够向我们的 Telegram 机器人发送消息和更新。通过配置这些设置,我们确保 MetaTrader 5 平台和 Telegram 之间的通信通畅安全,从而可以实时有效地监控和管理我们的交易活动。
完成所有这些工作后,一切就绪,我们现在可以开始在 MQL5 中实现,在其中我们定义用于创建将消息从 MQL5 中继到 Telegram 的程序的所有逻辑。让我们开始吧。
MQL5 中的实现
集成将基于 EA 交易,要创建 EA 交易,请在 MetaTrader 5 终端上单击“工具”选项卡并检查“MetaQuotes 语言编辑器”,或按键盘上的 F4。或者,单击工具栏上的 IDE(集成开发环境)图标。这将打开 MetaQuotes 语言编辑器环境,该环境可以编写交易机器人、技术指标、脚本和函数库。
打开 MetaEditor 后,在工具栏上,导航至文件选项卡并选中新文件,或者直接按 CTRL + N 即可创建新文档。或者,您可以单击工具选项卡上的“新建“图标。这将会弹出 MQL 向导。
在弹出的向导中,选中“EA 交易(模板)”,然后单击“下一步”。
在“EA 交易”的常规属性中,在名称部分下,提供您的 EA 的文件名。请注意,如果文件夹不存在,则要指定或创建文件夹,请在 EA 名称前使用反斜杠。例如这里我们默认为“Experts\”。这意味着我们的 EA 将在 Experts 文件夹中创建,我们可以在那里找到它。其他部分非常简单,但您可以点击向导底部的链接了解如何准确地执行该过程。
提供所需的 EA 交易文件名后,单击“下一步”,单击“下一步”,然后单击“完成”。完成所有这些后,我们就可以编写代码并创建程序了。
首先,我们开始定义一些有关 EA 交易的元数据。这包括 EA 的名称、版权信息以及 MetaQuotes 网站的链接。我们还指定了 EA 的版本,将其设置为“1.00”。
//+------------------------------------------------------------------+ //| TG NOTIFICATIONS EA.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00"
当加载该程序时,就会出现如下所示的信息。
接下来,我们定义几个将在整个代码中使用的常量。
const string TG_API_URL = "https://api.telegram.org"; const string botTkn = "7456439661:AAELUurPxI1jloZZl3Rt-zWHRDEvBk2venc"; const string chatID = "{YOUR CHAT ID}";
这里,“TG_API_URL”常量保存了 Telegram API 的基础 URL,这对于向 Telegram 的服务器发送超文本传输协议(HTTP) 请求至关重要。“botTkn”常量包含由 BotFather 提供的我们的 Telegram 机器人的唯一令牌,这对于身份验证是必需的。“chatID”常量是我们想要发送消息的 Telegram 聊天的唯一标识符,在这里您可以输入我们使用 Telegram API 的 getUpdates 方法获取的聊天 ID。请注意,我们使用了字符串常量变量。const 关键字确保我们的变量一旦定义就保持完整且不变。因此,我们不必再次重新定义它们,并且它们将在整个代码中保持其初始化值。这样,我们节省了时间和空间,因为我们不必在每次需要这些值的时候重新输入它们,我们只需调用必要的变量,而且错误输入其值的可能性也大大降低。
我们的代码将主要基于 EA 初始化部分,因为我们希望快速进行说明,而不必等待图表上的分时报价,这样我们就可以生成信号。因此, OnInit 事件处理函数将容纳大部分代码结构。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... return(INIT_SUCCEEDED); }
OnInit 函数是一个事件处理过程,在“EA 初始化”实例上调用该函数来执行必要的初始化(如有必要)。
为了与 Telegram 服务器通信,我们使用名为 WebRequest 的 MQL5 内置函数。该函数通常会重载整数数据类型函数,有两种形式。
为了简单起见,我们将使用第二个版本。让我们分解该函数,以便我们能够理解每个参数的含义。
int WebRequest( const string method, // HTTP method (e.g., "GET", "POST") const string url, // URL of the web server const string headers, // Optional HTTP headers int timeout, // Request timeout in milliseconds const char &data[], // Data to send with the request char &result[], // Buffer to store the response string &result_headers // Buffer to store the response headers );
让我们简单解释一下 WebRequest 函数的参数。
- method:用于请求的 HTTP 方法,常见的方法有“GET”和“POST”。“GET”通常用于从服务器获取数据。“POST”用于将数据发送到服务器。
- url:请求发送到的 Web 服务器的 URL。这包括协议(http:// 或 https://)、域和正在访问的路径/资源。
- headers:请求中包含的可选 HTTP 标头。标头可以向服务器提供附加信息(例如,内容类型、身份验证令牌)。
- timeout:等待服务器响应的最长时间(以毫秒为单位)。如果服务器在此时间内没有响应,则请求将被中止,并返回错误代码。例如,如果我们将超时设置为 10000 毫秒,就是 10000/1000 = 10 秒。
- data:与请求一起发送的数据。对于“POST”请求,这通常是请求的主体(例如,表单数据、JSON 有效负载)。
- result:存储来自服务器的响应数据的缓冲区。该数组将填充服务器的响应,然后我们可以在代码中处理它。
- result_headers:用于存储来自服务器的响应头的缓冲区。该字符串将填充服务器在其响应中发送的标头。
现在我们已经了解了参数的用途以及为什么需要它们,让我们继续定义一些我们将使用的最必要的变量。
char data[]; char res[]; string resHeaders; string msg = "EA INITIALIZED ON CHART "+_Symbol; //https://api.telegram.org/bot{HTTP_API_TOKEN}/sendmessage?chat_id={CHAT_ID}&text={MESSAGE_TEXT} const string url = TG_API_URL+"/bot"+botTkn+"/sendmessage?chat_id="+chatID+ "&text="+msg;
首先,我们声明 char 类型的 “data”和 “res” 数组。这些数组将分别在 WebRequest 函数中用于保存发送到 Web 服务器和从 Web 服务器接收的数据。“data” 数组用于我们可能想要通过 HTTP 请求发送的任何有效负载,但目前我们将其保持为空。“res” 数组将填充来自服务器的响应,使我们能够在程序中处理和利用服务器的答复。
接下来,我们定义一个名为 “resHeaders” 的 string 型变量来存储我们从服务器收到的 HTTP 响应的标头。HTTP 响应标头提供有关响应的重要元数据,例如内容类型、服务器信息和状态代码。通过获取这些标头,我们可以获得有关响应的更多背景信息,并使用我们的 EA 交易对其进行适当的处理。
然后,我们创建一个名为 “msg” 的字符串变量,其中包含我们要发送到 Telegram 的消息。在这种情况下,消息设置为 “EA INITIALIZED ON CHART”,后跟当前图表的交易品种,由内置的 _Symbol 变量表示。_Symbol 变量保存 EA 正在运行的金融工具的交易品种名称,例如 “AUDUSD” 或 “GBPUSD”。通过在我们的消息中包含这些信息,我们提供了有关已发生的操作或事件的清晰而具体的背景资料,这对于监控和记录目的特别有用。这只是我们想要在程序初始化时显示的任意的值,因此您可以使用自己的值。
然后,我们构建向 Telegram API 发出请求所需的地址(URL)。我们从存储在 “TG_API_URL” 常量中的基本 URL 开始,即 “https://api.telegram.org”。然后,我们将路径附加到 “sendMessage” API 方法,包括我们的机器人的令牌(botTkn)。此令牌通过 Telegram 服务器唯一地标识和验证我们的机器人,确保请求有效且获得授权。URL 路径如下所示:“/bot<botTkn>/sendmessage”,其中 <botTkn> 用实际机器人令牌替换。
接下来,我们将查询参数附加到 URL 中。第一个参数是 “chat_id”,它指定我们想要发送消息的 Telegram 聊天的唯一标识符。它存储在 “chatID” 常量中。第二个参数是文本,它包含我们要发送的实际消息,存储在 “msg” 变量中。这些参数与基本 URL 连接起来形成完整的请求 URL。最终的 URL 如下所示:“https://api.telegram.org/bot<botTkn>/sendmessage?chat_id=<chatID>&text=<msg>”,其中 <botTkn>、<chatID> 和 <msg> 被它们各自实际的值替换。
最后,我们只需调用该函数并传递必要的参数即可进行通信。
int send_res = WebRequest("POST",url,"",10000,data,res,resHeaders);
这里,我们使用 WebRequest 函数向指定的 URL 发送 HTTP POST 请求。与外部 Web 服务(如 Telegram API)通信需要我们使用此函数。我们必须指定 HTTP 方法;在本例中,它是 “POST”。当我们向执行某些操作的服务器发送数据时,我们使用此方法。我们希望该服务器执行的操作是向 Telegram 聊天发送消息。我们提供 “url” 变量,这是我们之前在代码中构建的。我们使用的 URL 包含 Telegram API 的基地址、我们唯一的机器人令牌、API 的 sendMessage 方法、我们要向其发送消息的聊天的 ID 以及消息本身的文本。
然后我们指定 headers 参数是一个空字符串,这表示此请求不需要任何额外的 HTTP 标头。超时指定为 10 秒,通常为 10*1000 = 10000 毫秒,在服务器通常应在几秒钟内响应的世界中,这已经是相当慷慨的了。此超时设置可防止请求无限期挂起,旨在保持 EA 响应。我们接下来要做的是将数据数组和响应数组传递给函数。数据数组保存我们想要随请求发送的任何额外信息,并且我们使用响应数组来保存请求的结果。最后,我们传递响应头字符串,函数也用它来“存储”服务器发送的响应头。
该函数返回一个整数状态代码,存储在 “send_res” 变量中,指示请求是否成功或是否发生错误。使用结果,我们可以检查消息是否发送成功,如果没有,则通知遇到的错误。
发出 HTTP 请求后,我们可以通过检查 “send_res” 变量中存储的状态代码来处理响应。为了实现这一点,我们可以使用条件语句来确定请求的结果,并根据返回的状态代码采取适当的措施。
if (send_res == 200){ Print("TELEGRAM MESSAGE SENT SUCCESSFULLY"); }
这里,如果我们的变量包含状态代码 200,那么我们就知道我们的请求成功了。我们可以将此视为我们的消息已到达指定 Telegram 聊天的标志。因此,在这种情况下,我们会在终端上打印类似“电报消息发送成功”的内容。
else if (send_res == -1){ if (GetLastError()==4014){ Print("PLEASE ADD THE ",TG_API_URL," TO THE TERMINAL"); } Print("UNABLE TO SEND THE TELEGRAM MESSAGE"); }
如果结果不等于 200,我们接下来检查它是否等于 -1。此状态告诉我们 HTTP 请求出现了问题 — 错误!但我们不能让最终用户停留在这个错误屏幕上。为了让事情对他们更有意义,我们可以对错误信息进行更详细和更巧妙的处理。这正是我们下一步要做的事情。
首先,我们检查函数调用失败时收到的具体错误(消息)。我们使用 GetLastError 函数来获取告诉我们出了什么问题的错误代码。然后,我们解释可能的情况(错误代码的含义)并向用户打印一条消息,指导他们解决导致错误的问题。在这种情况下,如果它等于 4014,我们就知道该 URL 未在终端上列出或启用。因此,我们通知用户在其交易终端上添加并启用正确的 URL。我们将对此进行测试,看看这一呼唤的意义。
当问题与 URL 限制无关时( GetLastError 没有产生 4014),我们不会只是无奈地耸耸肩。请注意,我们向用户打印一条消息,清楚说明故障的性质:“无法发送电报信息。”如果我们无法与机器人交流,那已经够糟糕了,但如果有一个机器人,而我们两个人在屏幕的这一边,完全都不说话,这比什么都糟糕。我们甚至捕捉到随机的“异常”响应情况。
else if (send_res != 200){ Print("UNEXPECTED RESPONSE ",send_res," ERR CODE = ",GetLastError()); }
如果 “send_res” 不等于 200(也就是说,它不正常),并且它不是 -1(这显然表明与 URL 限制相关的问题),那么我们就需要费脑筋了。如果一切顺利,我们将返回成功的整数值。
return(INIT_SUCCEEDED);
让我们测试一下,看看一切是否正常。
在 Telegram 机器人聊天中,我们得到的信息如下:
在交易终端上,我们得到的结果如下:
您可以看到,我们能够从交易终端发送一条消息到 Telegram 服务器,然后将其中继到 Telegram 聊天,这意味着发送成功了。
负责通过机器人从交易终端发送消息到 Telegram 聊天的完整源代码如下:
//+------------------------------------------------------------------+ //| TG NOTIFICATIONS EA.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" // Define constants for Telegram API URL, bot token, and chat ID const string TG_API_URL = "https://api.telegram.org"; // Base URL for Telegram API const string botTkn = "7456439661:AAELUurPxI1jloZZl3Rt-zWHRDEvBk2venc"; // Telegram bot token const string chatID = "{YOUR CHAT ID}"; // Chat ID for the Telegram chat // The following URL can be used to get updates from the bot and retrieve the chat ID // CHAT ID = https://api.telegram.org/bot{BOT TOKEN}/getUpdates // https://api.telegram.org/bot7456439661:AAELUurPxI1jloZZl3Rt-zWHRDEvBk2venc/getUpdates //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { char data[]; // Array to hold data to be sent in the web request (empty in this case) char res[]; // Array to hold the response data from the web request string resHeaders; // String to hold the response headers from the web request string msg = "EA INITIALIZED ON CHART " + _Symbol; // Message to send, including the chart symbol // Construct the URL for the Telegram API request to send a message // Format: https://api.telegram.org/bot{HTTP_API_TOKEN}/sendmessage?chat_id={CHAT_ID}&text={MESSAGE_TEXT} const string url = TG_API_URL + "/bot" + botTkn + "/sendmessage?chat_id=" + chatID + "&text=" + msg; // Send the web request to the Telegram API int send_res = WebRequest("POST", url, "", 10000, data, res, resHeaders); // Check the response status of the web request if (send_res == 200) { // If the response status is 200 (OK), print a success message Print("TELEGRAM MESSAGE SENT SUCCESSFULLY"); } else if (send_res == -1) { // If the response status is -1 (error), check the specific error code if (GetLastError() == 4014) { // If the error code is 4014, it means the Telegram API URL is not allowed in the terminal Print("PLEASE ADD THE ", TG_API_URL, " TO THE TERMINAL"); } // Print a general error message if the request fails Print("UNABLE TO SEND THE TELEGRAM MESSAGE"); } else if (send_res != 200) { // If the response status is not 200 or -1, print the unexpected response code and error code Print("UNEXPECTED RESPONSE ", send_res, " ERR CODE = ", GetLastError()); } return(INIT_SUCCEEDED); // Return initialization success status } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Code to execute when the expert is deinitialized } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Code to execute on every tick event } //+------------------------------------------------------------------+
由于这一次是成功的,在下一个子主题中,让我们将代码更改为几种不同的消息格式,以便我们可以看到发送消息的范围,犯可能犯的错误,并了解如何减轻这些错误。因此,它也同样重要。
测试集成
为了确保我们的 EA 交易正确地向 Telegram 发送消息,我们需要彻底测试集成。测试的一个重要方面是验证某些设置不正确时 EA 的行为,例如在交易终端中禁用“允许列出的 URL 的 WebRequest” 复选框时。为了确保正确执行,让我们禁用该复选框。
如果我们运行该程序,我们会收到一个错误,告诉用户只有在交易终端上包含并允许提供的链接时才能进行通信。
而且,您可以看到我们不仅会告知错误,还会向用户提供可行的解决方案来解决遇到的错误。
既然我们可以识别和解决错误,那么让我们继续使消息格式更具创意、更清晰、更美观。首先,让我们在初始消息中添加表情符号。
//--- Simple Notification with Emoji: string msg = "🚀 EA INITIALIZED ON CHART " + _Symbol + " 🚀";
这里,我们只需在初始消息中添加两个火箭表情符号。编译后,我们得到了这样的结果:
可以看到,带有表情符号的简单消息已成功发送。要获取表情符号,只需同时按下 Windows + 句点 (.) 键。我们现在可以继续发挥创造力,修改我们的消息通知,使其包含“买入”或“卖出”等交易信号、账户余额信息、交易实例的开启、止损和止盈等修改的交易水平、每日业绩摘要和账户状态更新信息。这些是任意消息,可以根据个人的交易风格进行修改。这是通过以下代码实现的。
//--- Simple Notification with Emoji: string msg = "🚀 EA INITIALIZED ON CHART " + _Symbol + " 🚀"; //--- Buy/Sell Signal with Emoji: string msg = "📈 BUY SIGNAL GENERATED ON " + _Symbol + " 📈"; string msg = "📉 SELL SIGNAL GENERATED ON " + _Symbol + " 📉"; //--- Account Balance Notification: double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE); string msg = "💰 Account Balance: $" + DoubleToString(accountBalance, 2) + " 💰"; //--- Trade Opened Notification: string orderType = "BUY"; // or "SELL" double lotSize = 0.1; // Example lot size double price = 1.12345; // Example price string msg = "🔔 " + orderType + " order opened on " + _Symbol + "; Lot size: " + DoubleToString(lotSize, 2) + "; Price: " + DoubleToString(price, 5) + " 🔔"; //--- Stop Loss and Take Profit Update: double stopLoss = 1.12000; // Example stop loss double takeProfit = 1.13000; // Example take profit string msg = "🔄 Stop Loss and Take Profit Updated on " + _Symbol + "; Stop Loss: " + DoubleToString(stopLoss, 5) + "; Take Profit: " + DoubleToString(takeProfit, 5) + " 🔄"; //--- Daily Performance Summary: double profitToday = 150.00; // Example profit for the day string msg = "📅 Daily Performance Summary 📅; Symbol: " + _Symbol + "; Profit Today: $" + DoubleToString(profitToday, 2); //--- Trade Closed Notification: string orderType = "BUY"; // or "SELL" double profit = 50.00; // Example profit string msg = "❌ " + orderType + " trade closed on " + _Symbol + "; Profit: $" + DoubleToString(profit, 2) + " ❌"; //--- Account Status Update: double accountEquity = AccountInfoDouble(ACCOUNT_EQUITY); double accountFreeMargin = AccountInfoDouble(ACCOUNT_FREEMARGIN); string msg = "📊 Account Status 📊; Equity: $" + DoubleToString(accountEquity, 2) + "; Free Margin: $" + DoubleToString(accountFreeMargin, 2);
当我们使用消息格式分别运行此代码片段时,我们得到以下的结果总结:
从上面的代码片段和图片可以看出集成已成功。这样,我们实现了从交易终端向 Telegram 机器人聊天发送消息的目标。如果您想将消息发送到 Telegram 频道或群组,您只需将机器人添加到群组或频道并使其成为管理员。例如,我们创建了一个小组并将其命名为“Forex Algo Trader Group”,取自我们的名称和徽标,当然您也可以为您的小组指定一个更有创意和更独特的名称。之后,我们让该机器人成为管理员。
但是,即使你将机器人提升为管理员,你仍然需要专门获取该群组的聊天 ID。如果机器人聊天 ID 仍然存在,则消息将始终转发给它,而不是转发给目标群组。因此,获取群组 ID 的过程与最初的过程类似。
// The following URL can be used to get updates from the bot and retrieve the chat ID // CHAT ID = https://api.telegram.org/bot{BOT TOKEN}/getUpdates https://api.telegram.org/bot7456439661:AAELUurPxI1jloZZl3Rt-zWHRDEvBk2venc/getUpdates
我们只需要向群组发送消息并在浏览器上运行代码即可。我们发送的消息如下:
在浏览器上,我们以结构化格式获取了以下信息:
{ "ok": true, "result": [ { "update_id": 794283177, "my_chat_member": { "chat": { "id": -4273023945, "title": "Forex Algo Trader Group", "type": "group", "all_members_are_administrators": true }, "from": { "id": <YOUR ID>, "is_bot": false, "first_name": "Forex Algo-Trader", "username": "Forex_Algo_Trader", "language_code": "en" }, "date": 1722593740, "old_chat_member": { "user": { "id": <YOUR ID> , "is_bot": true, "first_name": "mql5tg_allan_bot", "username": "mql5_tg_allan_bot" }, "status": "left" }, "new_chat_member": { "user": { "id": <YOUR ID>, "is_bot": true, "first_name": "mql5tg_allan_bot", "username": "mql5_tg_allan_bot" }, "status": "member" } } }, { "update_id": 794283178, "message": { "message_id": 64, "from": { "id": <FROM ID> , "is_bot": false, "first_name": "Forex Algo-Trader", "username": "Forex_Algo_Trader", "language_code": "en" }, "chat": { "id": -4273023945, "title": "Forex Algo Trader Group", "type": "group", "all_members_are_administrators": true }, "date": 1722593740, "new_chat_participant": { "id": <NEW ID> , "is_bot": true, "first_name": "mql5tg_allan_bot", "username": "mql5_tg_allan_bot" }, "new_chat_member": { "id": <NEW ID>, "is_bot": true, "first_name": "mql5tg_allan_bot", "username": "mql5_tg_allan_bot" }, "new_chat_members": [ { "id": <NEW ID> , "is_bot": true, "first_name": "mql5tg_allan_bot", "username": "mql5_tg_allan_bot" } ] } }, { "update_id": 794283179, "my_chat_member": { "chat": { "id": -4273023945, "title": "Forex Algo Trader Group", "type": "group", "all_members_are_administrators": true }, "from": { "id": <FROM ID>, "is_bot": false, "first_name": "Forex Algo-Trader", "username": "Forex_Algo_Trader", "language_code": "en" }, "date": 1722593975, "old_chat_member": { "user": { "id": <USER ID>, "is_bot": true, "first_name": "mql5tg_allan_bot", "username": "mql5_tg_allan_bot" }, "status": "member" }, "new_chat_member": { "user": { "id": <USER ID>, "is_bot": true, "first_name": "mql5tg_allan_bot", "username": "mql5_tg_allan_bot" }, "status": "administrator", "can_be_edited": false, "can_manage_chat": true, "can_change_info": true, "can_delete_messages": true, "can_invite_users": true, "can_restrict_members": true, "can_pin_messages": true, "can_promote_members": false, "can_manage_video_chats": true, "can_post_stories": false, "can_edit_stories": false, "can_delete_stories": false, "is_anonymous": false, "can_manage_voice_chats": true } } }, { "update_id": 794283180, "message": { "message_id": 65, "from": { "id": <YOUR FROM ID>, "is_bot": false, "first_name": "Forex Algo-Trader", "username": "Forex_Algo_Trader", "language_code": "en" }, "chat": { "id": -4273023945, "title": "Forex Algo Trader Group", "type": "group", "all_members_are_administrators": true }, "date": 1722594029, "text": "MESSAGE TO GET THE CHAT ID" } } ] }
这里我们的聊天 ID 在数字前面有一个负号。这是我们提取的 ID,并将其与初始 ID 进行替换。所以现在我们的聊天 ID 如下:
// Define constants for Telegram API URL, bot token, and chat ID const string TG_API_URL = "https://api.telegram.org"; // Base URL for Telegram API const string botTkn = "7456439661:AAELUurPxI1jloZZl3Rt-zWHRDEvBk2venc"; // Telegram bot token const string chatID = "-4273023945"; // Chat ID for the Telegram chat
如果我们运行它,我们会得到以下结果。
到目前为止,您可以看到我们能够在 MQL5 中创建一个程序,该程序可以将包含所有必要信息的消息从交易终端正确地发送到 Telegram 的机器人聊天字段。对于简单消息来说,这是成功的,但对于包含外来字符(如换行符 “\n” 或来自 Unicode 字符集的字母(如表情符号代码“U+1F600”))的复杂消息将不会发送。我们将在以后的部分中讨论这个问题。现在,让我们把一切保持简单并直奔主题。干杯!
结论
在本文中,我们创建了一个与 MQL5 和 Telegram 配合使用的 EA 交易。这允许终端和 Telegram 机器人之间的通信,这意味着您可以从终端向机器人发送消息,也可以从机器人向终端发送消息。这非常酷,原因有二:第一,因为机器人本质上是你和终端之间用于发送和接收消息的代理;第二,因为某种原因,这种交易设置看起来比通过电子邮件发送消息酷得多。
我们还深入研究了测试过程,找出了当 WebRequest 参数设置不正确时可能发生的错误。我们找出了这些错误的原因并进行了修复,以便程序现在能够以更高的可靠性运行。也就是说,它运行顺畅、无错误,能够在正确的时间将包含正确信息的消息发送到正确的地点。对错误“为什么”和“如何”的理解使我们能够对未来充满信心,因为我们知道我们的“基础细胞”是值得信赖的。
在本系列的后续部分中,我们将通过构建产生交易信号的自定义指标,将我们的集成提升到更高的水平。这些信号将用于触发向我们的 Telegram 群聊发送的消息,为我们提供我们寻找和抓住的潜在交易机会的实时更新。这不仅仅是为了让我们的交易策略更好地发挥作用,它还展示了我们如何将 MQL5 与 Telegram 结合起来创建一个动态交易工作流程,该工作流程可以发送提醒,而我们除了看手机之外无需做任何事情。请继续关注,我们将继续构建和完善这个集成系统。
本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/15457

