
Erstellen eines Handelsadministrator-Panels in MQL5 (Teil I): Aufbau einer Nachrichtenschnittstelle
Einführung
Es ist möglich, mit Ihren Systemnutzern direkt von MetaTrader 5 aus zu interagieren. Auf diese Weise kann ein Administrator in Echtzeit Einblicke in die Leistung des Systems geben. Sie kann auch als Validierung der kürzlich an einen sozialen Kanal übermittelten Systemsignale dienen. Wenn Sie bis zum Ende lesen, können Sie sehen, wie man eine interaktive Schnittstelle erstellen kann, wie in diesem Bild gezeigt:
Systemadministrator-Panel: Boom 500 Index, H1
Kommunikationspanel für Administratoren (MetaTrader 5) und Telegram App (Empfang von Echtzeit-Nachrichten vom Administrator)
In der heutigen hypervernetzten Welt, in der Millionen von Geschäften innerhalb von Millisekunden ausgeführt werden, sind effiziente Kommunikationskanäle in Handelsökosystemen wichtiger denn je. Mehr als 70 % der Händler nutzen Instant-Messaging-Plattformen wie Telegram für Echtzeit-Updates, was den Trend zu integrierten Kommunikationslösungen in Handelsumgebungen verdeutlicht. Dieser Wandel unterstreicht die Notwendigkeit für Händler, algorithmischen und unmittelbaren Zugang zu Expertenwissen und Empfehlungen zu erhalten.
Für Händler und Entwickler, die MetaTrader 5 verwenden, besteht die Herausforderung darin, die Lücke zwischen automatischer Signalgenerierung und effektiver menschlicher Intervention über Entfernungen hinweg zu schließen. Das Admin-Panel bietet Systemadministratoren die Möglichkeit, eine schnelle und direkte Kommunikation mit weltweit verteilten Händlern zu führen. Durch die Nutzung dieses Systems können Administratoren nahtlos Signale validieren oder ungültig machen und den Händlern über Plattformen wie Telegram wichtige Kommentare oder Empfehlungen geben.
In diesem Artikel wird die Erstellung dieser wichtigen Verwaltungsoberfläche mit MQL5 beschrieben. Es bietet eine schrittweise Anleitung für die Entwicklung dieses Programms, das die Kommunikation und Überwachung des Handels verbessert. Wir werden erforschen, wie man sich die Leistungsfähigkeit von MQL5 zunutze machen kann, um ein umfassendes System aufzubauen, das ein effektives Signalmanagement ermöglicht und die unmittelbare Kommunikation mit den Händlern integriert, wodurch die Art und Weise, wie Handelsgeschäfte weltweit durchgeführt werden, revolutioniert wird.
Flussdiagramm der Signale
Das Flussdiagramm veranschaulicht die Rollen des Systems, der Nutzer und der Administratoren in einem Handelsökosystem sowie die dazugehörigen Werkzeuge.
Hier ist eine Zusammenfassung der Themen, die wir in dieser Diskussion behandeln werden:
- Verstehen der Koordinaten in der MetaTrader 5 GUI Entwicklung
- Verstehen der Bibliotheksdateien in der MQL5-Entwicklung
- Erstellen eines nutzerdefinierten Administrator-Panel-Algorithmus in MQL5
- Integration der Telegram API für die Kommunikation mit Tradern
- Testen des Verwaltungsbereichs
- Tipps für die Verwendung
- Schlussfolgerung
Verstehen der Koordinaten in der MetaTrader 5 GUI Entwicklung
Bei der Entwicklung von grafischen Nutzeroberflächen (GUIs) innerhalb der MetaTrader 5-Plattform ist es wichtig, das Koordinatensystem zu verstehen, das definiert, wie grafische Elemente auf einem Chart positioniert und dimensioniert werden.
Koordinatensystem:
Das Koordinatensystem in MetaTrader 5 ist ein zweidimensionaler Raum, der durch eine horizontale (x) und eine vertikale (y) Achse definiert ist. Jedes Chartfenster hat sein eigenes Koordinatensystem, ausgehend von der linken oberen Ecke, die als Ursprungspunkt (0,0) bezeichnet wird.
Positionierungselemente:
Um Elemente im Koordinatenraum des Charts zu positionieren, geben wir normalerweise zwei Punkte mithilfe von Koordinaten an:
- Obere linke Ecke: Definiert durch die Koordinaten (x1, y1). Dies ist die Position, an der das Element beginnt.
- Rechte untere Ecke: Definiert durch die Koordinaten (x2, y2). Dies markiert das diagonale Ende des Elements.
Berechnung von Breite und Höhe:
Die Abmessungen des GUI-Elements ergeben sich aus der Differenz zwischen diesen Koordinaten:
- Breite: Berechnet als (Breite = x2 - x1)
- Höhe: Berechnet als (Höhe = y2 - y1)
Diese Berechnungen bestimmen die Größe Ihres Elements und stellen sicher, dass es in die angegebenen Grenzen des Charts passt.
Beispiel GUI-Layout & Beispielverwendung in MQL5
Praktisches Anwendungsbeispiel
Bei der Erstellung von Dialogen oder grafischen Steuerelementen, wie z. B. Bedienfeldern oder Schaltflächen, hilft die Verwendung dieser Koordinaten bei der eindeutigen und präzisen Positionierung und Größenbestimmung. Dieser Ansatz stellt sicher, dass alle GUI-Komponenten einheitlich platziert und skaliert werden, damit sie in den verfügbaren Platz auf Ihrem Chartfenster passen, was zu einer kohärenten Nutzeroberfläche beiträgt. Das Verständnis und die effektive Nutzung dieses Koordinatensystems sind von grundlegender Bedeutung für die Erstellung intuitiver und visuell ansprechender Anwendungen innerhalb der MetaTrader 5-Umgebung.
Ein weiteres Beispiel: Erstellen eines einfachen Panels mit einer Schaltfläche in MetaTrader 5
Lassen Sie uns ein einfaches Panel mit einer Schaltfläche im MetaTrader 5 Chart-Fenster erstellen und dabei das zuvor beschriebene Koordinatensystem verwenden.
Definieren wir die Koordinaten:
Zunächst legen wir die Koordinaten für das Panel und die Schaltfläche fest. Wir positionieren das Panel in der oberen linken Ecke des Charts und platzieren die Schaltfläche in diesem Panel.
Koordinaten des Panels:
- Obere linke Ecke (x1, y1): (10, 10)
- Rechte untere Ecke (x2, y2): (200, 100)
Mit diesen Koordinaten wird ein Feld erstellt, das 10 Pixel vom oberen und 10 Pixel vom linken Rand des Chartfensters beginnt, mit einer Breite von 190 Pixel (200 minus 10) und einer Höhe von 90 Pixel (100 minus 10).
Koordinaten der Schaltfläche:
- Obere linke Ecke (x1, y1): (20, 20)
- Rechte untere Ecke (x2, y2): (180, 60)
Diese Koordinaten platzieren die Schaltfläche innerhalb des Feldes, beginnend 20 Pixel von oben und 20 Pixel von links des Feldes, mit einer Breite von 160 Pixel (180 minus 20) und einer Höhe von 40 Pixel (60 minus 20). Zumindest haben wir jetzt die Mathematik im Kopf.
Verstehen der Bibliotheksdateien in der MQL5-Entwicklung
In MQL5 sind „.mqh“-Dateien Header-Dateien, die dazu dienen, den Code innerhalb der MetaTrader 5-Plattform zu organisieren und zu modularisieren, der hauptsächlich für die Entwicklung von Handelsalgorithmen und nutzerdefinierten Indikatoren verwendet wird. Die Dateien sind eine entscheidende Komponente für eine effiziente und wartbare Codeverwaltung in komplexen MQL5-Projekten.
In MetaEditor können Sie wie folgt navigieren, um die Include-Datei im MQL5-Ordner zu finden:
Auffinden der #include-Dateien in MQL5
Hier finden Sie eine Erklärung zu ihrem Zweck und ihrer Verwendung:
Zweck der (.mqh) Dateien:
1. Wiederverwendbarkeit des Codes: „.mqh“-Dateien sind dazu gedacht, wiederverwendbare Code-Komponenten wie Funktionsdefinitionen, Klassendeklarationen und Makrodefinitionen zu enthalten, die von mehreren MQL5-Programmen gemeinsam genutzt werden können.
2. Modularität: Durch die Aufteilung des Codes in verschiedene Dateien können Entwickler modulare Anwendungen erstellen. Auf diese Weise können bestimmte Code-Funktionen isoliert, gewartet und unabhängig voneinander entwickelt werden.
3. Organisation: Die Verwendung von Header-Dateien hilft dabei, den Code logisch zu organisieren. Entwickler können verschiedene Teile ihrer Anwendung in verschiedenen Dateien getrennt halten, z. B. indem sie Dienstprogrammfunktionen oder Konstanten in speziellen Headern unterbringen.
Typische Inhalte von (.mqh) Dateien:
- Funktionsdeklarationen: Funktionen, die in mehreren Skripten verwendet werden können.
- Klassen und Strukturen: Definitionen und Implementierungen von Klassen und Strukturen, die für die objektorientierte Programmierung verwendet werden.
- Konstanten und Makros: Definierte konstante Werte und Makros, die global verwendet werden können.
- Enthält: Die Datei kann auch andere „mqh“-Dateien enthalten, wodurch eine Hierarchie oder Kette von eingeschlossenen Funktionen entsteht.
Wie man (.mqh) Dateien verwendet:
Um eine „.mqh“-Datei in Ihrem MQL5-Skript zu verwenden (wie eine „.mq5“- oder eine andere „.mqh“-Datei), binden Sie sie mit der Direktive #include ein. Hier ist ein Beispiel:#include <MyLibrary.mqh>
Diese Direktive weist den Compiler an, den Inhalt von „MyLibrary.mqh“ an der Stelle einzubinden, an der die Direktive #include erscheint, sodass Ihr Skript auf die Funktionen, Klassen oder Makros zugreifen kann, die im eingebundenen Header definiert sind.
Vorteile:
- Verbesserte Lesbarkeit: Durch die Zusammenfassung von komplexem Code in Kopfzeilen bleibt das Hauptskript übersichtlicher und leichter zu verstehen.
- Vereinfachte Wartung: Änderungen oder Aktualisierungen können an einer einzelnen Header-Datei vorgenommen werden, und alle Skripte, die sie enthalten, übernehmen diese Aktualisierungen automatisch.
- Kollaboration: In Teamumgebungen kann die Aufteilung des Codes auf mehrere Dateien eine bessere Zusammenarbeit ermöglichen, da verschiedene Teammitglieder ohne Konflikte an unterschiedlichen Teilen der Codebasis arbeiten können.
In diesem Projekt werden wir zum Beispiel die in dieser Tabelle zusammengefassten Dateien implementieren:
Datei Name | Datei Typ | Beschreibung |
---|---|---|
Dialog.mqh: | Bibliotheksdatei; |
|
Button.mqh: | Bibliotheksdatei |
|
Edit.mqh: | Bibliotheksdatei |
|
Erstellen eines nutzerdefinierten Administrator-Panel-Algorithmus in MQL5
Wir erstellen eine neue Expertenvorlage in MetaEditor und nennen sie „Admin Panel“ oder einen anderen eindeutigen Namen. Wir behalten nur die Eigenschaften des Entwicklers - Ihren Namen, die Version und das Copyright - bei und löschen den Rest der Vorlage. Folgen Sie dann der nachstehenden Anleitung, um Ihr Panel zu erstellen.
Einen neuen Experten in MetaEditor erstellen
Bei der Erstellung des Programms „Admin Panel.mq5“ haben wir darauf geachtet, dass jedes Element einem bestimmten Zweck dient und gleichzeitig ein kohärenter Ablauf gewährleistet ist. Die Grundlage unseres Programms beginnt mit der Einbindung der Schlüsselbibliotheken wie „Trade.mqh“, „Dialog.mqh“, „Button.mqh“ und „Edit.mqh“, die wesentliche Klassen und Funktionen für die Erstellung interaktiver chartbasierter Oberflächen bereitstellen. Indem wir diese einbeziehen, nutzen wir die vorhandenen Ressourcen, sodass wir uns auf kundenspezifische Funktionen konzentrieren können.
#include <Trade\Trade.mqh> #include <Controls\Dialog.mqh> #include <Controls\Button.mqh> #include <Controls\Edit.mqh>
Anschließend haben wir die Klasse „CScalableDialog“ definiert, um ein skalierbares und verschiebbares Panel innerhalb des Charts zu verwalten. Diese Klasse erweitert die Klasse „CDialog“, die eine flexible Basis für unser Panel darstellt. Dabei habe ich Methoden wie „HandleDragging“ implementiert, damit die Nutzer das Panel einfach verschieben können, und „SetSize“, um eine dynamische Größenänderung zu ermöglichen. Dies gibt uns die Möglichkeit, eine nutzerfreundliche Oberfläche zu schaffen, die sich an verschiedene Bildschirmgrößen und Nutzerpräferenzen anpassen kann, was das Tool vielseitig macht.
class CScalableDialog : public CDialog { protected: bool m_Dragging; int m_OffsetX, m_OffsetY; int m_width, m_height; public: CScalableDialog() : m_Dragging(false), m_OffsetX(1020), m_OffsetY(720), m_width(500), m_height(400) {} void HandleDragging(const int id, const long lparam, const double dparam) { if (id == CHARTEVENT_MOUSE_MOVE && m_Dragging) { int new_x = (int)lparam - m_OffsetX; int new_y = (int)dparam - m_OffsetY; SetXPosition(new_x, new_y); } else if (id == CHARTEVENT_OBJECT_CLICK) { m_OffsetX = (int)lparam; m_OffsetY = (int)dparam; m_Dragging = true; } else if (id == CHARTEVENT_CLICK) { m_Dragging = false; } } void SetSize(int width, int height) { m_width = width; m_height = height; UpdateDialogSize(); } void UpdateDialogSize() { ObjectSetInteger(ChartID(), Name(), OBJPROP_XSIZE, m_width); ObjectSetInteger(ChartID(), Name(), OBJPROP_YSIZE, m_height); } void SetXPosition(int x, int y) { ObjectSetInteger(ChartID(), Name(), OBJPROP_XDISTANCE, x); ObjectSetInteger(ChartID(), Name(), OBJPROP_YDISTANCE, y); UpdateDialogSize(); } };
Innerhalb der Funktion „OnInit“ haben wir uns auf die Initialisierung der Schnittstellenkomponenten konzentriert. Dazu gehört das Erstellen von Schaltflächen, Eingabefeldern und das Einrichten des Layouts des Bedienfelds. Ich habe genau darauf geachtet, dass jedes Element richtig positioniert und funktional ist. Die Methode (adminPanel. Create) wird das Hauptdialogfeld eingerichtet, während in den nachfolgenden Zeilen Schaltflächen wie „sendButton“, „quickMessageButton“ und Hilfsschaltflächen zum Minimieren und Schließen des Bedienfelds hinzugefügt werden. Hier habe ich dafür gesorgt, dass alle Komponenten innerhalb des Panels reibungslos zusammenspielen.
int OnInit() { long chart_id = ChartID(); if (!adminPanel.Create(chart_id, "Admin Panel", 0, 30, 30, 500, 400)) { Print("Failed to create dialog"); return INIT_FAILED; } if (!inputBox.Create(chart_id, "InputBox", 0, 5, 5, 460,50 )) { Print("Failed to create input box"); return INIT_FAILED; } adminPanel.Add(inputBox); if (!sendButton.Create(chart_id, "SendButton", 0, 270, 50, 460, 80)) { Print("Failed to create send button"); return INIT_FAILED; } sendButton.Text("Send Message"); adminPanel.Add(sendButton); if (!quickMessageButton.Create(chart_id, "QuickMessageButton", 0, 180, 200, 350, 230)) { Print("Failed to create quick message button"); return INIT_FAILED; } quickMessageButton.Text("Invalid Signal"); adminPanel.Add(quickMessageButton); if (!minimizeButton.Create(chart_id, "MinimizeButton",0, 405, -22, 435, 0)) { Print("Failed to create minimize button"); return INIT_FAILED; } minimizeButton.Text("_"); adminPanel.Add(minimizeButton); if (!closeButton.Create(chart_id, "CloseButton",0 , +435, -22,+465,0)) { Print("Failed to create close button"); return INIT_FAILED; } closeButton.Text("X"); adminPanel.Add(closeButton); adminPanel.Show(); ChartSetInteger(ChartID(), CHART_EVENT_OBJECT_CREATE, true); ChartSetInteger(ChartID(), CHART_EVENT_OBJECT_DELETE, true); ChartSetInteger(ChartID(), CHART_EVENT_MOUSE_WHEEL, true); ChartRedraw(); Print("Initialization complete"); return INIT_SUCCEEDED; }
Mit der Funktion „OnChartEvent“ wird die Interaktionslogik verwaltet. Diese Funktion verarbeitet verschiedene Nutzeraktionen wie Klicks, Mausbewegungen und Objekterstellungsereignisse. Durch den Aufruf von Methoden wie „HandleDragging“ wird das Panel in die Lage versetzt, dynamisch auf Nutzereingaben zu reagieren. Die Switch-Case-Struktur innerhalb von „OnChartEvent“ ermöglicht es uns, verschiedene Ereignisse effizient an ihre jeweiligen Handler weiterzuleiten, um sicherzustellen, dass die Schnittstelle reaktionsschnell und intuitiv bleibt.
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { adminPanel.HandleDragging(id, lparam, dparam); switch(id) { case CHARTEVENT_KEYDOWN: Print("Key pressed: code=", lparam); break; case CHARTEVENT_MOUSE_MOVE: Print("Mouse move: x=", lparam, " y=", dparam); break; case CHARTEVENT_OBJECT_CREATE: Print("Created object: ", sparam); break; case CHARTEVENT_OBJECT_DELETE: Print("Deleted object: ", sparam); break; case CHARTEVENT_CLICK: Print("Mouse click on chart: x=", lparam, " y=", dparam); break; case CHARTEVENT_OBJECT_CLICK: if (sparam == "SendButton") { OnSendButtonClick(); } else if (sparam == "QuickMessageButton") { OnQuickMessageButtonClick(); } else if (sparam == "MinimizeButton") { OnMinimizeButtonClick(); } else if (sparam == "CloseButton") { OnCloseButtonClick(); } break; } }Die Funktionen zur Behandlung von Schaltflächenklicks („OnSendButtonClick“, „OnQuickMessageButtonClick“, „OnMinimizeButtonClick“ und „OnCloseButtonClick“) schließlich sind die Funktionen, mit denen das Programm auf der Grundlage von Nutzereingaben bestimmte Aktionen ausführt. „OnSendButtonClick“ ruft zum Beispiel die Nachricht aus dem Eingabefeld ab und sendet sie an Telegram, um eine Rückmeldung über den Erfolg des Vorgangs zu geben. Diese Funktionen sind einfach, aber entscheidend, da sie Nutzeraktionen in sinnvolle Ergebnisse umsetzen. Dabei habe ich darauf geachtet, dass die Schnittstelle nicht nur funktional ist, sondern auch den Erwartungen der Nutzer entspricht.
void OnSendButtonClick() { string customMessage = inputBox.Text(); if (SendMessageToTelegram(customMessage)) { Print("Message sent: ", customMessage); } else { Print("Failed to send message."); } } void OnQuickMessageButtonClick() { if (SendMessageToTelegram(QuickMessage)) { Print("Quick message sent: ", QuickMessage); } else { Print("Failed to send quick message."); } } void OnMinimizeButtonClick() { static bool minimized = false; if (minimized) { adminPanel.SetSize(500, 400); minimized = false; } else { adminPanel.SetSize(500, 30); minimized = true; } } void OnCloseButtonClick() { adminPanel.Destroy(); Print("Panel closed."); }
Integration der Telegram API für die Kommunikation mit Tradern
Bei der Integration von Telegram Messaging in das MQL5-Programm haben wir die Funktion „SendMessageToTelegram“ geschaffen, um die Kommunikation zwischen unserer Handelsschnittstelle und einem Telegram-Chat zu erleichtern. Die Funktion beginnt mit der Definition zweier wichtiger Variablen: „botToken“ und „chatId“. Dies sind eindeutige Bezeichner, die von Telegram zur Verfügung gestellt werden und es uns ermöglichen, unseren Bot zu authentifizieren und den Chat anzugeben, an den die Nachricht gesendet wird. Durch die Festcodierung dieser Werte stellen wir sicher, dass die Nachricht sicher und effizient an das richtige Ziel gesendet wird. Sie können api.telegram.org oder meine früheren Schriften besuchen, um mehr über „BOT TOKEN“ und „CHAT ID“ zu erfahren.
string botToken = "BOT TOKEN"; string chatId = "CHAT ID";
Dann konstruieren wir den „url“-String, der den Endpunkt für die Telegram Bot API darstellt, und kombinieren ihn mit dem „botToken“, um die vollständige URL zu erstellen, die zum Senden von Nachrichten erforderlich ist. Dieser Schritt ist entscheidend, da er die Verbindung zum Telegram-Server herstellt und es unserem System ermöglicht, programmatisch mit ihm zu interagieren. Daneben deklarieren wir ein „char“-Array „post_data“ für die Nutzdaten der Nachricht, die in JSON formatiert werden, um die Anforderungen der API zu erfüllen.
string url = "https://api.telegram.org/bot" + botToken + "/sendMessage"; char post_data[];
Um die Nachricht in JSON zu formatieren, werden die „chatId“ und der eigentliche „message“-Text in die „jsonMessage“-Zeichenkette verkettet. Diese Zeichenkette wird dann mit „StringToCharArray“ in ein Zeichenarray umgewandelt, und die Größe des Arrays wird mit „ArrayResize“ entsprechend angepasst, um sicherzustellen, dass es die Daten richtig einpasst. Dieser Schritt stellt sicher, dass die Nachrichtenstruktur mit den Erwartungen der Telegram-API kompatibel ist, was für eine erfolgreiche Kommunikation unerlässlich ist.
string jsonMessage = "{\"chat_id\":\"" + chatId + "\", \"text\":\"" + message + "\"}"; ArrayResize(post_data, StringToCharArray(jsonMessage, post_data));
Die Funktion setzt dann eine „timeout"-Variable, um festzulegen, wie lange das Programm auf eine Antwort des Telegram-Servers warten soll. Wir bereiten ein „result"-Array vor, um die Antwort des Servers zu speichern, und eine „responseHeaders"-Zeichenkette für alle zusätzlichen Informationen, die zurückgegeben werden. Diese Variablen sind wichtig für die Bearbeitung der Antwort und die Diagnose von Problemen, die während der Anfrage auftreten können.
int timeout = 5000; char result[]; string responseHeaders;
Die Funktion „WebRequest“ ist der Ort, an dem die eigentliche Kommunikation mit der Telegram API stattfindet. Wir senden die „POST“-Anforderung an die URL und übergeben die erforderlichen Kopfzeilen, die Zeitüberschreitung und „post_data“. Ist die Anfrage erfolgreich, was durch eine HTTP 200-Antwort angezeigt wird, gibt die Funktion eine Erfolgsmeldung aus und liefert „true“. Andernfalls wird der HTTP-Statuscode und die Fehlermeldung ausgegeben und „false“ zurückgegeben. Diese Fehlerbehandlung ist wichtig für die Fehlersuche und um sicherzustellen, dass unsere Funktion zum Senden von Nachrichten zuverlässig ist.
int res = WebRequest("POST", url, "Content-Type: application/json\r\n", timeout, post_data, result, responseHeaders); if (res == 200) // HTTP 200 OK { Print("Message sent successfully: ", message); return true; } else { Print("Failed to send message. HTTP code: ", res, " Error code: ", GetLastError()); Print("Response: ", CharArrayToString(result)); return false; }
Hier ist unser endgültiger Code, nachdem wir alle Abschnitte kombiniert haben:
//+------------------------------------------------------------------+ //| Admin Panel.mq5 | //| Copyright 2024, Clemence Benjamin | //| https://www.mql5.com/en/users/billionaire2024/seller | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property description "A responsive Admin Panel. Send messages to your telegram clients without leaving MT5" #property version "1.06" #include <Trade\Trade.mqh> #include <Controls\Dialog.mqh> #include <Controls\Button.mqh> #include <Controls\Edit.mqh> //+------------------------------------------------------------------+ //| Creating a scalable and draggable panel | //+------------------------------------------------------------------+ class CScalableDialog : public CDialog { protected: bool m_Dragging; int m_OffsetX, m_OffsetY; int m_width, m_height; public: CScalableDialog() : m_Dragging(false), m_OffsetX(1020), m_OffsetY(720), m_width(500), m_height(400) {} // Handle the event to allow dragging void HandleDragging(const int id, const long lparam, const double dparam) { if (id == CHARTEVENT_MOUSE_MOVE && m_Dragging) { int new_x = (int)lparam - m_OffsetX; int new_y = (int)dparam - m_OffsetY; SetXPosition(new_x, new_y); // Update the position without changing size } else if (id == CHARTEVENT_OBJECT_CLICK) { m_OffsetX = (int)lparam; m_OffsetY = (int)dparam; m_Dragging = true; } else if (id == CHARTEVENT_CLICK) { m_Dragging = false; } } void SetSize(int width, int height) { m_width = width; m_height = height; // Call the method to update the size of the dialog UpdateDialogSize(); } void UpdateDialogSize() { // Adjust the internal layout or size of the controls within the dialog here // Example: Resize or reposition child controls based on the new dimensions // Ensure that dialog dimensions are respected within its design ObjectSetInteger(ChartID(), Name(), OBJPROP_CORNER, 0); // This aligns the dialog to the chart corner ObjectSetInteger(ChartID(), Name(), OBJPROP_XSIZE, m_width); // Width of the dialog ObjectSetInteger(ChartID(), Name(), OBJPROP_YSIZE, m_height); // Height of the dialog } void SetXPosition(int x, int y) { // Set the X and Y positions of the dialog panel ObjectSetInteger(ChartID(), Name(), OBJPROP_XDISTANCE, x); ObjectSetInteger(ChartID(), Name(), OBJPROP_YDISTANCE, y); // Call the method to update the size of the dialog UpdateDialogSize(); } }; //+------------------------------------------------------------------+ //| Inputs | //+------------------------------------------------------------------+ input string QuickMessage = "Invalid Signal"; // Default quick message //+------------------------------------------------------------------+ //| Global variables | //+------------------------------------------------------------------+ CScalableDialog adminPanel; CButton sendButton; CButton quickMessageButton; CButton minimizeButton; CButton closeButton; CEdit inputBox; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { long chart_id = ChartID(); // Create the dialog if (!adminPanel.Create(chart_id, "Admin Panel", 0, 30, 30, 500, 400)) { Print("Failed to create dialog"); return INIT_FAILED; } // Create the input box if (!inputBox.Create(chart_id, "InputBox", 0, 5, 5, 460,50 )) { Print("Failed to create input box"); return INIT_FAILED; } adminPanel.Add(inputBox); // Create the send button for custom messages if (!sendButton.Create(chart_id, "SendButton", 0, 270, 50, 460, 80)) { Print("Failed to create send button"); return INIT_FAILED; } sendButton.Text("Send Message"); adminPanel.Add(sendButton); // Create the quick message button if (!quickMessageButton.Create(chart_id, "QuickMessageButton", 0, 180, 200, 350, 230)) { Print("Failed to create quick message button"); return INIT_FAILED; } quickMessageButton.Text("Invalid Signal"); adminPanel.Add(quickMessageButton); // Create the minimize button if (!minimizeButton.Create(chart_id, "MinimizeButton",0, 405, -22, 435, 0)) { Print("Failed to create minimize button"); return INIT_FAILED; } minimizeButton.Text("_"); adminPanel.Add(minimizeButton); // Create the close button if (!closeButton.Create(chart_id, "CloseButton",0 , +435, -22,+465,0)) { Print("Failed to create close button"); return INIT_FAILED; } closeButton.Text("X"); adminPanel.Add(closeButton); adminPanel.Show(); // Enable chart events ChartSetInteger(ChartID(), CHART_EVENT_OBJECT_CREATE, true); ChartSetInteger(ChartID(), CHART_EVENT_OBJECT_DELETE, true); ChartSetInteger(ChartID(), CHART_EVENT_MOUSE_WHEEL, true); ChartRedraw(); Print("Initialization complete"); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { adminPanel.Destroy(); Print("Deinitialization complete"); } //+------------------------------------------------------------------+ //| Expert event handling function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { // Handle dragging and other events adminPanel.HandleDragging(id, lparam, dparam); // Handle different types of events switch(id) { case CHARTEVENT_KEYDOWN: Print("Key pressed: code=", lparam); break; case CHARTEVENT_MOUSE_MOVE: Print("Mouse move: x=", lparam, " y=", dparam); break; case CHARTEVENT_OBJECT_CREATE: Print("Created object: ", sparam); break; case CHARTEVENT_OBJECT_DELETE: Print("Deleted object: ", sparam); break; case CHARTEVENT_CLICK: Print("Mouse click on chart: x=", lparam, " y=", dparam); break; case CHARTEVENT_OBJECT_CLICK: if (sparam == "SendButton") { OnSendButtonClick(); } else if (sparam == "QuickMessageButton") { OnQuickMessageButtonClick(); } else if (sparam == "MinimizeButton") { OnMinimizeButtonClick(); } else if (sparam == "CloseButton") { OnCloseButtonClick(); } break; default: if (id > CHARTEVENT_CUSTOM) Print("Custom event ID=", id, " lparam=", lparam, " dparam=", dparam, " sparam=", sparam); break; } } //+------------------------------------------------------------------+ //| Function to handle custom message send button click | //+------------------------------------------------------------------+ void OnSendButtonClick() { string message = inputBox.Text(); if (message != "") { if(SendMessageToTelegram(message)) Print("Custom message sent: ", message); else Print("Failed to send custom message."); } else { Print("No message entered."); } } //+------------------------------------------------------------------+ //| Function to handle quick message button click | //+------------------------------------------------------------------+ void OnQuickMessageButtonClick() { if(SendMessageToTelegram(QuickMessage)) Print("Quick Message Button Clicked - Quick message sent: ", QuickMessage); else Print("Failed to send quick message."); } //+------------------------------------------------------------------+ //| Function to handle minimize button click | //+------------------------------------------------------------------+ void OnMinimizeButtonClick() { static bool minimized = false; if (minimized) { // Restore full size adminPanel.SetSize(500, 400); // Restore full size (400x200) } else { // Minimize to header only adminPanel.SetSize(100, 80); // Minimize height to 30 (keeping the width 400) } minimized = !minimized; } //+------------------------------------------------------------------+ //| Function to handle close button click | //+------------------------------------------------------------------+ void OnCloseButtonClick() { adminPanel.Destroy(); Print("Admin Panel closed."); } ///+------------------------------------------------------------------+ //| Function to send the message to Telegram | //+------------------------------------------------------------------+ bool SendMessageToTelegram(string message) { // Replace with your bot token and chat ID string botToken = "Your BOT TOKEN"; string chatId = "Your Chat ID"; string url = "https://api.telegram.org/bot" + botToken + "/sendMessage"; char post_data[]; // Prepare the message data string jsonMessage = "{\"chat_id\":\"" + chatId + "\", \"text\":\"" + message + "\"}"; // Resize the character array to fit the JSON payload ArrayResize(post_data, StringToCharArray(jsonMessage, post_data)); int timeout = 5000; char result[]; string responseHeaders; // Make the WebRequest int res = WebRequest("POST", url, "Content-Type: application/json\r\n", timeout, post_data, result, responseHeaders); if (res == 200) // HTTP 200 OK { Print("Message sent successfully: ", message); return true; } else { Print("Failed to send message. HTTP code: ", res, " Error code: ", GetLastError()); Print("Response: ", CharArrayToString(result)); return false; } }
Testen des Verwaltungsbereichs
Nach erfolgreicher Kompilierung starteten wir das Programm, und es funktionierte wie vorgesehen.
Starten des Admin-Panels von Experten: Boom 500 Index
Tipps für die Verwendung
Wenn Sie einen Telegram-Bot und -Kanal erstellt haben und Zugriff auf die Telegram-Bot-API haben, müssen Sie nur den Quellcode unten bearbeiten, um Ihr Bot-Token und Ihre Chat-ID für die Verwendung des Admin-Panels zu kodieren. Alternativ können Sie die Token auch einfach beschaffen und in den kompilierten EA eingeben, der in den Anhängen unten bereitgestellt wird, ohne den Quellcode ändern zu müssen.
Bot-Token und Chat-ID eingeben
Schlussfolgerung
Zusammenfassend lässt sich sagen, dass die Entwicklung des Admin Panel Expert Advisor in MQL5 einen bedeutenden Fortschritt bei der Verwaltung und Kommunikation mit Händlern direkt von der MetaTrader 5-Plattform aus darstellt. Durch die Integration einer dynamischen und skalierbaren Nutzeroberfläche mit Echtzeit-Nachrichtenfunktionen über Telegram verbessert dieses Tool die Effizienz und Reaktionsfähigkeit bei Handelsgeschäften. Die Möglichkeit, Kurznachrichten oder nutzerdefinierte Benachrichtigungen direkt über das Panel zu versenden, ermöglicht eine sofortige Kommunikation und stellt sicher, dass wichtige Informationen ohne Verzögerung weitergeleitet werden. Dieses Projekt unterstreicht das Potenzial der Kombination von nutzerfreundlichen Schnittstellen mit robusten Kommunikationswerkzeugen und ebnet den Weg für interaktivere und effektivere Handelsmanagementlösungen.
Weitere Entwicklungen sind unabdingbar, einschließlich der Hinzufügung weiterer Schnelltasten, um die Zeit zwischen der Eingabe und dem Senden von Nachrichten zu verkürzen, insbesondere als Reaktion auf das aktuelle Marktverhalten. Darauf werden wir in den nächsten Beiträgen dieser Reihe näher eingehen. Ich danke Ihnen, Traders! Glückliche Entwicklung.
Ihr Feedback ist immer willkommen. Bitte prüfen Sie die beigefügten Dateien in Ihren Projekten.
Datei Name | Datei Beschreibung |
---|---|
Admin Panel.mq5 | Quellcode des Admin-Panels. |
Admin Panel.ex5 | Betriebsbereites Admin Panel Expert. Sie müssen nur Ihr korrektes Bot-Token und Ihre Chat-ID eingeben |
(terminal64_bK0FbSvNmw) | Ein Bild, das zeigt, wie das Admin Panel funktioniert. |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/15417





- 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.
Dankeschön
Herzlich willkommen! @Cracker Delicious
Wenn Sie in MetaTrader 5 das in der Datei enthaltene kompilierte Admin-Panel verwenden möchten, stellen Sie sicher, dass Sie Strg + O drücken, um WebRequest unter den Expert Advisor-Einstellungen zu aktivieren. Fügen Sie außerdem den Link zur Telegram API hinzu, damit es funktioniert.