
Senden von Nachrichten von MQL5 an Discord, Erstellen eines Discord-Bots für MetaTrader 5
Inhalt
- Einführung
- Erstellen eines Discord-Webhooks
- Senden der ersten Nachricht von MetaTrader 5 an Discord
- Erstellen einer Discord-Klasse in MQL5
- Die Identität des Discord-Bots
- Arbeiten mit Einbettungen und Bilddateien
- Senden von Handelsbenachrichtigungen an Discord
- Schlussfolgerung
Einführung
Wir leben nicht mehr in den Anfängen des Internets und des digitalen Urzeitalters; heute kann fast alles mit allem im Internet verbunden werden, es kommt nur darauf an, dass man bereit ist, die nötige Arbeit zu leisten.
Das Vorhandensein von APIs (Application Programming Interface), d. h. einer Reihe von Regeln und Protokollen, die es verschiedenen Softwareanwendungen ermöglichen, miteinander zu kommunizieren, hat es für mehr als eine Software oder Anwendung einfacher gemacht, sich mit einer anderen zu verbinden, und hat somit zu dem am meisten vernetzten Internet geführt, das wir heute sehen.
Um eine bereitgestellte API zu nutzen, müssen Sie sich an die Regeln und Protokolle halten, und ganz zu schweigen davon, dass Ihnen der API-Anbieter einen sicheren Zugang (falls vorhanden) gewähren muss.
Die Kommunikation zwischen MetaTrader 5 und externen Anwendungen ist nicht neu; sie wurde bereits bei mehreren Anwendungen durchgeführt, die zuverlässige API(s) anbieten, die MQL5-Entwickler zum Senden und Empfangen von Informationen über Web Requests verwenden. Die häufigste App, die MQL5-Händler für diese Kommunikation verwenden, ist Telegram.
In diesem Artikel werden wir besprechen, wie wir Nachrichten und Handelsinformationen (Signale) vom MetaTrader 5 an Discord senden können, indem wir die Programmiersprache MQL5 verwenden.
Erstellen eines Discord-Webhooks
Für diejenigen, die mit noch nicht vertraut sind:
Discord ist eine kostenlose Kommunikationsplattform, die es Nutzern ermöglicht, über Text, Sprache und Video zu chatten und Bildschirme gemeinsam zu nutzen. Es ist beliebt, um sich mit Freunden und Gemeinschaften zu verbinden, insbesondere im Bereich der Online-Spiele, wird aber auch für verschiedene andere Gruppen wie Buchclubs oder Nähkreise verwendet.
Ähnlich wie bei Telegram handelt es sich um eine Kommunikationsplattform, die es den Nutzern ermöglicht, miteinander zu kommunizieren. Beide Plattformen bieten APIs, die die Kommunikation auch außerhalb ihrer Plattformen ermöglichen, aber Discord ist Telegram weit voraus, wenn es um die Integration und Automatisierung geht.
Diese Plattform ermöglicht es den Nutzern, flexible Gemeinschaften zu schaffen und verschiedene Arten von Apps (auch als Bots bekannt) zu verwalten.
Es gibt verschiedene Möglichkeiten, Bots zu erstellen und die Kommunikation und den Prozess der Informationsweitergabe an Discord zu automatisieren, aber die einfachste Möglichkeit ist die Verwendung eines Webhooks in einem der Kanäle Ihrer Community. Hier erfahren Sie, wie Sie eine solche erstellen.
![]()
Abbildung 0.
Gehen Sie in Ihrer Community zu den Servereinstellungen.
![]()
Abbildung 02.
Gehen Sie in den Servereinstellungen zu Integrationen > Webhooks.
![]()
Abbildung 03.
Klicken Sie auf die Schaltfläche New Webhook, um einen Webhook zu erstellen. Es wird ein Webhook mit dem Standardnamen Captain Hook erstellt. Sie können diesen Namen nach Belieben ändern.
![]()
Abbildung 04.
Nachdem Sie den Namen geändert haben, können Sie den Kanal auswählen, auf den Sie diesen Webhook anwenden möchten. In diesem Server habe ich einen Kanal namens Handelssignale, auf den ich diesen Webhook anwenden möchte. Siehe Abbildung 01.
Schließlich müssen wir noch die Webhook-URL kopieren. Dies ist unser API-Gateway, das wir mit Web Requests in MQL5 verwenden können.
![]()
Abbildung 05.
Senden der ersten Nachricht von MetaTrader 5 an Discord
Als erstes müssen wir https://discord.com in die Liste der erlaubten URLs in MetaTrader 5 aufnehmen, da sonst alles, was wir danach besprechen werden, nicht funktionieren wird.
In MetaTrader 5 gehen Sie zu Extras > Options > Expert Advisors > WebRequest für folgende URLs erlauben, aktivieren es und fügen Sie dann die URL in das unten stehende Fenster ein.
Mit der Webhook-URL können wir eine POST-Anfrage an diesen API-Endpunkt mit JSON-formatierten Daten senden.
Dateiname: Diskurs EA.mq5
#include <jason.mqh> //https://www.mql5.com/en/code/13663 string discord_webhook_url = "https://discord.com/api/webhooks/1384809399767269527/105Kp27yKnQDpKD01VdEb01GS5P-KH5o5rYKuJb_xD_D8O23GPkGLXGn9pHBB1aOt4wR"; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- CJAVal js(NULL, jtUNDEF); //Creating a json object string raw_json = "{\"content\": \"Hello world from MetaTrader5!\"}"; bool b = js.Deserialize(raw_json); //Parse JSON string into a structured object string json; js.Serialize(json); //Convert the object to a valid JSON string //--- Sending a Post webrequest char data[]; ArrayResize(data, StringToCharArray(json, data, 0, StringLen(json))); //--- serialize to string //--- send data char res_data[]; //For storing the body of the response string res_headers=NULL; //For storing response headers (if needed) string headers="Content-Type: application/json; charset=utf-8"; uint timeout=10000; //10 seconds timeout for the HTTP request int ret = WebRequest("POST", discord_webhook_url, headers, timeout, data, res_data, res_headers); //Send a post request if (ret==-1) { printf("func=%s line=%d, Failed to send a webrequest. Error = %s",__FUNCTION__,__LINE__,ErrorDescription(GetLastError())); return false; } //--- Check if the post request was successful or not if (ret==204) { if (MQLInfoInteger(MQL_DEBUG)) Print("Message sent to discord successfully"); } else { printf("Failed to send message to discord. Json response Error = %s",CharArrayToString(res_data)); } //--- return(INIT_SUCCEEDED); }
Alle Informationen und Nachrichten, die Sie an Discord senden möchten, müssen immer im JSON-Format vorliegen.
Alles, was unter dem Schlüssel content in einem JSON-Objekt steht, stellt den Haupttext der an Discord gesendeten Nachricht dar.
Die Ausführung des obigen Codes sendet eine einfache Nachricht an Discord.
Fantastisch! Das war jedoch ein mühsamer Prozess, um die JSON-Daten und alles andere zu handhaben, nur um eine einfache Nachricht an Discord zu senden. Daher sollten wir alles in eine Klasse packen, um das Senden von Nachrichten zu vereinfachen, ohne sich jedes Mal um die technischen Details kümmern zu müssen.
Erstellen einer Discord-Klasse in MQL5
Um sicherzustellen, dass wir über eine Standardfunktionalität verfügen, fügen wir eine Protokollierung hinzu, um die vom API-Endpunkt erzeugten Fehler und den gesamten Prozess des Sendens von Anfragen zu verfolgen.
Dateiname: Discord.mqh.
#include <errordescription.mqh> #include <logging.mqh> #include <jason.mqh> class CDiscord { protected: string m_webhook_url; string m_headers; uint m_timeout; CLogging logging; bool PostRequest(const string json); string GetFormattedJson(const string raw_json); public: CDiscord(const string webhook_url, const string headers="Content-Type: application/json; charset=utf-8", const uint timeout=10000); ~CDiscord(void); bool SendMessage(const string message); bool SendEmbeds(const string title, const string description_, color clr, const string footer_text, const datetime time); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CDiscord::CDiscord(const string webhook_url, string headers="Content-Type: application/json; charset=utf-8", uint timeout=10000): m_webhook_url(webhook_url), m_headers(headers), m_timeout(timeout) { //--- Initialize the logger logging.Config("Discord server"); if (!logging.init()) return; logging.info("Initialized",MQLInfoString(MQL_PROGRAM_NAME),__LINE__); }
Wir verpacken die sich wiederholenden Prozesse zum Senden von POST-Anfragen und zum Konvertieren von Texten in das JSON-Format.
string CDiscord::GetFormattedJson(const string raw_json) { CJAVal js(NULL, jtUNDEF); bool b = js.Deserialize(raw_json); string json; js.Serialize(json); return json; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CDiscord::PostRequest(const string json) { char res[]; //--- serialize to string char data[]; ArrayResize(data, StringToCharArray(json, data, 0, StringLen(json))); //--- send data char res_data[]; string res_headers=NULL; int ret = WebRequest("POST", m_webhook_url, m_headers, m_timeout, data, res_data, res_headers); //Send a post request if (ret==-1) { printf("func=%s line=%d, Failed to send a webrequest. Error = %s",__FUNCTION__,__LINE__,ErrorDescription(GetLastError())); return false; } //--- Check if the post request was successful or not if (ret==204) { if (MQLInfoInteger(MQL_DEBUG)) Print("Message sent to discord successfully"); logging.info("Message sent to discord successfully",MQLInfoString(MQL_PROGRAM_NAME), __LINE__); } else { printf("Failed to send message to discord. Json response Error = %s",CharArrayToString(res_data)); logging.error(CharArrayToString(res_data), MQLInfoString(MQL_PROGRAM_NAME), __LINE__); } return true; }
Im Folgenden finden Sie eine einfache Funktion zum Senden von Nachrichten an Discord.
bool CDiscord::SendMessage(const string message) { string raw_json = StringFormat("{\"content\": \"%s\"}",message); string json = GetFormattedJson(raw_json); //Deserialize & Serialize the message in JSON format return PostRequest(json); }
So wird sie verwendet.
Dateiname: Discord EA.mq5
#include <Discord.mqh> CDiscord *discord; string discord_webhook_url = "https://discord.com/api/webhooks/1384809399767269527/105Kp27yKnQDpKD01VdEb01GS5P-KH5o5rYKuJb_xD_D8O23GPkGLXGn9pHBB1aOt4wR"; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- discord = new CDiscord(discord_webhook_url); discord.SendMessage("Hello from MetaTrader5!"); }
Diese einfache und leistungsstarke Funktion kann zum Versenden von Nachrichten verschiedener Art verwendet werden, da Discord einen in Markdown formatierten Text verwendet.
Beispiel Markdown-Nachricht
discord.SendMessage( "# h1 header\n" "## h2 header\n" "### h3 header\n\n" "**bold text** normal text\n" "[MQL5](https://www.mql5.com)\n" "" );
Ausgabe:
Und das ist noch nicht einmal das Coolste, was man mit dem von Discord bereitgestellten Markdown-Texteditor machen kann. Lassen Sie uns einige Codezeilen mit Discord austauschen.
discord.SendMessage("```MQL5\n" //we put the type of language for markdown highlighters after three consecutive backticks "if (CheckPointer(discord)!=POINTER_INVALID)\n" " delete discord;\n" "```"); discord.SendMessage("```Python\n" "while(True):\n" " break\n" "```");
Ausgabe:
Damit wollte ich Ihnen zeigen, wie leistungsfähig Markdown-Texteditoren sind.
Hinzufügen von Emojis zu Ihren Nachrichten
Emojis sind in Textnachrichten sehr nützlich; sie verleihen ihnen Eleganz, verbessern die Lesbarkeit, und nicht zuletzt sorgen sie für eine Prise Humor.
Im Gegensatz zu anderen Kommunikationsplattformen mit Emojis, die aus bestimmten numerischen Codes bestehen, verwendet Discord eine einzigartige Syntax, um Emojis direkt in Textnachrichten zu identifizieren und darzustellen.
Alles, was Sie tun müssen, ist, den Namen des Emoji zwischen zwei Doppelpunkte zu setzen – einen Doppelpunkt am Anfang und den anderen am Ende des Emoji-Namens.
Wenn die Codes dieser Emojis in eine Textnachricht eingefügt werden, werden sie in Discord als Emojis dargestellt.
discord.SendMessage(":rotating_light: Trade Alert!");
Nachricht.
Es gibt Tausende von Emojis, und es ist schwierig, den Überblick über sie alle zu behalten. Hier ist ein Spickzettel: https://github.com/ikatyang/emoji-cheat-sheet/blob/master/README.md. Ich habe eine einfache Bibliotheksdatei mit einigen der Emoji-Codes und der Syntax erstellt. Bitte zögern Sie nicht, weitere Emoji-Codes hinzuzufügen, wenn es Ihnen gefällt.
Dateiname: diskord emojis.mqh
#define DISCORD_EMOJI_ROCKET ":rocket:" #define DISCORD_EMOJI_CHART_UP ":chart_with_upwards_trend:" #define DISCORD_EMOJI_CHART_DOWN ":chart_with_downwards_trend:" #define DISCORD_EMOJI_BAR_CHART ":bar_chart:" #define DISCORD_EMOJI_BOMB ":bomb:" #define DISCORD_EMOJI_THUMBS_UP ":thumbsup:" #define DISCORD_EMOJI_THUMBS_DOWN ":thumbsdown:" #define DISCORD_EMOJI_WARNING ":warning:" #define DISCORD_EMOJI_JOY ":joy:" #define DISCORD_EMOJI_SOB ":sob:" #define DISCORD_EMOJI_SMILE ":smile:" #define DISCORD_EMOJI_FIRE ":fire:" #define DISCORD_EMOJI_STAR ":star:" #define DISCORD_EMOJI_BLUSH ":blush:" #define DISCORD_EMOJI_THINKING ":thinking:" #define DISCORD_EMOJI_ROTATING_LIGHT ":rotating_light:" #define DISCORD_EMOJI_X ":x:" #define DISCORD_EMOJI_WHITE_CHECK_MARK ":white_check_mark:" #define DISCORD_EMOJI_BALLOT_BOX_WITH_CHECK ":ballot_box_with_check:" #define DISCORD_EMOJI_HASH ":hash:" #define DISCORD_EMOJI_ASTERISK ":asterisk:" #define DISCORD_EMOJI_ZERO ":zero:" #define DISCORD_EMOJI_ONE ":one:" #define DISCORD_EMOJI_TWO ":two:" #define DISCORD_EMOJI_THREE ":three:" #define DISCORD_EMOJI_FOUR ":four:" #define DISCORD_EMOJI_FIVE ":five:" #define DISCORD_EMOJI_SIX ":six:" #define DISCORD_EMOJI_SEVEN ":seven:" #define DISCORD_EMOJI_EIGHT ":eight:" #define DISCORD_EMOJI_NINE ":nine:" #define DISCORD_EMOJI_TEN ":keycap_ten:" #define DISCORD_EMOJI_RED_CIRCLE ":red_circle:" #define DISCORD_EMOJI_GREEN_CIRCLE ":green_circle:"
Eine Nachricht senden.
discord.SendMessage(DISCORD_EMOJI_ROTATING_LIGHT " Trade Alert! " DISCORD_EMOJI_JOY);
Ergebnis der Nachricht.
Erwähnen von Nutzern und Rollen
Diese einfache Nachricht kann mit Erwähnungen und Rollen umgehen, die für eine wirksame Nachrichtenübermittlung entscheidend sind.
- @everyone – Damit werden alle Nutzer im Kanal benachrichtigt, auch wenn sie offline sind.
- @here – Dies benachrichtigt alle aktuell aktiven Nutzer im Chat. Alle Nutzer, die online sind.
- <@user_id> – Dies benachrichtigt einen bestimmten Nutzer oder mehrere Nutzer.
- <@&role_id> – Damit werden alle Nutzer benachrichtigt, die einer bestimmten Rolle zugeordnet sind. Zum Beispiel das Senden von Handelssignalen an alle Nutzer, denen die Rolle eines manuellen Händlers zugewiesen wurde.
Beispiel für die Verwendung.
discord.SendMessage("@everyone This is an information about a trading account"); discord.SendMessage("@here This is a quick trading signals for all of you that are active");
Das Ergebnis einer Nachricht.
Die Identität des Discord-Bots
Das Gute an einem Webhook ist, dass er nicht auf das standardmäßige Erscheinungsbild (Name und Avatar) beschränkt ist; Sie können diese Werte jederzeit ändern, wenn Sie eine Postanforderung senden.
Diese Fähigkeit ist sehr praktisch, da Sie mehrere Handelsroboter haben können, die eine Art von Informationen an eine oder zwei Gemeinschaften senden, die sich alle einen Webhook teilen. Die Möglichkeit, eine unterschiedliche Identität zu verwenden, hilft dabei, die Absender und empfangenen Nachrichten zu unterscheiden.
Wir können diese Identität jedes Mal, wenn die Discord-Klasse aufgerufen (initiiert) wird, zu einer Notwendigkeit machen, um die Identität global zu machen.
class CDiscord { protected: //... //... public: string m_name; string m_avatar_url; CDiscord(const string webhook_url, const string name, const string avatar_url, const string headers="Content-Type: application/json; charset=utf-8", const uint timeout=10000); }
Wir deklarieren diese Variablen öffentlich, da ein Nutzer sie möglicherweise ändern oder auf sie zugreifen möchte (nach der Initialisierung der Klasse).
Das macht es noch einfacher, die Protokolle für jeden Nutzernamen zu verfolgen, der diesem Discord-Messenger zugewiesen wird.
CDiscord::CDiscord(const string webhook_url, const string name, const string avatar_url, const string headers="Content-Type: application/json; charset=utf-8", const uint timeout=10000): m_webhook_url(webhook_url), m_headers(headers), m_timeout(timeout), m_name(name), m_avatar_url(avatar_url) { //--- Initialize the logger logging.Config(m_name); if (!logging.init()) return; logging.info("Initialized",MQLInfoString(MQL_PROGRAM_NAME),__LINE__); }
Nun müssen wir diese Identitätsinformationen (Name und Avatar) überall dort anfügen, wo ein JSON-String gefunden wird.
bool CDiscord::SendMessage(const string message) { string raw_json = StringFormat("{" "\"username\": \"%s\"," "\"avatar_url\": \"%s\"," "\"content\": \"%s\"" "}", m_name, m_avatar_url, message); string json = GetFormattedJson(raw_json); //Deserialize & Serialize the message in JSON format return PostRequest(json); }
In der Funktion SendJSON() müssen wir diese Identität optional machen, weil ein Nutzer eine andere Vorstellung haben könnte. Deshalb hat er sich für eine Funktion entschieden, die einen rohen JSON-String annimmt, der ihm die Kontrolle darüber gibt, welche Informationen er senden möchte.
bool CDiscord::SendJSON(const string raw_json, bool use_id=true) { CJAVal js; js.Deserialize(raw_json); if (use_id) //if a decides to use the ids assigned to the class constructor, we append that information to the json object { js["username"] = m_name; js["avatar_url"] = m_avatar_url; } string json; js.Serialize(json); return PostRequest(json); }
Lassen Sie uns eine andere Identität für unseren Bot festlegen.
#include <Discord.mqh> CDiscord *discord; input string discord_webhook_url = "https://discord.com/api/webhooks/1384809399767269527/105Kp27yKnQDpKD01VdEb01GS5P-KH5o5rYKuJb_xD_D8O23GPkGLXGn9pHBB1aOt4wR"; input string avatar_url_ = "https://imgur.com/m7sVf51.jpeg"; input string bots_name = "Signals Bot"; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- discord = new CDiscord(discord_webhook_url, bots_name, avatar_url_); discord.SendMessage("Same webhook but, different Identity :smile: cheers!"); //--- return(INIT_SUCCEEDED); }
Das Ergebnis.
Arbeiten mit Einbettungen und Bilddateien
Auch wenn Sie das Bild an die Nachricht angehängt haben, die im vorherigen Abschnitt beim Erstellen einer Discord-Klasse besprochen wurde, gibt es einen richtigen Weg, um Dateien anzuhängen und Elemente in eine Nachricht einzubetten.
Wir können dies mit einer unabhängigen JSON-Anfrage erreichen.
discord.SendJSON( "{" "\"content\": \"Here's the latest chart update:\"," "\"embeds\": [" "{" "\"title\": \"Chart Update\"," "\"image\": {" "\"url\": \"https://imgur.com/SBsomI7.png\"" "}" "}" "]" "}" );
Ergebnisse.
Leider ist es nicht möglich, ein Bild direkt von MQL5 über Web Request zu senden, obwohl Discord die Dateien empfangen kann. Das Beste, was Sie derzeit tun können, ist, ein Bild über einen Link weiterzugeben, über den die Datei online gehostet wird.
Im vorherigen Beispiel musste ich imgur.com verwenden.
Senden von Handelsbenachrichtigungen von MetaTrader 5 an Discord
Händler nutzen häufig die Möglichkeit, Informationen von MetaTrader 5 an externe Plattformen zu senden, um Updates über ihre Handelsaktivitäten zu übermitteln. Lassen Sie uns diesen Bot (Expert Advisor) für eine solche Aufgabe verwenden.
Angefangen bei den Benachrichtigungen zur Eröffnung eines Handelsgeschäfts.
01: Senden von Benachrichtigungen über die Eröffnung von Handelsgeschäften
Die Funktion OnTradeTransaction ist für diese Aufgabe sehr nützlich.
Nachfolgend finden Sie Konditionsprüfer, mit denen Sie den Zustand einer aktuellen Position und eines Geschäfts überprüfen können.
#define IS_TRANSACTION_POSITION_OPENED (trans.type == TRADE_TRANSACTION_DEAL_ADD && HistoryDealSelect(trans.deal) && (ENUM_DEAL_ENTRY)HistoryDealGetInteger(trans.deal, DEAL_ENTRY) == DEAL_ENTRY_IN) #define IS_TRANSACTION_POSITION_CLOSED (trans.type == TRADE_TRANSACTION_DEAL_ADD && HistoryDealSelect(trans.deal) && (ENUM_DEAL_ENTRY)HistoryDealGetInteger(trans.deal, DEAL_ENTRY) == DEAL_ENTRY_OUT && ((ENUM_DEAL_REASON)HistoryDealGetInteger(trans.deal, DEAL_REASON) != DEAL_REASON_SL && (ENUM_DEAL_REASON)HistoryDealGetInteger(trans.deal, DEAL_REASON) != DEAL_REASON_TP)) #define IS_TRANSACTION_POSITION_MODIFIED (trans.type == TRADE_TRANSACTION_POSITION)
void OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) { ulong deal_ticket = trans.deal; ulong position_ticket = trans.position; //--- m_deal.Ticket(deal_ticket); //select a deal by it's ticket if (IS_TRANSACTION_POSITION_OPENED) { if (deal_ticket==0) return; if (!m_position.SelectByTicket(position_ticket)) //select a position by ticket return; if (!m_symbol.Name(m_deal.Symbol())) //select a symbol from a position { printf("line=%d Failed to select symbol %s. Error = %s",__LINE__,m_deal.Symbol(),ErrorDescription(GetLastError())); return; } string message = DISCORD_EMOJI_ROTATING_LIGHT " **TRADE OPENED ALERT** \n\n" "- **Symbol:**"+m_position.Symbol()+"\n" "- **Trade Type:** "+ (m_position.PositionType()==POSITION_TYPE_BUY ? DISCORD_EMOJI_GREEN_CIRCLE: DISCORD_EMOJI_RED_CIRCLE) +" "+m_position.TypeDescription()+"\n" "- **Entry Price:** `"+DoubleToString(m_deal.Price(), m_symbol.Digits())+"`\n" "- **Stop Loss:** `"+DoubleToString(m_position.StopLoss(), m_symbol.Digits())+"`\n" "- **Take Profit:** `"+DoubleToString(m_position.TakeProfit(), m_symbol.Digits())+"`\n" "- **Time UTC:** `"+TimeToString(TimeGMT())+"`\n" "- **Position Ticket:** `"+(string)position_ticket+"`\n" "> "DISCORD_EMOJI_WARNING" *Risk what you can afford to lose.*"; discord.SendMessage(message); } //... //... Other lines of code //... }
Anmerkung:
Bei der Formatierung von Marktwerten wie Einstiegskurs, Stop-Loss und Take-Profit usw. umschließe ich jeden mit einem einzelnen Backtick (`). Dadurch wird in Discord ein Inline-Code-Block erzeugt, der die Zahlen optisch voneinander trennt und das Kopieren für die Nutzer erleichtert.
Verwenden von Discord.
- Ein einzelner Backtick (`) zur Formatierung von Inline-Code – ideal für kurze Werte wie Preise.
- Dreifache Backticks (```) zur Formatierung von mehrzeiligen Codeblöcken – wird für größere Codeblöcke oder Nachrichten verwendet.
Ich habe zwei gegensätzliche Handelsgeschäfte manuell mit dem One-Click-Trading in MetaTrader 5 eröffnet, hier das Ergebnis.
02: Versenden von Benachrichtigungen über Handelsänderungen
if (IS_TRANSACTION_POSITION_MODIFIED) { if (!m_position.SelectByTicket(position_ticket)) { printf("Failed to modify a position. Erorr = %s",ErrorDescription(GetLastError())); return; } if (!m_symbol.Name(m_deal.Symbol())) { printf("line=%d Failed to select symbol %s. Error = %s",__LINE__,m_deal.Symbol(),ErrorDescription(GetLastError())); return; } string message = DISCORD_EMOJI_BAR_CHART " **TRADE MODIFIED ALERT** \n\n" "- **Symbol:** `"+m_position.Symbol()+"`\n" "- **Trade Type:** "+ (m_position.PositionType()==POSITION_TYPE_BUY ? DISCORD_EMOJI_GREEN_CIRCLE: DISCORD_EMOJI_RED_CIRCLE) +" "+m_position.TypeDescription()+"\n" "- **Entry Price:** `"+DoubleToString(m_position.PriceOpen(), m_symbol.Digits())+"`\n" "- **New Stop Loss:** `"+DoubleToString(m_position.StopLoss(), m_symbol.Digits())+"`\n" "- **New Take Profit:** `"+DoubleToString(m_position.TakeProfit(), m_symbol.Digits())+"`\n" "- **Time UTC:** `"+TimeToString(TimeGMT())+"`\n" "- **Position Ticket:** `"+(string)position_ticket+"`\n" "> "DISCORD_EMOJI_WARNING" *Risk what you can afford to lose.*"; discord.SendMessage(message); }
In dieser Nachricht ist alles gleich wie bei den Handelsbenachrichtigungen, nur die Namen der Felder für Stop Loss und Take Profit wurden geändert.
03: Senden von Benachrichtigungen über den Abschluss von Handelsgeschäften
if (IS_TRANSACTION_POSITION_CLOSED) { if (!m_symbol.Name(m_deal.Symbol())) { printf("line=%d Failed to select symbol %s. Error = %s",__LINE__,m_deal.Symbol(),ErrorDescription(GetLastError())); return; } m_symbol.RefreshRates(); //Get recent ask and bid prices long reason_integer; m_deal.InfoInteger(DEAL_REASON, reason_integer); string reason_text = GetDealReasonText(reason_integer); string message = DISCORD_EMOJI_X " **TRADE CLOSED ALERT**\n\n" "- **Symbol:** `" + m_deal.Symbol() + "`\n" "- **Trade Type:** " + (m_position.PositionType() == POSITION_TYPE_BUY ? DISCORD_EMOJI_GREEN_CIRCLE : DISCORD_EMOJI_RED_CIRCLE) + " " + m_position.TypeDescription() + "\n" "- **Entry Price:** `" + DoubleToString(m_deal.Price(), m_symbol.Digits()) + "`\n" "- **Exit Price:** `" + (m_position.PositionType() == POSITION_TYPE_BUY ? (DoubleToString(m_symbol.Bid(), m_symbol.Digits())) : (DoubleToString(m_symbol.Ask(), m_symbol.Digits()))) + "`\n" "- **Profit:** " + (m_deal.Profit() >= 0 ? DISCORD_EMOJI_THUMBS_UP : DISCORD_EMOJI_THUMBS_DOWN) + " `" + DoubleToString(m_deal.Profit(), 2) + "`\n" "- **Close Reason:** `" + reason_text+ "`\n" "- **Commission:** `" + DoubleToString(m_position.Commission(), 2) + "`\n" "- **Swap:** `" + DoubleToString(m_position.Swap(), 2)+ "`\n" "- **Time (UTC):** `" + TimeToString(TimeGMT()) + "`\n" "- **Deal Ticket:** `" + string(deal_ticket) + "`\n" "> "DISCORD_EMOJI_WARNING" *Risk what you can afford to lose.*"; discord.SendMessage(message); }
In der Nachricht über den Abschluss eines Handelsgeschäfts wird ein Emoji mit dem Daumen nach oben angezeigt, wenn das Handelsgeschäft mit Gewinn abgeschlossen wurde, und ein Emoji mit dem Daumen nach unten, wenn es mit Verlust abgeschlossen wurde. Anders als beim Öffnen und Ändern der Position, wo wir eine Ticketnummer für die Position hatten. Eine geschlossene Position ist keine Position mehr – es handelt sich um ein Handelsgeschäft, daher verwenden wir dafür die Ticketnummer.
Dieses Handelsgeschäft wurde manuell abgeschlossen, daher lautet der Grund Client (Desktop Terminal), dies entspricht ENUM_DEAL_REASON.
string GetDealReasonText(long reason) { switch((int)reason) { case DEAL_REASON_CLIENT: return "Client (Desktop Terminal)"; case DEAL_REASON_MOBILE: return "Mobile App"; case DEAL_REASON_WEB: return "Web Platform"; case DEAL_REASON_EXPERT: return "Expert Advisor"; case DEAL_REASON_SL: return "Stop Loss Hit"; case DEAL_REASON_TP: return "Take Profit Hit"; case DEAL_REASON_SO: return "Stop Out (Margin)"; case DEAL_REASON_ROLLOVER: return "Rollover Execution"; case DEAL_REASON_VMARGIN: return "Variation Margin Charged"; case DEAL_REASON_SPLIT: return "Stock Split Adjustment"; case DEAL_REASON_CORPORATE_ACTION: return "Corporate Action"; default: return "Unknown Reason"; } }
Fazit
Discord Webhooks sind ein guter Ausgangspunkt für die Integration von MetaTrader 5 und Discord und ermöglichen die Kommunikation zwischen diesen beiden leistungsstarken Plattformen. Wie ich jedoch bereits sagte, haben alle APIs Regeln und Einschränkungen – die Discord Webhook-API ist nicht anders, denn Webhook-Anfragen sind begrenzt.
- Sie können nur 5 Nachrichten alle 2 Sekunden mit einem einzigen Webhook senden.
- Für einen einzelnen Webhook sind maximal 30 Nachrichten pro Minute und Kanal zulässig.
Bei Überschreitung dieser Begrenzung gibt Discord HTTP 429 (Too Many Requests) zurück. Um dieses Problem zu lösen, können Sie in Ihrem MQL5-Code Verzögerungen oder Warteschlangen hinzufügen.
Außerdem spreche ich in diesem Artikel von Discord-Bots, aber ein Webhook unterscheidet sich sehr von einem Discord-Bot. Der gesamte Arbeitsablauf zwischen MQL5 und Discord ist das, was ich als Bot bezeichne.
Bots sind im Wesentlichen Programme, die innerhalb von Discord laufen und eine breite Palette von Funktionen bieten, von einfachen Befehlen bis hin zu komplexen Automatisierungen. Webhooks hingegen sind einfache URLs, die es externen Anwendungen ermöglichen, automatisierte Nachrichten an einen bestimmten Discord-Kanal zu senden
Im Folgenden wird der Unterschied zwischen einem Discord-Webhook und einem Discord-Bot tabellarisch dargestellt.
Webhooks | Bots | |
---|---|---|
Funktion |
|
|
Personalisierung |
|
|
Belastung und Sicherheit |
|
|
Ein Discord-Bot ist ziemlich komplex und für MQL5-Programmierer nicht sehr praktisch, da wir oft nur eine Funktion wünschen, um unsere Mithändler über den Handelsfortschritt zu informieren. Ganz zu schweigen davon, dass man zur Erstellung eines Discord-Bots einige Python Module benötigt.
Sie können jedoch diesen vollwertigen Discord-Bot entwickeln, der mit MetaTrader 5 funktioniert, wenn Sie das möchten.
Da wir ein MetaTrader 5-Python-Paket haben, können Sie sich von der Python-Umgebung aus zu einer vollständigen Integration zwischen diesen beiden Plattformen vorarbeiten.
Mit freundlichen Grüßen.
Tabelle der Anhänge
Dateiname | Beschreibung und Verwendung |
---|---|
Include\discord emojis.mqh | Enthält Emoji-Codes und eine mit Discord kompatible Syntax. |
Include\discord.mqh | Es enthält die CDiscord-Klasse zum Senden von Nachrichten im JSON-Format an die Discord-Plattform. |
Include\errordescription.mqh | Enthält Beschreibungen aller von MetaTrader 5 erzeugten Fehlercodes in der Sprache MQL5. |
Include\jason.mqh | Eine Bibliothek zur Serialisierung und Deserialisierung des JSON-Protokolls. |
Include\logging.mqh | Eine Bibliothek zur Protokollierung aller Informationen und Fehler, die von der Klasse CDiscord (Webhook-Sender) erzeugt werden. |
Experts\Discord EA.mq5 | Ein Expert Advisor (EA) zum Testen des Discord-Webhooks und zum Senden von Handelsalarmen an die zugewiesene Discord-Webhook-URL. |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/18550
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.





- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.