English Русский 中文 Español Deutsch Português
preview
MQL5-Telegram統合エキスパートアドバイザーの作成(第1回):MQL5からTelegramへのメッセージ送信

MQL5-Telegram統合エキスパートアドバイザーの作成(第1回):MQL5からTelegramへのメッセージ送信

MetaTrader 5トレーディングシステム | 11 10月 2024, 16:15
176 0
Allan Munene Mutiiria
Allan Munene Mutiiria

はじめに

この記事では、TelegramMetaTrader 5を統合するプロセスを順を追って解説します。MetaQuotes Language 5(MQL5)プログラミング言語でカスタムエキスパートアドバイザー(EA)を作成し、Telegramチャットとの連携を図ります。私たちの主な仕事は、リアルタイムで動作し、テレグラム上のチャットで取引に関する重要な情報を自動的に通知する、取引アシスタントをプログラムすることです。Telegramボットを利用することで、重要な市場データや取引の意思決定をサポートする更新情報を受け取ることができます。

この目標を達成するために、まずTelegramボットを作成し、EAがTelegramのアプリケーションプログラミングインタフェース (API)と通信できるように設定します。まず、新しいボットの作成と既存のボットの管理を支援するTelegramボットであるBotFatherを設定します。BotFatherを利用して新しいボットを作成し、ボットに名前を付け、また、アプリケーションプログラミングインターフェース(API)からボットを識別し、アクセスするために使用する「トークン」という重要な情報も取得します。その後、TelegramチャットIDを取得し、これらの2つの情報を基にAPIへのアクセスを構築します。

この記事では、MetaTrader 5とTelegram間で双方向の通信を実現するEAの作成手順を、包括的なコーディングチュートリアルとして提供します。EAの実装方法だけでなく、なぜその手法を採用するのかについても詳しく説明します。また、セットアップや運用中に発生する可能性のあるエラーについても解説します。これらのエラーを避けるための予防策を中心に説明しますが、万が一、予測や対策にもかかわらずエラーが発生した場合に、どのように対処すればよいかもお伝えします。

簡単に吸収できるように、内容は以下のトピックに分けて説明します。

  1. MQL5とTelegramの統合の紹介
  2. Telegramボットのセットアップ
  3. Telegram通信用にMetaTrader 5を設定する
  4. MQL5での実装
  5. 統合のテスト
  6. 結論

この記事を読み終わる頃には、MetaTrader 5とTelegram間で自動化された通信を確立し、実際に機能するEAを構築できるようになっています。


MQL5とTelegramの統合の紹介

  • 本連載の概要と目的

本連載は、MetaTrader 5プラットフォームでの取引と、Telegramアプリでの即時コミュニケーションをシームレスに連携させることを目的としています。連載が終わるころには、MQL5で動作するEA(EA)が完成し、取引プラットフォームを通じてTelegramアカウントにメッセージを送受信したり、画像を中継したりできるようになります。本連載の各部分は、前の部分に基づいており、EAの機能と使用することができる全体的な取引システムをより洗練されたものにしていきます。

  • TelegramをMQL5に統合するメリット

TelegramをMQL5に統合することにはいくつかの利点があります。まず、インスタント通知を送信できる点です。MQL5で動作するEAを設定し、Telegramを通じて取引に関するアラートを受け取るようにプログラムすることが可能です。これにより、重要な取引機会やポジションの更新をリアルタイムで把握でき、タイムリーな意思決定が可能となります。もう一つ、Telegramを介して取引アルゴリズムと通信する主な方法は、Telegram ボットを使用することです。ボットは、アラートを送信したり、取引に関する機密性の高いデータを安全かつ制限付きで通信するサービスをプログラムする際に、いくつかの明確な利点を提供します。さらに、チャートやスクリーンショットなどの取引に関連するさまざまなメディアを共有することができ、ボットと連携することで、取引アルゴリズムがより効果的にニーズに応えるようにすることが可能です。技術的には、ボットはユーザーとサーバー間の通信を中継します。以下は、その時系列的なプロセスを詳細に可視化したものです。

中継プロセス

  • 現代取引における妥当性

