English Русский 日本語
preview
Vom Neuling zum Experten: Animierte Nachrichtenüberschrift mit MQL5 (IX) – Verwaltung mehrerer Symbole in einem einzigen Chart für den Nachrichtenhandel

Vom Neuling zum Experten: Animierte Nachrichtenüberschrift mit MQL5 (IX) – Verwaltung mehrerer Symbole in einem einzigen Chart für den Nachrichtenhandel

MetaTrader 5Beispiele |
145 2
Clemence Benjamin
Clemence Benjamin

Inhalt


Einführung

In Zeiten hoher Volatilität – z. B. bei der Veröffentlichung von Wirtschaftsnachrichten – setzen Händler häufig auf Ausbrüche, da die unmittelbare Reaktion des Marktes nicht vorhersehbar ist. Wenn eine wichtige Nachricht veröffentlicht wird, steigt der Kurs in der Regel stark an, gefolgt von Korrekturen und möglichen Trendfortsetzungen. Unter diesen Umständen möchten Händler vielleicht mit mehreren Symbolen gleichzeitig handeln, aber das ist mit dem Standard-Setup von MetaTrader 5 nur schwer zu erreichen. Ein einzelnes Chart unterstützt nur einen Expert Advisor, d. h. Händler müssen mehrere Charts öffnen und jedem Symbol einen eigenen EA zuordnen.

In der heutigen Diskussion stellen wir eine Lösung für diese Einschränkung vor, eine Multi-Symbol-Handelsfunktion, die in den News Headline EA integriert ist. Mit dieser Verbesserung können Händler mehrere Paare von einem einzigen Chart aus über intuitive Handelsschaltflächen verwalten. Wir werden erforschen, wie die Leistungsfähigkeit von MQL5, die sowohl die Standardbibliothek als auch nutzerdefinierte Handelsklassen nutzt, die Erstellung eines ausgeklügelten EAs ermöglicht, der in der Lage ist, mehrere Symbole nahtlos in einem Chart zu verarbeiten.

Eine Expert Advisor-Unterstützung pro Paar.

Abb. 1: Es ist nur ein EA pro Chart auf dem MetaTrader 5-Terminal erlaubt

Das obige Bild veranschaulicht die Beschränkung des MetaTrader 5-Setups, bei dem nur ein EA auf einem einzigen Chart laufen kann. Um effektiv mit mehreren Symbolen handeln zu können, benötigen wir einen ausgeklügelten EA, der sowohl das aktuelle Chartpaar als auch andere Paare gleichzeitig verwalten kann – selbst wenn er nur von einem Chart aus operiert.

Am Ende dieser Diskussion wollen wir Folgendes erreichen:

  • Entwicklung eines anspruchsvolleren EA.
  • Erweitern einer bestehende MQL5-Header-Klasse mit neuen Funktionen.
  • Nutzen der MQL5-Standardbibliothek, um neue Klassen zu erstellen.
  • Integrieren von neuen Funktionen in einen bestehenden EA.
  • Modularisierung und strukturierte Gruppierung von Eingaben.


Das Konzept verstehen

Diese Phase beginnt mit einem kurzen Überblick über unsere bisherige Arbeit. Wir begannen mit einem einfachen EA für animierte Schlagzeilen, der Daten aus dem Wirtschaftskalender und externen Nachrichten-APIs wie Alpha Vantage abruft. Im Laufe der Zeit haben wir lokal gehostete KI-Modelle, automatisierte Strategien des Nachrichtenhandels und manuelle Handelsschaltflächen integriert, um den EA noch zuverlässiger zu machen.

Diese Neuerungen verbesserten zwar das System, stellten aber keine vollständige Lösung dar. Der algorithmische Handel entwickelt sich ständig weiter, und mit jedem technologischen Fortschritt tauchen neue Herausforderungen auf, die uns dazu veranlassen, unsere Systeme zu verbessern. Heute befassen wir uns mit einer dieser Herausforderungen: den Handel mit mehreren Paaren innerhalb desselben EA zu ermöglichen.

Warum ist das notwendig?

Eine berechtigte Frage, die man sich stellen könnte, lautet: Warum brauchen wir diese Funktion?

Bei Ereignissen mit hoher Volatilität, wie z. B. der Veröffentlichung von Wirtschaftsnachrichten, müssen Händler schnell reagieren und oft mehrere Positionen und Symbole innerhalb von Sekunden verwalten. Diese Entwicklung bietet einen entscheidenden Vorteil, da sie den algorithmischen und den manuellen Handel an einem Ort zusammenführt und so die Effizienz und Kontrolle verbessert. Mit einem Mausklick kann ein Händler Handelsgeschäfte über mehrere Symbole hinweg platzieren und mehrere Positionen gleichzeitig verwalten – und dabei sowohl an Geschwindigkeit als auch an Leistungseffizienz gewinnen.

Prozess der Funktionsintegration

Vor diesem Hintergrund wollen wir kurz skizzieren, wie die neue Funktion hinzugefügt werden soll. Um unseren EA zu erweitern, setzen wir auf die Einbindung von Headern und nutzerdefinierten Schaltflächenklassen, die die Hauptcodebasis sauber und modular halten.

Für den Multi-Symbol-Handel benötigen wir die Möglichkeit, die gewünschten Paare auszuwählen, die neben dem Paar des aktuellen Charts ausgeführt werden, wenn manuelle Handelsschaltflächen gedrückt werden. Um dies zu erreichen, werden wir die Klassen CCheckBox und CLabel aus der MQL5-Standardbibliothek verwenden. Diese Komponenten ermöglichen es uns, auswählbare Paare anzuzeigen, Nutzereingaben zu verwalten und Auswahlen direkt mit den Ereignisbehandlern der Schaltflächen zu verknüpfen.

Schließlich wird unsere Klasse CTradingButtons erweitert, um diese neuen Funktionen nahtlos zu integrieren.


Umsetzung

Wir werden dies in zwei Hauptphasen angehen. Zunächst werden wir die Klasse CTradingButtons im Header von TradingButtons modifizieren, um die in unserem Entwurf beschriebenen Multi-Symbol-Handelsfunktionen zu implementieren. In der zweiten Phase wird der Schwerpunkt auf der Anpassung des News Headline EA liegen, um diese neuen Möglichkeiten zu unterstützen.

Folgen Sie uns aufmerksam, wenn wir den Code aufschlüsseln und erklären, wie jeder Teil dazu beiträgt, die Idee zum Leben zu erwecken. Der Übersichtlichkeit halber werden die einzelnen Codeabschnitte und ihre Erläuterungen von oben nach unten durchnummeriert, wobei der Schwerpunkt auf den neuen Funktionen liegt.

Wenn Sie sich mit den grundlegenden Teilen des Codes befassen möchten, empfehle ich Ihnen, frühere Veröffentlichungen in dieser Reihe zu lesen, in denen wir die ersten Versionen im Detail behandelt haben.


Modifizierung der Klasse CtradingButtons für den Handel mit mehreren Symbolen

Wir haben diesen Header bereits in einem früheren Artikel vorgestellt, den Sie zur Verdeutlichung nachlesen können. In diesem Abschnitt erweitern wir es um eine neue Funktion.

Übersicht auf hoher Ebene

