
Erstellen von einem Trading Administrator Panel in MQL5 (Teil VI): Das Panel zur Handelsverwaltung (II)
Inhalt:
Einführung
Aufbauend auf unserer Fähigkeit, Sicherheitstests zu bestehen und auf das „Admin Home Panel“ zuzugreifen, wo wir primären Zugriff auf wichtige Funktionen haben, ist es heute unser Ziel, die Implementierung von MQL5 weiter voranzutreiben, während wir die Leistung unserer multifunktionalen Schnittstelle in einem aktiv entwickelten Projekt verbessern. Unsere vorherige Publikation diente als Einführung in die vielfältigen Funktionen des Panels und stellte die neuesten Möglichkeiten vor, ohne die Funktionen der einzelnen Schaltflächen des Trade Management Panels im Detail zu erläutern. Wir werden dafür sorgen, dass jede Schaltfläche im Handelsverwaltungsbereich beim Anklicken eine Antwort erzeugt.
Außerdem möchte ich eine Frage ansprechen: Sind wir durch das aktuelle Panel-Layout eingeschränkt? Um dies zu erforschen, werden wir alternative Layout-Ideen in Betracht ziehen, die uns dabei helfen können, die Möglichkeiten der Dialogklasse in der bekannten Entwicklungssprache für Handelsalgorithmen, MQL5, besser zu nutzen. Unten habe ich ein Bild eingefügt, das die Möglichkeit zeigt, die vertikale Skalierung des Charts anzupassen, was ich für nützlich halte, um den verfügbaren Platz für unser Panel zu maximieren. Ich glaube auch, dass es von Vorteil wäre, wenn beide Panels gleichzeitig angezeigt werden könnten, ohne dass der Blick auf das Chart verloren geht. Um diese Funktion zu erleichtern, werden wir eine Schaltfläche in das Admin Home Panel einfügen, mit der die Nutzer alle Panels auf einmal anzeigen können.
Die vertikale Skalierung des MetaTrader 5-Charts schafft Freiräume und macht die Ansicht des Kerzenbereichs klarer
Bevor wir fortfahren, möchte ich allen die Gelegenheit geben, sich mit den verschiedenen Elementen unserer multifunktionalen Schnittstelle vertraut zu machen. Dies wird dazu beitragen, einige der unausgesprochenen Herausforderungen zu bewältigen, die bei der Arbeit an dieser Artikelserie auftreten.- Wenn Kompilierungsfehler auftreten, liegt das wahrscheinlich daran, dass der Code mit den Standardbibliotheksdateien ausgeführt wird, die nicht erweitert worden sind. Um dieses Problem zu lösen, stellen Sie sicher, dass Sie den Inhalt des Verzeichnisses MQL5/Include/controls mit den Dateien aus dem Ordner Extended Header überschreiben, die in den vorherigen Artikeln bereitgestellt wurden.
- Die andere Herausforderung besteht darin, sicherzustellen, dass die Chat-ID und das Bot-Token aktualisiert werden, damit der Verifizierungscode an Ihr Konto gesendet wird.
Für die zweite Herausforderung besteht die Lösung darin, auf die Telegram-App zuzugreifen, um zwei Bots zu erstellen: einen für die Authentifizierung beim Start der Anwendung und einen für die Kommunikation über individuelle Chats, Gruppen und Kanäle innerhalb des Kommunikationspanels des EA-Programms.
Bitte geben Sie im Folgenden Ihre aktuelle Chat-ID und Ihr Bot-Token ein. Vergewissern Sie sich, dass die Chat-ID nicht von einer Gruppe oder einem Kanal stammt, da Sie sonst Ihren Code mit mehreren Nutzern teilen würden; sie sollte sehr persönlich bleiben. Um zu überprüfen, ob Sie die richtige Chat-ID haben, sollten Sie einen Chat mit dem Bot starten und die API auf die Chat-ID überprüfen. Beachten Sie, dass diese Werte vor der Kompilierung fest in Ihren Quellcode codiert werden und sich von der Chat-ID und dem Bot-Token unterscheiden, die Sie beim Starten der Anwendung eingeben.
Wir haben dies bereits in unseren früheren Beiträgen besprochen, und die Schritte sind einfach zu befolgen.
SCHRITT 1:
Stellen Sie sicher, dass Sie ein registrierter Telegram-Nutzer sind. Laden Sie dazu die Telegram-App für Ihr Smartphone oder Ihren Desktop herunter und folgen Sie den Anweisungen in der App, um sich anzumelden.
SCHRITT 2:
Starten Sie einen Chat mit BotFather, um zwei Bots zu erstellen: einen für die Zwei-Faktor-Authentifizierung (2FA) und den anderen für die Kommunikation. Sie erhalten ein eindeutiges Bot-Token für jeden Bot, mit dem Sie auf die Telegram-API zugreifen und Chat-IDs erhalten können. Jeder Bot hat sein eigenes Token, das Sie nach Belieben benennen können, damit Sie den Zweck des Bots leicht erkennen können.
SCHRITT 3:
Rufen Sie das API durch einen Klick auf den folgenden Link: https://api.telegram.org/botErsetzMichDurchDenTockenVomBotFather/getUpdates.
Telegram API-Zugriff mit dem Chrome Browser
SCHRITT 4:
Starten Sie eine Konversation mit Ihrem speziellen Bot für die Übermittlung des 2FA-Codes. Sie können den Kommunikationsbot auch zu allen Gruppen oder Kanälen hinzufügen, in denen Sie Handelseinblicke teilen möchten, und ihn als Administrator festlegen, um sicherzustellen, dass er ordnungsgemäß funktioniert. Sobald Sie die Einrichtung abgeschlossen haben, beginnen Sie eine Unterhaltung innerhalb der Gruppen, um die Chat-ID abzurufen. Aktualisieren Sie anschließend Ihren Browser auf der Registerkarte API, um die aktualisierten Informationen zu sehen.
Telegramm-Chat: Starten Sie eine Unterhaltung mit dem Bot (in diesem Fall habe ich meinen Bot Admin Panel genannt)
Telegram API : Hier können wir unsere Chat-ID für 2FA erhalten
Im obigen Bild habe ich einen persönlichen Chat eingeleitet, hauptsächlich um meine Chat-ID für die 2FA-Übertragung zu erhalten. Sie können denselben Bot auch zu Gruppen und Kanälen hinzufügen. Wenn Sie dort Unterhaltungen beginnen, werden die Chat-IDs automatisch in der API angezeigt, genau wie oben dargestellt, normalerweise unter der ersten Unterhaltung. Ich habe den Bot beispielsweise zu einem meiner Bildungskanäle hinzugefügt, und die API-Nachricht, die ich erhalten habe, ist in der folgenden Abbildung dargestellt.
Zusammenfassend lässt sich sagen, dass ein und derselbe Bot für mehrere Kanäle verwendet werden kann, jeder mit seiner eigenen eindeutigen Chat-ID. Alternativ können Sie auch für jeden Kanal einen anderen Bot verwenden, wenn Sie dies wünschen.
Hinzufügen eines Bots als Administrator in einem Telegram-Kanal
Das API JSON mit der Chat-ID des Kanals ist unten abgebildet.
Kanal-Chat erzeugt JASON
In diesem Codeschnipsel sollten Sie die Bot-Zugangsdaten für die Übermittlung des 2FA-Codes eingeben:// Constants for 2FA. Here put the chat ID dedicated for verification code delivery. It must be kept secure always. const string Hardcoded2FAChatId = "REPLACE WITH YOUR CHAT ID"; const string Hardcoded2FABotToken = "REPLACE WITH YOU BOT TOKEN"; //Obtain your bot token from a telegram bot father. //If you don't already have a bot you can start the chat with the bot father to create one.
Das folgende Bild zeigt, wo die Telegram-Anmeldeinformationen für die Handelskommunikation während der Initialisierung der App eingegeben werden müssen. Sie können die Schnellmeldungen auch nach Bedarf anpassen:
Einstellungen der Initialisierungseingänge erklärt
Bitte beachten Sie, dass der obige Codeabschnitt und das Bild zwei verschiedene Chat-IDs anzeigen, wie bereits erwähnt. Die eine wird für die Übermittlung von Verifizierungscodes verwendet, die andere für die Übertragung von Verwaltungsmitteilungen über persönliche Chats oder Telegram-Gruppen. Jeder mit dem Bot verbundene Nutzer, jede Gruppe und jeder Kanal hat eine eindeutige Chat-ID.
Schließlich haben wir während der gesamten Diskussion dieselbe PIN, 2024, verwendet; Sie können sie jedoch im Quellcode für Ihren eigenen Gebrauch anpassen. Bei der 2FA übernimmt der Algorithmus des Generators für den sechsstelligen Code diese Aufgabe automatisch; Sie müssen nur sicherstellen, dass Sie Ihre eindeutige Chat-ID für die sichere Übermittlung des Codes haben.
Mit dieser kurzen Zusammenfassung hoffe ich, dass Sie auf die heutigen Fortschritte vorbereitet sind. Zusammenfassend werden wir uns auf die Behandlung für die Schaltflächen des Trade Management konzentrieren und dann ihr Layout in Bezug auf Position und Dimensionen auf dem Chart verbessern.
Verbesserung des Handelsmanagement-Panels
Zunächst möchte ich Ihnen den Unterschied zwischen den Schaltflächen des Kommunikationspanels und des Handelsverwaltungspanels erläutern. Ich weiß, dass die meisten von uns mit den Funktionen für Massengeschäfte vertraut sind, die sowohl in der Desktop- als auch in der mobilen Version von MetaTrader 5 verfügbar sind.
Wie die Namen des Panels schon vermuten lassen, sind ihre Funktionen selbsterklärend; allerdings können sie aufgrund der ähnlichen Titel oder Beschreibungen verwirrend sein. So sind beispielsweise die Schaltflächen im Kommunikationsbereich ausschließlich für die Kommunikation vorgesehen, während die Schaltflächen im Handelsverwaltungsbereich speziell für die Abwicklung von Geschäften programmiert sind.
Es ist möglich, für dieselben Schaltflächen, die im Kommunikationspanel verwendet werden, Handelsereignisse zu implementieren, sodass beide Aufgaben beim Anklicken gleichzeitig ausgeführt werden können. Es gibt jedoch mehrere Gründe dafür, die Schaltflächen für die Kommunikation von den Schaltflächen für das Handelsmanagement zu trennen. Ein wichtiger Grund ist, dass der Administrator möglicherweise Handelsgeschäfte verwalten möchte, die nicht unbedingt für die Veröffentlichung bestimmt sind.
In den nachstehenden Abbildungen sind die wichtigsten Unterschiede hervorgehoben.
Kommunikations-Panel: Schaltflächen für Nachrichten
Fast alle Schaltflächen hier sind für die Kommunikation gedacht, mit Ausnahme der Navigationstasten. Außerdem können die von ihnen gesendeten Schnellmeldungen während der Initialisierung angepasst werden. Die Schaltfläche „Alle schließen“ dient nur dazu, die Nachricht an den gewünschten Telegram-Client zu senden und führt keine weiteren Aktionen aus.
Handelsmanagement-Panel: (Diese Schaltflächen müssen Handelsoperationen ausführen, wenn sie angeklickt werden)
Anhand der obigen Bilder haben wir den Zweck der einzelnen Funktionen verdeutlicht. Wenn wir uns nun dem Handelsmanagement-Panel zuwenden, gibt es noch viel zu tun. Unser Panel hat derzeit nur eine begrenzte Anzahl von Schaltflächen, und wir wollen es verbessern, um den Platz für die Anzeige von Charts zu maximieren. Neue Schaltflächen sind für einige wichtige Handelsvorgänge unerlässlich, z. B. die Schaltfläche „Close All Orders“ (Alle Aufträge schließen).
Anpassen des Layouts der Handelsverwaltung
Das neue Interface-Layout ist ein innovatives Design, das mehr Raum für die Sichtbarkeit von Charts schafft und gleichzeitig die üblichen Verwaltungsvorgänge innerhalb dieser Entwicklungsreihe ermöglicht. Dieser Ansatz nutzt die Positionskoordinaten der Panels in Bezug auf den MetaTrader 5 Chart.
Derzeit ist das Admin Home Panel zu groß für seinen Inhalt, und wir werden das auch noch anpassen. Um den Prozess übersichtlicher zu gestalten, werden wir ihn in drei Abschnitte unterteilen.
Einstellen des Handelsmanagement-Panels
Während der Initialisierung wird unser Panel mit folgendem Code erstellt:
if (!tradeManagementPanel.Create(ChartID(), "Trade Management Panel", 0, 30, 30, 500, 500))
{
Print("Failed to create Communictions panel dialog");
return INIT_FAILED;
}
Im obigen Code wird:
X1 =30
X2 =500
Daher ist die Breite = X2 -X1 = 500-30 = 470.
Wenn wir X2-Wert erhöhen, wird die neue Breite entsprechend dem Designkonzept erweitert. Zum Beispiel werde ich sie um 50 % der ursprünglichen Breite vergrößern. Bitte sehen Sie sich das unten stehende Codefragment an.
// Let's increase our panel width by 50% of the former panel and is likely to be 250px but we will add an extra 30px to cover for the initial px on x1 co-ordinate.
// For the y co-ordinate we will reduce so much to 150px
if (!tradeManagementPanel.Create(ChartID(), "Trade Management Panel", 0, 30, 30, 780, 150))
{
Print("Failed to create Communictions panel dialog");
return INIT_FAILED;
}
Das Ergebnis nach dem Kompilieren und Testen ist wie folgt:
Neues Layout des Handels-Panels
Durch die jüngste Änderung sind einige der Schaltflächen nicht mehr in der gewünschten Reihenfolge angeordnet, sodass sie über dem Chart schweben, anstatt innerhalb der Panelgrenzen zu bleiben. Um dieses Problem zu lösen, navigieren wir zur Funktion CreateTradeManagementControls() und passen die Koordinaten der Schaltflächen an, wie im folgenden Codeschnipsel gezeigt
// Create the Trade Management Panel controls
// Here we adjusted our button coordinates to fit well in the new Trade Management Panel
bool CreateTradeManagementControls()
{
long chart_id = ChartID();
// Buy Button
if (!buyButton.Create(chart_id, "BuyButton", 0, 130, 5, 210, 40))
{
Print("Failed to create Buy button");
return false;
}
buyButton.Text("Buy");
tradeManagementPanel.Add(buyButton);
// Sell Button
if (!sellButton.Create(chart_id, "SellButton", 0, 220, 5, 320, 40))
{
Print("Failed to create Sell button");
return false;
}
sellButton.Text("Sell");
tradeManagementPanel.Add(sellButton);
// Close Position Button
if (!closePosButton.Create(chart_id, "ClosePosButton", 0, 130, 50, 260, 70))
{
Print("Failed to create Close Position button");
return false;
}
closePosButton.Text("Close Position");
tradeManagementPanel.Add(closePosButton);
// Modify Position Button
if (!modifyPosButton.Create(chart_id, "ModifyPosButton", 0, 270, 50, 410, 70))
{
Print("Failed to create Modify Position button");
return false;
}
modifyPosButton.Text("Modify Position");
tradeManagementPanel.Add(modifyPosButton);
// Set Stop-Loss Button
if (!setSLButton.Create(chart_id, "SetSLButton", 0, 330, 5, 430, 40))
{
Print("Failed to create Set Stop-Loss button");
return false;
}
setSLButton.Text("Set SL");
tradeManagementPanel.Add(setSLButton);
// Set Take-Profit Button
if (!setTPButton.Create(chart_id, "SetTPButton", 0, 440, 5, 540, 40))
{
Print("Failed to create Set Take-Profit button");
return false;
}
setTPButton.Text("Set TP");
tradeManagementPanel.Add(setTPButton);
return true;
}
Das Kompilieren und Ausführen des Codes ergab das folgende Bild, in dem alle Schaltflächen nun richtig platziert sind.
Handelsmanagement-Panel: Schaltflächen übersichtlich angeordnet
Nachdem wir nun die Änderungen am Layout abgeschlossen und die Schaltflächen angeordnet haben, können wir nun die vorhandenen Schaltflächen bearbeiten und neue hinzufügen.
Ein weiterer wichtiger Aspekt ist die Vermeidung von Konflikten mit den internen Tasten. Das folgende Bild veranschaulicht beispielsweise, wie sich die nativen Schaltflächen mit unserem Verwaltungsbereich überschneiden.
Schnellschaltflächen, die das Admin-Panel überlappen
Um dieses Problem zu lösen, werden wir eine Verschiebung auf unsere x-Koordinaten anwenden und sie nach rechts verschieben, um die Position des Panels zu verschieben. Den aktualisierten Wert finden Sie im nachstehenden Codeabschnitt:
//1
//2
//2
if (!tradeManagementPanel.Create(ChartID(), "Trade Management Panel", 0, 260, 30, 1040, 150))
{
Print("Failed to create Communictions panel dialog");
return INIT_FAILED;
}
Die Kompilierung war erfolgreich, und das Problem wurde behoben. Siehe das Layout unten:
Die Quick-Buttons sind gut angeordnet und nicht überlappend
Hilfsfunktion und Erstellung einer neuen Schaltfläche
In meinen C++-Kursen betonte mein Dozent oft die Bedeutung der Wiederholungsfunktion und hielt sie für ein grundlegendes Konzept für jeden, der sich als Programmierer bezeichnen möchte. Später, als ich Hilfsfunktionen in MQL5 untersuchte, dachte ich zunächst, ich sei auf etwas Ähnliches wie die Wiederholungsfunktion von C++ gestoßen. Mir wurde jedoch bald klar, dass diese Funktionen zwar bestimmte Vorteile haben, aber unterschiedlichen Zwecken dienen.
Zusammenfassend lässt sich sagen, dass MQL5-Hilfsfunktionen mit „Funktionsobjekten“ verglichen werden können, die das Verhalten parametrisieren, während es bei C++-Wiederholungshilfsmitteln eher um die Anwendung konsistenter Transformationen oder Muster geht.
Hier sind einige Gemeinsamkeiten zwischen den beiden:
- Beide zielen darauf ab, sich wiederholenden Code zu reduzieren.
- Beides verbessert die Klarheit und Wartbarkeit des Codes.
In dieser Diskussion haben wir das Konzept der Hilfsfunktionen vorgestellt, da wir uns darauf vorbereiten, mehrere Schaltflächen zu implementieren, um unsere Arbeit intelligent und präsentabel zu gestalten. Bleiben Sie dran, wenn wir uns mit seiner Umsetzung beschäftigen!
Eine Funktion, die ich besonders gerne verwende, wenn ich mehrere Handelsgeschäfte verwalte, ist die Möglichkeit, den Prozess zu rationalisieren, sodass ich mehrere Handelsgeschäfte effizient auf einmal abwickeln kann.
Mengenoperation mit Handelsgeschäften: Wird in MetaTrader 5 verwendet, um viele Handelsgeschäfte zu verwalten
Wir werden Handelsoperationen bevorzugen, die mit einem einzigen Klick ausgeführt werden können. Später werden wir uns auf die Funktionen zur Modifizierung des Handels konzentrieren, wie z. B. die Anpassung von Stop-Levels und deren Konfiguration direkt über das Verwaltungspanel. Das obige Bild kann uns auch als Inspiration für die Namen der Schaltflächen dienen, die wir in unserem Projekt verwenden wollen.
Nachstehend finden Sie eine Übersicht über die Schaltflächen:
- Alle Positionen schließen
- Positionen im Plus schließen
- Positionen im Minus schließen
- Kaufpositionen schließen
- Verkaufspositionen schließen
- Alle schwebenden Aufträge löschen
- Alle Limit-Aufträge löschen
- Alle Stop-Aufträge löschen
- Alle Stop-Limit-Ordern löschen
Inzwischen sind wir mit den Schaltflächen bereits aus unseren früheren Diskussionen vertraut. Das Verfahren zur Erstellung der einzelnen Schaltflächen ist weitgehend identisch und unterscheidet sich nur in den Koordinaten. Um sich wiederholende Aufgaben zu minimieren, verwenden wir eine Hilfsfunktion, die speziell für die Rationalisierung des Prozesses entwickelt wurde. Auf diese Weise wird der Code verkleinert und alle neuen Schaltflächen werden effizient integriert.
Zunächst deklarieren wir unsere Schaltflächen als globale Variablen:
// Button Declarations CButton buyButton; // Button for Buy operations CButton sellButton; // Button for Sell operations CButton closeAllButton; // Button for closing all positions CButton closeProfitButton; // Button for closing profitable positions CButton closeLossButton; // Button for closing losing positions CButton closeBuyButton; // Button for closing Buy positions CButton closeSellButton; // Button for closing Sell positions CButton deleteAllOrdersButton; // Button for deleting all orders CButton deleteLimitOrdersButton; // Button for deleting limit orders CButton deleteStopOrdersButton; // Button for deleting stop orders CButton deleteStopLimitOrdersButton; // Button for deleting stop limit orders
Nachdem wir unsere Deklarationen abgeschlossen haben, ist es an der Zeit, die Hilfsfunktion für die Erstellung dieser Schaltflächen, wie ich sie implementiert habe, einzuführen. Die verschlankte Hilfsfunktion CreateButton vereinfacht sich wiederholende Aufgabe der Erstellung und Konfiguration von Schaltflächen im Trade Management Panel.
Diese Funktion nimmt Parameter für die Referenz, den Namen, den Beschriftungstext und die Koordinaten der Schaltfläche entgegen, während sie die zugrunde liegende Erstellungs- und Einrichtungslogik, einschließlich der Fehlerbehandlung, übernimmt. Durch die Zentralisierung dieses Prozesses eliminieren wir redundanten Code und stellen sicher, dass alle Schaltflächen mit minimalem Aufwand einheitlich erstellt werden.
Diese Modularität ist von entscheidender Bedeutung, da sie die Lesbarkeit und Wartbarkeit des Codes verbessert und es einfacher macht, das Panel um zusätzliche Schaltflächen zu erweitern oder die Funktionalität an einer zentralen Stelle anzupassen, anstatt sie auf mehrere Instanzen zu verteilen. Im Wesentlichen fungiert die Hilfsfunktion als Brücke zwischen der Gestaltung des Panels und der Erstellung der Schaltflächen und gewährleistet eine nahtlose Integration.
Hier ist der Code für unsere Hilfsfunktion:
//Helper Function For seamless Button creation bool CreateButton(CButton &button, const string name, const string text, int x1, int y1, int x2, int y2) { long chart_id = ChartID(); if (!button.Create(chart_id, name, 0, x1, y1, x2, y2)) { Print("Failed to create button: ", name); return false; } button.Text(text); tradeManagementPanel.Add(button); return true; }
Das obige Codeschnipsel kapselt den gesamten Prozess der Schaltflächenerstellung. Die Funktion CreateTradeManagementControls dient als Hauptorganisator und ruft wiederholt CreateButton auf, um jede Schaltfläche logisch im Handelsverwaltungsbereich zu definieren und zu positionieren. Anstatt die Logik zur Erstellung von Schaltflächen für jedes Steuerelement zu duplizieren, konzentriert sich diese Funktion ausschließlich auf die Angabe eindeutiger Details wie Koordinaten, Beschriftungen und Schaltflächentypen.
Durch den modularen Aufbau von CreateButton bleibt diese übergeordnete Funktion übersichtlich und konzentriert sich auf ihren Hauptzweck: die Strukturierung des Layouts des Panels. Diese beiden Funktionen arbeiten harmonisch zusammen - CreateTradeManagementControls kümmert sich um die Struktur, während die sich wiederholenden Aufgaben an CreateButton delegiert werden - um eine saubere, effiziente und anpassungsfähige Implementierung des Trade Management Panels zu erhalten. Und der Code für alle Schaltflächen ist hier zu finden:
//+------------------------------------------------------------------+ //| Create Trade Management Controls | //+------------------------------------------------------------------+ bool CreateTradeManagementControls() { // Coordinates for buttons (adjust as needed) const int Y1_TOP = 5, Y2_TOP = 40; const int Y1_MID = 50, Y2_MID = 70; const int Y1_BOTTOM = 80, Y2_BOTTOM = 100; // Buy Button if (!CreateButton(buyButton, "BuyButton", "Buy", 130, Y1_TOP, 210, Y2_TOP)) return false; // Sell Button if (!CreateButton(sellButton, "SellButton", "Sell", 220, Y1_TOP, 320, Y2_TOP)) return false; // Close All Positions Button if (!CreateButton(closeAllButton, "CloseAllButton", "Close All", 130, Y1_MID, 230, Y2_MID)) return false; // Close Profitable Positions Button if (!CreateButton(closeProfitButton, "CloseProfitButton", "Close Profitable", 240, Y1_MID, 380, Y2_MID)) return false; // Close Losing Positions Button if (!CreateButton(closeLossButton, "CloseLossButton", "Close Losing", 390, Y1_MID, 510, Y2_MID)) return false; // Close Buy Positions Button if (!CreateButton(closeBuyButton, "CloseBuyButton", "Close Buys", 520, Y1_MID, 620, Y2_MID)) return false; // Close Sell Positions Button if (!CreateButton(closeSellButton, "CloseSellButton", "Close Sells", 630, Y1_MID, 730, Y2_MID)) return false; // Delete All Orders Button if (!CreateButton(deleteAllOrdersButton, "DeleteAllOrdersButton", "Delete All Orders", 130, Y1_BOTTOM , 270, Y2_BOTTOM )) return false; // Delete Limit Orders Button if (!CreateButton(deleteLimitOrdersButton, "DeleteLimitOrdersButton", "Delete Limits", 275, Y1_BOTTOM , 385, Y2_BOTTOM )) return false; // Delete Stop Orders Button if (!CreateButton(deleteStopOrdersButton, "DeleteStopOrdersButton", "Delete Stops", 390, Y1_BOTTOM , 515, Y2_BOTTOM )) return false; // Delete Stop Limit Orders Button if (!CreateButton(deleteStopLimitOrdersButton, "DeleteStopLimitOrdersButton", "Delete Stop Limits", 520, Y1_BOTTOM , 660, Y2_BOTTOM )) return false; return true; // All buttons created successfully }
Hier ist das Ergebnis des neuen Layouts
Neues Layout nach Integration der neuen Schaltflächen
Beim Hinzufügen neuer Schaltflächen wurden einige ältere entfernt, um die Einheitlichkeit zu wahren. Im Moment konzentrieren wir uns auf Vorgänge, die sofort ausgeführt werden müssen, ohne dass zusätzliche Daten eingegeben werden müssen, z. B. Auftragsänderungen.
Kodierung von Tastenereignisse
Um die Funktionsweise des Trade Management Panels zu verbessern, haben wir für jede Schaltfläche spezielle Handler-Funktionen implementiert, die bestimmte Handelsoperationen ermöglichen. Hier finden Sie eine Erläuterung zu den einzelnen Codefragmenten:
1. Die Ereignisbehandlung der Kauf-Schaltfläche (OnBuyButtonClick)
Die Funktion OnBuyButtonClick ermöglicht die Erstellung einer Marktorder zum Kauf des angegebenen Vermögenswerts. Durch die Verwendung der Klasse CTrade werden die wesentlichen Handelsparameter wie Losgröße, Slippage, Stop-Loss und Take-Profit gehandhabt und eine präzise Ausführung gewährleistet. Dies ist entscheidend für Händler, die schnell Kaufpositionen in einer programmgesteuerten Umgebung eröffnen wollen.
//+------------------------------------------------------------------+ //| Handle Buy button click | //+------------------------------------------------------------------+ void OnBuyButtonClick() { CTrade trade; double lotSize = 0.1; // Example lot size double slippage = 3; // Example slippage double stopLoss = 0; // Example stop loss (in points) double takeProfit = 0; // Example take profit (in points) // Open Buy order double askPrice; if (SymbolInfoDouble(Symbol(), SYMBOL_ASK, askPrice) && askPrice > 0) { if (trade.Buy(lotSize, Symbol(), askPrice, slippage, stopLoss, takeProfit)) { Print("Buy order executed successfully."); } else { Print("Failed to execute Buy order. Error: ", GetLastError()); } } else { Print("Failed to retrieve Ask price. Error: ", GetLastError()); } // Execute Buy order logic here Print("Executing Buy operation"); }
2. Die Ereignisbehandlung der Verkaufs-Schaltfläche (OnSellButtonClick)
Die Funktion OnSellButtonClick spiegelt den Buy-Handler wider und ermöglicht es dem Nutzer, einen Vermögenswert über eine Marktorder zu verkaufen. Durch die Strukturierung der Verkaufslogik wird eine konsistente Handhabung von Parametern wie Losgröße und Slippage gewährleistet, sodass das Handelspanel effizient für die Einleitung von Verkaufsaufträgen bei Bedarf eingesetzt werden kann.
//+------------------------------------------------------------------+ //| Handle Sell button click | //+------------------------------------------------------------------+ void OnSellButtonClick() { CTrade trade; double lotSize = 0.1; // Example lot size double slippage = 3; // Example slippage double stopLoss = 0; // Example stop loss (in points) double takeProfit = 0; // Example take profit (in points) double bidPrice; if (SymbolInfoDouble(Symbol(), SYMBOL_BID, bidPrice) && bidPrice > 0) { // Open Sell order if (trade.Sell(lotSize, Symbol(), bidPrice, slippage, stopLoss, takeProfit)) { Print("Sell order opened successfully."); } else { Print("Error opening sell order: ", trade.ResultRetcode()); } } else { Print("Failed to retrieve Bid price. Error: ", GetLastError()); } }
3. Alle Positionen schließen (OnCloseAllButtonClick)
Diese Funktion automatisiert die Schließung aller aktiven Positionen, indem sie durch die offenen Handelsgeschäfte iteriert und CTrade.PositionClose für die Ausführung verwendet. Es ist besonders nützlich für Händler, die alle Handelsgeschäfte schnell aufgeben wollen, um sich gegen plötzliche Marktschwankungen abzusichern oder die Ausstiegsbedingungen einer Strategie zu erfüllen.
//+------------------------------------------------------------------+ //| Handle Close All button click | //+------------------------------------------------------------------+ void OnCloseAllButtonClick() { CPositionInfo position; for (int i = 0; i < PositionsTotal(); i++) { if (position.SelectByIndex(i)) { CTrade trade; if (position.Type() == POSITION_TYPE_BUY) trade.PositionClose(position.Ticket()); else if (position.Type() == POSITION_TYPE_SELL) trade.PositionClose(position.Ticket()); } } Print("All positions closed."); }
4. Schaltfläche zum Schließen aller Positionen im Gewinn (OnCloseProfitButtonClick)
Mit der Funktion OnCloseProfitButtonClick können Händler Gewinne sichern, indem sie nur profitable Positionen schließen. Es werden die Handelsgeschäfte im Gewinn gefiltert und für selektive Schließungen gesorgt, die sich an Strategien orientieren, die auf die Sicherung von Gewinnen ausgerichtet sind, während verlustbringende Handelsgeschäfte zur weiteren Bewertung aufbewahrt werden.
//+------------------------------------------------------------------+ //| Handle Close Profitable button click | //+------------------------------------------------------------------+ void OnCloseProfitButtonClick() { CPositionInfo position; for (int i = 0; i < PositionsTotal(); i++) { if (position.SelectByIndex(i) && position.Profit() > 0) { CTrade trade; if (position.Type() == POSITION_TYPE_BUY) trade.PositionClose(position.Ticket()); else if (position.Type() == POSITION_TYPE_SELL) trade.PositionClose(position.Ticket()); } } Print("Profitable positions closed."); }
5. Die Behandlung zum Schließen von Verlustpositionen (OnCloseLossButtonClick)
Dieser ist ein Instrument für das Risikomanagement, indem alle Positionen, die einen Verlust aufweisen, geschlossen werden. Indem nur Geschäfte mit negativem Gewinn angestrebt werden, können weitere Drawdowns verringert werden, was für die Aufrechterhaltung des Kontoguthabens und die Einhaltung der vordefinierten Verlustlimits von entscheidender Bedeutung ist.
//+------------------------------------------------------------------+ //| Handle Close Losing button click | //+------------------------------------------------------------------+ void OnCloseLossButtonClick() { CPositionInfo position; for (int i = 0; i < PositionsTotal(); i++) { if (position.SelectByIndex(i) && position.Profit() < 0) { CTrade trade; if (position.Type() == POSITION_TYPE_BUY) trade.PositionClose(position.Ticket()); else if (position.Type() == POSITION_TYPE_SELL) trade.PositionClose(position.Ticket()); } } Print("Losing positions closed."); } void OnCloseBuyButtonClick() { // Close Buy positions logic Print("Closing Buy positions"); } void OnCloseSellButtonClick() { // Close Sell positions logic Print("Closing Sell positions"); }
6. Alle schwebenden Aufträge löschen (OnDeleteAllOrdersButtonClick)
Diese Funktion löscht alle ausstehenden Aufträge und stellt sicher, dass keine verbleibenden Limit- oder Stop-Aufträge das Konto beeinflussen. Durch die Verwendung der Klasse COrderInfo zum Abrufen und Stornieren von Aufträgen wird ein sauberes Auftragsbuch aufrechterhalten und unbeabsichtigte Ausführungen verhindert.
//+------------------------------------------------------------------+ //| Handle Delete All Orders button click | //+------------------------------------------------------------------+ void OnDeleteAllOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i)) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All orders deleted."); }
7. Alle Limit-Orders löschen (OnDeleteLimitOrdersButtonClick)
Die Funktion OnDeleteLimitOrdersButtonClick konzentriert sich ausschließlich auf die Stornierung von Limit-Orders. Dies ist für Händler von entscheidender Bedeutung, die ihre Strategie anpassen und gleichzeitig Stopp- oder andere Ordertypen beibehalten müssen, was eine präzise Kontrolle der Orderverwaltung ermöglicht.
//+------------------------------------------------------------------+ //| Handle Delete Limit Orders button click | //+------------------------------------------------------------------+ void OnDeleteLimitOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i) && order.Type() == ORDER_TYPE_BUY_STOP_LIMIT) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All limit orders deleted."); }
8. Löschen von Stop-Ordern (OnDeleteStopOrdersButtonClick)
Diese Ereignisbehandlung zielt darauf ab, alle Stop-Orders zu löschen, um sicherzustellen, dass sie in volatilen Märkten nicht zu unerwünschten Abschlüssen führen. Durch die Isolierung von Stop-Aufträgen erhalten Händler eine granulare Kontrolle über die Verwaltung schwebender Aufträge.
//+------------------------------------------------------------------+ //| Handle Delete Stop Orders button click | //+------------------------------------------------------------------+ void OnDeleteStopOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i) && order.Type() == ORDER_TYPE_BUY_STOP && ORDER_TYPE_SELL_STOP) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All stop orders deleted."); }
9. Löschen von Stop-Limit-Ordern (OnDeleteStopLimitOrdersButtonClick)
Die Funktion verwaltet die Löschung von Stop-Limit-Ordern, was für Strategien mit hybriden Auftragstypen nützlich ist. Es erhöht die Flexibilität und passt die Auftragsabwicklung an die aktuellen Marktaussichten oder Strategieänderungen des Händlers an.
//+------------------------------------------------------------------+ //| Handle Delete Stop Limit Orders button click | //+------------------------------------------------------------------+ void OnDeleteStopLimitOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i) && order.Type() == ORDER_TYPE_BUY_LIMIT && ORDER_TYPE_SELL_STOP_LIMIT) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All stop limit orders deleted."); }
Integration in OnChartEvent:
Um Schaltflächenklicks mit diesen Funktionen zu verbinden, integrieren wir ihre Aufrufe in die Funktion OnChartEvent. Durch die Verknüpfung des Wertes der Schaltfläche von Sparam mit der entsprechenden Ereignisbehandlung sorgt das Programm für eine reibungslose Interaktion zwischen der grafischen Nutzeroberfläche und der Backend-Handelslogik und macht das Panel reaktionsschnell und nutzerfreundlich.
//+------------------------------------------------------------------+ //| Handle chart events | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if (id == CHARTEVENT_OBJECT_CLICK) { // Panel navigation buttons if (sparam == "HomeButtonComm") { adminHomePanel.Show(); communicationsPanel.Hide(); } else if (sparam == "HomeButtonTrade") { adminHomePanel.Show(); tradeManagementPanel.Hide(); } if (sparam == "TradeMgmtAccessButton") { tradeManagementPanel.Show(); adminHomePanel.Hide(); } else if (sparam == "CommunicationsPanelAccessButton") { communicationsPanel.Show(); adminHomePanel.Hide(); } // Control buttons for panel resizing and closing else if (sparam == "MinimizeButton") { OnMinimizeButtonClick(); } else if (sparam == "MaximizeButton") { OnMaximizeButtonClick(); } else if (sparam == "CloseButton") { ExpertRemove(); } { if (sparam == "LoginButton") { OnLoginButtonClick(); } else if (sparam == "CloseAuthButton") { OnCloseAuthButtonClick(); } else if (sparam == "TwoFALoginButton") { OnTwoFALoginButtonClick(); } else if (sparam == "Close2FAButton") { OnClose2FAButtonClick(); } } switch (id) { case CHARTEVENT_OBJECT_CLICK: if (sparam == "SendButton") OnSendButtonClick(); else if (sparam == "ClearButton") OnClearButtonClick(); else if (sparam == "ChangeFontButton") OnChangeFontButtonClick(); else if (sparam == "ToggleThemeButton") OnToggleThemeButtonClick(); else if (sparam == "MinimizeButton") OnMinimizeButtonClick(); else if (sparam == "MaximizeButton") OnMaximizeButtonClick(); else if (sparam == "CloseButton") OnCloseButtonClick(); else if (StringFind(sparam, "QuickMessageButton") != -1) { long index = StringToInteger(StringSubstr(sparam, 18)); OnQuickMessageButtonClick(index - 1); } break; case CHARTEVENT_OBJECT_ENDEDIT: if (sparam == "InputBox") OnInputChange(); break; } } // Trade management buttons if (sparam == "BuyButton") OnBuyButtonClick(); else if (sparam == "SellButton") OnSellButtonClick(); else if (sparam == "CloseAllButton") OnCloseAllButtonClick(); else if (sparam == "CloseProfitButton") OnCloseProfitButtonClick(); else if (sparam == "CloseLossButton") OnCloseLossButtonClick(); else if (sparam == "CloseBuyButton") OnCloseBuyButtonClick(); else if (sparam == "CloseSellButton") OnCloseSellButtonClick(); else if (sparam == "DeleteAllOrdersButton") OnDeleteAllOrdersButtonClick(); else if (sparam == "DeleteLimitOrdersButton") OnDeleteLimitOrdersButtonClick(); else if (sparam == "DeleteStopOrdersButton") OnDeleteStopOrdersButtonClick(); else if (sparam == "DeleteStopLimitOrdersButton") OnDeleteStopLimitOrdersButtonClick(); }
Dann schaut unser endgültiger Code mit jetzt viele Zeilen wie folgt aus:
//+------------------------------------------------------------------+ //| 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 secure and responsive Admin Panel. Send messages to your telegram clients without leaving MT5" #property version "1.22" #include <Trade\Trade.mqh> #include <Controls\Dialog.mqh> #include <Controls\Button.mqh> #include <Controls\Edit.mqh> #include <Controls\Label.mqh> // Input parameters for quick messages input string QuickMessage1 = "Updates"; input string QuickMessage2 = "Close all"; input string QuickMessage3 = "In deep profits"; input string QuickMessage4 = "Hold position"; input string QuickMessage5 = "Swing Entry"; input string QuickMessage6 = "Scalp Entry"; input string QuickMessage7 = "Book profit"; input string QuickMessage8 = "Invalid Signal"; input string InputChatId = "YOUR_CHAT_ID"; input string InputBotToken = "YOUR_BOT_TOKEN"; // Constants for 2FA const string Hardcoded2FAChatId = "Replace chat ID with yours"; const string Hardcoded2FABotToken = "Replace with your bot token"; // Global variables CDialog adminHomePanel, tradeManagementPanel, communicationsPanel; CDialog authentication, twoFactorAuth; CButton homeButtonComm, homeButtonTrade; CButton sendButton, clearButton, changeFontButton, toggleThemeButton; CButton loginButton, closeAuthButton, twoFALoginButton, close2FAButton; CButton quickMessageButtons[8], minimizeButton, maximizeButton, closeButton; CButton tradeMgmtAccessButton, communicationsPanelAccessButton; CEdit inputBox, passwordInputBox, twoFACodeInput; CLabel charCounter, passwordPromptLabel, feedbackLabel, twoFAPromptLabel, twoFAFeedbackLabel; bool minimized = false; bool darkTheme = false; int MAX_MESSAGE_LENGTH = 4096; string availableFonts[] = { "Arial", "Courier New", "Verdana", "Times New Roman" }; int currentFontIndex = 0; string Password = "2024"; // Hardcoded password string twoFACode = ""; // Button Declarations for Trade Management CButton buyButton; // Button for Buy operations CButton sellButton; // Button for Sell operations CButton closeAllButton; // Button for closing all positions CButton closeProfitButton; // Button for closing profitable positions CButton closeLossButton; // Button for closing losing positions CButton closeBuyButton; // Button for closing Buy positions CButton closeSellButton; // Button for closing Sell positions CButton deleteAllOrdersButton; // Button for deleting all orders CButton deleteLimitOrdersButton; // Button for deleting limit orders CButton deleteStopOrdersButton; // Button for deleting stop orders CButton deleteStopLimitOrdersButton; // Button for deleting stop limit orders //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { if (!ShowAuthenticationPrompt()) { Print("Authorization failed. Exiting..."); return INIT_FAILED; } if (!adminHomePanel.Create(ChartID(), "Admin Home Panel", 0, 30, 30, 500, 500)) { Print("Failed to create Admin Home Panel"); return INIT_FAILED; } if (!CreateAdminHomeControls()) { Print("Home panel control creation failed"); return INIT_FAILED; } if (!communicationsPanel.Create(ChartID(), "Communications Panel", 0, 30, 30, 500, 500)) { Print("Failed to create Communications panel dialog"); return INIT_FAILED; } if (!tradeManagementPanel.Create(ChartID(), "Trade Management Panel", 0,260, 30, 1040, 170)) { Print("Failed to create Trade Management panel dialog"); return INIT_FAILED; } if (!CreateControls()) { Print("Control creation failed"); return INIT_FAILED; } if (!CreateTradeManagementControls()) { Print("Trade management control creation failed"); return INIT_FAILED; } adminHomePanel.Hide(); // Hide home panel by default on initialization communicationsPanel.Hide(); // Hide the Communications Panel tradeManagementPanel.Hide(); // Hide the Trade Management Panel return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Handle chart events | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if (id == CHARTEVENT_OBJECT_CLICK) { // Panel navigation buttons if (sparam == "HomeButtonComm") { adminHomePanel.Show(); communicationsPanel.Hide(); } else if (sparam == "HomeButtonTrade") { adminHomePanel.Show(); tradeManagementPanel.Hide(); } if (sparam == "TradeMgmtAccessButton") { tradeManagementPanel.Show(); adminHomePanel.Hide(); } else if (sparam == "CommunicationsPanelAccessButton") { communicationsPanel.Show(); adminHomePanel.Hide(); } // Control buttons for panel resizing and closing else if (sparam == "MinimizeButton") { OnMinimizeButtonClick(); } else if (sparam == "MaximizeButton") { OnMaximizeButtonClick(); } else if (sparam == "CloseButton") { ExpertRemove(); } { if (sparam == "LoginButton") { OnLoginButtonClick(); } else if (sparam == "CloseAuthButton") { OnCloseAuthButtonClick(); } else if (sparam == "TwoFALoginButton") { OnTwoFALoginButtonClick(); } else if (sparam == "Close2FAButton") { OnClose2FAButtonClick(); } } switch (id) { case CHARTEVENT_OBJECT_CLICK: if (sparam == "SendButton") OnSendButtonClick(); else if (sparam == "ClearButton") OnClearButtonClick(); else if (sparam == "ChangeFontButton") OnChangeFontButtonClick(); else if (sparam == "ToggleThemeButton") OnToggleThemeButtonClick(); else if (sparam == "MinimizeButton") OnMinimizeButtonClick(); else if (sparam == "MaximizeButton") OnMaximizeButtonClick(); else if (sparam == "CloseButton") OnCloseButtonClick(); else if (StringFind(sparam, "QuickMessageButton") != -1) { long index = StringToInteger(StringSubstr(sparam, 18)); OnQuickMessageButtonClick(index - 1); } break; case CHARTEVENT_OBJECT_ENDEDIT: if (sparam == "InputBox") OnInputChange(); break; } } // Trade management buttons if (sparam == "BuyButton") OnBuyButtonClick(); else if (sparam == "SellButton") OnSellButtonClick(); else if (sparam == "CloseAllButton") OnCloseAllButtonClick(); else if (sparam == "CloseProfitButton") OnCloseProfitButtonClick(); else if (sparam == "CloseLossButton") OnCloseLossButtonClick(); else if (sparam == "CloseBuyButton") OnCloseBuyButtonClick(); else if (sparam == "CloseSellButton") OnCloseSellButtonClick(); else if (sparam == "DeleteAllOrdersButton") OnDeleteAllOrdersButtonClick(); else if (sparam == "DeleteLimitOrdersButton") OnDeleteLimitOrdersButtonClick(); else if (sparam == "DeleteStopOrdersButton") OnDeleteStopOrdersButtonClick(); else if (sparam == "DeleteStopLimitOrdersButton") OnDeleteStopLimitOrdersButtonClick(); } //+------------------------------------------------------------------+ //| Trade management button handlers | //+------------------------------------------------------------------+ void OnBuyButtonClick() { CTrade trade; double lotSize = 0.1; // lot size double slippage = 3; // slippage double stopLoss = 0; // stop loss (in points) double takeProfit = 0; // take profit (in points) // Open Buy order double askPrice; if (SymbolInfoDouble(Symbol(), SYMBOL_ASK, askPrice) && askPrice > 0) { if (trade.Buy(lotSize, Symbol(), askPrice, slippage, stopLoss, takeProfit)) { Print("Buy order executed successfully."); } else { Print("Failed to execute Buy order. Error: ", GetLastError()); } } else { Print("Failed to retrieve Ask price. Error: ", GetLastError()); } // Execute Buy order logic here Print("Executing Buy operation"); } //+------------------------------------------------------------------+ //| Handle Sell button click | //+------------------------------------------------------------------+ void OnSellButtonClick() { CTrade trade; double lotSize = 0.1; // lot size double slippage = 3; // slippage double stopLoss = 0; // stop loss (in points) double takeProfit = 0; // take profit (in points) double bidPrice; if (SymbolInfoDouble(Symbol(), SYMBOL_BID, bidPrice) && bidPrice > 0) { // Open Sell order if (trade.Sell(lotSize, Symbol(), bidPrice, slippage, stopLoss, takeProfit)) { Print("Sell order opened successfully."); } else { Print("Error opening sell order: ", trade.ResultRetcode()); } } else { Print("Failed to retrieve Bid price. Error: ", GetLastError()); } } //+------------------------------------------------------------------+ //| Handle Close All button click | //+------------------------------------------------------------------+ void OnCloseAllButtonClick() { CPositionInfo position; for (int i = 0; i < PositionsTotal(); i++) { if (position.SelectByIndex(i)) { CTrade trade; if (position.Type() == POSITION_TYPE_BUY) trade.PositionClose(position.Ticket()); else if (position.Type() == POSITION_TYPE_SELL) trade.PositionClose(position.Ticket()); } } Print("All positions closed."); } //+------------------------------------------------------------------+ //| Handle Close Profitable button click | //+------------------------------------------------------------------+ void OnCloseProfitButtonClick() { CPositionInfo position; for (int i = 0; i < PositionsTotal(); i++) { if (position.SelectByIndex(i) && position.Profit() > 0) { CTrade trade; if (position.Type() == POSITION_TYPE_BUY) trade.PositionClose(position.Ticket()); else if (position.Type() == POSITION_TYPE_SELL) trade.PositionClose(position.Ticket()); } } Print("Profitable positions closed."); } //+------------------------------------------------------------------+ //| Handle Close Losing button click | //+------------------------------------------------------------------+ void OnCloseLossButtonClick() { CPositionInfo position; for (int i = 0; i < PositionsTotal(); i++) { if (position.SelectByIndex(i) && position.Profit() < 0) { CTrade trade; if (position.Type() == POSITION_TYPE_BUY) trade.PositionClose(position.Ticket()); else if (position.Type() == POSITION_TYPE_SELL) trade.PositionClose(position.Ticket()); } } Print("Losing positions closed."); } void OnCloseBuyButtonClick() { // Close Buy positions logic Print("Closing Buy positions"); } void OnCloseSellButtonClick() { // Close Sell positions logic Print("Closing Sell positions"); } //+------------------------------------------------------------------+ //| Handle Delete All Orders button click | //+------------------------------------------------------------------+ void OnDeleteAllOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i)) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All orders deleted."); } //+------------------------------------------------------------------+ //| Handle Delete Limit Orders button click | //+------------------------------------------------------------------+ void OnDeleteLimitOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i) && order.Type() == ORDER_TYPE_BUY_STOP_LIMIT) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All limit orders deleted."); } //+------------------------------------------------------------------+ //| Handle Delete Stop Orders button click | //+------------------------------------------------------------------+ void OnDeleteStopOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i) && order.Type() == ORDER_TYPE_BUY_STOP && ORDER_TYPE_SELL_STOP) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All stop orders deleted."); } //+------------------------------------------------------------------+ //| Handle Delete Stop Limit Orders button click | //+------------------------------------------------------------------+ void OnDeleteStopLimitOrdersButtonClick() { COrderInfo order; for (int i = 0; i < OrdersTotal(); i++) { if (order.SelectByIndex(i) && order.Type() == ORDER_TYPE_BUY_LIMIT && ORDER_TYPE_SELL_STOP_LIMIT) { CTrade trade; trade.OrderDelete(order.Ticket()); } } Print("All stop limit orders deleted."); } //+------------------------------------------------------------------+ //| Show authentication input dialog | //+------------------------------------------------------------------+ bool ShowAuthenticationPrompt() { if (!authentication.Create(ChartID(), "Authentication", 0, 100, 100, 500, 300)) { Print("Failed to create authentication dialog"); return false; } if (!passwordInputBox.Create(ChartID(), "PasswordInputBox", 0, 20, 70, 260, 95)) { Print("Failed to create password input box"); return false; } authentication.Add(passwordInputBox); if (!passwordPromptLabel.Create(ChartID(), "PasswordPromptLabel", 0, 20, 20, 260, 40)) { Print("Failed to create password prompt label"); return false; } passwordPromptLabel.Text("Enter password: Access Admin Panel"); authentication.Add(passwordPromptLabel); if (!feedbackLabel.Create(ChartID(), "FeedbackLabel", 0, 20, 140, 380, 160)) { Print("Failed to create feedback label"); return false; } feedbackLabel.Text(""); feedbackLabel.Color(clrRed); // Red color for incorrect attempts authentication.Add(feedbackLabel); if (!loginButton.Create(ChartID(), "LoginButton", 0, 20, 120, 100, 140)) { Print("Failed to create login button"); return false; } loginButton.Text("Login"); authentication.Add(loginButton); if (!closeAuthButton.Create(ChartID(), "CloseAuthButton", 0, 120, 120, 200, 140)) { Print("Failed to create close button for authentication"); return false; } closeAuthButton.Text("Close"); authentication.Add(closeAuthButton); authentication.Show(); ChartRedraw(); return true; } //+------------------------------------------------------------------+ //| Show two-factor authentication input dialog | //+------------------------------------------------------------------+ void ShowTwoFactorAuthPrompt() { if (!twoFactorAuth.Create(ChartID(), "Two-Factor Authentication", 0, 100, 100, 500, 300)) { Print("Failed to create 2FA dialog"); return; } if (!twoFACodeInput.Create(ChartID(), "TwoFACodeInput", 0, 20, 70, 260, 95)) { Print("Failed to create 2FA code input box"); return; } twoFactorAuth.Add(twoFACodeInput); if (!twoFAPromptLabel.Create(ChartID(), "TwoFAPromptLabel", 0, 20, 20, 380, 40)) { Print("Failed to create 2FA prompt label"); return; } twoFAPromptLabel.Text("Enter the 2FA code sent to your Telegram:"); twoFactorAuth.Add(twoFAPromptLabel); if (!twoFAFeedbackLabel.Create(ChartID(), "TwoFAFeedbackLabel", 0, 20, 140, 380, 160)) { Print("Failed to create 2FA feedback label"); return; } twoFAFeedbackLabel.Text(""); twoFAFeedbackLabel.Color(clrRed); // Red color for incorrect 2FA attempts twoFactorAuth.Add(twoFAFeedbackLabel); if (!twoFALoginButton.Create(ChartID(), "TwoFALoginButton", 0, 20, 120, 100, 140)) { Print("Failed to create 2FA login button"); return; } twoFALoginButton.Text("Verify"); twoFactorAuth.Add(twoFALoginButton); if (!close2FAButton.Create(ChartID(), "Close2FAButton", 0, 120, 120, 200, 140)) { Print("Failed to create close button for 2FA"); return; } close2FAButton.Text("Close"); twoFactorAuth.Add(close2FAButton); twoFactorAuth.Show(); ChartRedraw(); } //+------------------------------------------------------------------+ //| Admin Home Panel controls creation | //+------------------------------------------------------------------+ bool CreateAdminHomeControls() { long chart_id = ChartID(); if (!tradeMgmtAccessButton.Create(chart_id, "TradeMgmtAccessButton", 0, 50, 50, 250, 90)) { Print("Failed to create Trade Management Access button"); return false; } tradeMgmtAccessButton.Text("Trade Management Panel"); adminHomePanel.Add(tradeMgmtAccessButton); if (!communicationsPanelAccessButton.Create(chart_id, "CommunicationsPanelAccessButton", 0, 50, 100, 250, 140)) { Print("Failed to create Communications Panel Access button"); return false; } communicationsPanelAccessButton.Text("Communications Panel"); adminHomePanel.Add(communicationsPanelAccessButton); if (!minimizeButton.Create(chart_id, "MinimizeButton", 0, 375, -22, 405, 0)) { Print("Failed to create minimize button"); return false; } minimizeButton.Text("_"); adminHomePanel.Add(minimizeButton); if (!maximizeButton.Create(chart_id, "MaximizeButton", 0, 405, -22, 435, 0)) { Print("Failed to create maximize button"); return false; } maximizeButton.Text("[ ]"); adminHomePanel.Add(maximizeButton); if (!closeButton.Create(chart_id, "CloseButton", 0, 435, -22, 465, 0)) { Print("Failed to create close button"); return false; } closeButton.Text("X"); adminHomePanel.Add(closeButton); return true; } //Helper Function seamless Button creation bool CreateButton(CButton &button, const string name, const string text, int x1, int y1, int x2, int y2) { long chart_id = ChartID(); if (!button.Create(chart_id, name, 0, x1, y1, x2, y2)) { Print("Failed to create button: ", name); return false; } button.Text(text); tradeManagementPanel.Add(button); return true; } //+------------------------------------------------------------------+ //| Create Trade Management Controls (Buttons) | //+------------------------------------------------------------------+ bool CreateTradeManagementControls() { // Coordinates for buttons (adjust as needed) const int Y1_TOP = 5, Y2_TOP = 40; const int Y1_MID = 50, Y2_MID = 70; const int Y1_BOTTOM = 80, Y2_BOTTOM = 100; // Create Buttons if (!CreateButton(buyButton, "BuyButton", "Buy", 130, Y1_TOP, 210, Y2_TOP)) return false; if (!CreateButton(sellButton, "SellButton", "Sell", 220, Y1_TOP, 320, Y2_TOP)) return false; if (!CreateButton(closeAllButton, "CloseAllButton", "Close All", 130, Y1_MID, 230, Y2_MID)) return false; if (!CreateButton(closeProfitButton, "CloseProfitButton", "Close Profitable", 240, Y1_MID, 380, Y2_MID)) return false; if (!CreateButton(closeLossButton, "CloseLossButton", "Close Losing", 390, Y1_MID, 510, Y2_MID)) return false; if (!CreateButton(closeBuyButton, "CloseBuyButton", "Close Buys", 520, Y1_MID, 620, Y2_MID)) return false; if (!CreateButton(closeSellButton, "CloseSellButton", "Close Sells", 630, Y1_MID, 730, Y2_MID)) return false; if (!CreateButton(deleteAllOrdersButton, "DeleteAllOrdersButton", "Delete All Orders", 130, Y1_BOTTOM , 270, Y2_BOTTOM )) return false; if (!CreateButton(deleteLimitOrdersButton, "DeleteLimitOrdersButton", "Delete Limits", 275, Y1_BOTTOM , 385, Y2_BOTTOM )) return false; if (!CreateButton(deleteStopOrdersButton, "DeleteStopOrdersButton", "Delete Stops", 390, Y1_BOTTOM , 515, Y2_BOTTOM )) return false; if (!CreateButton(deleteStopLimitOrdersButton, "DeleteStopLimitOrdersButton", "Delete Stop Limits", 520, Y1_BOTTOM , 660, Y2_BOTTOM )) return false; return true; // All buttons created successfully } //+------------------------------------------------------------------+ //| Handle login button click | //+------------------------------------------------------------------+ void OnLoginButtonClick() { string enteredPassword = passwordInputBox.Text(); if (enteredPassword == Password) { twoFACode = GenerateRandom6DigitCode(); SendMessageToTelegram("A login attempt was made on the Admin Panel. Please use this code to verify your identity: " + twoFACode, Hardcoded2FAChatId, Hardcoded2FABotToken); authentication.Destroy(); ShowTwoFactorAuthPrompt(); Print("Password authentication successful. A 2FA code has been sent to your Telegram."); } else { feedbackLabel.Text("Wrong password. Try again."); passwordInputBox.Text(""); } ///Handlers for the trade management } //+------------------------------------------------------------------+ //| Handle 2FA login button click | //+------------------------------------------------------------------+ void OnTwoFALoginButtonClick() { // If 2FA is successful, show the trade management panel string enteredCode = twoFACodeInput.Text(); if (enteredCode == twoFACode) { twoFactorAuth.Destroy(); adminHomePanel.Show(); Print("2FA authentication successful. Access granted to Trade Management Panel."); } else { twoFAFeedbackLabel.Text("Wrong code. Try again."); twoFACodeInput.Text(""); } } //+------------------------------------------------------------------+ //| Handle close button for authentication | //+------------------------------------------------------------------+ void OnCloseAuthButtonClick() { authentication.Destroy(); ExpertRemove(); // Exit the expert Print("Authentication dialog closed."); } //+------------------------------------------------------------------+ //| Handle close button for 2FA | //+------------------------------------------------------------------+ void OnClose2FAButtonClick() { twoFactorAuth.Destroy(); ExpertRemove(); Print("2FA dialog closed."); } //+------------------------------------------------------------------+ //| Create necessary UI controls | //+------------------------------------------------------------------+ bool CreateControls() { long chart_id = ChartID(); if (!inputBox.Create(chart_id, "InputBox", 0, 5, 25, 460, 95)) { Print("Failed to create input box"); return false; } communicationsPanel.Add(inputBox); // Create Home Button for Communications Panel if (!homeButtonComm.Create(chart_id, "HomeButtonComm", 0, 20, 120, 120,150)) { Print("Failed to create Home button for Communications Panel"); return false; } homeButtonComm.Text("Home 🏠"); communicationsPanel.Add(homeButtonComm); // Create Home Button for Trade Management Panel if (!homeButtonTrade.Create(chart_id, "HomeButtonTrade", 0, 20, 10, 120, 30)) { Print("Failed to create Home button for Trade Management Panel"); return false; } homeButtonTrade.Text("Home 🏠"); tradeManagementPanel.Add(homeButtonTrade); if (!charCounter.Create(chart_id, "CharCounter", 0, 380, 5, 460, 25)) { Print("Failed to create character counter"); return false; } charCounter.Text("0/" + IntegerToString(MAX_MESSAGE_LENGTH)); communicationsPanel.Add(charCounter); if (!clearButton.Create(chart_id, "ClearButton", 0, 235, 95, 345, 125)) { Print("Failed to create clear button"); return false; } clearButton.Text("Clear"); communicationsPanel.Add(clearButton); if (!sendButton.Create(chart_id, "SendButton", 0, 350, 95, 460, 125)) { Print("Failed to create send button"); return false; } sendButton.Text("Send"); communicationsPanel.Add(sendButton); if (!changeFontButton.Create(chart_id, "ChangeFontButton", 0, 95, 95, 230, 115)) { Print("Failed to create change font button"); return false; } changeFontButton.Text("Font<>"); communicationsPanel.Add(changeFontButton); if (!toggleThemeButton.Create(chart_id, "ToggleThemeButton", 0, 5, 95, 90, 115)) { Print("Failed to create toggle theme button"); return false; } toggleThemeButton.Text("Theme<>"); communicationsPanel.Add(toggleThemeButton); if (!minimizeButton.Create(chart_id, "MinimizeButton", 0, 375, -22, 405, 0)) { Print("Failed to create minimize button"); return false; } minimizeButton.Text("_"); communicationsPanel.Add(minimizeButton); if (!maximizeButton.Create(chart_id, "MaximizeButton", 0, 405, -22, 435, 0)) { Print("Failed to create maximize button"); return false; } maximizeButton.Text("[ ]"); communicationsPanel.Add(maximizeButton); if (!closeButton.Create(chart_id, "CloseButton", 0, 435, -22, 465, 0)) { Print("Failed to create close button"); return false; } closeButton.Text("X"); communicationsPanel.Add(closeButton); return CreateQuickMessageButtons(); } //+------------------------------------------------------------------+ //| Create quick message buttons | //+------------------------------------------------------------------+ bool CreateQuickMessageButtons() { string quickMessages[] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 }; int startX = 5, startY = 160, width = 222, height = 65, spacing = 5; for (int i = 0; i < ArraySize(quickMessages); i++) { bool created = quickMessageButtons[i].Create(ChartID(), "QuickMessageButton" + IntegerToString(i + 1), 0, startX + (i % 2) * (width + spacing), startY + (i / 2) * (height + spacing), startX + (i % 2) * (width + spacing) + width, startY + (i / 2) * (height + spacing) + height); if (!created) { Print("Failed to create quick message button ", i + 1); return false; } quickMessageButtons[i].Text(quickMessages[i]); communicationsPanel.Add(quickMessageButtons[i]); } return true; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { communicationsPanel.Destroy(); Print("Deinitialization complete"); } //+------------------------------------------------------------------+ //| Handle custom message send button click | //+------------------------------------------------------------------+ void OnSendButtonClick() { string message = inputBox.Text(); if (StringLen(message) > 0) { if (SendMessageToTelegram(message, InputChatId, InputBotToken)) Print("Custom message sent: ", message); else Print("Failed to send custom message."); } else { Print("No message entered."); } } //+------------------------------------------------------------------+ //| Handle clear button click | //+------------------------------------------------------------------+ void OnClearButtonClick() { inputBox.Text(""); OnInputChange(); Print("Input box cleared."); } //+------------------------------------------------------------------+ //| Handle quick message button click | //+------------------------------------------------------------------+ void OnQuickMessageButtonClick(long index) { string quickMessages[] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 }; string message = quickMessages[(int)index]; if (SendMessageToTelegram(message, InputChatId, InputBotToken)) Print("Quick message sent: ", message); else Print("Failed to send quick message."); } //+------------------------------------------------------------------+ //| Update character counter | //+------------------------------------------------------------------+ void OnInputChange() { int currentLength = StringLen(inputBox.Text()); charCounter.Text(IntegerToString(currentLength) + "/" + IntegerToString(MAX_MESSAGE_LENGTH)); ChartRedraw(); } //+------------------------------------------------------------------+ //| Handle toggle theme button click | //+------------------------------------------------------------------+ void OnToggleThemeButtonClick() { darkTheme = !darkTheme; UpdateThemeColors(); Print("Theme toggled: ", darkTheme ? "Dark" : "Light"); } //+------------------------------------------------------------------+ //| Update theme colors for the panel | //+------------------------------------------------------------------+ void UpdateThemeColors() { color textColor = darkTheme ? clrWhite : clrBlack; color buttonBgColor = darkTheme ? clrDarkSlateGray : clrGainsboro; color borderColor = darkTheme ? clrSlateGray : clrGray; color bgColor = darkTheme ? clrDarkBlue : clrWhite; UpdateButtonTheme(clearButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(sendButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(toggleThemeButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(changeFontButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(minimizeButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(maximizeButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(closeButton, textColor, buttonBgColor, borderColor); for (int i = 0; i < ArraySize(quickMessageButtons); i++) { UpdateButtonTheme(quickMessageButtons[i], textColor, buttonBgColor, borderColor); } ChartRedraw(); } //+------------------------------------------------------------------+ //| Apply theme settings to a button | //+------------------------------------------------------------------+ void UpdateButtonTheme(CButton &button, color textColor, color bgColor, color borderColor) { button.SetTextColor(textColor); button.SetBackgroundColor(bgColor); button.SetBorderColor(borderColor); } //+------------------------------------------------------------------+ //| Handle change font button click | //+------------------------------------------------------------------+ void OnChangeFontButtonClick() { currentFontIndex = (currentFontIndex + 1) % ArraySize(availableFonts); SetFontForAll(availableFonts[currentFontIndex]); Print("Font changed to: ", availableFonts[currentFontIndex]); ChartRedraw(); } //+------------------------------------------------------------------+ //| Set font for all input boxes and buttons | //+------------------------------------------------------------------+ void SetFontForAll(string fontName) { inputBox.Font(fontName); clearButton.Font(fontName); sendButton.Font(fontName); toggleThemeButton.Font(fontName); changeFontButton.Font(fontName); minimizeButton.Font(fontName); maximizeButton.Font(fontName); closeButton.Font(fontName); for (int i = 0; i < ArraySize(quickMessageButtons); i++) { quickMessageButtons[i].Font(fontName); } } //+------------------------------------------------------------------+ //| Generate a random 6-digit code for 2FA | //+------------------------------------------------------------------+ string GenerateRandom6DigitCode() { int code = MathRand() % 1000000; // Produces a 6-digit number return StringFormat("%06d", code); // Ensures leading zeros } //+------------------------------------------------------------------+ //| Handle minimize button click | //+------------------------------------------------------------------+ void OnMinimizeButtonClick() { minimized = true; communicationsPanel.Hide(); minimizeButton.Hide(); maximizeButton.Show(); closeButton.Show(); Print("Panel minimized."); } //+------------------------------------------------------------------+ //| Handle maximize button click | //+------------------------------------------------------------------+ void OnMaximizeButtonClick() { if (minimized) { communicationsPanel.Show(); minimizeButton.Show(); maximizeButton.Hide(); closeButton.Hide(); minimized = false; Print("Panel maximized."); } } //+------------------------------------------------------------------+ //| Handle close button click for admin panel | //+------------------------------------------------------------------+ void OnCloseButtonClick() { ExpertRemove(); Print("Admin panel closed."); } //+------------------------------------------------------------------+ //| Send the message to Telegram | //+------------------------------------------------------------------+ bool SendMessageToTelegram(string message, string chatId, string botToken) { string url = "https://api.telegram.org/bot" + botToken + "/sendMessage"; string jsonMessage = "{\"chat_id\":\"" + chatId + "\", \"text\":\"" + message + "\"}"; char postData[]; ArrayResize(postData, StringToCharArray(jsonMessage, postData) - 1); int timeout = 5000; char result[]; string responseHeaders; int responseCode = WebRequest("POST", url, "Content-Type: application/json\r\n", timeout, postData, result, responseHeaders); if (responseCode == 200) { Print("Message sent successfully: ", message); return true; } else { Print("Failed to send message. HTTP code: ", responseCode, " Error code: ", GetLastError()); Print("Response: ", CharArrayToString(result)); return false; } } //+------------------------------------------------------------------+
Tests
Bei den Tests funktionierten alle Schaltflächen korrekt und reagierten wie programmiert, was unser Handelsverwaltungspanel zu einer wertvollen Komponente im Instrument des Handelsadministrators macht. Sowohl die Integration der neuen Schaltflächen als auch die Implementierung der zugehörigen Ereignisbehandlungen wurden erfolgreich abgeschlossen.
Die Ereignisbehandlung der Schaltflächen im Trade Management Panel funktioniert.
Dies sind die Kommentare der Experten, die die erfolgreiche Ausführung und den Abschluss des Auftrags anzeigen
Schlussfolgerung
In dieser Diskussion haben wir die Telegramm-Konfiguration überarbeitet und das Handelsmanagement-Panel mit neuen Schaltflächen für das Handelsmanagement erweitert. Wir haben auch das Layout verbessert, indem wir den vertikalen Maßstab verkleinert und den horizontalen Maßstab vergrößert haben, einschließlich einer Positionsverschiebung in x-Richtung. Mit dieser Anpassung wurden Überschneidungsprobleme zwischen unserem Panel und den integrierten Schnellhandelsschaltflächen behoben, wodurch die Sichtbarkeit des Charts verbessert wurde und die Handelsschaltflächen weiterhin leicht zugänglich sind.
Nach der Fertigstellung des Layouts haben wir Event-Handler für die Schaltflächen integriert, um sicherzustellen, dass sie beim Anklicken angemessen reagieren.
Ich hoffe, dass diese Diskussion ein Licht auf die breiteren Möglichkeiten der GUI-Programmierung in MQL5 geworfen und das kreative Potenzial bei der Gestaltung verschiedener GUI-Komponenten aufgezeigt hat. Mit geschickten und phantasievollen Köpfen gibt es noch so viel mehr zu erforschen als diese Grundlage.
Viel Spaß beim Entwickeln, liebe Handelskollegen!
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/16328
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.