今日の取引の世界では、プレーヤーには迅速な適応力が求められています必然的に、私たちトレーダーは、デスクに縛られることなく市場にアクセスしながら戦略を自動化する方法を模索してきました。その一環として、強力なプログラミング言語であるMQL5と、インスタントメッセージングアプリのTelegramを組み合わせたアプローチが注目されています。これにより、ほぼカスタマイズされた取引ダッシュボードとして機能させることが可能になります。この代理取引Telegramの設定は、ユーザーが管理する口座に関連する出来事を通知するための基盤を提供します。チームがある場合でもない場合でも、Telegramのピアツーピア更新機能は、トレーダーのツールキットに加えるべき正当な候補となるアプリです。

  • 連載の土台を作る

統合の本質的なコンセプトと基本的なツールを理解することが最も重要です。まずは、Telegramボットを作成し、それを用いてメッセージを送信するためのMQL5の設定を行う基本的なステップから始めます。このプロセスは非常に重要であり、将来的により高度で洗練された、有用な機能を構築するためのしっかりとした土台を築くことができます。第1回が終わるころには、EAからTelegramにテキストメッセージを送信できる、基本的だが機能的なシステムが完成するでしょう。この基礎をしっかりと身につけることで、実践的なスキルを向上させるだけでなく、画像の送信やMQL5とTelegram間の双方向通信の処理といった、より複雑なタスクに挑む準備も整います。最終的な統合は、以下のようになります。

MQL5-TELEGRAMの最終的な統合

これが、他の部分の基本的な土台となります。


Telegramボットのセットアップ

TelegramをMetaTrader 5に接続する最初のステップは、Telegramボットを作成することです。このボットは、TelegramとMetaTrader 5の間で送受信されるメッセージの仲介役として機能します。ボットの作成にはBotFatherを使用し、必要な権限を設定してボットとの通信を可能にするAPIトークンを取得します。

ボットを作成するには、まずTelegramアプリを開き、BotFather を検索します。BotFatherは、他のボットを作成・管理するために特別に用意されたボットです。名前が似たようなボットがたくさん存在することがありますので、正確に「BotFather」と入力して検索してください。

正しいBOTFATHER

BotFatherでチャットを開始し、コマンド「/newbot」を入力して新しいボットを作成します。その後、BotFatherはボットの名前とユーザー名を入力するよう促します。設定が完了すると、固有のAPIトークンが発行されます。このトークンは、あなたのアプリケーションがTelegramのサーバーと認証し、サーバーが正当であると認識するために重要です。このプロセスを説明するために、以下のようなGIF(Graphics Interchange Format)画像を用いて可視化し、正しい手順が理解できるようにしました。

作成ステップGIF

ボットのセットアップ:APIトークンを取得したら、ボットをニーズに合わせて設定する必要があります。BotFatherの「/setcommands」コマンドを使用して、ボットがコマンドを認識し、反応するようにプログラムできます。ボットを開くには、ボットの名前で検索するか、以下のように「BotFather」が提供する最初のリンクをクリックしてください。

ボットを開くGIF

また、ボットにもっとフレンドリーなユーザーインターフェイスを与えることもできます。プロファイル、説明文、写真を追加することで、少し魅力的になりますが、これはオプションのステップです。ボットを設定する次のステップは、要件に従って実際のメッセージングを処理できるようにすることです。

チャット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

以下が結果です。

チャットIDが1になる

結果を見ると、提供された内容がすべて正しいことを示すtrueが返されていても、メッセージの更新が含まれていないことがわかります。もしリンクに正しくない情報を入力すると、不正なWebリクエストが発生し、以下のようにfalseが返されます。

{"ok":false,"error_code":404,"description":"Not Found"}

ここでの場合、trueを返しますが、構造体は空です。ボットにメッセージを送り、更新があるようにする必要があるからです。この場合、「/start」コマンドを送信します。

ボット開始メッセージ

メッセージを送信し、再度リンクを更新すると、今度は更新があります。ここで注意が必要なのは、送信されたメッセージは24時間だけTelegramサーバーに保存され、その後は破棄されるという点です。したがって、この方法でチャット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ボットにメッセージを送信するプログラムを作成することができます。


Telegram通信用にMetaTrader 5を設定する

MetaTrader 5プラットフォームがTelegramと通信できるようにするには、Telegram API URLをMetaTrader 5の許可URLリストに追加する必要があります。まず、MetaTrader 5を開き、[ツール]メニューに移動します。そこから[オプション]を選択します。オプションは CTRL + Oで開くこともできます。

ツール -> オプション