Diese Klasse (CTradingButtons) bündelt drei Verantwortlichkeiten, sodass sie als kompaktes Multipair-Handelsmodul fungiert, das Sie in einen EA einfügen können: (1) eine Nutzeroberfläche (Canvas + Schaltflächen + dynamisch erstellte Kontrollkästchen für Symbole), (2) einen kleinen Trade Wrapper (eine CTrade-Instanz, die Aufträge sendet) und (3) eine Symbolauflösungs- und Multipair-Engine (ordnet angeforderte Basisnamen wie EURUSD den Brokersymbolen zu und wendet Aktionen auf alle ausgewählten Symbole an). Der High-Level-Entwurf hält die Indexausrichtung über Arrays hinweg aufrecht: die angeforderte Liste (was der EA übergibt), die aufgelösten Brokersymbole (was das Terminal tatsächlich handelt) und die Kontrollkästchen (was der Nutzer umschaltet) – Index i repräsentiert dasselbe Paar in allen Arrays. Dies macht die Verdrahtung von UI → EA-Auswahlfeldern einfach und vorhersehbar. 

// top-of-file: class skeleton + key members (from TradingButtons.mqh)

class CTradingButtons

{

private:

   // UI & buttons
   CButton btnMultiToggle;
   CButton btnBuy, btnSell, btnCloseAll, btnDeleteOrders, btnCloseProfit, btnCloseLoss, btnBuyStop, btnSellStop;
   CCanvas buttonPanel;

   // trading

   CTrade  trade;

   // multipair UI & resolution

   CCheckBox *pairChecks[];      // dynamic checkbox pointers, index-aligned with requested list
   string     availablePairs[];  // resolved broker symbols (index-aligned)
   string     resolvedBases[];   // original requested bases (for logging)
   bool       multiEnabled;
public:

   double LotSize;
   int    StopLoss;
   int    TakeProfit;
   int    StopOrderDistancePips;
   double RiskRewardRatio;
   CTradingButtons() { /* default init inlined in full file */ }
   void Init();
   void Deinit();
   // ... other methods follow

};

Felder & Konstruktor – was die Klasse speichert

Die Klasse speichert Layout-Parameter (Breite/Höhe/Abstand der Schaltflächen), die Größe der Kontrollkästchen und die Startkoordinaten, das dynamische Kontrollkästchen-Array, die aufgelösten Symbol-Arrays und die Handelskonfiguration (Losgröße, Stopps, Risiko/Ertrag). Sein Konstruktor setzt sinnvolle Standardwerte (z.B. LotSize=0.01, StopLoss=50, TakeProfit=100, multiEnabled=true), sodass der EA mit einer funktionierenden Konfiguration starten und später überschreiben kann, was er braucht. Die Beibehaltung dieser Felder als öffentlich (für Handelsparameter) und privat (für UI-Interna) hält die Schnittstelle einfach und sicher. 

// constructor + key field defaults (actual defaults in your file)

CTradingButtons() :
   buttonWidth(100), buttonHeight(30), buttonSpacing(10),
   checkWidth(120), checkHeight(20), checkSpacing(6), checkStartX(10),
   LotSize(0.01), StopLoss(50), TakeProfit(100),
   StopOrderDistancePips(8), RiskRewardRatio(2.0),
   multiEnabled(true)

{

   // constructor body intentionally minimal — Init() performs heavier setup

}

Initialisierung und Bereinigung

Init() konfiguriert den CTrade-Wrapper (magische Zahl, Abweichung) und baut die Nutzeroberfläche auf (Panel, Schaltflächen, Multi-Toggle). Deinit() zerstört sorgfältig alle dynamischen Objekte (Kontrollkästchen, Schaltflächen, Leinwand) und gibt Arrays frei, um verwaiste Chart-Objekte oder Speicherlecks zu vermeiden. Das Cleanup durchläuft das Array pairChecks[] in einer Schleife und ruft Destroy() und delete für dynamische Zeiger auf. Anschließend wird das Array wieder freigegeben – ein kritischer Punkt, wenn der EA während der Entwicklung wiederholt ausgeführt und entladen wird. 

// Init & Deinit excerpt

void Init()

{
   trade.SetExpertMagicNumber(123456);
   trade.SetDeviationInPoints(10);
   CreateButtonPanel();
   CreateButtons();
   CreateMultiToggle();
   UpdateMultiToggleVisual();

}

void Deinit()

{
   // destroy checkboxes
   for(int i = 0; i < ArraySize(pairChecks); i++)

   {
      if(CheckPointer(pairChecks[i]) == POINTER_DYNAMIC)
         pairChecks[i].Destroy();
         delete pairChecks[i];
      }
   }
   ArrayFree(pairChecks);

   // destroy buttons and panel
   btnMultiToggle.Destroy();
   btnBuy.Destroy();
   btnSell.Destroy();
   btnCloseAll.Destroy();
   btnDeleteOrders.Destroy();
   btnCloseProfit.Destroy();
   btnCloseLoss.Destroy();
   btnBuyStop.Destroy();
   btnSellStop.Destroy();
   buttonPanel.Destroy();
   ObjectDelete(0, "ButtonPanel");

}

Symbolauflösung (wichtig für Multipair)

Um einen „freundlichen“ Namen wie EURUSD zu handeln, muss der EA ihn auf den genauen Symbolstring des Brokers abbilden (z. B. EURUSD, EURUSD.ecn, FX.EURUSD, usw.). ResolveSymbol(base) versucht zunächst eine exakte Übereinstimmung (schneller Pfad). Schlägt dies fehl, werden alle Terminalsymbole in einer Schleife durchlaufen, es wird nach „starts-with“ und „contains“ gesucht (wobei „starts-with“ bevorzugt wird), und deaktivierte Symbole werden ausgeschlossen. Dieser Auflösungsschritt erzeugt availablePairs[i]-Einträge, die von Handelsroutinen und UI-Kontrollkästchen verwendet werden – es ist die Verbindung zwischen den vom EA angeforderten Namen und den tatsächlich handelbaren Symbolen des Brokers. 

// ResolveSymbol implementation (exact + starts-with + contains search)

string ResolveSymbol(const string base)

