English 日本語
preview
Erstellen eines Handelsadministrator-Panels in MQL5 (Teil IX): Code Organisation (IV): Handelsmanagement-Panel-Klasse

Erstellen eines Handelsadministrator-Panels in MQL5 (Teil IX): Code Organisation (IV): Handelsmanagement-Panel-Klasse

MetaTrader 5Beispiele |
94 0
Clemence Benjamin
Clemence Benjamin

Inhalt


Einführung

In unseren vorangegangenen Diskussionen haben wir die Code-Organisation als eine entscheidende Strategie für eine reibungslose und skalierbare Erweiterung des Trading Administrator Panel-Projekts vorgestellt, die dem Prinzip der Trennung von Belangen folgt. Dieser Ansatz hat es mir ermöglicht, mich auf jedes Unter-Panel innerhalb des NewAdminPanel zu konzentrieren und sicherzustellen, dass unser Programm modular und gut strukturiert bleibt. Da wir jede Funktion unabhängig voneinander entwickeln, können wir sie verfeinern, um die bestmögliche Funktionalität zu bieten.

Früher hatte unser Handelspanel nur begrenzte Möglichkeiten, aber jetzt ist es leistungsfähiger als je zuvor. Es bietet die Flexibilität, schnelle Handelsgeschäfte auszuführen und gleichzeitig ein integriertes Risikomanagement einzubauen - und das alles über dieselbe Schnittstelle. Schwebende Aufträge können auch direkt über das Panel eingerichtet werden, was den Handelsprozess vereinfacht.

Mit dieser Aktualisierung werden zwei große Herausforderungen angegangen:

  1. Aufbau großer, gut organisierter Programme, die einfacher zu entwickeln und zu pflegen sind.
  2. Sicherstellung eines schnellen Zugriffs auf Handelsoperationen innerhalb eines All-in-One-EAs, der eine Kommunikationsschnittstelle, eine Handelsverwaltungsschnittstelle und in naher Zukunft auch eine Analyseschnittstelle integriert.

Im Folgenden werde ich einen Überblick über diese Diskussion geben und darlegen, wie wir diese Verbesserungen zu Ende führen werden.


Überblick über die Diskussion

Das Hauptziel unserer Artikel ist es, die Verwendung von MQL5 durch Anwendung auf verschiedene Projekte praktisch zu machen. Heute werden wir uns mit der Entwicklung der Klasse für ein Handelsverwaltungs-Panel befassen und dabei berücksichtigen, dass in MQL5 ein Klassenkopf Deklarationen von ähnlichen Variablen enthält. In diesem Zusammenhang werden alle Handelsfunktionen, die wir in unser Panel aufnehmen wollen, von integrierten Klassen wie CTrade, CDialog, CLabel und CEdit erben.

Sobald die Klasse vollständig entwickelt ist, werden wir ihre Methoden in das Hauptprogramm - NewAdminPanel EA - integrieren. Unsere Diskussion wäre nicht vollständig, wenn wir nicht die Testergebnisse mit Ihnen teilen und Ihnen die Quelldateien zur Verfügung stellen würden, damit Sie die Implementierung überprüfen, sich Ideen holen und mit dem Code experimentieren können, um Ihre eigenen Projekte zu verbessern.

In diesem Stadium beschloss ich, die Erstellung des Home-Panels innerhalb des Hauptprogramms zu zentralisieren, da dies die Länge des Codes nicht wesentlich erhöhte. Obwohl der frühere Ansatz seine Vorteile hatte, habe ich mich für diese Struktur entschieden, um die Entwicklung zu vereinfachen und Abhängigkeiten zu reduzieren. Mein Ziel ist es, das Hauptprogramm zu fokussieren und für jede spezifische Funktion eine eigene Klasse zu verwenden. Die wichtigsten Elemente der Nutzeroberfläche werden nun direkt im Hauptprogramm erstellt, was zu einem schlankeren und effizienteren Design führt. Infolgedessen werden die Methoden der Klasse AdminHomeDialog in NewAdminPanel nicht mehr aufgerufen. 

Das folgende Bild zeigt, was wir am Ende unserer Diskussion erstellen werden. Aber das ist erst der Anfang - wenn es einmal aufgebaut ist, dient es als solide Grundlage für zukünftige Erweiterungen und Verbesserungen.

Handelsmanagement-Panel (bis zum Ende der Diskussion)

Vorteile dieses Projekts

Die Instrumente, die wir hier entwickeln, bieten mehrere entscheidende Vorteile:

  • Schneller Handel - Effizientes Ausführen von Handelsgeschäften.
  • Risikomanagement - Legen Sie Stop Loss (S/L) und Take Profit (T/P) fest, bevor Sie Aufträge erteilen, und planen Sie Ihre Handelsgeschäfte im Voraus mit schwebenden Aufträgen.
  • Kommunikationsfunktionen - Senden Sie Nachrichten an andere Händler über das Kommunikationspanel, das wir zuvor erstellt haben.
  • Lernen Sie MQL5 für Fortgeschrittene - Gewinnen Sie einen tieferen Einblick in die objektorientierte Programmierung in MQL5.
  • Engagement der Gemeinschaft - Teilen Sie Ihre Erkenntnisse und Erfahrungen im Kommentarbereich mit.
  • Wiederverwendbarkeit - Das CTradeManagementPanel kann in anderen Projekten verwendet werden.
In den nächsten Abschnitten werden die Funktionen der Klasse Trade Management Panel detailliert beschrieben, gefolgt von ihrer Integration in das Hauptprogramm.


Die Klasse des Handelsmanagement-Panels (CTradeManagementPanel)

1. Einrichten der Basis mit Kopfzeilen und Makros

Bevor wir etwas bauen, müssen wir die richtigen Werkzeuge einsetzen. Der erste Schritt besteht darin, Header-Dateien einzubinden, die die Handelsausführung, die Elemente der Nutzeroberfläche und die Ereignisverwaltung regeln. Anstatt Layout-Werte wie Schaltflächengrößen und -abstände über den gesamten Code zu verstreuen, definieren wir Makros am Anfang. Dies gewährleistet ein einheitliches Design der Nutzeroberfläche und erleichtert die spätere Anpassung der Abmessungen, ohne mehrere Dateien durchsuchen zu müssen.

#include <Trade\Trade.mqh>
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
#include <Controls\Edit.mqh>
#include <Controls\Label.mqh>