オプションウィンドウがポップアップしたら、[エキスパートアドバイザ]タブに移動します。[WebRequestを許可するURLリスト]というラベルのついたボックスをチェックし、https://api.telegram.orgというURLをリストに追加します。このステップは、EAにTelegram APIにHTTPリクエストを送信するのに必要な権限を付与し、Telegramボットにメッセージやアップデートを送信できるようにするため、非常に重要です。これらの設定をおこなうことで、MetaTrader 5プラットフォームとTelegram間の円滑かつ安全な通信が確保され、取引活動をリアルタイムで効果的に監視・管理することが可能になります。

オプションウィンドウ

これらすべてを実行すると、準備は完了です。MQL5での実装を開始できます。ここで、MQL5からTelegramにメッセージを中継するプログラムを作成するために使用されるすべてのロジックを定義します。では、始めましょう。


MQL5での実装

統合はEAに基づいておこなわれます。EAを作成するには、MetaTrader 5端末で[ツール]タブをクリックし、[MetaQuotes言語エディタ]を選択するか、キーボードのF4を押します。または、ツールバーのIDE (Integrated Development Environment)アイコンをクリックします。これにより、自動売買ロボット、テクニカル指標、スクリプト、関数のライブラリを作成できるMetaQuotes言語エディタ環境が開きます。

オープンIDE

MetaEditorを開いたら、ツールバーの[ファイル]タブで[新しいファイル]を選択するか、CTRL + Nキーを押して新規ドキュメントを開きます。または、[ツール]タブの新規アイコンをクリックすることもできます。MQLウィザードのポップアップが表示されます。

新しいEAを作成する

ウィザードが表示されたら、[EA(テンプレート)]を選択し、[次へ]をクリックします。

MQL WIZARD

EAの一般プロパティで、[名前]フィールドにEAのファイル名を入力します。フォルダが存在しない場合にフォルダを指定または作成するには、EA名の前にバックスラッシュを使用することに注意してください。例えば、ここではデフォルトで「Experts」となっています。つまり、私たちのEAはExpertsフォルダに作成され、そこで見つけることができます。他のセクションはいたって簡単ですが、ウィザードの一番下にあるリンクをたどれば、正確な手順を知ることができます。

NEW EA

希望する EAファイル名を入力した後、[次へ]をクリックし、[完了]をクリックします。ここまでできたら、あとはコードを書いてプログラムを作るだけです。

まず、EAに関するメタデータを定義することから始めます。これには、EA名、著作権情報、MetaQuotes Webサイトへのリンクが含まれます。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"

プログラムをロードすると、下図のような情報が表示されます。

EA ロードアップインフォメーション

次に、コード全体で使われる定数をいくつか定義します。 

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を保持します。これは、Hyper Text Transfer Protocol(HTTP)リクエストをTelegramのサーバーに送信するために不可欠です。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内蔵の関数を使います。この関数は通常、整数データ型のオーバーロード関数で、2つの形式があります。

WEBREQUEST関数