{
   if(StringLen(base) == 0) return("");
   // 1) Try exact symbol name first
   string baseName = base;
   if(SymbolInfoInteger(baseName, SYMBOL_SELECT) != 0 || SymbolSelect(baseName, false))
   {
      if(SymbolInfoInteger(baseName, SYMBOL_TRADE_MODE) != SYMBOL_TRADE_MODE_DISABLED)

      {
         PrintFormat("ResolveSymbol: exact match found %s", baseName);

         return(baseName);
      }
   }

   // 2) search all terminal symbols

   int total = SymbolsTotal(false);
   string base_u = base; StringToUpper(base_u);
   string firstStarts = ""; string firstContains = "";

   for(int i = 0; i < total; i++)

   {
      string sym = SymbolName(i, false);
      string sym_u = sym; StringToUpper(sym_u);
      if(sym_u == base_u) continue;
      if(SymbolInfoInteger(sym, SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_DISABLED) continue;
      if(StringFind(sym_u, base_u) == 0)
      {
         if(firstStarts == "") firstStarts = sym;
      }
      else if(StringFind(sym_u, base_u) >= 0)

      {
         if(firstContains == "") firstContains = sym;
      }
   }

   if(firstStarts != "") { PrintFormat("ResolveSymbol: resolved %s -> %s (starts-with)", base, firstStarts); return(firstStarts); }
   if(firstContains != "") { PrintFormat("ResolveSymbol: resolved %s -> %s (contains)", base, firstContains); return(firstContains); }
   PrintFormat("ResolveSymbol: no match for %s", base);
   return("");
}

Erstellen der Multipaar-Nutzeroberfläche – CreatePairCheckboxes(...)

CreatePairCheckboxes(inMajorPairs[], inPairSelected[], yPos) ist die Routine, die: (a) jede angeforderte Basis in ein Maklersymbol auflöst, (b) sicherstellt, dass das Symbol in der Marktübersicht (SymbolSelect) vorhanden und handelbar ist, und (c) dynamisch eine CCheckBox für jedes aufgelöste Symbol erstellt, wobei die Indexausrichtung mit den Arrays des EA erhalten bleibt. Nicht aufgelöste oder deaktivierte Einträge werden als Platzhalter beibehalten, sodass availablePairs[i] korrekt auf das Original inMajorPairs[i] abgebildet wird. Der anfängliche Aktivierungsstatus für jedes erstellte Kontrollkästchen wird von inPairSelected[i] übernommen, sodass die UI- und EA-Auswahl-Arrays von Anfang an synchronisiert sind. 

// CreatePairCheckboxes: resolve requested bases -> create checkboxes aligned by index

void CreatePairCheckboxes(string &inMajorPairs[], bool &inPairSelected[], int yPos)

{
   // cleanup previous

   for(int i = 0; i < ArraySize(pairChecks); i++)

   {
      if(CheckPointer(pairChecks[i]) == POINTER_DYNAMIC)
      {
         pairChecks[i].Destroy();
         delete pairChecks[i];
      }
   }

   ArrayFree(pairChecks);
   ArrayResize(availablePairs, ArraySize(inMajorPairs));
   ArrayResize(resolvedBases, ArraySize(inMajorPairs));
   for(int k = 0; k < ArraySize(availablePairs); k++) { availablePairs[k] = ""; resolvedBases[k] = ""; }
   int count = ArraySize(inMajorPairs);
   if(count == 0) return;

   // Resolve each requested base

   for(int i = 0; i < count; i++)
   {
      string requested = inMajorPairs[i];
      string resolved = ResolveSymbol(requested);
      if(resolved == "")
      {
         PrintFormat("CreatePairCheckboxes: could not resolve %s -> skipping checkbox", requested);
         availablePairs[i] = "";
         resolvedBases[i] = requested;
         continue;
      }
      if(!SymbolSelect(resolved, true))
         PrintFormat("CreatePairCheckboxes: SymbolSelect failed for %s (from %s) Err=%d", resolved, requested, GetLastError());
      if(SymbolInfoInteger(resolved, SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_DISABLED)
      {
         PrintFormat("CreatePairCheckboxes: resolved symbol %s is disabled (from %s) - skipping", resolved, requested);
         availablePairs[i] = "";
         resolvedBases[i] = requested;
         continue;
      }
      availablePairs[i] = resolved;
      resolvedBases[i] = requested;
   }

   // Create checkbox controls (preserve index alignment)

   ArrayResize(pairChecks, count);
   int xPos = checkStartX;
   int chartW = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
   int wrapX = chartW - (buttonWidth * 3) - 30;
   for(int i = 0; i < count; i++)
   {
      if(StringLen(availablePairs[i]) == 0) { pairChecks[i] = NULL; continue; }
      pairChecks[i] = new CCheckBox();
      string objName = "Chk_" + availablePairs[i];
      if(!pairChecks[i].Create(ChartID(), objName, 0, xPos, yPos, xPos + checkWidth, yPos + checkHeight))
      {

         PrintFormat("CreatePairCheckboxes: failed to create checkbox %s Err=%d", objName, GetLastError());
         delete pairChecks[i];
         pairChecks[i] = NULL;
         availablePairs[i] = "";
         continue;
      }
      pairChecks[i].Text(" " + availablePairs[i]);
      pairChecks[i].Color(clrBlack);
      bool checked = false;
      if(i < ArraySize(inPairSelected)) checked = inPairSelected[i];
      pairChecks[i].Checked(checked);
      xPos += checkWidth + checkSpacing;
      if(xPos + checkWidth > wrapX) { xPos = checkStartX; yPos += checkHeight + checkSpacing; }
   }

   ChartRedraw();
   PrintFormat("CreatePairCheckboxes: created checkboxes (resolved count=%d)", CountResolvedPairs());
}

Zählung/Hilfsmittel – CountResolvedPairs()

Kleine Helferlein halten den Code lesbar. CountResolvedPairs() zählt einfach die nicht leeren availablePairs[]-Einträge und wird für die Protokollierung oder Aktualisierung des UI-Textes verwendet. Es handelt sich um einen Einzeiler, der jedoch bei der Initialisierung und Fehlersuche nützlich ist. 

// Count resolved availablePairs entries

int CountResolvedPairs()
{
   int c = 0;
   for(int i = 0; i < ArraySize(availablePairs); i++)
      if(StringLen(availablePairs[i]) > 0) c++;
   return c;
}

Ereignisbehandlung – HandleChartEvent(...)

Alle Klicks von den Chart-Objekten werden an HandleChartEvent weitergeleitet. Sie erkennt drei Kategorien an: (A) Klicks auf Checkboxen (Objektnamen mit dem Präfix Chk_ – es wird festgestellt, welches aufgelöste Symbol angeklickt wurde, und das Array inPairSelected[i] synchronisiert), (B) die Multi-Toggle-Schaltfläche (schaltet multiEnabled um und aktualisiert das Bildmaterial) und (C) Aktionsschaltflächen (Kaufen/Verkaufen/Alles schließen/Anhängige löschen/Stopps setzen) – jeder Schaltflächenklick delegiert an die entsprechende Operation und übergibt die vom EA angeforderten Paare und Auswahlflags. Die Funktion ist der UI → Engine-Router und hält die UI- und EA-Arrays auf dem gleichen Stand. 

// HandleChartEvent: routes object clicks to checkboxes / toggle / actions

void HandleChartEvent(const int id, const string &sparam, string &inMajorPairs[], bool &inPairSelected[])

{
   if(id == CHARTEVENT_OBJECT_CLICK)
   {
      // Checkbox click handling
      if(StringFind(sparam, "Chk_") == 0)
      {
         for(int i = 0; i < ArraySize(availablePairs); i++)
         {
            if(StringLen(availablePairs[i]) == 0) continue;
            string expected = "Chk_" + availablePairs[i];
            if(expected == sparam)

            {
               if(CheckPointer(pairChecks[i]) == POINTER_DYNAMIC)
               {
                 bool current = pairChecks[i].Checked();
                  if(i < ArraySize(inPairSelected)) inPairSelected[i] = current;
                  else { ArrayResize(inPairSelected, i+1); inPairSelected[i] = current; }
                  PrintFormat("HandleChartEvent: checkbox for %s toggled -> %s", availablePairs[i], current ? "true":"false");
               }
               break;
            }
         }
         return;
      }
      // Multi toggle

      if(sparam == btnMultiToggle.Name())

      {
         multiEnabled = !multiEnabled;
         UpdateMultiToggleVisual();
         PrintFormat("HandleChartEvent: Multi toggle clicked. New multiEnabled=%s", (multiEnabled ? "true":"false"));
         return;
      }

      // Buttons - delegate to command handlers

      if(sparam == btnBuy.Name())        OpenBuyOrder(inMajorPairs, inPairSelected);
      else if(sparam == btnSell.Name()) OpenSellOrder(inMajorPairs, inPairSelected);
      else if(sparam == btnCloseAll.Name()) CloseAllPositions(inMajorPairs, inPairSelected);
      else if(sparam == btnDeleteOrders.Name()) DeleteAllPendingOrders(inMajorPairs, inPairSelected);
      else if(sparam == btnCloseProfit.Name()) CloseProfitablePositions(inMajorPairs, inPairSelected);
      else if(sparam == btnCloseLoss.Name())   CloseLosingPositions(inMajorPairs, inPairSelected);
      else if(sparam == btnBuyStop.Name())     PlaceBuyStop(inMajorPairs, inPairSelected);
      else if(sparam == btnSellStop.Name())    PlaceSellStop(inMajorPairs, inPairSelected);
   }
}

Hilfsmittel zur UI-Erstellung

Die Erstellung der Nutzeroberfläche ist in kleine Hilfsprogramme aufgeteilt: CreateButtonPanel() erstellt ein Canvas-Bitmap (Panel-Hintergrund und dekoratives Rechteck), CreateButtons() instanziiert und gestaltet jede Aktionsschaltfläche mit einheitlicher Schriftart/Größe/Position, und CreateMultiToggle() erstellt die Umschalttaste, die über den Hauptaktionsschaltflächen platziert wird. UpdateMultiToggleVisual() aktualisiert den Schalter von Text und Farbe, um anzuzeigen, ob der Multipair-Modus aktiv ist. Diese Hilfsmittel halten visuellen Code von der Geschäftslogik fern und erleichtern Stiländerungen. 

// Create panel + buttons + multi-toggle visual helpers

void CreateButtonPanel()

{
   int panelWidthLocal = buttonWidth + 20;
   int panelHeightLocal = (buttonHeight + buttonSpacing) * 9 + buttonSpacing + 40;
   int x = 0, y = 40;

   if(!buttonPanel.CreateBitmap(0, 0, "ButtonPanel", x, y, panelWidthLocal, panelHeightLocal, COLOR_FORMAT_ARGB_NORMALIZE))
   {
      Print("Failed to create button panel: Error=", GetLastError());
      return;
   }
   ObjectSetInteger(0, "ButtonPanel", OBJPROP_ZORDER, 10);
   buttonPanel.FillRectangle(0, 0, panelWidthLocal, panelHeightLocal, ColorToARGB(clrDarkGray, 200));
   buttonPanel.Rectangle(0, 0, panelWidthLocal - 1, panelHeightLocal - 1, ColorToARGB(clrRed, 255));
   buttonPanel.Update(true);
   ChartRedraw(0);
}
void CreateMultiToggle()
{
   int x = 10, y = 120;
   string font = "Calibri"; int fontSize = 8;
   color buttonBgColor = clrBlack;

   if(btnMultiToggle.Create(0, "btnMultiToggle", 0, x, y, x + buttonWidth, y + buttonHeight))
   {

      ObjectSetString(0, "btnMultiToggle", OBJPROP_FONT, font);
      ObjectSetInteger(0, "btnMultiToggle", OBJPROP_FONTSIZE, fontSize);
      ObjectSetInteger(0, "btnMultiToggle", OBJPROP_BGCOLOR, buttonBgColor);
      ObjectSetInteger(0, "btnMultiToggle", OBJPROP_ZORDER, 11);
   }
}

void UpdateMultiToggleVisual()
{
   if(multiEnabled)
   {
      btnMultiToggle.Text("MULTI:ON");
      btnMultiToggle.ColorBackground(clrGreen);
      btnMultiToggle.Color(clrWhite);
   }
   else
   {
      btnMultiToggle.Text("MULTI:OFF");
      btnMultiToggle.ColorBackground(clrRed);
      btnMultiToggle.Color(clrWhite);
   }
}

Handelshilfsfunktionen

Diese Helfer kapseln die einfachen Handelsmechanismen ein. PipSize(symbol) gibt eine Pip-Größe zurück (in Ihrem Code wird SYMBOL_POINT * 10.0 verwendet), IsSymbolValid(symbol) prüft, ob Geld-/Briefkurs vorhanden sind, und TradeBuySingle()/TradeSellSingle() validiert die Handelbarkeit, die Lot-Grenzen, berechnet den Preis/SL/TP unter Verwendung der Pip-Größe, legt den Füllungstyp fest und übermittelt den Auftrag durch trade.Buy()/trade.Sell(). Diese Hilfsfunktionen zentralisieren die Logik der Auftragsübermittlung, sodass die Multipaar-Schleifen sie nur pro Symbol aufrufen. 

// Pip size, validation, and single-symbol trade helpers

double PipSize(string symbol)

{
   double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
   if(point <= 0) { Print("Invalid point size for ", symbol, ": Error=", GetLastError()); return 0; }
   return point * 10.0;
}
bool IsSymbolValid(string symbol)
{
   bool inMarketWatch = SymbolInfoDouble(symbol, SYMBOL_BID) > 0 && SymbolInfoDouble(symbol, SYMBOL_ASK) > 0;
   if(!inMarketWatch) Print("Symbol ", symbol, " invalid: Not in Market Watch or no valid bid/ask price.");
   return inMarketWatch;
}
bool TradeBuySingle(const string symbol)
{
   if(!IsSymbolValid(symbol)) return false;
   long tradeMode = SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE);
   if(tradeMode != SYMBOL_TRADE_MODE_FULL) { Print("TradeBuySingle: Skipping ", symbol, ": Trading disabled"); return false; }
   double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
   double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
   if(LotSize < minLot || LotSize > maxLot) { Print("TradeBuySingle: invalid lot"); return false; }

   double price = SymbolInfoDouble(symbol, SYMBOL_ASK);
   double sl = StopLoss > 0 ? price - StopLoss * PipSize(symbol) : 0;
   double tp = TakeProfit > 0 ? price + TakeProfit * PipSize(symbol) : 0;
   trade.SetTypeFillingBySymbol(symbol);
   int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
   price = NormalizeDouble(price, digits);
   sl    = NormalizeDouble(sl, digits);
   tp    = NormalizeDouble(tp, digits);

   if(trade.Buy(LotSize, symbol, price, sl, tp))
   { Print("Buy order placed on ", symbol, ": Ticket #", trade.ResultOrder()); return true; }
   else { Print("Buy order failed on ", symbol, ": Retcode=", trade.ResultRetcode()); return false; }
}
bool TradeSellSingle(const string symbol)
{
   if(!IsSymbolValid(symbol)) return false;
   long tradeMode = SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE);
   if(tradeMode != SYMBOL_TRADE_MODE_FULL) { Print("TradeSellSingle: Skipping ", symbol, ": Trading disabled"); return false; }

   double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
   double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
   if(LotSize < minLot || LotSize > maxLot) { Print("TradeSellSingle: invalid lot"); return false; }

   double price = SymbolInfoDouble(symbol, SYMBOL_BID);
   double sl = StopLoss > 0 ? price + StopLoss * PipSize(symbol) : 0;
   double tp = TakeProfit > 0 ? price - TakeProfit * PipSize(symbol) : 0;
   trade.SetTypeFillingBySymbol(symbol);

   int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);

   price = NormalizeDouble(price, digits);
   sl    = NormalizeDouble(sl, digits);
   tp    = NormalizeDouble(tp, digits);

   if(trade.Sell(LotSize, symbol, price, sl, tp))
   { Print("Sell order placed on ", symbol, ": Ticket #", trade.ResultOrder()); return true; }
   else { Print("Sell order failed on ", symbol, ": Retcode=", trade.ResultRetcode()); return false; }
}