//+------------------------------------------------------------------+
//| Defines for dimensions and spacing                               |
//+------------------------------------------------------------------+
#define BUTTON_WIDTH          100
#define BUTTON_HEIGHT         30
#define DELETE_BUTTON_WIDTH   130   
#define EDIT_WIDTH            80
#define EDIT_HEIGHT           20
#define DEFAULT_LABEL_HEIGHT  20    
#define SECTION_LABEL_WIDTH   250
#define GAP                   10
#define INPUT_LABEL_GAP       3     

2. Definition der Kernklasse und ihrer Komponenten

Das Herzstück des Handelspanels ist eine Klasse, die sowohl die Schnittstelle als auch die Handelsausführungslogik verwaltet. Durch die Ableitung von einer Basis-Dialogklasse erhält sie integrierte UI-Management-Funktionen, während wir uns auf die Anpassung des Verhaltens konzentrieren können.

Innerhalb dieser Klasse definieren wir wichtige Mitgliedsvariablen. Dazu gehören ein Verweis auf das Handelsdiagramm, ein Handelsausführungsobjekt und eine strukturierte Sammlung von UI-Steuerelementen. Durch die getrennte Organisation dieser Elemente wird sichergestellt, dass die Nutzeroberfläche sauber von der Logik der Auftragsabwicklung getrennt bleibt.

//+------------------------------------------------------------------+
//| Trade Management Panel class                                     |
//+------------------------------------------------------------------+
class CTradeManagementPanel : public CAppDialog
{
protected:
   // Store chart and subwindow values for helper functions.
   long m_chart;
   int  m_subwin;
   
   CTrade m_trade;  // Trade object for executing trades

   // Section Labels
   CLabel m_secQuickLabel;
   CLabel m_secPendingLabel;
   CLabel m_secAllOpsLabel;
   
   // Section 1: Quick Execution
   CButton m_buyButton;      // Market Buy button
   CButton m_sellButton;     // Market Sell button
   CEdit   m_volumeEdit;     // Volume input
   CLabel  m_lotLabel;       // "Lot:" label above volume input
   // TP and SL for market orders—with a label to their right
   CEdit   m_tpEdit;
   CLabel  m_tpRightLabel;   // "TP:" label
   CLabel  m_tpErrorLabel;
   CEdit   m_slEdit;
   CLabel  m_slRightLabel;   // "SL:" label
   CLabel  m_slErrorLabel;
   
   // Section 2: Pending Orders
   // Column Headers for pending orders
   CLabel  m_pendingPriceHeader;
   CLabel  m_pendingTPHeader;
   CLabel  m_pendingSLHeader;
   CLabel  m_pendingExpHeader;
   
   // Buy pending orders
   CButton m_buyLimitButton;
   CEdit   m_buyLimitPriceEdit;
   CEdit   m_buyLimitTPEdit;
   CEdit   m_buyLimitSLEdit;
   CEdit   m_buyLimitExpEdit;   // Expiration input for Buy Limit
   CButton m_buyStopButton;
   CEdit   m_buyStopPriceEdit;
   CEdit   m_buyStopTPEdit;
   CEdit   m_buyStopSLEdit;
   CEdit   m_buyStopExpEdit;    // Expiration input for Buy Stop
   
   // Sell pending orders
   CButton m_sellLimitButton;
   CEdit   m_sellLimitPriceEdit;
   CEdit   m_sellLimitTPEdit;
   CEdit   m_sellLimitSLEdit;
   CEdit   m_sellLimitExpEdit;  // Expiration input for Sell Limit
   CButton m_sellStopButton;
   CEdit   m_sellStopPriceEdit;
   CEdit   m_sellStopTPEdit;
   CEdit   m_sellStopSLEdit;
   CEdit   m_sellStopExpEdit;   // Expiration input for Sell Stop
   
   // Section 3: All Order Operations
   CButton m_closeAllButton;
   CButton m_closeProfitButton;
   CButton m_closeLossButton;
   CButton m_closeBuyButton;
   CButton m_closeSellButton;
   CButton m_deleteAllOrdersButton;
   CButton m_deleteLimitOrdersButton;
   CButton m_deleteStopOrdersButton;
   CButton m_deleteStopLimitOrdersButton;
   CButton m_resetButton;        
   
   //--- Helper: Create a text label using
   bool CreateLabelEx(CLabel &label, int x, int y, int height, string label_name, string text, color clr)
   {
      string unique_name = m_name + label_name;
      if(!label.Create(m_chart, unique_name, m_subwin, x, y, x, y+height))
         return false;
      if(!Add(label))
         return false;
      if(!label.Text(text))
         return false;
      label.Color(clr);
      return true;
   }
   
   //--- Helper: Create and add a button control
   bool CreateButton(CButton &button, string name, int x, int y, int w = BUTTON_WIDTH, int h = BUTTON_HEIGHT, color clr = clrWhite)
   {
      if(!button.Create(m_chart, name, m_subwin, x, y, x+w, y+h))
         return false;
      button.Text(name);
      button.Color(clr);
      if(!Add(button))
         return false;
      return true;
   }
   
   //--- Helper: Create and add an edit control
   bool CreateEdit(CEdit &edit, string name, int x, int y, int w = EDIT_WIDTH, int h = EDIT_HEIGHT)
   {
      if(!edit.Create(m_chart, name, m_subwin, x, y, x+w, y+h))
         return false;
      if(!Add(edit))
         return false;
      return true;
   }
   
   // Event handler declarations
   virtual void OnClickBuy();
   virtual void OnClickSell();
   virtual void OnClickBuyLimit();
   virtual void OnClickBuyStop();
   virtual void OnClickSellLimit();
   virtual void OnClickSellStop();
   virtual void OnClickCloseAll();
   virtual void OnClickCloseProfit();
   virtual void OnClickCloseLoss();
   virtual void OnClickCloseBuy();
   virtual void OnClickCloseSell();
   virtual void OnClickDeleteAllOrders();
   virtual void OnClickDeleteLimitOrders();
   virtual void OnClickDeleteStopOrders();
   virtual void OnClickDeleteStopLimitOrders();
   virtual void OnClickReset();  
   
   // Validation helpers for market orders
   bool ValidateBuyParameters(double volume, double tp, double sl, double ask);
   bool ValidateSellParameters(double volume, double tp, double sl, double bid);
   
public:
   CTradeManagementPanel();
   ~CTradeManagementPanel();
   virtual bool Create(const long chart, const string name, const int subwin,
                         const int x1, const int y1, const int x2, const int y2);
   virtual bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
   void Toggle();
};