簡単にするために、2番目のバージョンを使うことにします。各パラメータの意味を理解するために、関数を分解してみましょう。

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ミリ秒に設定すると、10秒(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配列にはサーバーからの応答が格納され、プログラム内でその応答を処理して利用できるようになります。

次に、サーバーから受け取るHTTP応答のヘッダを格納するために、resHeadersという文字列変数を定義します。このHTTP応答ヘッダーは、コンテンツタイプやサーバー情報、ステータスコードなど、応答に関する重要なメタデータを提供します。これらのヘッダーをキャプチャすることで、応答に関するより多くのコンテキストを取得し、EAで適切に処理することができるようになります。

次に、Telegramに送信したいメッセージを格納するmsgという文字列変数を作成します。この場合、メッセージは EA INITIALIZED ON CHART となり、その後に組み込み変数_Symbolで表される現在のチャートの銘柄が続きます。Symbol変数には、AUDUSDやGBPUSD など、EAが実行されている金融商品の銘柄名が格納されます。この情報をメッセージに含めることで、発生したアクションやイベントに関する明確かつ具体的なコンテキストを提供し、モニタリングやロギングの目的に特に役立ちます。これは、プログラムが初期化されたときに表示したい任意の値です。

次に、Telegram APIへのリクエストに必要なUniform Resource Locator (URL)を構築します。まずは、TG_API_URL定数に格納されているベースURL「https://api.telegram.org」から始めます。これに、ボットのトークン(botTkn)を含むsendMessage APIメソッドへのパスを追加します。このトークンは、Telegramのサーバーと私たちのボットを一意に識別認証し、リクエストが有効で承認されていることを保証します。URLパスは「/bot<botTkn>/sendmessage」のようになります。ここで、<botTkn>は実際のボットトークンに置き換えられます。

次に、URLにクエリーパラメータを追加します。最初のパラメータはchat_idで、メッセージを送信したいTelegramチャットの一意な識別子を指定します。これはchatID定数に格納されます。2番目のパラメータはtextで、送信したい実際のメッセージが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 にHTTPPOST リクエストを送信します。Telegram APIのような外部のWebサービスと通信するには、この関数を使う必要があります。HTTPメソッドを指定しなければなりません。この方法は、何らかのアクションを実行するサーバーにデータを送信するときに使われます。このサーバーに実行させたいアクションは、Telegramチャットにメッセージを送信することです。先ほどコード内で作成したurl変数を提供します。使用するURLには、Telegram APIのベースアドレス、独自のボットトークン、APIのsendMessageメソッド、メッセージを送信したいチャットのID、メッセージのテキストが含まれています。

次に、headersパラメータが空文字列であることを指定します。これは、このリクエストが余計なHTTPヘッダを必要としないことを示します。タイムアウトは10秒と指定されていますが、これは通常10*1000=10000ミリ秒であり、サーバーが通常数秒以内に応答しなければならない世界では、かなり寛大である傾向があります。このタイムアウトは、リクエストが無制限にぶら下がることを防ぎ、EAの応答性を保つように設計されています。次にすることは、データ配列と応答配列を関数に渡すことです。data配列にはリクエストと一緒に送りたい追加情報を格納し、response配列にはリクエストの結果を格納します。最後に、応答ヘッダー文字列を渡す。この関数は、サーバーから送られた応答ヘッダーを「保存」する際にも使用します。

この関数は、send_res変数に格納されている、リクエストが成功したかエラーが発生したかを示すステータスコードを整数で返します。その結果を使って、メッセージが正常に送信されたかどうかをチェックし、そうでなければ、発生したエラーを知らせることができます。

HTTPリクエストをおこなった後、send_res変数に格納されているステータスコードをチェックすることで、応答を処理することができます。これを実現するために、条件文を使ってリクエストの結果を決定し、返されたステータスコードに基づいて適切なアクションを取ることができます。

   if (send_res == 200){
      Print("TELEGRAM MESSAGE SENT SUCCESSFULLY");
   }

ここで、変数にステータスコード200が含まれていれば、リクエストは成功したことになります。これは、メッセージが指定されたTelegramチャットに届いたことを示すサインと受け取ることができます。この場合、端末に「TELEGRAM MESSAGE SENT SUCCESSFULLY」と表示します。

   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を返さない)も諦めません。ユーザーに対して、障害の内容を明確に記したメッセージを出力します。「UNABLE TO SEND THE TELEGRAM MESSAGE.」です。ボットとコミュニケーションがとれないのは最悪ですが、ボットと、画面のこちら側にいる私たち2人が完全に無言になってしまうのは、何よりも最悪です。ランダムな異常な応答条件もキャッチします。

   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チャットに中継されました。

取引端末からボットを介して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の動作を検証することです。たとえば、取引端末で「WebRequestを許可するURLリスト」チェックボックスが無効になっている場合などです。これを確実にするために、チェックボックスを無効にしてみましょう。

無効なチェックボックス

プログラムを実行すると、提供されたリンクが取引端末に含まれ、許可されている場合にのみ通信が可能であることを指示するエラーが表示されます。

詳細エラー

さらに、エラーを知らせるだけでなく、発生したエラーを軽減するための実行可能な解決策をユーザーに提示していることもおわかりいただけるでしょう。

さて、エラーを特定し、解決することができたので、メッセージフォーマットをより創造的で、明確で、派手なものにしましょう。まず、最初のメッセージに絵文字を入れてみましょう。

   //--- Simple Notification with Emoji:
   string msg = "🚀 EA INITIALIZED ON CHART " + _Symbol + " 🚀";

ここでは、2つのロケットの絵文字を最初のメッセージに追加しています。コンパイルするとこうなります。

ロケット絵文字

絵文字付きのシンプルなメッセージが正常に送信されたことがわかります。絵文字を取得するには、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

あとはグループにメッセージを送り、ブラウザ上でコードを実行するだけです。送ったメッセージは以下の通りです。