Hauptfunktionen – wie Multipair-Befehle angewendet werden

Die wichtigsten Operationen (z.B. OpenBuyOrder, OpenSellOrder, CloseAllPositions, PlaceBuyStop, PlaceSellStop) akzeptieren die von EA bereitgestellten Arrays inMajorPairs[] und inPairSelected[]. Wenn multiEnabled wahr ist, durchlaufen die Routinen alle Indizes und rufen die Handelshelfer unter Verwendung von availablePairs[i] für jeden ausgewählten Index auf. Wenn multiEnabled false ist, handelt die Routine nur mit dem Chart-Symbol. OpenBuyOrder/OpenSellOrder verfolgen auch, ob das Chart-Symbol bereits gehandelt wurde, indem sie Checkboxen ankreuzen und falls nicht, zum Handel des Chart-Symbols zurückkehren – dies garantiert die Erwartungen des Nutzers, wenn er zwischen dem Chart-fokussierten und dem Multipair-Modus wechselt. 

// OpenBuyOrder / OpenSellOrder excerpt (multipair iteration + fallback to chart symbol)

void OpenBuyOrder(string &inMajorPairs[], bool &inPairSelected[])

{
   Print("Starting OpenBuyOrder");
   string chartSym = Symbol();
   if(!multiEnabled)

   {
      PrintFormat("OpenBuyOrder: multipair disabled => trading only chart symbol %s", chartSym);
      if(SymbolInfoInteger(chartSym, SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_DISABLED) { Print("chart symbol not tradeable"); return; }
      TradeBuySingle(chartSym);
      return;
   }
   bool chartTraded = false;
   for(int i = 0; i < ArraySize(inMajorPairs); i++)
   {
      if(i < ArraySize(inPairSelected) && inPairSelected[i] && StringLen(availablePairs[i]) > 0)
      {
         string symbol = availablePairs[i];
         Print("Attempting Buy order on ", symbol, " (requested ", resolvedBases[i], ")");
         if(TradeBuySingle(symbol) && symbol == chartSym) chartTraded = true;
      }
      else
      {
         if(i < ArraySize(inMajorPairs)) Print("Skipping ", inMajorPairs[i], ": Not selected or unresolved");
      }
   }
   if(!chartTraded && SymbolInfoInteger(chartSym, SYMBOL_TRADE_MODE) != SYMBOL_TRADE_MODE_DISABLED)
   {
      PrintFormat("OpenBuyOrder: attempting BUY on chart symbol %s", chartSym);
      TradeBuySingle(chartSym);
   }
}
void OpenSellOrder(string &inMajorPairs[], bool &inPairSelected[])

{
   // (same structure as OpenBuyOrder but calling TradeSellSingle)
   // Implementation mirrors the buy flow but uses SELL specifics.
}


Integration der Multi-Symbols-Handelsfunktionen mit dem New Headline EA

Wo das Multipair-System eingeführt wird (einschließlich & Eingänge)

Der EA zieht den multipair-fähigen UI/Handelskopf oben ein und stellt einen Eingang zur Verfügung, um Multipair beim Start zu aktivieren/deaktivieren. Dies ist der einzige Ort, an dem der EA deklariert: (a) dass er das externe Multipair-UI/Handelsobjekt verwenden wird und (b) dass der Nutzer den anfänglichen Multipair-Modus festlegen kann. Dadurch wird die Funktion für den EA-Nutzer sichtbar und er kann ihr zustimmen. 

#include <TradingButtons.mqh>             // header that implements the multipair UI & trading logic.
// ... other includes ...
input bool   EnableMultipair = true;      // initial multipair enabled state

Wir müssen die Kopfzeile einfügen und eine Eingabe bereitstellen, damit die Nutzer das erwartete Verhalten bei der Initialisierung auswählen.

Aufbewahrungsort von Multipaar-Daten (majorPairs und Auswahlflags)

 Der EA definiert ein String-Array majorPairs[] mit den angeforderten Paarnamen und ein paralleles boolesches Array pairSelected[], das festhält, welche Paare geprüft werden. Diese beiden Arrays sind der Vertrag zwischen dem EA und der Kopfzeile: Index i in beiden Arrays bezieht sich auf dasselbe Währungspaar. Die Kopfzeile erstellt Kontrollkästchen und verwendet das boolesche Array, um zu wissen, welche Paare ausgewählt sind. 

// MULTIPAIR arrays (provided to the header)
// default major pairs (you can edit or later replace with resolved broker symbols)
string majorPairs[] = {"EURUSD","GBPUSD","USDJPY","USDCHF","AUDUSD","USDCAD","NZDUSD"};
bool   pairSelected[];

Beibehaltung einer einfachen, indexausgerichteten Paarliste + Auswahlflags. Es ist lesbar, kann einfach per Referenz übergeben werden und macht die Synchronisierung einfach.

Initialisierung der Auswahlvorgaben und Übergabe der Eingaben an die Kopfzeile (OnInit-Setup)

Während OnInit() passt der EA die Größe von pairSelected an majorPairs an und setzt jedes Element auf true. Dann konfiguriert der EA die öffentlichen Parameter der ButtonsEA (Losgröße, Stops, Risikoeinstellungen) und initialisiert den Header durch Aufruf von Init() und SetMultiEnabled(EnableMultipair). Dadurch wird sichergestellt, dass der Header im gewählten Modus des EA startet und die gleichen Handelsparameter verwendet. 

// In OnInit()
ArrayResize(pairSelected, ArraySize(majorPairs));
for(int i = 0; i < ArraySize(pairSelected); i++) pairSelected[i] = true;

// Initialize TradingButtons
buttonsEA.LotSize = ButtonLotSize;
buttonsEA.StopLoss = ButtonStopLoss;
buttonsEA.TakeProfit = ButtonTakeProfit;
buttonsEA.StopOrderDistancePips = StopOrderDistancePips;
buttonsEA.RiskRewardRatio = RiskRewardRatio;
buttonsEA.Init();
buttonsEA.SetMultiEnabled(EnableMultipair); // pass initial multipair state

Synchronisieren Sie die Konfiguration vor der Initialisierung des UI/Handelsobjekts – setzen Sie zuerst die öffentlichen Felder und den Modus, rufen Sie dann Init() auf, damit der Header die richtigen Laufzeitparameter hat.

Erstellen von Kontrollkästchen (UI-Ausrichtung) – CreatePairCheckboxes-Aufruf

Hier lassen wir den EA einen vertikalen CheckboxY-Versatz berechnen (damit die Checkboxen unterhalb der Nachrichtenspuren erscheinen) und rufen CreatePairCheckboxes(majorPairs, pairSelected, checkboxY) auf. Dadurch werden die Kontrollkästchen in der Kopfzeile erstellt, wobei die Indexausrichtung mit majorPairs erhalten bleibt. Der Header setzt auch den Anfangszustand jedes Kontrollkästchens aus pairSelected[], damit UI und EA synchron sind. Dadurch kann die UI-Komponente die Steuerelemente rendern, aber EA-Arrays per Referenz übergeben. Dadurch bleibt der EA der maßgebliche Speicher dafür, welche Paare existieren und welche ausgewählt sind (der Header manipuliert dieselben Arrays).

// create pair checkboxes aligned below the canvas lanes

int checkboxY = InpTopOffset + (InpSeparateLanes ? 8 : 28) * lineH + 6; // adjust +6 px margin if needed

buttonsEA.CreatePairCheckboxes(majorPairs, pairSelected, checkboxY);

Event-Routing – Weiterleitung von Chart-Ereignissen an den Header

 Der EA implementiert selbst keine Schaltflächenklick-Logik, sondern leitet alle Klicks auf Chart-Objekte an den Header weiter, indem er buttonsEA.HandleChartEvent(...) von OnChartEvent aufruft. Dieser Single-Call-Kontrakt vereinfacht den EA, da der Header die Verantwortung für Multipair-Toggle, Checkbox-Klicks und manuelle Trade-Button-Aktionen übernimmt. 

// OnChartEvent: forward to the header with majorPairs and pairSelected arrays
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   // Header will handle multipair toggle and trade behaviour
   buttonsEA.HandleChartEvent(id, sparam, majorPairs, pairSelected);
}

 Durch die Anwendung eines separaten Event-Routings wird der EA zu einem Event-Conduit, während der Header die UI-Ereignisse und Handelsentscheidungen sauber abwickelt. Auf diese Weise bleiben die Zuständigkeiten gut begrenzt.