3. Strukturierung der Nutzeroberfläche mit logischen Abschnitten

Eine gut organisierte Schnittstelle macht den Unterschied aus. Anstatt die Schaltflächen und Eingabefelder wahllos zu verteilen, unterteilen wir das Panel in drei Hauptbereiche.

  1. Der erste Bereich ist für schnelle Marktaufträge vorgesehen, wo die Nutzer sofort kaufen oder verkaufen, das Handelsvolumen festlegen und die Werte für Stop-Loss und Take-Profit konfigurieren können.
  2. Der zweite Abschnitt ist den schwebenden Aufträgen gewidmet. Hier können die Nutzer Preise, Verfallszeiten und Auftragsarten wie Buy Limit oder Sell Stop festlegen.
  3. Der dritte Abschnitt behandelt Massenaktionen wie das Schließen aller Handelsgeschäfte, das Schließen nur profitabler Handelsgeschäfte oder das Löschen der schwebenden Aufträge. Durch die Zusammenfassung dieser Funktionen wird sichergestellt, dass die Nutzeroberfläche einfach zu navigieren ist.

//+------------------------------------------------------------------+
//| Create the trade management panel                                |
//+------------------------------------------------------------------+
bool CTradeManagementPanel::Create(const long chart, const string name, const int subwin,
                                     const int x1, const int y1, const int x2, const int y2)
{
   // Save chart and subwin for later use.
   m_chart  = chart;
   m_subwin = subwin;
   
   if(!CAppDialog::Create(chart, name, subwin, x1, y1, x2, y2))
      return false;
   
   int curX = GAP;
   int curY = GAP;
   
   // Section 1: Quick Order Execution
   if(!CreateLabelEx(m_secQuickLabel, curX, curY-10, DEFAULT_LABEL_HEIGHT, "SecQuick", "Quick Order Execution:", clrBlack))
      return false;
   curY += DEFAULT_LABEL_HEIGHT + GAP;
   
   // Market order row:
   if(!CreateButton(m_buyButton, "Buy", curX, curY, BUTTON_WIDTH, BUTTON_HEIGHT, clrGreen))
      return false;
   int volX = curX + BUTTON_WIDTH + GAP;
   if(!CreateLabelEx(m_lotLabel, volX, curY - DEFAULT_LABEL_HEIGHT, DEFAULT_LABEL_HEIGHT, "Lot", "Lot Size:", clrBlack))
      return false;
   if(!CreateEdit(m_volumeEdit, "VolumeEdit", volX, curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   double minVolume = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
   m_volumeEdit.Text(DoubleToString(minVolume, 2));
   int sellBtnX = volX + EDIT_WIDTH + GAP;
   if(!CreateButton(m_sellButton, "Sell", sellBtnX, curY, BUTTON_WIDTH, BUTTON_HEIGHT, clrRed))
      return false;
   curY += BUTTON_HEIGHT + GAP;
   
   // Next row: TP and SL for market orders
   if(!CreateEdit(m_tpEdit, "TPEdit", 4*curX+ GAP , curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_tpEdit.Text("0.00000");
   if(!CreateLabelEx(m_tpRightLabel, curX  + INPUT_LABEL_GAP, curY, DEFAULT_LABEL_HEIGHT, "TP", "TP:", clrBlack))
      return false;
   if(!CreateLabelEx(m_tpErrorLabel, curX, curY + DEFAULT_LABEL_HEIGHT, DEFAULT_LABEL_HEIGHT, "TPError", "", clrBlack))
      return false;
   int slX = 2*EDIT_WIDTH  ; 
   if(!CreateEdit(m_slEdit, "SLEdit", slX + 4*curX, curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_slEdit.Text("0.00000");
   if(!CreateLabelEx(m_slRightLabel, slX  , curY, DEFAULT_LABEL_HEIGHT, "SL", "SL:", clrBlack))
      return false;
   if(!CreateLabelEx(m_slErrorLabel, slX, curY + DEFAULT_LABEL_HEIGHT, DEFAULT_LABEL_HEIGHT, "SLError", "", clrBlack))
      return false;
   curY += EDIT_HEIGHT + GAP*2;
   
   // Section 2: Pending Orders
   if(!CreateLabelEx(m_secPendingLabel, curX, curY, DEFAULT_LABEL_HEIGHT, "SecPend", "Pending Orders:", clrBlack))
      return false;
   curY += DEFAULT_LABEL_HEIGHT + GAP;
   
   // Column headers for pending orders (each label includes a colon)
   int headerX = curX + BUTTON_WIDTH + GAP;
   if(!CreateLabelEx(m_pendingPriceHeader, headerX, curY, DEFAULT_LABEL_HEIGHT, "PendPrice", "Price:", clrBlack))
      return false;
   if(!CreateLabelEx(m_pendingTPHeader, headerX + EDIT_WIDTH + GAP, curY, DEFAULT_LABEL_HEIGHT, "PendTP", "TP:", clrBlack))
      return false;
   if(!CreateLabelEx(m_pendingSLHeader, headerX + 2*(EDIT_WIDTH + GAP), curY, DEFAULT_LABEL_HEIGHT, "PendSL", "SL:", clrBlack))
      return false;
   if(!CreateLabelEx(m_pendingExpHeader, headerX + 3*(EDIT_WIDTH + GAP), curY, DEFAULT_LABEL_HEIGHT, "PendExp", "Expiration Date:", clrBlack))
      return false;
   curY += DEFAULT_LABEL_HEIGHT + GAP;
   
   // Prepare default expiration value as current day end time.
   datetime now = TimeCurrent();
   string exp_default = TimeToString(now, TIME_DATE) + " 23:59:59";
   
   // --- Buy Pending Orders ---
   // Buy Limit Order row:
   if(!CreateButton(m_buyLimitButton, "Buy Limit", curX, curY, BUTTON_WIDTH, BUTTON_HEIGHT, clrBlue))
      return false;
   int pendingX = curX + BUTTON_WIDTH + GAP;
   if(!CreateEdit(m_buyLimitPriceEdit, "BuyLimitPrice", pendingX, curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   string askStr = DoubleToString(SymbolInfoDouble(Symbol(), SYMBOL_ASK), 5);
   m_buyLimitPriceEdit.Text(askStr);
   int pending2X = pendingX + EDIT_WIDTH + GAP;
   if(!CreateEdit(m_buyLimitTPEdit, "BuyLimitTP", pending2X, curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_buyLimitTPEdit.Text("0.00000");
   int pending3X = pending2X + EDIT_WIDTH + GAP;
   if(!CreateEdit(m_buyLimitSLEdit, "BuyLimitSL", pending3X, curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_buyLimitSLEdit.Text("0.00000");
   int pending4X = pending3X + EDIT_WIDTH + GAP; // Double width for expiration input
   if(!CreateEdit(m_buyLimitExpEdit, "BuyLimitExp", pending4X, curY, 2*EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_buyLimitExpEdit.Text(exp_default);
   curY += BUTTON_HEIGHT + GAP;
   
   // Buy Stop Order row:
   if(!CreateButton(m_buyStopButton, "Buy Stop", curX, curY, BUTTON_WIDTH, BUTTON_HEIGHT, clrBlue))
      return false;
   pendingX = curX + BUTTON_WIDTH + GAP;
   if(!CreateEdit(m_buyStopPriceEdit, "BuyStopPrice", pendingX, curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_buyStopPriceEdit.Text(askStr);
   pending2X = pendingX + EDIT_WIDTH + GAP;
   if(!CreateEdit(m_buyStopTPEdit, "BuyStopTP", pending2X, curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_buyStopTPEdit.Text("0.00000");
   pending3X = pending2X + EDIT_WIDTH + GAP;
   if(!CreateEdit(m_buyStopSLEdit, "BuyStopSL", pending3X, curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_buyStopSLEdit.Text("0.00000");
   pending4X = pending3X + EDIT_WIDTH + GAP;
   if(!CreateEdit(m_buyStopExpEdit, "BuyStopExp", pending4X, curY, 2*EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_buyStopExpEdit.Text(exp_default);
   curY += BUTTON_HEIGHT + GAP;
   
   // --- Sell Pending Orders ---
   // Sell Limit Order row:
   if(!CreateButton(m_sellLimitButton, "Sell Limit", curX, curY, BUTTON_WIDTH, BUTTON_HEIGHT, clrRed))
      return false;
   pendingX = curX + BUTTON_WIDTH + GAP;
   if(!CreateEdit(m_sellLimitPriceEdit, "SellLimitPrice", pendingX, curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   string bidStr = DoubleToString(SymbolInfoDouble(Symbol(), SYMBOL_BID), 5);
   m_sellLimitPriceEdit.Text(bidStr);
   pending2X = pendingX + EDIT_WIDTH + GAP;
   if(!CreateEdit(m_sellLimitTPEdit, "SellLimitTP", pending2X, curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_sellLimitTPEdit.Text("0.00000");
   pending3X = pending2X + EDIT_WIDTH + GAP;
   if(!CreateEdit(m_sellLimitSLEdit, "SellLimitSL", pending3X, curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_sellLimitSLEdit.Text("0.00000");
   pending4X = pending3X + EDIT_WIDTH + GAP;
   if(!CreateEdit(m_sellLimitExpEdit, "SellLimitExp", pending4X, curY, 2*EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_sellLimitExpEdit.Text(exp_default);
   curY += BUTTON_HEIGHT + GAP;
   
   // Sell Stop Order row:
   if(!CreateButton(m_sellStopButton, "Sell Stop", curX, curY, BUTTON_WIDTH, BUTTON_HEIGHT, clrRed))
      return false;
   pendingX = curX + BUTTON_WIDTH + GAP;
   if(!CreateEdit(m_sellStopPriceEdit, "SellStopPrice", pendingX, curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_sellStopPriceEdit.Text(bidStr);
   pending2X = pendingX + EDIT_WIDTH + GAP;
   if(!CreateEdit(m_sellStopTPEdit, "SellStopTP", pending2X, curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_sellStopTPEdit.Text("0.00000");
   pending3X = pending2X + EDIT_WIDTH + GAP;
   if(!CreateEdit(m_sellStopSLEdit, "SellStopSL", pending3X, curY, EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_sellStopSLEdit.Text("0.00000");
   pending4X = pending3X + EDIT_WIDTH + GAP;
   if(!CreateEdit(m_sellStopExpEdit, "SellStopExp", pending4X, curY, 2*EDIT_WIDTH, EDIT_HEIGHT))
      return false;
   m_sellStopExpEdit.Text(exp_default);
   curY += BUTTON_HEIGHT + GAP;
   
   // Section 3: All Order Operations
   if(!CreateLabelEx(m_secAllOpsLabel, curX, curY, DEFAULT_LABEL_HEIGHT, "SecAllOps", "All Order Operations:", clrBlack))
      return false;
   curY += DEFAULT_LABEL_HEIGHT + GAP;   
   
   int deleteX = curX + 2*BUTTON_WIDTH + 2*GAP; 
   int deleteY = curY  ;      
   CreateButton(m_closeAllButton, "Close All", curX, curY, BUTTON_WIDTH, BUTTON_HEIGHT, clrRed);
   CreateButton(m_closeProfitButton, "Close Profit", curX + BUTTON_WIDTH + GAP, curY, BUTTON_WIDTH, BUTTON_HEIGHT, clrGreen);
   CreateButton(m_deleteLimitOrdersButton, "Delete Limits", deleteX, curY, DELETE_BUTTON_WIDTH, BUTTON_HEIGHT, clrRed);
   curY += BUTTON_HEIGHT + GAP;
   
   CreateButton(m_closeLossButton, "Close Loss", curX, curY, BUTTON_WIDTH, BUTTON_HEIGHT, clrRed);
   CreateButton(m_closeBuyButton, "Close Buy", curX + BUTTON_WIDTH + GAP, curY, BUTTON_WIDTH, BUTTON_HEIGHT, clrGreen);
   CreateButton(m_deleteStopOrdersButton, "Delete Stops", deleteX, curY  , DELETE_BUTTON_WIDTH+10, BUTTON_HEIGHT, clrRed);
   CreateButton(m_resetButton, "Reset", deleteX+ 2*BUTTON_WIDTH-3*curX, curY, DELETE_BUTTON_WIDTH, 2*BUTTON_HEIGHT, clrRed);
   curY += BUTTON_HEIGHT + GAP;
   
   CreateButton(m_closeSellButton, "Close Sell", curX, curY, BUTTON_WIDTH, BUTTON_HEIGHT, clrBlue);
   CreateButton(m_deleteAllOrdersButton, "Delete All", curX + BUTTON_WIDTH + GAP, curY, BUTTON_WIDTH, BUTTON_HEIGHT, clrRed);
   CreateButton(m_deleteStopLimitOrdersButton, "Delete StopLimits", deleteX, curY , DELETE_BUTTON_WIDTH+10, BUTTON_HEIGHT, clrDarkRed);
   curY += BUTTON_HEIGHT + GAP;
  
   return true;
}

4. Automatisieren der Erstellung von UI-Controls mit Hilfsfunktionen

Die manuelle Platzierung jeder Schaltfläche und jedes Eingabefeldes würde den Code wiederholen und schwerer zu pflegen machen. Stattdessen schreiben wir Hilfsfunktionen, die das Erstellen, Positionieren und Gestalten von Steuerelementen übernehmen.

Durch die Zentralisierung dieser Logik bleibt der UI-Code übersichtlich. Wenn wir uns entscheiden, das Aussehen von Schaltflächen oder Beschriftungen zu ändern, müssen wir nur eine Funktion aktualisieren, anstatt Dutzende von Zeilen in der gesamten Codebasis zu ändern.

 //--- Helper: Create a text label using
   bool CreateLabelEx(CLabel &label, int x, int y, int height, string label_name, string text, color clr)
   {
      string unique_name = m_name + label_name;
      if(!label.Create(m_chart, unique_name, m_subwin, x, y, x, y+height))
         return false;
      if(!Add(label))
         return false;
      if(!label.Text(text))
         return false;
      label.Color(clr);
      return true;
   }
   
   //--- Helper: Create and add a button control
   bool CreateButton(CButton &button, string name, int x, int y, int w = BUTTON_WIDTH, int h = BUTTON_HEIGHT, color clr = clrWhite)
   {
      if(!button.Create(m_chart, name, m_subwin, x, y, x+w, y+h))
         return false;
      button.Text(name);
      button.Color(clr);
      if(!Add(button))
         return false;
      return true;
   }
   
   //--- Helper: Create and add an edit control
   bool CreateEdit(CEdit &edit, string name, int x, int y, int w = EDIT_WIDTH, int h = EDIT_HEIGHT)
   {
      if(!edit.Create(m_chart, name, m_subwin, x, y, x+w, y+h))
         return false;
      if(!Add(edit))
         return false;
      return true;
   }

5. Behandlung von Nutzerinteraktionen durch ein zentrales Ereignissystem

Sobald die Nutzeroberfläche eingerichtet ist, brauchen wir einen Weg, um Interaktionen zu handhaben. Anstatt jeder Taste eine eigene Funktion zuzuweisen, verwenden wir einen zentralen Event-Dispatcher.

Dieser Dispatcher lauscht auf Nutzeraktionen, bestimmt, welches Steuerelement das Ereignis ausgelöst hat, und ruft die entsprechende Funktion auf. So bleibt die Ereignisbehandlung sauber und übersichtlich. Wenn Sie auf eine Schaltfläche klicken, um einen Handel zu platzieren, werden die Eingabedaten an die Auftragsausführungslogik gesendet, während ein Klick auf die Schaltfläche „Zurücksetzen“ die Felder löscht.

//+------------------------------------------------------------------+
//| Event handler                                                    |
//+------------------------------------------------------------------+
bool CTradeManagementPanel::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   if(id == CHARTEVENT_OBJECT_CLICK)
   {
      if(sparam == m_buyButton.Name())            OnClickBuy();
      else if(sparam == m_sellButton.Name())        OnClickSell();
      else if(sparam == m_buyLimitButton.Name())    OnClickBuyLimit();
      else if(sparam == m_buyStopButton.Name())     OnClickBuyStop();
      else if(sparam == m_sellLimitButton.Name())   OnClickSellLimit();
      else if(sparam == m_sellStopButton.Name())    OnClickSellStop();
      else if(sparam == m_closeAllButton.Name())    OnClickCloseAll();
      else if(sparam == m_closeProfitButton.Name()) OnClickCloseProfit();
      else if(sparam == m_closeLossButton.Name())   OnClickCloseLoss();
      else if(sparam == m_closeBuyButton.Name())    OnClickCloseBuy();
      else if(sparam == m_closeSellButton.Name())   OnClickCloseSell();
      else if(sparam == m_deleteAllOrdersButton.Name())  OnClickDeleteAllOrders();
      else if(sparam == m_deleteLimitOrdersButton.Name()) OnClickDeleteLimitOrders();
      else if(sparam == m_deleteStopOrdersButton.Name())   OnClickDeleteStopOrders();
      else if(sparam == m_deleteStopLimitOrdersButton.Name()) OnClickDeleteStopLimitOrders();
      else if(sparam == m_resetButton.Name())       OnClickReset(); // Handle reset button click
   }
   return true;
}

6. Validierung und Ausführung von Market Orders

Bevor ein Handel ausgeführt wird, überprüft das System die Eingaben, um Fehler zu vermeiden. Es wird geprüft, ob das Handelsvolumen innerhalb akzeptabler Grenzen liegt und ob Stop-Loss und Take-Profit im Verhältnis zum Marktpreis richtig gesetzt sind.

Wenn die Eingabe gültig ist, bearbeitet das Handelsausführungsobjekt den Auftrag. Andernfalls warnt das System den Nutzer und verhindert, dass ein fehlerhafter Abschluss getätigt wird. Dieser Validierungsschritt ist entscheidend, um kostspielige Fehler zu vermeiden und sicherzustellen, dass das Panel zuverlässig funktioniert.

//+------------------------------------------------------------------+
//| Validate Buy order parameters (Market orders)                    |
//+------------------------------------------------------------------+
bool CTradeManagementPanel::ValidateBuyParameters(double volume, double tp, double sl, double ask)
{
   bool valid = true;
   m_tpErrorLabel.Text("");
   m_slErrorLabel.Text("");
   if(volume <= 0)
   {
      m_tpErrorLabel.Text("Invalid volume");
      m_tpErrorLabel.Color(clrRed);
      valid = false;
   }
   if(tp != 0 && tp <= ask)
   {
      m_tpErrorLabel.Text("Invalid TP");
      m_tpErrorLabel.Color(clrRed);
      valid = false;
   }
   if(sl != 0 && sl >= ask)
   {
      m_slErrorLabel.Text("Invalid SL");
      m_slErrorLabel.Color(clrRed);
      valid = false;
   }
   return valid;
}

//+------------------------------------------------------------------+
//| Validate Sell order parameters (Market orders)                   |
//+------------------------------------------------------------------+
bool CTradeManagementPanel::ValidateSellParameters(double volume, double tp, double sl, double bid)
{
   bool valid = true;
   m_tpErrorLabel.Text("");
   m_slErrorLabel.Text("");
   if(volume <= 0)
   {
      m_tpErrorLabel.Text("Invalid volume");
      m_tpErrorLabel.Color(clrRed);
      valid = false;
   }
   if(tp != 0 && tp >= bid)
   {
      m_tpErrorLabel.Text("Invalid TP");
      m_tpErrorLabel.Color(clrRed);
      valid = false;
   }
   if(sl != 0 && sl <= bid)
   {
      m_slErrorLabel.Text("Invalid SL");
      m_slErrorLabel.Color(clrRed);
      valid = false;
   }
   return valid;
}

7. Verwaltung schwebender Aufträge mit zusätzlichen Parametern

Schwebende Aufträge erfordern mehr Einstellungen als Marktaufträge. Die Nutzer müssen einen Einstiegskurs und eine Verfallszeit angeben, weshalb wir unsere Validierungsfunktionen erweitern, um diese Eingaben zu verarbeiten.

Eine Hilfsfunktion interpretiert die Ablaufeinstellungen, ob der Nutzer eine feste Zeit oder eine Option „Good Till Canceled“ wünscht. Diese Struktur stellt sicher, dass anhängige Aufträge vor ihrer Übermittlung den richtigen Regeln folgen.

//+------------------------------------------------------------------+
//| Helper: Parse expiration input                                   |
//+------------------------------------------------------------------+
void ParseExpiration(string sExp, ENUM_ORDER_TYPE_TIME &type_time, datetime &expiration)
{
   if(StringCompare(StringToUpper(sExp), "GTC") == 0)
   {
      type_time = ORDER_TIME_GTC;
      expiration = 0;
   }
   else
   {
      type_time = ORDER_TIME_SPECIFIED;
      expiration = StringToTime(sExp);
   }
}

//+------------------------------------------------------------------+
//| Button click handlers - Pending Orders                           |
//+------------------------------------------------------------------+
void CTradeManagementPanel::OnClickBuyLimit()
{
   double price  = StringToDouble(m_buyLimitPriceEdit.Text());
   double tp     = StringToDouble(m_buyLimitTPEdit.Text());
   double sl     = StringToDouble(m_buyLimitSLEdit.Text());
   double volume = StringToDouble(m_volumeEdit.Text());
   string sExp   = m_buyLimitExpEdit.Text();
   ENUM_ORDER_TYPE_TIME type_time;
   datetime expiration;
   ParseExpiration(sExp, type_time, expiration);
   m_trade.BuyLimit(volume, price, Symbol(), sl, tp, type_time, expiration, "");
}

void CTradeManagementPanel::OnClickBuyStop()
{
   double price  = StringToDouble(m_buyStopPriceEdit.Text());
   double tp     = StringToDouble(m_buyStopTPEdit.Text());
   double sl     = StringToDouble(m_buyStopSLEdit.Text());
   double volume = StringToDouble(m_volumeEdit.Text());
   string sExp   = m_buyStopExpEdit.Text();
   ENUM_ORDER_TYPE_TIME type_time;
   datetime expiration;
   ParseExpiration(sExp, type_time, expiration);
   m_trade.BuyStop(volume, price, Symbol(), sl, tp, type_time, expiration, "");
}

void CTradeManagementPanel::OnClickSellLimit()
{
   double price  = StringToDouble(m_sellLimitPriceEdit.Text());
   double tp     = StringToDouble(m_sellLimitTPEdit.Text());
   double sl     = StringToDouble(m_sellLimitSLEdit.Text());
   double volume = StringToDouble(m_volumeEdit.Text());
   string sExp   = m_sellLimitExpEdit.Text();
   ENUM_ORDER_TYPE_TIME type_time;
   datetime expiration;
   ParseExpiration(sExp, type_time, expiration);
   m_trade.SellLimit(volume, price, Symbol(), sl, tp, type_time, expiration, "");
}

void CTradeManagementPanel::OnClickSellStop()
{
   double price  = StringToDouble(m_sellStopPriceEdit.Text());
   double tp     = StringToDouble(m_sellStopTPEdit.Text());
   double sl     = StringToDouble(m_sellStopSLEdit.Text());
   double volume = StringToDouble(m_volumeEdit.Text());
   string sExp   = m_sellStopExpEdit.Text();
   ENUM_ORDER_TYPE_TIME type_time;
   datetime expiration;
   ParseExpiration(sExp, type_time, expiration);
   m_trade.SellStop(volume, price, Symbol(), sl, tp, type_time, expiration, "");
}

8. Implementierung von Großaufträgen für ein effizientes Handelsmanagement

Die manuelle Verwaltung mehrerer Handelsgeschäfte kann mühsam sein. Deshalb haben wir Funktionen eingebaut, die es den Nutzern ermöglichen, Aktionen auf mehrere Aufträge gleichzeitig anzuwenden.

Die Nutzer können alle Handelsgeschäfte oder nur die mit Gewinn oder die mit Verlust schließen oder die schwebenden Aufträge löschen. Die Ereignisbehandlungsprogramme für diese Aktionen durchlaufen die offenen Positionen und wenden die gewünschte Operation effizient an. Das macht die Verwaltung mehrerer Aufträge viel schneller und einfacher.

//+------------------------------------------------------------------+
//| Button click handlers - All Order Operations                     |
//+------------------------------------------------------------------+
void CTradeManagementPanel::OnClickCloseAll()
{
   for(int i = PositionsTotal()-1; i >= 0; i--)
      m_trade.PositionClose(PositionGetTicket(i));
}

void CTradeManagementPanel::OnClickCloseProfit()
{
   for(int i = PositionsTotal()-1; i >= 0; i--)
      if(PositionGetDouble(POSITION_PROFIT) > 0)
         m_trade.PositionClose(PositionGetTicket(i));
}

void CTradeManagementPanel::OnClickCloseLoss()
{
   for(int i = PositionsTotal()-1; i >= 0; i--)
      if(PositionGetDouble(POSITION_PROFIT) < 0)
         m_trade.PositionClose(PositionGetTicket(i));
}

void CTradeManagementPanel::OnClickCloseBuy()
{
   for(int i = PositionsTotal()-1; i >= 0; i--)
      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
         m_trade.PositionClose(PositionGetTicket(i));
}

void CTradeManagementPanel::OnClickCloseSell()
{
   for(int i = PositionsTotal()-1; i >= 0; i--)
      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
         m_trade.PositionClose(PositionGetTicket(i));
}

void CTradeManagementPanel::OnClickDeleteAllOrders()
{
   for(int i = OrdersTotal()-1; i >= 0; i--)
      m_trade.OrderDelete(OrderGetTicket(i));
}

void CTradeManagementPanel::OnClickDeleteLimitOrders()
{
   for(int i = OrdersTotal()-1; i >= 0; i--)
      if(OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_BUY_LIMIT ||
         OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_SELL_LIMIT)
         m_trade.OrderDelete(OrderGetTicket(i));
}

void CTradeManagementPanel::OnClickDeleteStopOrders()
{
   for(int i = OrdersTotal()-1; i >= 0; i--)
      if(OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_BUY_STOP ||
         OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_SELL_STOP)
         m_trade.OrderDelete(OrderGetTicket(i));
}

void CTradeManagementPanel::OnClickDeleteStopLimitOrders()
{
   for(int i = OrdersTotal()-1; i >= 0; i--)
      if(OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_BUY_STOP_LIMIT ||
         OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_SELL_STOP_LIMIT)
         m_trade.OrderDelete(OrderGetTicket(i));
}

9. Hinzufügen von Reset- und Sichtbarkeitssteuerungen für bessere Nutzerfreundlichkeit

Um die Nutzerfreundlichkeit zu verbessern, haben wir zwei kleine, aber nützliche Funktionen hinzugefügt. Die erste ist eine Reset-Schaltfläche, die alle Eingabefelder löscht und das Panel in den Standardzustand zurückversetzt. Dies ist hilfreich, wenn Nutzer nach Änderungen wieder von vorne beginnen möchten.

Die zweite Funktion ist ein Umschalter für die Sichtbarkeit, mit dem der Nutzer das Panel ein- oder ausblenden kann. Auf diese Weise bleibt der Arbeitsbereich übersichtlich und das Bedienfeld ist dennoch leicht zugänglich, wenn es benötigt wird.

//+------------------------------------------------------------------+
//| Reset all input fields to default values                         |
//+------------------------------------------------------------------+
void CTradeManagementPanel::OnClickReset()
{
   // Reset volume to minimum allowed
   double minVolume = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
   m_volumeEdit.Text(DoubleToString(minVolume, 2));

   // Reset TP and SL for market orders
   m_tpEdit.Text("0.00000");
   m_slEdit.Text("0.00000");

   // Reset pending order prices to current ASK/BID
   double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
   double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
   m_buyLimitPriceEdit.Text(DoubleToString(ask, 5));
   m_buyStopPriceEdit.Text(DoubleToString(ask, 5));
   m_sellLimitPriceEdit.Text(DoubleToString(bid, 5));
   m_sellStopPriceEdit.Text(DoubleToString(bid, 5));

   // Reset pending order TP/SL to 0
   m_buyLimitTPEdit.Text("0.00000");
   m_buyLimitSLEdit.Text("0.00000");
   m_buyStopTPEdit.Text("0.00000");
   m_buyStopSLEdit.Text("0.00000");
   m_sellLimitTPEdit.Text("0.00000");
   m_sellLimitSLEdit.Text("0.00000");
   m_sellStopTPEdit.Text("0.00000");
   m_sellStopSLEdit.Text("0.00000");

   // Reset expiration dates to current day's end
   datetime now = TimeCurrent();
   string exp_default = TimeToString(now, TIME_DATE) + " 23:59:59";
   m_buyLimitExpEdit.Text(exp_default);
   m_buyStopExpEdit.Text(exp_default);
   m_sellLimitExpEdit.Text(exp_default);
   m_sellStopExpEdit.Text(exp_default);

   // Clear error messages
   m_tpErrorLabel.Text("");
   m_slErrorLabel.Text("");
}

Ich habe den vollständigen Quellcode unter diesem Artikel angehängt, den Sie herunterladen können. Im nächsten Abschnitt werde ich Sie Schritt für Schritt durch die Integration der Klasse „Trade Management Panel“ in das Hauptprogramm führen.


Integration mit (New_Admin_Panel)

1. Einbinden des Trade Management-Kopfes in das New_Admin_Panel-System

Zuerst binden wir das TradeManagementPanel ein, indem wir seine Header-Datei einbeziehen. Damit ist alles, was wir für die Handelsausführung und -verwaltung benötigen, in unserem Verwaltungsbereich verfügbar. Einfach, aber wichtig.

#include <TradeManagementPanel.mqh>

2. Einrichten einer Trade Panel-Instanz

Das Handelsfeld muss im gesamten EA zugänglich sein, daher definieren wir es als globalen Zeiger. Auf diese Weise können wir überprüfen, ob sie bereits erstellt wurde, und bei Bedarf mit ihr interagieren.

CTradeManagementPanel  *g_tradePanel = NULL;

3. Hinzufügen einer Schaltfläche für die Handelsverwaltung

Die Nutzer müssen die Möglichkeit haben, das Handelsforum zu öffnen, daher haben wir eine spezielle Schaltfläche in das Admin-Home-Panel eingefügt. Wir verwenden eine Hilfsfunktion, um ein einheitliches Layout und Styling zu gewährleisten. Diese Schaltfläche befindet sich direkt auf der Nutzeroberfläche und ist bereit, das Handelspanel zu starten, wenn sie angeklickt wird.

CButton g_tradeMgmtButton;

4. Das Handelspanel anklickbar machen

Und jetzt wird es interessant. Wir haben eine Funktion geschaffen, die den Lebenszyklus des Handelspanels verwaltet.

  1. Wenn das Handelspanel nicht existiert, erstellen wir es.
  2. Wenn sie bereits vorhanden ist, schalten wir sie einfach ein oder aus.

void HandleTradeManagement()
{
   if(g_tradePanel == NULL)
   {
      g_tradePanel = new CTradeManagementPanel();
      if(!g_tradePanel.Create(g_chart_id, "TradeManagementPanel", g_subwin, 310, 20, 310+565, 20+510))
      {
         delete g_tradePanel;
         g_tradePanel = NULL;
         Print("Failed to create Trade Management Panel");
         return;
      }
   }
   g_tradePanel.Toggle();
   ChartRedraw();
}

Mit dieser Einrichtung erhalten die Nutzer mit einem Mausklick sofortigen Zugang zum Handelsmanagement.

5. Einbindung der Handelsverwaltung in Veranstaltungen

Als Nächstes stellen wir sicher, dass das Trade Panel auf Nutzeraktionen reagiert. Innerhalb der Ereignisbehandlung leiten wir die Interaktionen an das Panel weiter, wenn es geöffnet ist. Dadurch wird sichergestellt, dass das Panel in Echtzeit reagiert, sei es bei der Ausführung von Aufträgen, der Anpassung von Stop-Loss oder der Schließung von Handelsgeschäften.

if(g_tradePanel != NULL && g_tradePanel.IsVisible())
   return g_tradePanel.OnEvent(id, lparam, dparam, sparam);

6. Aufräumen, wenn der EA herunterfährt

Wenn der EA entfernt wird, müssen wir Speicher freigeben und Lecks verhindern. Das bedeutet, dass das Handelspanel ordnungsgemäß vernichtet werden muss. 

if(g_tradePanel != NULL)
{
   g_tradePanel.Destroy(reason);
   delete g_tradePanel;
   g_tradePanel = NULL;
}

Keine übrig gebliebenen Instanzen. Keine Verschwendung von Ressourcen. Einfach ein sauberes Herunterfahren. Die vollständige Quelldatei für das New_Admin_Panel ist unten zum Download angehängt. Sie können dasselbe Verfahren mit ein paar Änderungen anwenden, um das Trade Management Panel in Ihre eigenen Projekte zu integrieren. Im nächsten Abschnitt werden wir die Testergebnisse vorstellen.


Tests

Nachdem ich den Code erfolgreich kompiliert hatte, startete ich ihn auf der Plattform MetaTrader 5. Die folgenden Abbildungen zeigen die erfolgreiche Einrichtung des Trade Management Panels über das Admin Home Panel. Über das Home-Panel können wir das Handelsmanagement-Panel ein- und ausschalten, sodass wir bei Bedarf den Chart vollständig anzeigen können. Wenn das Handelsmanagement-Panel aktiv ist, können wir seine Steuerelemente direkt auf dem Chart bedienen, während wir weiterhin die Kursentwicklung beobachten - ein Vorteil für den Scalp-Handel. Siehe das Bild unten.

Verwendung des Trade Management Panels


Schlussfolgerung

Die Entwicklung der Klasse Trade Management Panel ist ein weiterer Meilenstein bei der Anwendung der Modularisierung, um unseren Code effektiv zu strukturieren und große Programmkomponenten projektübergreifend wiederverwendbar zu machen. Wie wir bereits erwähnt haben, bietet dieser Ansatz zahlreiche Vorteile. Wir sind den Entwicklungsprozess Schritt für Schritt durchgegangen und haben gezeigt, wie er abläuft, und ich bin sicher, dass es wertvolle Hinweise gibt, die man mitnehmen kann.

Ich erhebe nicht den Anspruch, in diesem Bereich perfekt zu sein - ich lerne und verbessere mich ständig. Vielleicht gibt es Fehler, die die Erfahreneren erkennen können, und ich freue mich über konstruktives Feedback in den Kommentaren, damit alle davon profitieren. Ich schätze die Vorteile, die dieses Panel denjenigen bietet, die es nützlich finden.

Ich möchte auch Omega J Msigwa für seinen Beitrag zur Codebase mit dem Quellcode des Informative Dashboard danken, der während der Entwicklung hilfreiche Einblicke lieferte. Zögern Sie nicht, den beigefügten Code zu erweitern und zu ändern, um Ihre MQL5-Kenntnisse zu verbessern und noch leistungsfähigere Tools zu erstellen.

Datei Beschreibung
TradeManagementPanel.mqh Quellcode des Headers der Klasse, die eine grafische Schnittstelle für die effiziente Ausführung, Verwaltung und Änderung von Handelsgeschäften innerhalb des New_Admin_Panel EA bereitstellt. Er kann auch mit anderen EAs integriert werden.
Neues_Admin_Panel.mq5 Der Quellcode des New_Admin_Panel EA dient als zentrale Schnittstelle für die Verwaltung von Handelsausführung, Kommunikation, Analysen und anderen administrativen Funktionen, wenn er für die Ausführung innerhalb der Handelsplattform kompiliert wird.

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/17396

Beigefügte Dateien |
New_Admin_Panel.mq5 (17.12 KB)
Automatisieren von Handelsstrategien in MQL5 (Teil 12): Umsetzung der Strategie der Mitigation Order Blocks (MOB) Automatisieren von Handelsstrategien in MQL5 (Teil 12): Umsetzung der Strategie der Mitigation Order Blocks (MOB)
In diesem Artikel bauen wir ein MQL5-Handelssystem auf, das die Orderblock-Erkennung für den Handel des Smart Money automatisiert. Wir skizzieren die Regeln der Strategie, implementieren die Logik in MQL5 und integrieren das Risikomanagement für eine effektive Handelsausführung. Schließlich führen wir Backtests durch, um die Leistung des Systems zu bewerten und es für optimale Ergebnisse zu verfeinern.
Resampling-Techniken für die Bewertung von Vorhersagen und Klassifizierungen in MQL5 Resampling-Techniken für die Bewertung von Vorhersagen und Klassifizierungen in MQL5
In diesem Artikel werden wir Methoden zur Bewertung der Modellqualität erforschen und implementieren, die einen einzigen Datensatz sowohl als Trainings- als auch als Validierungssatz verwenden.
Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 19): ZigZag Analyzer Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 19): ZigZag Analyzer
Jeder, der Preisaktionen handelt, verwendet Trendlinien manuell, um Trends zu bestätigen und potenzielle Wende- oder Fortsetzungsniveaus zu erkennen. In dieser Serie über die Entwicklung eines Preisaktionsanalyse-Toolkits stellen wir ein Tool vor, das sich auf das Zeichnen von schrägen Trendlinien zur einfachen Marktanalyse konzentriert. Dieses Tool vereinfacht den Prozess für Händler, indem es die wichtigsten Trends und Niveaus, die für eine wirksame Bewertung der Preisaktionen unerlässlich sind, klar umreißt.
Erweiterte Speicherverwaltung und Optimierungstechniken in MQL5 Erweiterte Speicherverwaltung und Optimierungstechniken in MQL5
Entdecken Sie praktische Techniken zur Optimierung der Speichernutzung in MQL5-Handelssystemen. Lernen Sie, effiziente, stabile und schnell arbeitende Expert Advisors und Indikatoren zu erstellen. Wir werden untersuchen, wie der Speicher in MQL5 wirklich funktioniert, die häufigsten Fallen, die Ihre Systeme verlangsamen oder zum Ausfall führen, und - was am wichtigsten ist - wie man sie beheben kann.