チャットIDを取得するための初期グループメッセージ

ブラウザ上では、構造化されたフォーマットで以下の情報が得られます。

{
  "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

これを実行すると、次のような結果が得られます。

Telegramグループチャット

ここまでで、取引端末からTelegramのボットチャットフィールドに必要な情報をすべて含んだメッセージを正しく送信するプログラムをMQL5で作成できたことがお分かりいただけたと思います。これは単純なメッセージでは成功しますが、改行文字「\n」や、絵文字コード U+1F600 のようなUnicode文字セットの文字のような外国文字を含む複雑なメッセージでは送信されません。それについては、次の部分で考えてみたいと思います。とりあえず、すべてをシンプルに、単刀直入に言いましょう。ではまた。


結論

この記事では、MQL5と で動作するEAを作成しました。このシステムにより、端末からボットへ、またボットから端末へメッセージを送ることが可能になります。これは、2つの主な理由から非常に魅力的です。1つ目は、ボットがあなたと端末の間でメッセージを送受信するためのプロキシとして機能することです。2つ目は、何らかの理由でこの取引の仕組みが、電子メールでメッセージを送信することよりもずっと魅力的に感じられることです。

また、WebRequestのパラメータが正しく設定されていない場合に発生する可能性のあるエラーを的確に特定し、テストプロセスを検証しました。これらのエラーの原因を究明し、プログラムの信頼性を向上させるために修正を加えました。これにより、スムーズかつエラーなく動作し、適切な情報を適切な場所に、適切なタイミングで送信できるようになります。エラーの「理由」と「対処法」を理解することで、基礎となる要素が信頼できるものであることを認識し、将来にわたって自信を持って拡張していくことができます。

本連載次の部分では、売買シグナルを生成するカスタム指標を構築し、統合をさらに進化させます。これらのシグナルは、Telegramのグループチャットに送信され、私たちが求める潜在的な取引機会をリアルタイムで通知します。これは単に取引戦略をより効果的に機能させるためだけでなく、MQL5とTelegramを組み合わせることで、携帯電話を見ている以外の何もしなくてもアラートが送信される、ダイナミックな取引ワークフローを構築できることを示すためでもあります。この統合システムの構築と改良を引き続き行っていきますので、どうぞご期待ください。


MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/15457

添付されたファイル |
MQL5-Telegram統合エキスパートアドバイザーの作成(第2回):MQL5からTelegramへのシグナル送信 MQL5-Telegram統合エキスパートアドバイザーの作成(第2回):MQL5からTelegramへのシグナル送信
この記事では、移動平均クロスオーバーシグナルをTelegramに送信するMQL5-Telegram統合エキスパートアドバイザー(EA)を作成します。移動平均クロスオーバーから売買シグナルを生成し、MQL5で必要なコードを実装し、統合がシームレスに機能するようにするプロセスを詳しく説明します。その結果、リアルタイムの取引アラートをTelegramのグループチャットに直接提供するシステムが完成します。
データサイエンスと機械学習(第29回):AI訓練に最適なFXデータを選ぶための重要なヒント データサイエンスと機械学習(第29回):AI訓練に最適なFXデータを選ぶための重要なヒント
この記事では、AIモデルのパフォーマンスを向上させるために、最も適切で高品質なFXデータを選択するための重要な側面について深く掘り下げます。
知っておくべきMQL5ウィザードのテクニック(第31回):損失関数の選択 知っておくべきMQL5ウィザードのテクニック(第31回):損失関数の選択
損失関数は、機械学習アルゴリズムの重要な指標です。これは、与えられたパラメータセットが目標に対してどれだけうまく機能しているかを定量的に評価し、学習プロセスにフィードバックを提供する役割を果たします。本記事では、MQL5のカスタムウィザードクラスを使って、損失関数のさまざまな形式を探っていきます。
知っておくべきMQL5ウィザードのテクニック(第30回):機械学習におけるバッチ正規化のスポットライト 知っておくべきMQL5ウィザードのテクニック(第30回):機械学習におけるバッチ正規化のスポットライト
バッチ正規化とは、ニューラルネットワークのような機械学習アルゴリズムに投入するデータの前処理です。これは、アルゴリズムが使用する活性化の種類を常に意識しながらおこなわれます。そこで、エキスパートアドバイザー(EA)を使って、そのメリットを享受するためのさまざまなアプローチを探ります。