Wie manuelle Multipair-Vorgänge ausgelöst werden (Rolle des Kopfteils)

Der Kopfteil ist der Ausführungsmotor für manuelle Multiplexgeschäfte. Liefern Sie einfache Arrays und lassen Sie den Header Symbole iterieren und auflösen. So bleibt der EA übersichtlich. Wenn ein Nutzer auf eine Kauf-/Verkaufs-Schaltfläche klickt oder Multipair umschaltet, verwendet das HandleChartEvent des Headers die übergebenen majorPairs- und pairSelected-Arrays, um zu entscheiden, wo gehandelt werden soll – z. B. werden die Indizes iteriert und nur diejenigen gehandelt, bei denen pairSelected[i] == true ist. Der EA liefert nur die Arrays und die Konfiguration; der Header übernimmt die Auflösung und den Handel über mehrere Symbole hinweg. (Siehe Kopfzeile für die Handelshilfen pro Symbol und die Multipaar-Iteration). 
// (conceptual) header receives arrays and performs per-index iteration:
// Pseudocode excerpt of header behavior (actual code in TradingButtons.mqh)
for(i = 0; i < ArraySize(majorPairs); i++)
{
   if(i < ArraySize(pairSelected) && pairSelected[i])
   {
      // resolve broker symbol for majorPairs[i]
      // call TradeBuySingle(resolvedSymbol) or TradeSellSingle(...)
   }
}

Automatisierte Auftragslogik bleibt chart-spezifisch (wie Multi-Symbol mit Automatisierung koexistiert)

Die automatische Stop-Platzierung vor einem Ereignis und die Post-Impact-Order in diesem EA beziehen sich auf das Chart-Symbol (_Symbol) und nicht auf die MajorPairs. Das manuelle Multipair-System ist getrennt: Manueller Multipair-Handel (Schaltflächen) und automatisierte ereignisgesteuerte Trades sind unterschiedliche Abläufe. Durch diese Trennung werden versehentliche automatisierte Multi-Symbol-Aufträge vermieden, es sei denn, Sie erweitern die Automatisierung ausdrücklich auf die Verwendung von majorPairs. 

// Example: automated BuyStop/SellStop placement uses _Symbol (chart symbol)
if(trade.BuyStop(InpOrderVolume, buyPrice, _Symbol, buySL, buyTP))
   ticketBuyStop = trade.ResultOrder();
if(trade.SellStop(InpOrderVolume, sellPrice, _Symbol, sellSL, sellTP))
   ticketSellStop = trade.ResultOrder();

Die wichtigste Lehre aus dem obigen Code ist, dass manuelle Multipair-Kontrollen von automatisierten chart-spezifischen Strategien getrennt bleiben sollten, es sei denn, Sie wollen, dass die Automatisierung über viele Symbole hinweg agiert. Eine klare Trennung verhindert Überraschungen.

Synchronisationsmuster: der EA besitzt die Daten, der Header besitzt die UI/Logik

Der EA definiert und speichert majorPairs[] und pairSelected[] (den maßgeblichen Status). Die Kopfzeile liest diese (erstellt Steuerelemente, wirkt auf angekreuzte Elemente) und schreibt Änderungen zurück (Anklicken von Kontrollkästchen setzt pairSelected[i]), da Arrays per Referenz übergeben werden. Dieses Zwei-Wege-Synchronisationsmuster ist einfach und robust: Der EA kann pairSelected[] jederzeit einsehen (z. B. in OnTimer) und der Header aktualisiert es, wenn der Nutzer interagiert. 

// EA owns arrays; header is given references and updates them when checkboxes are toggled
buttonsEA.CreatePairCheckboxes(majorPairs, pairSelected, checkboxY);
...
// header's HandleChartEvent updates pairSelected[] in-place when checkboxes are clicked

Wir verwenden eine Übergabe als Referenz für den gemeinsamen Laufzeit. Das ist nicht sehr aufwändig und hält UI und EA ohne zusätzliche Nachrichtenübermittlung synchron.

Überlegungen zur Platzierung und visuellen Gestaltung (Kästen unter Nachrichtenspuren)

Der EA berechnet checkboxY auf der Grundlage der Nachrichtenspuren und der Konfigurationsoptionen (InpTopOffset, InpSeparateLanes, lineH), sodass die Multipair-Checkboxen visuell unter den Nachrichten-/Indikatorspuren erscheinen. Die Integration von UI-Elementen aus anderen Modulen ist sowohl eine Aufgabe des Layouts als auch der Logik – die dynamische Berechnung von Offsets bedeutet, dass sich die UI anpasst, wenn sich die Höhe oder Position der Fahrspuren ändert. 

// compute vertical position for checkboxes so they sit below the lanes
int checkboxY = InpTopOffset + (InpSeparateLanes ? 8 : 28) * lineH + 6;
buttonsEA.CreatePairCheckboxes(majorPairs, pairSelected, checkboxY);

 Wenn Sie Hintergründe und externe UI-Panels kombinieren, sollten Sie die Layout-Mathematik im EA zentralisieren, damit beide Systeme einheitliche Abstandsregeln verwenden.


Tests

Der Einsatz des EA auf dem MetaTrader 5-Terminal führte zu hervorragenden Ergebnissen. Ich konnte die Paare auswählen, die ich handeln wollte, und sie reagierten sofort auf die Handelsschaltflächen. Die Aufträge wurden in algorithmischer Geschwindigkeit ausgeführt, und mit einem einzigen Klick konnte ich alle Positionen für mehrere Paare schließen – eine unschätzbare Funktion für den Nachrichtenhandel und andere Scalping-Strategien mit hoher Volatilität.

Die folgende Abbildung zeigt das Ergebnis des Live-Chart-Tests. Es ist wichtig zu beachten, dass die manuellen Funktionen eine Echtzeit-Interaktion mit dem Chart erfordern, während die automatisierten Komponenten des EAs im Strategy Tester gründlich evaluiert werden können, um die Effizienz sicherzustellen.

Handel mit mehreren Symbolen mit dem News Headline EA

Handel mit mehreren Symbolen mit dem Nachrichten-Schlagzeilen-EA



Schlussfolgerung

Teil IX markiert einen weiteren wichtigen Meilenstein in der Entwicklung des News Headline EA: die Integration des Multi-Symbol-Handels. Dieser Fortschritt behebt eine seit langem bestehende Einschränkung, indem er es Händlern ermöglicht, mehrere Paare in einem einzigen Chart zu verwalten. Obwohl es sich nicht um ein vollautomatisches Handelssystem handelt, fungiert diese Funktion als manuelle Handelsschnittstelle, die durch algorithmische Ausführung unterstützt wird und Geschwindigkeit und Präzision bietet, während die Entscheidungsfindung bei hoher Volatilität dem Händler überlassen bleibt.

Der Entwicklungsprozess selbst war sehr aufschlussreich, da wir die Prinzipien der Modularisierung und der Trennung von Belangen angewandt haben, um ein kompaktes und dennoch leistungsstarkes System zu schaffen. Was als einfache Kalender- und News-Feed-Anzeige begann, hat sich inzwischen zu einem vielseitigen Framework entwickelt, das manuelle und automatisierte Funktionen miteinander verbindet, um die praktischen Herausforderungen von Nachrichtenhändlern zu lösen. Obwohl das System mit Blick auf die wichtigsten Währungspaare entwickelt wurde, kann es mit geringfügigen Kompatibilitätsanpassungen für nutzerdefinierte Symbole angepasst werden.

Eine der größten Herausforderungen, auf die wir gestoßen sind, war die maklerspezifische Benennung von Symbolen. So scheiterte der Handel zunächst, weil das Konto EURUSD.0 und nicht den Standard-EURUSD verwendete. Um dieses Problem zu lösen, haben wir den EA so verbessert, dass er sich dynamisch an die Maklernomenklatur der wichtigsten Paare anpasst.

Wir haben auch die CCheckBox-Klasse aus der MQL5-Standardbibliothek genutzt, um eine reibungslose Paarauswahl zu ermöglichen und damit die Flexibilität und Erweiterbarkeit der MQL5-Sprache zu demonstrieren.

Ich hoffe, dass diese Diskussion nützliche Einsichten und praktische Lektionen vermittelt hat. Der vollständige Quellcode ist unten angehängt, verwenden Sie ihn zusammen mit diesem Artikel, der die Implementierung dokumentiert. Der Einfachheit halber habe ich die wichtigsten Erkenntnisse auch in Tabellenform zusammengefasst. Feedback und Kommentare sind immer willkommen.


Wichtige Lektionen

Wichtige Lektion Beschreibung
Index-ausgerichtete Arrays Beide Projekte verwenden die Arrays majorPairs[] und pairSelected[], die nach Index ausgerichtet sind. Dadurch wird sichergestellt, dass ein Kontrollkästchen, ein angeforderter Basisname und ein aufgelöstes Maklersymbol alle einheitlich auf dasselbe Währungspaar verweisen.
Pass-by-Reference-Synchronisierung Arrays werden per Referenz vom EA an TradingButtons.mqh übergeben, sodass der Header die Auswahlzustände direkt aktualisieren kann, wenn die Kontrollkästchen umgeschaltet werden, sodass der EA-Zustand sofort synchronisiert wird.
Explizite Ereignisweiterleitung Der EA verarbeitet Schaltflächenklicks nicht direkt. Stattdessen leitet OnChartEvent Ereignisse an buttonsEA.HandleChartEvent() weiter, wo der Header Multipair-Toggles, Checkbox-Klicks und Handelsaktionen interpretiert.
Abstraktion der Symbolauflösung ResolveSymbol() in der Kopfzeile ordnet nutzerfreundliche Basen (z. B. EURUSD) auf maklerspezifische Symbole (z. B. EURUSD.ecn) zu. Der EA ist unabhängig von den Eigenheiten des Brokers bei der Namensgebung.
Getrennte manuelle und automatisierte Abläufe Im EA wirken automatisierte Pre-Event/Post-Event-Orders immer auf das Chart-Symbol, während die Multipair-Funktionalität den manuellen Tastenaktionen vorbehalten ist. Durch diese Trennung werden unerwartete massenhafte Handelsgeschäfte vermieden.
Dynamische UI-Erstellung & Bereinigung Die Kopfzeile erstellt/entfernt dynamisch Kontrollkästchen und Schaltflächen während Init()/Deinit(). Der EA berechnet Layout-Offsets (unterhalb der Nachrichtenspuren), damit sich die Komponenten nahtlos in seine Nutzeroberfläche einfügen.
Initialisieren vor Init() In OnInit() setzt der EA LotSize, StopLoss, TakeProfit und EnableMultipair, bevor er buttonsEA.Init() aufruft. Dadurch wird sichergestellt, dass sich der Header selbst mit der richtigen Konfiguration erstellt.
Zentralisierte Handelshilfsmittel Die Handelslogik ist in wiederverwendbaren Hilfsfunktionen wie TradeBuySingle() und TradeSellSingle() gekapselt. Dadurch wird Code-Duplizierung in Multipaar-Schleifen und Schaltflächen-Handlern vermieden.
Multipair-Toggle-Verhalten Die Taste btnMultiToggle schaltet zwischen dem Einzelsymbol- und dem Multipaar-Modus um. Im Multipaar-Modus durchlaufen die Aktionen alle ausgewählten Paare; im Einzelmodus beziehen sich die Aktionen nur auf das Chart-Symbol.
Rückgriff auf das Chart-Symbol Wenn der Multipair-Modus aktiviert ist, aber das Chart-Symbol nicht ausgewählt ist, sorgt die Kopfzeile dennoch dafür, dass ein Handel auf dem Chart-Symbol platziert wird. Dies liefert vorhersehbare Ergebnisse für Nutzer, die sich auf ihr Chart konzentrieren.
Koordinierung des Layouts Der EA berechnet checkboxY, um Multipair-Kontrollkästchen sauber unter der scrollenden Nachrichtenleinwand zu platzieren. Hier wird gezeigt, wie man UI-Panels von Drittanbietern mit nutzerdefinierten Indikator-Overlays ohne Überlappung integriert.
Fehlerprotokollierung & Übersichtlichkeit Beide Module geben detaillierte Protokolle aus (z. B. Fehler bei der Symbolauflösung, Retcodes bei der Auftragsvergabe). Diese Rückverfolgbarkeit hilft Programmierern und Nutzern bei der schnellen Diagnose von Konfigurationsproblemen.
Zwei-Wege-Synchronisationsmuster Die Zustände der Kontrollkästchen werden von pairSelected[] (EA zu UI) initialisiert, und wenn sie angeklickt werden, aktualisieren sie pairSelected[] (UI zu EA). Diese Endlosschleife garantiert, dass beide Module den gleichen Auswahlstatus haben.
Sichere Verwendung des dynamischen Speichers Die Kopfzeile verwendet new CCheckBox() für jedes Paar und löscht sie sorgfältig in Deinit(). Dadurch lernen MQL5-Programmierer, wie sie GUI-Objekte in länger laufenden EAs sicher verwalten können.
Erweiterbarkeit durch Modularität Durch die Kapselung des Multipair-Handels in einem eigenständigen Header kann dieselbe Klasse in mehreren EAs (wie dem News Headline EA) wiederverwendet werden, ohne dass die Multipair-Logik neu geschrieben werden muss – ein skalierbares Muster für die Wiederverwendung von Code.


Anlagen

Dateiname Version Beschreibung
News_Headline_EA.mq5 1.13 Ein Expert Advisor, der wirtschaftliche Kalenderereignisse und Schlagzeilen direkt in den Chart integriert. Es verwaltet Stop-Orders vor dem Ereignis, Trades nach dem Ereignis und zeigt scrollende Nachrichten an. Version 1.13 erweitert die Funktionalität um die Unterstützung des Multipair-Handels durch das TradingButtons-Modul, das die manuelle Ausführung von Multipair-Orders neben dem automatisierten chartbasierten Event-Trading ermöglicht.
TradingButtons.mqh 1 Ein modularer Header, der eine Multipair-Handelsschnittstelle bietet. Es erstellt Schaltflächen für Kauf-, Verkaufs-, Schließ-, Lösch- und Stop-Aufträge sowie Kontrollkästchen für die Auswahl mehrerer Währungspaare. Sie enthält eine Logik zur Symbolauflösung, Hilfen zur Auftragsplatzierung und eine Umschaltfunktion zwischen dem Handel mit einem Symbol und dem Handel mit mehreren Paaren. Entwickelt für die Wiederverwendung in verschiedenen EAs, einschließlich News Headline EA.

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

Beigefügte Dateien |
TradingButtons.mqh (38.59 KB)
Letzte Kommentare | Zur Diskussion im Händlerforum (2)
Stanislav Korotky
Stanislav Korotky | 17 Sept. 2025 in 18:34

Was ist der wirkliche Sinn dieses Zeug? Die angegebene Argumentation ist irrational, weil EAs in der Lage sind, viele Symbole von jedem Chart aus zu handeln (out of the box), und Sie können leicht zwischen den Charts wechseln, ohne die EAs zu beeinträchtigen - sie werden nicht neu geladen, wenn das Symbol/Zeitrahmen des Charts geändert wird.

PS. Der ursprüngliche Kommentar ist auf Englisch gepostet - bitte lesen Sie ihn für das richtige Verständnis - die automatische Übersetzung kann lächerliche Texte produzieren.

Clemence Benjamin
Clemence Benjamin | 6 Okt. 2025 in 06:02
Stanislav Korotky #:

Was ist der wirkliche Sinn dieses Zeug? Die angegebene Argumentation ist irrational, weil EAs in der Lage sind, viele Symbole aus jedem Diagramm zu handeln (out of the box), und Sie können leicht zwischen Diagrammen wechseln, ohne die EAs zu beeinflussen - sie werden nicht neu geladen, wenn das Symbol/Zeitrahmen des Diagramms geändert wird.

PS. Der ursprüngliche Kommentar ist auf Englisch gepostet - bitte lesen Sie ihn für das richtige Verständnis - die automatische Übersetzung kann lächerliche Texte produzieren.

Hallo Stanislav Korotky,

vielen Dank, dass Sie Ihre Sichtweise mit uns teilen. Ich verstehe Ihren Standpunkt voll und ganz - in der Tat kann ein EA mehrere Symbole von einem einzigen Chart aus handeln, und ein manueller Wechsel der Symbole führt nicht zu einem Neuladen oder einer Unterbrechung des laufenden EA.

Meine Idee zielt jedoch speziell auf Situationen ab, in denen eine gleichzeitige Ausführung über mehrere Paare hinweg erforderlich ist - z. B. während einschneidender Nachrichtenereignisse, wenn Sie synchronisierte Orders für GBPUSD und EURUSD zum selben Zeitpunkt platzieren möchten. In solchen Fällen ist ein manueller Symbolwechsel nicht sinnvoll.

Deshalb lege ich großen Wert auf die programmatische Verwaltung mehrerer Symbole - so wird sichergestellt, dass der EA Trades für ausgewählte Paare automatisch verarbeiten und ausführen kann, selbst wenn er an einen Chart mit einem anderen Basissymbol angehängt ist.

Statistische Arbitrage durch kointegrierte Aktien (Teil 2): Expert Advisor, Backtests und Optimierung Statistische Arbitrage durch kointegrierte Aktien (Teil 2): Expert Advisor, Backtests und Optimierung
In diesem Artikel wird eine Beispielimplementierung eines Expert Advisors für den Handel mit einem Korb von vier Nasdaq-Aktien vorgestellt. Die Aktien wurden zunächst anhand von Pearson-Korrelationstests gefiltert. Die gefilterte Gruppe wurde dann mit Johansen-Tests auf Kointegration geprüft. Schließlich wurde der kointegrierte Spread mit dem ADF- und dem KPSS-Test auf Stationarität geprüft. Hier sehen wir einige Anmerkungen zu diesem Prozess und die Ergebnisse der Backtests nach einer kleinen Optimierung.
Formulierung eines dynamischen Multi-Paar-EA (Teil 4): Volatilität und Risikoanpassung Formulierung eines dynamischen Multi-Paar-EA (Teil 4): Volatilität und Risikoanpassung
In dieser Phase erfolgt die Feinabstimmung Ihres Multi-Pair-EAs, um die Handelsgröße und das Risiko in Echtzeit anhand von Volatilitätsmetriken wie ATR anzupassen und so die Konsistenz, den Schutz und die Leistung unter verschiedenen Marktbedingungen zu verbessern.
Beherrschung von Protokollaufzeichnungen (Teil 10): Vermeidung von Log Replay durch Implementierung einer Unterdrückung Beherrschung von Protokollaufzeichnungen (Teil 10): Vermeidung von Log Replay durch Implementierung einer Unterdrückung
Wir haben ein System zur Unterdrückung von Protokollen in der Logify-Bibliothek erstellt. Es wird beschrieben, wie die Klasse CLogifySuppression das Konsolenrauschen durch Anwendung konfigurierbarer Regeln reduziert, um sich wiederholende oder irrelevante Meldungen zu vermeiden. Wir behandeln auch das externe Konfigurations-Framework, Validierungsmechanismen und umfassende Tests, um Robustheit und Flexibilität bei der Protokollerfassung während der Bot- oder Indikatorentwicklung zu gewährleisten.
Selbstoptimierende Expert Advisors in MQL5 (Teil 12): Aufbau von linearen Klassifikatoren durch Matrixfaktorisierung Selbstoptimierende Expert Advisors in MQL5 (Teil 12): Aufbau von linearen Klassifikatoren durch Matrixfaktorisierung
Dieser Artikel befasst sich mit der leistungsfähigen Rolle der Matrixfaktorisierung im algorithmischen Handel, insbesondere in MQL5-Anwendungen. Von Regressionsmodellen bis hin zu Multi-Target-Klassifikatoren gehen wir durch praktische Beispiele, die zeigen, wie einfach diese Techniken mit Hilfe von integrierten MQL5-Funktionen integriert werden können. Ganz gleich, ob Sie die Kursrichtung vorhersagen oder das Verhalten von Indikatoren modellieren wollen, dieser Leitfaden schafft eine solide Grundlage für den Aufbau intelligenter Handelssysteme mit Hilfe von Matrixmethoden.