English Русский 日本語
preview
Vom Neuling zum Experten: Animierte Schlagzeilen mit MQL5 (X) – Multiple Symbol Chart View für den Nachrichtenhandel

Vom Neuling zum Experten: Animierte Schlagzeilen mit MQL5 (X) – Multiple Symbol Chart View für den Nachrichtenhandel

MetaTrader 5Beispiele |
76 0
Clemence Benjamin
Clemence Benjamin

Inhalt:


Einführung

Im letzten Artikel haben wir eine Funktion zur Verwaltung mehrerer Symbole vorgestellt, mit der Händler schnell ihre bevorzugten Handelspaare auswählen können. Dadurch wurde der Zeitaufwand für den Wechsel zwischen den Charts verringert, nur um ein Paar für den Handel zu konfigurieren.

Ein Problem blieb jedoch bestehen: Die Händler konnten zwar ausgewählte Paare verwalten, hatten jedoch keinen direkten Zugang zu den Chart-APIs für diese Paare und damit auch keine Möglichkeit, deren Preise für Analysen bequem einzusehen. Um dieses Problem zu lösen, haben wir heute unseren Handel mit mehreren Symbolen verfeinert, indem wir eine spezielle Klasse für die Visualisierung mehrerer Charts entwickelt haben, die nahtlos in den Chart integriert ist und als Teil des breiteren Funktionssets des News Headline EA.

Falls Sie sich an dieser Stelle verloren fühlen, hier eine kurze Zusammenfassung unserer Fortschritte. Ich empfehle auch, unsere früheren Veröffentlichungen zu diesem Thema zu lesen, um ein tieferes Verständnis zu erlangen.

Die früheste Version des News Headline EA konzentrierte sich auf die Wiedergabe geplanter Kalenderereignisse in klar definierten, nach Wichtigkeit geordneten Bahnen auf dem Chart. Das Konzept der Laufbänder, der „Lanes“ wurde schnell erweitert: Wir integrierten eine News-Feed-API von Alpha Vantage, fügten lokal gehostete KI-Modell-Insights hinzu und schufen Lanes für integrierte indikatorbasierte Insights. Darauf aufbauend haben wir automatisierte Funktionen für den Nachrichtenhandel eingeführt, einschließlich spezieller Funktionen für den NFP-Handel (Non-Farm Payrolls), kombiniert mit der Integration manueller Handelsschaltflächen.

In jüngster Zeit haben wir uns auf den Handel mit mehreren Symbolen spezialisiert, um bei volatilen Ereignissen schnelle Entscheidungen treffen zu können. Diese Funktion hat die Verwaltung und den Handel mit mehreren Paaren unter schnellen Marktbedingungen erheblich erleichtert.

Heute konzentrieren wir uns darauf, diesen Ansatz für den Handel mit mehreren Symbolen zu verfeinern, indem wir den Händlern die Möglichkeit geben, mehrere Charts in Echtzeit direkt im EA anzuzeigen.


Strategie zur Umsetzung

Eine unserer wichtigsten Prioritäten ist es, Wissen so zu vermitteln, dass auch ein unerfahrener Leser die Konzepte leicht und klar erfassen kann. In diesem Abschnitt werden wir den Ansatz und die Umsetzung aufschlüsseln, mit denen wir dieses Ziel erreichen wollen.

Da unser Programm wächst, ist es wichtig, einen strukturierten und wartbaren Ansatz für die Integration neuer Funktionen zu wählen. Eine meiner Lieblingstechniken ist die Modularisierung, die eine reibungslose Entwicklung gewährleistet und es uns ermöglicht, wiederverwendbare Hilfsprogramme in Form von Headern und Klassen zu erstellen.

Bei einem anspruchsvollen Programm wie dem News Headline EA folge ich einem einheitlichen Arbeitsablauf:

  1. Beginnen wir mit der Entwicklung eines eigenständigen Miniprogramms, um die neue Funktion zu testen.
  2. Sobald sich die Funktion als praktikabel und stabil erweist, kann mit der Integration in den Haupt-EA begonnen werden.

Dieser Prozess sorgt für einen zielgerichteten Arbeitsablauf, reduziert Fehler und stellt sicher, dass neue Funktionen nahtlos integriert werden, ohne bestehende Funktionen zu beeinträchtigen.

Heute besteht unsere Aufgabe darin, eine CChartMiniTiles-Klasse zu erstellen, die die Anzeige mehrerer Symbolcharts in einem einzigen Chart mit anpassbaren Abmessungen ermöglicht. Anschließend werden wir die Klasse in einem Dummy-EA (MiniChartsEA) implementieren, um das Konzept zu validieren. Sobald die Klasse bestätigt ist, wird sie in den News Headline EA integriert und für eine reibungslose Funktionalität angepasst.

Beachten Sie bitte, dass Namen wie CChartMiniTiles und MiniChartsEA nur Platzhalter sind, die ich für diese Anleitung gewählt habe. Sie können auch andere Namen verwenden, solange Sie verstehen, wie das Programm funktioniert.

In den nächsten 4 Unterabschnitten werden wir uns auf die Umsetzung konzentrieren:

  1. ChartMiniTiles-Header
  2. Beispiel EA (MiniChartsEA) zum Testen des Headers
  3. Erste Tests
  4. Integration der ChartsMiniTiles in die Nachrichtenüberschrift EA

1.0 ChartMiniTiles Header

Diese Header-Datei definiert die Klasse CChartMiniTiles, ein wiederverwendbares Dienstprogramm zur Anzeige und Verwaltung mehrerer Minichart innerhalb eines einzelnen MetaTrader 5-Charts. Der Zweck dieser Klasse ist es, die Integration von Multi-Symbol-Chartansichten in größere Projekte, wie z.B. den News Headline EA, zu vereinfachen und gleichzeitig den Code modular und wartbar zu halten.

Durch die Isolierung dieser Funktionalität in einem eigenständigen Header stellen wir sicher, dass die Funktion unabhängig getestet werden kann (z. B. mit einem Dummy-EA) und später nahtlos in komplexere Systeme integriert werden kann. Dieser Ansatz verbessert den Arbeitsablauf und verringert die Wahrscheinlichkeit von Fehlern während der Entwicklung.

In den folgenden Abschnitten wird der Code-Entwicklungsprozess in nummerierte Schritte unterteilt, wobei sich jeder Schritt auf einen bestimmten Aspekt der Programmstruktur und -funktionalität konzentriert.

1.1. Übersicht und Zweck der Klasse

Dieser Eröffnungsblock dokumentiert den Zweck der Header-Datei und definiert die zur Kompilierzeit in der Klasse verwendeten Standardwerte. Durch die Verwendung von Makros werden Layout-, Timing- und Toggle-Vorgaben zentralisiert, sodass Betreuer das Verhalten schnell anpassen können, ohne sich mit Implementierungsdetails beschäftigen zu müssen. In dem Header des Kommentars werden die Funktionen genannt: Mini-Chartkacheln, die mit OBJ_CHART erstellt werden, automatische Symbolauflösung für verschiedene Makler, eine Umschalttaste für die schnelle Steuerung der Sichtbarkeit, reaktionsschnelle Berechnung des Layouts und eine Option für den reservierten oberen Bereich, um Konflikte mit anderen UI-Elementen zu vermeiden. Dieser Abschnitt bereitet den Leser darauf vor, wie der Kurs aufgebaut ist und was er leisten soll.

//+------------------------------------------------------------------+
//| ChartMiniTilesClass.mqh                                          |
//| Class wrapper for ChartMiniTiles functionality                   |
//| - CChartMiniTiles class                                           |
//| - bottom-anchored mini-chart tiles using OBJ_CHART                |
//| - broker-adaptive symbol lookup, toggle button, responsive layout |
//| - supports top-reserved area to avoid overlapping top UI     |
//+------------------------------------------------------------------+
#ifndef __CHART_MINI_TILES_CLASS_MQH__
#define __CHART_MINI_TILES_CLASS_MQH__

//--- compile-time defaults (macros are safe in MQL5)
#define CMT_DEFAULT_WIDTH       120
#define CMT_DEFAULT_HEIGHT      112    // quadrupled default
#define CMT_DEFAULT_X_OFFSET    10
#define CMT_DEFAULT_Y_OFFSET    40     // bottom offset from bottom
#define CMT_DEFAULT_SPACING     6
#define CMT_DEFAULT_PERIOD      PERIOD_M1
#define CMT_DEFAULT_CHART_SCALE 2

// toggle button defaults
#define CMT_TOG_X               8
#define CMT_TOG_Y               6
#define CMT_TOG_W               72
#define CMT_TOG_H               20
#define CMT_TOG_NAME            "CMT_ToggleButton"

1.2. Konstruktor und Destruktor

Der Konstruktor initialisiert die Klasse in einem bekannten, sicheren Zustand, indem er die Standardwerte der Kompilierzeit verwendet. Es bereitet interne Arrays, Standardkachelgrößen und -versätze sowie Umschaltknopfeinstellungen vor und setzt m_top_reserved auf Null (kein reservierter Bereich als Standard). Der Destruktor ruft Delete() auf, um sicherzustellen, dass alle von der Klasse erstellten Objekte entfernt werden, wenn die Instanz den Gültigkeitsbereich verlässt. Dieser deterministische Auf- und Abbau verhindert, dass Objekte auf dem Chart zurückbleiben, und reduziert die Probleme bei der Fehlersuche.

//+------------------------------------------------------------------+
//| CChartMiniTiles class declaration                                |
//+------------------------------------------------------------------+
class CChartMiniTiles
  {
public:
                     CChartMiniTiles(void);
                    ~CChartMiniTiles(void);

   bool              Init(const string majorSymbols,
                          const int width = -1,
                          const int height = -1,
                          const int xOffset = -1,
                          const int yOffset = -1,        // bottom offset (pixels from bottom)
                          const int spacing = -1,
                          const int period = -1,
                          const bool dateScale = true,
                          const bool priceScale = false,
                          const int chartScale = -1);

   void              UpdateLayout(void);
   void              Delete(void);

   bool              HandleEvent(const int id,const string sparam); // forward OnChartEvent
   void              SetToggleButtonPos(const int x,const int y);
   void              SetTilesVisible(const bool visible);
   void              Toggle(void);

   // NEW: reserve top area height (pixels from top) that tiles must NOT cover
   void              SetTopReservedHeight(const int pixels);

private:
   // state
   string            m_object_names[];   // object names created
   string            m_symbols[];        // resolved broker symbols
   int               m_count;

   int               m_width;
   int               m_height;
   int               m_xoffset;
   int               m_yoffset;         // bottom offset
   int               m_spacing;
   int               m_period;
   bool              m_date_scale;
   bool              m_price_scale;
   int               m_chart_scale;
   bool              m_visible;

   int               m_tog_x;
   int               m_tog_y;
   int               m_tog_w;
   int               m_tog_h;
   string            m_tog_name;

   // NEW
   int               m_top_reserved;    // pixels from top that must be left free for other UI

private:
   // helpers
   string            MakeObjectName(const string base);
   string            TrimString(const string s);
   string            FindBrokerSymbol(const string baseSymbol);
   int               ComputeBaseYFromTop(void);

   void              CreateToggleButton(void);
   void              DeleteToggleButton(void);
   void              CollapseAll(void);
  };

//+------------------------------------------------------------------+
//| Constructor / Destructor                                         |
//+------------------------------------------------------------------+
CChartMiniTiles::CChartMiniTiles(void)
  {
   m_count       = 0;
   ArrayResize(m_object_names,0);
   ArrayResize(m_symbols,0);

   m_width       = CMT_DEFAULT_WIDTH;
   m_height      = CMT_DEFAULT_HEIGHT;
   m_xoffset     = CMT_DEFAULT_X_OFFSET;
   m_yoffset     = CMT_DEFAULT_Y_OFFSET;
   m_spacing     = CMT_DEFAULT_SPACING;
   m_period      = CMT_DEFAULT_PERIOD;
   m_date_scale  = false;
   m_price_scale = false;
   m_chart_scale = CMT_DEFAULT_CHART_SCALE;
   m_visible     = true;

   m_tog_x = CMT_TOG_X;
   m_tog_y = CMT_TOG_Y;
   m_tog_w = CMT_TOG_W;
   m_tog_h = CMT_TOG_H;
   m_tog_name = CMT_TOG_NAME;

   m_top_reserved = 0; // default: no reserved area
  }

CChartMiniTiles::~CChartMiniTiles(void)
  {
   Delete();
  }

1.3. Helfer-Methoden

Diese gezielten Hilfsfunktionen normalisieren die Eingaben und verbergen die Eigenheiten der Makler, damit der Rest der Klasse einfacher sein kann. MakeObjectName bereinigt Zeichenketten in sichere Objektnamen (durch Ersetzen von Leer- und Sonderzeichen). TrimString entfernt führende/nachlaufende Leerzeichen, einschließlich Tabulatoren und Zeilenumbrüche. FindBrokerSymbol versucht eine exakte Symbolauswahl und führt andernfalls eine von Groß- und Kleinschreibung unabhängige Suche in der Symbolliste des Brokers durch, um eine Übereinstimmung zu finden – dies ist entscheidend für die Übertragbarkeit zwischen Brokern, die Suffixe anhängen oder unterschiedliche Namenskonventionen verwenden. ComputeBaseYFromTop bestimmt die vertikale Grundlinie für unten verankerte Kacheln und schützt gleichzeitig vor ungültigen Werten für die Kartenhöhe.

//+------------------------------------------------------------------+
//| Helpers implementation                                           |
//+------------------------------------------------------------------+
string CChartMiniTiles::MakeObjectName(const string base)
  {
   string name = base;
   StringReplace(name, " ", "_");
   StringReplace(name, ".", "_");
   StringReplace(name, ":", "_");
   StringReplace(name, "/", "_");
   StringReplace(name, "\\", "_");
   return(name);
  }

string CChartMiniTiles::TrimString(const string s)
  {
   if(s == NULL) return("");
   int len = StringLen(s);
   if(len == 0) return("");
   int left = 0;
   int right = len - 1;
   while(left <= right)
     {
      int ch = StringGetCharacter(s, left);
      if(ch == 32 || ch == 9 || ch == 10 || ch == 13) left++;
      else break;
     }
   while(right >= left)
     {
      int ch = StringGetCharacter(s, right);
      if(ch == 32 || ch == 9 || ch == 10 || ch == 13) right--;
      else break;
     }
   if(left > right) return("");
   return StringSubstr(s, left, right - left + 1);
  }

string CChartMiniTiles::FindBrokerSymbol(const string baseSymbol)
  {
   if(StringLen(baseSymbol) == 0) return("");
   if(SymbolSelect(baseSymbol, true))
      return(baseSymbol);

   string baseUpper = baseSymbol; StringToUpper(baseUpper);

   int total = SymbolsTotal(true);
   for(int i = 0; i < total; i++)
     {
      string s = SymbolName(i, true);
      if(StringLen(s) == 0) continue;
      string sUpper = s; StringToUpper(sUpper);
      if(StringFind(sUpper, baseUpper) >= 0)
         return(s);
     }
   return("");
  }

int CChartMiniTiles::ComputeBaseYFromTop(void)
  {
   int chartTotalHeight = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS);
   if(chartTotalHeight <= 0) chartTotalHeight = 600;
   int base_y_from_top = chartTotalHeight - m_yoffset - m_height;
   if(base_y_from_top < 0) base_y_from_top = 0;
   if(base_y_from_top + m_height > chartTotalHeight) base_y_from_top = MathMax(0, chartTotalHeight - m_height);
   return base_y_from_top;
  }

1.4. Toggle Button Steuerung

Die interaktive Steuerung erfolgt über eine Umschalttaste. CreateToggleButton stellt sicher, dass ein Schaltflächenobjekt vorhanden ist (oder erstellt es, falls es fehlt) und legt die visuellen Eigenschaften fest: Position, Größe, Schriftart, Hintergrundfarbe, Textfarbe, Auswählbarkeit und den durch m_visible bestimmten Anfangszustandstext. DeleteToggleButton entfernt sie sauber. CollapseAll ist die leichtgewichtige Ausblendmethode, die Kacheln effektiv ausblendet, indem sie aus dem Bildschirm verschoben und ihre Größe auf Null gesetzt wird, anstatt sie zu löschen – so bleibt der Status für eine schnelle Wiederanzeige erhalten und der Overhead der Neuerstellung von Objekten wird vermieden.

//+------------------------------------------------------------------+
//| Toggle button helpers                                            |
//+------------------------------------------------------------------+
void CChartMiniTiles::CreateToggleButton(void)
  {
   if(ObjectFind(ChartID(), m_tog_name) == -1)
      ObjectCreate(ChartID(), m_tog_name, OBJ_BUTTON, 0, 0, 0, 0, 0);

   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_XDISTANCE, m_tog_x);
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_YDISTANCE, m_tog_y);
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_XSIZE, m_tog_w);
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_YSIZE, m_tog_h);

   ObjectSetString(ChartID(), m_tog_name, OBJPROP_FONT, "Arial");
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_FONTSIZE, 10);
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_BGCOLOR, clrDarkSlateGray);
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_COLOR, clrWhite);
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_SELECTABLE, 1);
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_STATE, m_visible ? 1 : 0);
   ObjectSetString(ChartID(), m_tog_name, OBJPROP_TEXT, m_visible ? "Tiles: ON" : "Tiles: OFF");
  }

void CChartMiniTiles::DeleteToggleButton(void)
  {
   if(ObjectFind(ChartID(), m_tog_name) >= 0)
      ObjectDelete(ChartID(), m_tog_name);
  }

void CChartMiniTiles::CollapseAll(void)
  {
   for(int i = 0; i < ArraySize(m_object_names); i++)
     {
      string name = m_object_names[i];
      if(StringLen(name) == 0) continue;
      if(ObjectFind(ChartID(), name) == -1) continue;
      ObjectSetInteger(ChartID(), name, OBJPROP_XDISTANCE, -1);
      ObjectSetInteger(ChartID(), name, OBJPROP_YDISTANCE, -1);
      ObjectSetInteger(ChartID(), name, OBJPROP_XSIZE, 0);
      ObjectSetInteger(ChartID(), name, OBJPROP_YSIZE, 0);
     }
  }

1.5. Initialisierung von Minichart

Init ist die zentrale Einrichtungsroutine: Sie löscht zunächst alle vorherigen Zustände, wendet übergebene Parameter an, die auf die Standardwerte zurückfallen, analysiert die durch Kommata getrennte Liste majorSymbols, trimmt jedes Symbol und löst es über FindBrokerSymbol in ein maklerspezifisches Symbol auf und baut das Array m_symbols auf. Es berechnet die Layout-Einschränkungen aus der Chartbreite und den Kachelabmessungen und erzwingt dann eine Zeilenbegrenzung, um ein Eindringen in m_top_reserved (den reservierten oberen Bereich) zu vermeiden. Für jedes aufgelöste Symbol wird ein OBJ_CHART erstellt, die Eigenschaften (Symbol, Zeitraum, Abstände, Größen, Datums-/Preisskalen und Chartskala) festgelegt und der erstellte Objektname für spätere Aktualisierungen oder Löschungen gespeichert. Nach der Erstellung wird die Schaltfläche zum Umschalten erstellt, das ursprüngliche Sichtbarkeitskennzeichen beachtet, das Chart neu gezeichnet und der Erfolg zurückgegeben. Diese Methode umfasst die Protokollierung der Symbolauflösung und der erstellten Objekte, sodass das Laufzeitverhalten transparent ist.

//+------------------------------------------------------------------+
//| NEW: set top reserved height (pixels from top)                   |
//+------------------------------------------------------------------+
void CChartMiniTiles::SetTopReservedHeight(const int pixels)
  {
   m_top_reserved = MathMax(0, pixels);
  }

//+------------------------------------------------------------------+
//| Init: create mini tiles                                           |
//+------------------------------------------------------------------+
bool CChartMiniTiles::Init(const string majorSymbols,
                           const int width,
                           const int height,
                           const int xOffset,
                           const int yOffset,
                           const int spacing,
                           const int period,
                           const bool dateScale,
                           const bool priceScale,
                           const int chartScale)
  {
   Delete();

   m_width       = (width  <= 0) ? CMT_DEFAULT_WIDTH  : width;
   m_height      = (height <= 0) ? CMT_DEFAULT_HEIGHT : height;
   m_xoffset     = (xOffset <= 0) ? CMT_DEFAULT_X_OFFSET : xOffset;
   m_yoffset     = (yOffset <= 0) ? CMT_DEFAULT_Y_OFFSET : yOffset;
   m_spacing     = (spacing <= 0) ? CMT_DEFAULT_SPACING : spacing;
   m_period      = (period <= 0) ? CMT_DEFAULT_PERIOD : period;
   m_date_scale  = dateScale;
   m_price_scale = priceScale;
   m_chart_scale = (chartScale <= 0) ? CMT_DEFAULT_CHART_SCALE : chartScale;

   ArrayFree(m_object_names);
   ArrayFree(m_symbols);
   m_count = 0;

   string raw[]; StringSplit(majorSymbols, ',', raw);
   int rawCount = ArraySize(raw);
   if(rawCount == 0) return(false);

   for(int i = 0; i < rawCount; i++)
     {
      string base = TrimString(raw[i]);
      if(StringLen(base) == 0) continue;
      string resolved = FindBrokerSymbol(base);
      if(resolved == "")
        {
         PrintFormat("CMT: symbol not found on this broker: %s", base);
         continue;
        }
      int n = ArraySize(m_symbols);
      ArrayResize(m_symbols, n + 1);
      m_symbols[n] = resolved;
     }

   m_count = ArraySize(m_symbols);
   PrintFormat("CMT: %d symbols resolved for mini-tiles.", m_count);
   for(int i=0;i<m_count;i++) PrintFormat("CMT: symbol[%d] = %s", i, m_symbols[i]);

   if(m_count == 0) return(false);

   ArrayResize(m_object_names, m_count);
   for(int i = 0; i < m_count; i++) m_object_names[i] = "";

   int base_y_from_top = ComputeBaseYFromTop();

   int chartW = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
   if(chartW <= 0) chartW = 800;
   int columns = MathMax(1, chartW / (m_width + m_spacing));

   // --- NEW: limit rows to avoid top reserved region
   int rows = (m_count + columns - 1) / columns;
   int availableAbove = MathMax(0, base_y_from_top - m_top_reserved);
   int maxRowsAllowed = 1 + (availableAbove / (m_height + m_spacing)); // bottom row + how many rows can fit above
   if(maxRowsAllowed < 1) maxRowsAllowed = 1;
   if(rows > maxRowsAllowed)
     {
      // increase columns to fit within allowed rows
      columns = (m_count + maxRowsAllowed - 1) / maxRowsAllowed;
      if(columns < 1) columns = 1;
      rows = (m_count + columns - 1) / columns;
     }
   // ---

   int createdCount = 0;
   for(int i = 0; i < m_count; i++)
     {
      string sym = m_symbols[i];
      string objName = MakeObjectName("CMT_" + sym + "_" + IntegerToString(i));
      m_object_names[i] = objName;

      int col = i % columns;
      int row = i / columns;

      int xdist = m_xoffset + col * (m_width + m_spacing);
      int ydist = base_y_from_top - row * (m_height + m_spacing);
      if(ydist < 0) ydist = 0;

      bool created = ObjectCreate(ChartID(), objName, OBJ_CHART, 0, 0, 0, 0, 0);
      if(!created)
        {
         PrintFormat("CMT: failed to create OBJ_CHART for %s (obj=%s)", sym, objName);
         m_object_names[i] = "";
         continue;
        }

      ObjectSetString(ChartID(), objName, OBJPROP_SYMBOL, sym);
      ObjectSetInteger(ChartID(), objName, OBJPROP_PERIOD, m_period);
      ObjectSetInteger(ChartID(), objName, OBJPROP_XDISTANCE, xdist);
      ObjectSetInteger(ChartID(), objName, OBJPROP_YDISTANCE, ydist);
      ObjectSetInteger(ChartID(), objName, OBJPROP_XSIZE, m_width);
      ObjectSetInteger(ChartID(), objName, OBJPROP_YSIZE, m_height);
      ObjectSetInteger(ChartID(), objName, OBJPROP_DATE_SCALE, (int)m_date_scale);
      ObjectSetInteger(ChartID(), objName, OBJPROP_PRICE_SCALE, (int)m_price_scale);
      ObjectSetInteger(ChartID(), objName, OBJPROP_SELECTABLE, 1);
      ObjectSetInteger(ChartID(), objName, OBJPROP_CHART_SCALE, m_chart_scale);

      createdCount++;
     }

   PrintFormat("CMT: created %d / %d mini-chart objects.", createdCount, m_count);

   CreateToggleButton();

   if(!m_visible)
     SetTilesVisible(false);

   ChartRedraw();
   return(true);
  }

1.6. Layout-Updates

UpdateLayout berechnet die Positionen und Größen neu, wenn sich die Geometrie oder die Sichtbarkeit des Charts ändert. Zunächst wird der ausgeblendete Zustand behandelt, indem die Kacheln zusammengeklappt werden und die Umschalttaste auf „AUS“ aktualisiert wird. Wenn es sichtbar ist, berechnet es die Spalten anhand der Chartbreite neu, erzwingt die Einschränkung „oben reserviert“ (sodass Zeilen nie in den reservierten Bereich hineinreichen) und aktualisiert jedes OBJ_CHART mit den entsprechenden OBJPROP_XDISTANCE, OBJPROP_YDISTANCE, Größen und Chartskalen. Zum Schluss wird der Zustand der Umschalttaste auf „ON“ aktualisiert und ChartRedraw() aufgerufen, damit die Nutzeroberfläche aktualisiert wird. Diese Methode soll immer dann aufgerufen werden, wenn die Größe des Charts geändert wird oder wenn der EA das Layout aktualisieren möchte.

//+------------------------------------------------------------------+
//| UpdateLayout - reposition tiles (respects m_visible and top reserved)|
//+------------------------------------------------------------------+
void CChartMiniTiles::UpdateLayout(void)
  {
   if(!m_visible)
     {
      CollapseAll();
      if(ObjectFind(ChartID(), m_tog_name) >= 0)
        {
         ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_XDISTANCE, m_tog_x);
         ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_YDISTANCE, m_tog_y);
         ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_STATE, 0);
         ObjectSetString(ChartID(), m_tog_name, OBJPROP_TEXT, "Tiles: OFF");
        }
      ChartRedraw();
      return;
     }

   if(m_count == 0) return;

   int chartW = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
   if(chartW <= 0) chartW = 800;
   int chartTotalHeight = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS);
   if(chartTotalHeight <= 0) chartTotalHeight = 600;

   int columns = MathMax(1, chartW / (m_width + m_spacing));

   int base_y_from_top = ComputeBaseYFromTop();

   // --- NEW: ensure rows don't surpass top-reserved area
   int rows = (m_count + columns - 1) / columns;
   int availableAbove = MathMax(0, base_y_from_top - m_top_reserved);
   int maxRowsAllowed = 1 + (availableAbove / (m_height + m_spacing));
   if(maxRowsAllowed < 1) maxRowsAllowed = 1;
   if(rows > maxRowsAllowed)
     {
      columns = (m_count + maxRowsAllowed - 1) / maxRowsAllowed;
      if(columns < 1) columns = 1;
      rows = (m_count + columns - 1) / columns;
     }
   // ---

   for(int i = 0; i < m_count; i++)
     {
      string name = m_object_names[i];
      if(StringLen(name) == 0) continue;
      if(ObjectFind(ChartID(), name) == -1) continue;

      int col = i % columns;
      int row = i / columns;
      int xdist = m_xoffset + col * (m_width + m_spacing);
      int ydist = base_y_from_top - row * (m_height + m_spacing);
      if(ydist < 0) ydist = 0;

      ObjectSetInteger(ChartID(), name, OBJPROP_XDISTANCE, xdist);
      ObjectSetInteger(ChartID(), name, OBJPROP_YDISTANCE, ydist);
      ObjectSetInteger(ChartID(), name, OBJPROP_XSIZE, m_width);
      ObjectSetInteger(ChartID(), name, OBJPROP_YSIZE, m_height);
      ObjectSetInteger(ChartID(), name, OBJPROP_CHART_SCALE, m_chart_scale);
     }

   if(ObjectFind(ChartID(), m_tog_name) >= 0)
     {
      ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_XDISTANCE, m_tog_x);
      ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_YDISTANCE, m_tog_y);
      ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_STATE, 1);
      ObjectSetString(ChartID(), m_tog_name, OBJPROP_TEXT, "Tiles: ON");
     }

   ChartRedraw();
  }

1.7. Sichtbarkeit und Umschalten

Diese kleine Gruppe von Methoden steuert den sichtbaren Zustand der Kacheln. SetTilesVisible aktualisiert das Flag m_visible und positioniert die Kacheln neu oder klappt sie zusammen, je nach dem neuen Zustand; außerdem werden der Zustand und der Text der Umschalttaste aktualisiert. Die Umschalttaste ist ein bequemer Weg, der die Sichtbarkeit umkehrt und SetTilesVisible aufruft. SetToggleButtonPos ermöglicht die dynamische Neupositionierung der Umschalttaste; wenn die Schaltfläche bereits vorhanden ist, werden ihre OBJPROP_XDISTANCE und OBJPROP_YDISTANCE aktualisiert. Diese Methoden sind die programmatischen und UI-Einstiegspunkte für das Ein- und Ausblenden und die Neupositionierung der Kachelsteuerungen.

//+------------------------------------------------------------------+
//| Set visibility programmatically                                  |
//+------------------------------------------------------------------+
void CChartMiniTiles::SetTilesVisible(const bool visible)
  {
   m_visible = visible;
   if(m_count == 0)
     {
      if(ObjectFind(ChartID(), m_tog_name) >= 0)
        {
         ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_STATE, m_visible ? 1 : 0);
         ObjectSetString(ChartID(), m_tog_name, OBJPROP_TEXT, m_visible ? "Tiles: ON" : "Tiles: OFF");
         ChartRedraw();
        }
      return;
     }

   if(m_visible)
     UpdateLayout();
   else
     {
      CollapseAll();
      ChartRedraw();
     }

   if(ObjectFind(ChartID(), m_tog_name) >= 0)
     {
      ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_STATE, m_visible ? 1 : 0);
      ObjectSetString(ChartID(), m_tog_name, OBJPROP_TEXT, m_visible ? "Tiles: ON" : "Tiles: OFF");
     }
  }

//+------------------------------------------------------------------+
//| Toggle                                                           |
//+------------------------------------------------------------------+
void CChartMiniTiles::Toggle(void)
  {
   SetTilesVisible(!m_visible);
  }

//+------------------------------------------------------------------+
//| Set toggle position                                               |
//+------------------------------------------------------------------+
void CChartMiniTiles::SetToggleButtonPos(const int x,const int y)
  {
   m_tog_x = x;
   m_tog_y = y;
   if(ObjectFind(ChartID(), m_tog_name) >= 0)
     {
      ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_XDISTANCE, m_tog_x);
      ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_YDISTANCE, m_tog_y);
     }
  }

1.8. Bereinigung und Ereignisbehandlung

Schließlich führt Delete eine gründliche Bereinigung durch: Es durchläuft das Objektnamen-Array und löscht jedes erstellte OBJ_CHART, entfernt die Umschalttaste, gibt die Arrays mit ArrayFree frei, setzt m_count zurück und zeichnet das Chart neu. HandleEvent ist die Event-Forwarding-Methode, die von OnChartEvent eines EAs aufgerufen werden soll; sie filtert nach CHARTEVENT_OBJECT_CLICK und nach dem Namen der Toggle-Schaltfläche – wenn der Toggle angeklickt wurde, ruft sie Toggle() auf und gibt true zurück, um anzuzeigen, dass das Ereignis behandelt wurde. So bleibt die EA-Integration einfach: Ereignisse weiterleiten und Init/Delete in OnInit/OnDeinit aufrufen.

//+------------------------------------------------------------------+
//| Delete all objects                                                |
//+------------------------------------------------------------------+
void CChartMiniTiles::Delete(void)
  {
   for(int i = 0; i < ArraySize(m_object_names); i++)
     {
      string name = m_object_names[i];
      if(StringLen(name) == 0) continue;
      if(ObjectFind(ChartID(), name) >= 0) ObjectDelete(ChartID(), name);
     }
   DeleteToggleButton();
   ArrayFree(m_object_names);
   ArrayFree(m_symbols);
   m_count = 0;
   ChartRedraw();
  }

//+------------------------------------------------------------------+
//| HandleEvent - forward OnChartEvent to class (returns true if handled)|
//+------------------------------------------------------------------+
bool CChartMiniTiles::HandleEvent(const int id,const string sparam)
  {
   if(id != CHARTEVENT_OBJECT_CLICK) return(false);
   if(StringLen(sparam) == 0) return(false);
   if(sparam == m_tog_name)
     {
      Toggle();
      return(true);
     }
   return(false);
  }

//+------------------------------------------------------------------+
#endif // __CHART_MINI_TILES_CLASS_MQH__

Den vollständigen Quellcode für diesen Header finden Sie am Ende dieser Ausarbeitung, zusammen mit den anderen Dateien, auf die hier verwiesen wird.

2.0 Beispiel EA (MiniChartsEA) zum Testen des Headers

2.1. EA Überblick und Zweck

Dieser EA ist ein Testfeld für die Klasse CChartMiniTiles. Es instanziiert die Klasse, initialisiert Minichart für mehrere Symbole und validiert die Funktionalität zum Umschalten, Ändern der Größe und Aktualisieren vor der Integration in größere Projekte.

//+------------------------------------------------------------------+
//|                                                  MiniChartsEA.mq5|
//|          Dummy EA to test CChartMiniTiles (ChartMiniTilesClass)  |
//+------------------------------------------------------------------+
#property copyright "2025"
#property link      "https://www.mql5.com/en/users/billionaire2024/seller"
#property version   "1.00"
#property description "Mini-charts EA using CChartMiniTiles class"

// --- Include the class header
#include <ChartMiniTiles.mqh>

2.2. Eingaben und globale Variablen

In diesem Abschnitt werden Parameter und Zustandsvariablen definiert, die die Minidiagramme steuern (Symbolliste, Dimensionen, Aktualisierungsverhalten).

//--- Inputs
input string MajorSymbols      = "EURUSD,GBPUSD,USDJPY,USDCHF,USDCAD,AUDUSD,NZDUSD"; 
input int    BarsWidth         = 20;   // bars used to estimate tile pixel width
input int    TileHeightPx      = 112;  // tile height in pixels
input int    HorizontalSpacing = 6;    // spacing between tiles
input int    UpdateInterval    = 1000; // ms timer update interval
input int    XOffset           = 10;   // left margin in pixels
input int    BottomOffset      = 40;   // distance from bottom in pixels
input int    ToggleButtonX     = 8;    // toggle button X
input int    ToggleButtonY     = 6;    // toggle button Y
input bool   DateScale         = false;// show date scale
input bool   PriceScale        = false;// show price scale
input int    ChartScale        = 2;    // chart zoom level

//--- object instance of our class
CChartMiniTiles tiles;

//--- internal state
int pixelWidth = 120;

2.3. Helfer-Methoden

Diese Methode schätzt dynamisch die Kachelbreite in Pixeln, je nachdem, wie viele Balken gerade sichtbar sind.

//+------------------------------------------------------------------+
//| Helper: estimate pixel width from BarsWidth                      |
//+------------------------------------------------------------------+
int CalculateChartWidthFromBars(int barsWidth)
{
   int mainChartWidth = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
   int visibleBars    = (int)ChartGetInteger(0, CHART_VISIBLE_BARS);

   if(visibleBars <= 0 || mainChartWidth <= 0)
      return MathMax(80, BarsWidth * 6); // fallback

   return MathMax(80, barsWidth * mainChartWidth / visibleBars);
}

2.4. Toggle Button Steuerung

Wird durch das Tiles-Objekt (CChartMiniTiles) verwaltet. Der EA selbst legt nur die Ausgangsposition der Umschalttaste fest.

// Inside OnInit we call:
tiles.SetToggleButtonPos(ToggleButtonX, ToggleButtonY);

2.5. Initialisierung von Minichart

In dieser Phase werden alle Minidiagramme mit nutzerdefinierten Einstellungen erstellt.

//+------------------------------------------------------------------+
//| Expert initialization                                            |
//+------------------------------------------------------------------+
int OnInit()
{
   // compute pixel width from BarsWidth heuristic
   pixelWidth = CalculateChartWidthFromBars(BarsWidth);

   // set toggle button position
   tiles.SetToggleButtonPos(ToggleButtonX, ToggleButtonY);

   // initialize tiles
   bool ok = tiles.Init(MajorSymbols,
                        pixelWidth,
                        TileHeightPx,
                        XOffset,
                        BottomOffset,
                        HorizontalSpacing,
                        PERIOD_M1,
                        DateScale,
                        PriceScale,
                        ChartScale);

   if(!ok)
   {
      Print("MiniChartsEA: tiles.Init() failed. Check Experts log for symbol issues.");
      return(INIT_FAILED);
   }

   // start timer for adaptive updates
   EventSetMillisecondTimer(UpdateInterval);

   Print("MiniChartsEA initialized.");
   return(INIT_SUCCEEDED);
}

2.6. Layout-Updates

Dadurch wird sichergestellt, dass die Kacheln die richtige Größe und Position haben, wenn sich das Chart ändert oder die Zeit fortschreitet.

//+------------------------------------------------------------------+
//| Timer: update layout                                             |
//+------------------------------------------------------------------+
void OnTimer()
{
   tiles.UpdateLayout();
}

2.7. Sichtbarkeit und Umschalten

Hier delegiert der EA Toggle-Button-Klicks an die Klasse und achtet auf Chart-Änderungen, damit alles ausgerichtet bleibt.

//+------------------------------------------------------------------+
//| Chart events - forward to tiles                                  |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   // Let tiles handle toggle button clicks
   if(tiles.HandleEvent(id, sparam))
      return;

   // If chart resized or layout changed, reflow tiles
   if(id == CHARTEVENT_CHART_CHANGE)
      tiles.UpdateLayout();
}

2.8. Bereinigung und Ereignisbehandlung

Dies gewährleistet eine saubere Entfernung der Objekte, wenn der EA beendet wird.

//+------------------------------------------------------------------+
//| Deinitialization                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   EventKillTimer();
   tiles.Delete();
   Print("MiniChartsEA deinitialized.");
}

3.0 Erste Tests

In diesem Stadium fügen wir unseren Beispiel-EA zum Chart hinzu und beobachten die Ergebnisse. In meinem Testlauf zeigte das Chart Kacheln für die wichtigsten Paare an, die ich ausgewählt hatte, jeweils angepasst an das Symbolformat meines Brokers (mit einem .0-Suffix). Die Umschalttaste funktionierte einwandfrei, sodass ich die Kacheln problemlos ein- und ausschalten konnte. Diese Funktion bietet Händlern die Flexibilität, das Hauptdiagramm bei Bedarf vollständig anzuzeigen – eine einfache, aber leistungsstarke Steuerung.

Diese Funktionalität wird noch wertvoller werden, wenn die Klasse in den News Headline EA integriert wird, wo mehrere Komponenten eine komplexere Chartumgebung schaffen werden. Die Möglichkeit, die Minikacheln schnell umzuschalten, sorgt für einen aufgeräumten, übersichtlichen Arbeitsbereich.

Die folgende Abbildung zeigt den Einsatz und die Ausgabe von MiniChartsEA.

Testen der MiniChatTilesEA

Abbildung 1: Testergebnisse des MiniChartsEA auf dem EURUSD-Chart.

Jetzt können wir mit der Integration der CChartMiniTiles-Klasse in den News Headline EA fortfahren. Im nächsten Abschnitt werden wir den aktualisierten Code im Detail untersuchen und dann das daraus resultierende Verhalten im Chart überprüfen.

4.0 Integration der ChartsMiniTiles in die NewsHeadlineEA

4.1. Die Header von ChartMiniTiles einbinden – die Klasse für den EA verfügbar machen

Um die Klasse der Minikacheln zu verwenden, müssen Sie deren Header am oberen Rand des EA einfügen. Dies bringt die Klassendeklaration und -implementierung in die Kompiliereinheit des EA, sodass Sie eine Instanz erstellen und ihre Methoden aufrufen können. Die Platzierung des Includes zusammen mit den anderen Headern (TradingButtons, Canvas, Trade) sorgt für Ordnung bei den Importen und signalisiert die Abhängigkeit für zukünftige Betreuer. Wenn die Datei in MQL5/Include/ fehlt, wird sich der Compiler an dieser Stelle beschweren; dies ist also der allererste Integrationsschritt.

#include <TradingButtons.mqh>
#include <Trade\Trade.mqh>
#include <Canvas\Canvas.mqh>
#include <ChartMiniTiles.mqh>   // <-- CTM class include (make sure this file is in MQL5/Include/)

4.2. Deklarieren Sie die CChartMiniTiles-Instanz – erstellen Sie den Kachelmanager des EA

Durch die Deklaration einer globalen CChartMiniTiles-Kachel erhält der gesamte EA Zugriff auf einen einzigen Kachelmanager. Diese Instanz enthält den Status (erstellte Objektnamen, Symbolliste, Sichtbarkeitsflagge, reservierte obere Höhe) und stellt Methoden für Initialisierung, Layoutaktualisierung, Ereignisbehandlung und Bereinigung zur Verfügung. Die Deklaration unter anderen Globals erleichtert die Verwaltung ihres Lebenszyklus in OnInit / OnTimer / OnChartEvent / OnDeinit.

//+------------------------------------------------------------------+
//| ChartMiniTiles instance (CTM)                                     |
//+------------------------------------------------------------------+
CChartMiniTiles tiles;   // class instance for mini tiles

4.3. Erstellen der Symbolliste und Schätzen der Kachelpixelbreite – Vorbereiten der ChartMiniTiles-Eingaben

Vor dem Aufruf von tiles.Init benötigen Sie eine durch Kommata getrennte Zeichenkette und eine angemessene Pixelbreite für die Kacheln. Dieser Abschnitt konstruiert ctmSymbols aus Ihrem Array majorPairs[] mit JoinSymbolArray() und berechnet pixelWidth mit einer Balken-zu-Pixeln-Heuristik, die auf der Breite des Hauptdiagramms und den sichtbaren Balken basiert. Wenn Sie dies bei der Initialisierung tun, wird sichergestellt, dass die Kachelgrößen an das aktuelle Chartlayout angepasst werden und dass die Symbolbenennung des Brokers durch FindBrokerSymbol innerhalb der Klasse aufgelöst wird.

   // Build a comma-separated symbol list from majorPairs[] and initialize CTM.
   string ctmSymbols = JoinSymbolArray(majorPairs);
   // Estimate pixel width from Bars heuristic (simple fallback)
   int mainChartWidth = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
   int visibleBars    = (int)ChartGetInteger(0, CHART_VISIBLE_BARS);
   int pixelWidth = 120;
   if(visibleBars > 0 && mainChartWidth > 0)
      pixelWidth = MathMax(80, CTM_TileWidthBars * mainChartWidth / visibleBars);

4.4. Platzieren und Festlegen der Position der Umschalttaste – die Nutzeroberfläche muss zugänglich bleiben.

Die Umschalttaste ist das nutzerseitige Steuerelement zum Ein- und Ausblenden von Kacheln. Durch die absichtliche Positionierung direkt unter dem Handelsbereich wird sichergestellt, dass es keine wichtigen Bedienelemente der Nutzeroberfläche überdeckt. Nach der Berechnung von tradingPanelBottomY ruft der EA tiles.SetToggleButtonPos(toggleX, toggleY) auf, um die Klasse anzuweisen, wo die Schaltfläche erstellt werden soll. Diese Platzierung erfolgt vor der Initialisierung der Kacheln, damit die Schaltfläche vorhanden ist und mit der Logik des reservierten Bereichs übereinstimmt, die dann folgt.

   // Place the CTM toggle button JUST BELOW the trading panel bottom
   int toggleX = 8;
   int toggleY = tradingPanelBottomY + 6; // +6 px margin so it doesn't touch trading controls
   tiles.SetToggleButtonPos(toggleX, toggleY);

 4.5. Reservieren des oberen Bereichs der Nutzeroberfläche für die Handelssteuerungen – Vermeiden von Überschneidungen.

Um zu vermeiden, dass die Mini-Kacheln das Handelsfenster und die Umschalttaste überdecken, berechnet der EA einen topReserve-Wert und ruft tiles.SetTopReservedHeight (topReserve) auf. Die Tiles-Klasse verwendet diesen Wert, um zu begrenzen, wie viele Zeilen von unten nach oben gestapelt werden können; dadurch bleibt der obere Bereich für Schaltflächen, Leinwände oder andere UI-Elemente erhalten. Die Reservierung des oberen Platzes vor dem Aufruf von Init garantiert, dass die Layoutberechnungen diesen Platz sofort berücksichtigen.

   // Reserve the area above tiles so the trading UI remains free. We reserve up to the toggle bottom.
   int topReserve = toggleY + CMT_TOG_H + 4; // leave a few px extra
   tiles.SetTopReservedHeight(topReserve);

4.6. Initialisierung der Kacheln – Erstellen von OBJ_CHART-Objekten für jedes Symbol

Dies ist der zentrale Integrationsaufruf. Der EA übergibt die aufgelöste Symbolliste, die berechnete Pixelbreite, die Kachelhöhe, die Offsets, die Abstände, die Chartperiode und die Skalierung an tiles.Init(...). Die Klasse löst maklerspezifische Namen auf, erstellt OBJ_CHART-Objekte, legt deren Eigenschaften fest (Symbol, Periode, Skalen, Größen) und erstellt die Umschalttaste. Der EA prüft den booleschen Rückgabewert (ctm_ok), um Initialisierungsfehler angemessen zu behandeln (z. B. wenn keine Symbole auf diesem Broker aufgelöst wurden).

   // Initialize tiles: (symbols, widthPx, heightPx, xOffset, bottomOffset, spacing, period, dateScale, priceScale, chartScale)
   bool ctm_ok = tiles.Init(ctmSymbols, pixelWidth, CTM_TileHeightPx, CTM_XOffset, CTM_BottomOffset, CTM_Spacing, PERIOD_M1, false, false, CTM_ChartScale);
   if(!ctm_ok)
   {
      Print("CTM: initialization failed (no matching symbols?); tiles disabled.");
   }

4.7. Das Layout reaktionsfähig halten – UpdateLayout aufrufen, wenn sich das Chart ändert oder ein Timer läuft

Nach der Initialisierung muss der EA die Kacheln an der richtigen Stelle halten, wenn sich die Kartengröße oder das Layout ändert. Die Integration umfasst drei Orte:

  • Weiterleitung von Chartänderungsereignissen zur Neupositionierung von Kacheln (sodass Änderungen der Nutzergröße oder des Arbeitsbereichs berücksichtigt werden).
  • Regelmäßiger Aufruf von tiles.UpdateLayout() in der OnTimer-Schleife, um dynamische UI-Verschiebungen zu handhaben oder um sich von externen Änderungen zu erholen.
  • Aufruf von tiles.UpdateLayout() am Ende der OnTimer-Hauptverarbeitungsschleife, damit die ChartMiniTiles (CTM) immer nach anderen UI-Aktualisierungen (Leinwände, Nachrichten, KI-Einsichten) aktualisiert wird.

Nachfolgend finden Sie die genauen Ausschnitte, die in Ihrem EA verwendet werden, um diese Fälle zu behandeln.

OnChartEvent-Weiterleitung und Reaktion auf Chartwechsel:

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   // Let CTM handle object clicks first (toggle button)
   if(tiles.HandleEvent(id, sparam))
      return;

   // Forward to the TradingButtons header afterward
   buttonsEA.HandleChartEvent(id, sparam, majorPairs, pairSelected);

   // Also respond to chart change events for CTM layout
   if(id == CHARTEVENT_CHART_CHANGE)
      tiles.UpdateLayout();
}

End-of-OnTimer-Update (hält CTM bei jedem Timer-Tick synchron):

   // Keep CTM updated every tick (timer-driven)
   tiles.UpdateLayout();
}

4.8. Aufräumarbeiten bei der Deinitialisierung – Kacheln und Umschaltknöpfe löschen

Wenn der EA aufhört oder entfernt wird, muss er alle von ihm erstellten Objekte entfernen. Durch den Aufruf von tiles.Delete() werden alle OBJ_CHART und die Umschalttaste entfernt, die Arrays freigegeben und das Chart neu gezeichnet. Dies ist der letzte Integrationsschritt und verhindert, dass verwaiste Objekte auf dem Chart verbleiben.

   // delete CTM tiles and toggle button
   tiles.Delete();

Checkliste zur schnellen Integration (Zusammenfassung)

  1. #include <ChartMiniTiles.mqh> am Anfang.
  2. Deklarieren von CChartMiniTiles tiles; global.
  3. Erstellen von ctmSymbols und Berechnen der Pixelbreite vor Init.
  4. Setzen der Umschaltposition über tiles.SetToggleButtonPos(...).
  5. Reservieren des oberen UI-Bereichs über tiles.SetTopReservedHeight(...).
  6. Initialisieren mit tiles.Init(...) und Rückgabe prüfen.
  7. Weiterleiten von OnChartEvent an tiles.HandleEvent(...) und aufrufen von tiles.UpdateLayout() bei Chartänderungen und periodischen Updates auf.
  8. Rufen Sie tiles.Delete() in OnDeinit auf.


Tests und Ergebnisse

Dies markiert die letzte Testphase des integrierten News Headline EA. Nachdem wir das fehlerfreie Programm in MetaEditor 5 kompiliert haben, setzen wir es auf einem MetaTrader 5-Terminalchart ein, um sein Verhalten zu beobachten. Die folgenden Screenshots zeigen die Ergebnisse meines Testlaufs.

Abbildung 2: Einsatz des News Headline EA auf dem AUDUSD-Chart mit Mini-Chart-Kacheln für den Handel mit mehreren Symbolen

Mehrere Eigenschaften des News Headline EA

Abbildung 3: ChartMiniTiles funktionieren in News Headline EA

Nach Prüfung der oben genannten Ergebnisse haben wir unsere Lösung für das festgestellte Problem erfolgreich integriert. Händler können sich nun mehrere Paare auf einem einzigen Chart anzeigen lassen, und die Steuerungsschaltflächen funktionieren wie erwartet. Eine weitere bemerkenswerte Errungenschaft ist, dass wir diese neue Funktion implementiert haben, ohne dass es zu Überschneidungen oder Beeinträchtigungen mit der bestehenden Funktionalität im News Headline EA kam, dank eines angemessenen Layout-Managements und der Fähigkeiten der MQL5-Sprache. Im nächsten Abschnitt werden wir abschließend die wichtigsten Errungenschaften dieser Arbeit hervorheben.


Schlussfolgerung

Wir haben erfolgreich eine Klasse integriert, die mehrere Mini-Chartansichten in einem einzigen Hauptdiagramm verwaltet, indem wir den New Headline EA verwenden. Dieser Ansatz bietet Händlern ein leistungsfähiges Tool, mit dem sie mehrere Symbole gleichzeitig überwachen und handeln können, was die Effizienz erhöht – insbesondere in Zeiten hoher Volatilität, wie z. B. bei wichtigen Nachrichtenmeldungen. Wenn mehrere Positionen für verschiedene Paare eröffnet werden, ermöglicht dieses Tool den Händlern, diese über eine einzige Schnittstelle zu verwalten und zu verfolgen, was eine schnelle Kontrolle und Ausführung von Handelsgeschäften ermöglicht.

Aus pädagogischer Sicht bietet diese Diskussion wertvolle Einblicke, einschließlich der Entwicklung nutzerdefinierter Klassen, Multi-Symbol-Handelsstrategien, schneller Auftragsausführung und Paarauswahl – und das alles, ohne den aktuellen Chart zu verlassen.

Dies zeigt zwar, dass der Handel mit mehreren Paaren möglich ist, aber es besteht noch erheblicher Spielraum für Verbesserungen. Vor allem die Verfeinerung von Techniken, die eine flexiblere Analyse ausgewählter Paare ermöglichen, ist von entscheidender Bedeutung. Bei einer weiteren Entwicklung könnte der Algorithmus automatische Analysemethoden enthalten, um das derzeitige System zu verbessern. Künftige Veröffentlichungen werden sich mit diesen Verbesserungen befassen.

Wir freuen uns auf Ihre Ideen und Beiträge zu dieser Diskussion. Im Anhang finden Sie den Quellcode und ein Bild, das das Hauptdiagramm zusammen mit dem ChartMiniTiles-Setup zeigt.



Wichtige Lektionen

Wichtige LektionBeschreibung:
Mehrfach-Symbol-ManagementHändler können effizient mehrere Handelspaare auswählen und überwachen, ohne immer wieder die Charts wechseln zu müssen.
Dedizierte Multi-Chart-KlasseDie Verwendung einer eigenständigen Klasse zur Verwaltung mehrerer Minidiagramme vereinfacht die Integration und erhält den modularen Code aufrecht.
Eigenständige Tests vor der IntegrationDie Entwicklung und Validierung einer Funktion in einem separaten Test-EA gewährleistet Stabilität, bevor sie in den Haupt-EA integriert wird.
Anpassbare Mini-Chart-LayoutsMinichart können in der Größe verändert und nach den Wünschen der Nutzer angeordnet werden, was die Sichtbarkeit und den Arbeitsablauf verbessert.
Multi-Symbol-Visualisierung in EchtzeitDie Anzeige mehrerer Symbole in einem einzigen Chart ermöglicht es Händlern, bei volatilen Marktbedingungen schneller zu reagieren.
Modulare ProgrammierungDie Aufteilung der Funktionalität in Header und Klassen fördert die Wartbarkeit und Wiederverwendbarkeit in verschiedenen Projekten.
Inkrementelle FunktionsentwicklungDas schrittweise Hinzufügen neuer Funktionen reduziert Fehler und gewährleistet eine reibungslose Integration in bestehende Systeme.
Ereignisbehandlung in MinichartsJedes Minidiagramm kann auf Nutzerinteraktionen reagieren und ermöglicht so interaktive und dynamische Analysen.
Integration mit Main EANach den Tests wird die Klasse der Minicharts in den Haupt-EA integriert, um eine nahtlose Multi-Symbol-Handelsfunktionalität zu bieten.
Wiederverwendbare Utility-KlassenKlassen wie CChartMiniTiles dienen als modulare Werkzeuge, die für andere Projekte und EAs angepasst werden können.
Effiziente Workflow-PraktikenDie Verwendung eines strukturierten Arbeitsablaufs – Prototyp, Test, Integration – verbessert die Entwicklungsgeschwindigkeit und reduziert Fehler.
Schnelle EntscheidungshilfeMinichart bieten Händlern einen konsolidierten Überblick über mehrere Märkte und ermöglichen so schnellere Handelsentscheidungen.
Dynamische ObjektverwaltungDer Code zeigt, wie Chartobjekte dynamisch für jedes Minidiagramm erstellt, aktualisiert und zerstört werden können, was für ein skalierbares EA-Design unerlässlich ist.
Effiziente SpeichernutzungDurch die Verwaltung von Minichart als separate Objekte und die Aktualisierung nur der sichtbaren Elemente optimiert der EA die Speicher- und CPU-Auslastung.
Nahtlose EreignisfortpflanzungDie Klasse des Minichart zeigt, wie Chart-Ereignisse hierarchisch gehandhabt werden können, um sicherzustellen, dass Ereignisse die richtige Chartinstanz ohne Konflikte erreichen.


Anlagen

DateinameVersionBeschreibung
ChartMiniTiles.mqh1.0Definiert die Klasse CChartMiniTiles, die für die Verwaltung und Anzeige mehrerer Mini-Chartansichten innerhalb eines einzigen Hauptdiagramms zuständig ist. Bietet modulare Multi-Symbol-Visualisierungs- und Interaktionsmöglichkeiten.
MiniChartsEA.mq51.0Dummy-EA, der zum Testen der CChartMiniTiles-Klasse vor der Integration in den Haupt-EA für Nachrichtenschlagzeilen erstellt wurde. Validiert das Layout, die Größenänderung und die Ereignisbehandlung von Minicharts.
NewsHeadlineEA.mq51.14Main Expert Advisor, der mehrere Funktionen integriert: Visualisierung der Nachrichtenspur, automatisierter Handel auf der Grundlage von Kalenderereignissen und Multi-Symbol-Handel mit Minichart.
TradingButtons.mqh1.0Bietet Schaltflächen für die Ausführung von Handelsgeschäften, die Auswahl von Paaren und die Verwaltung von Aufträgen direkt im Chart. Unterstützt schnelle Multi-Symbol-Handelsinteraktionen im EA.
terminal64_Dp0JGQhX5.pngK.A.Ein breiter Terminal-Chart-Screenshot, der die ChartMiniTiles-Funktion des News Headline EA illustriert und den Multi-Symbol-Handel, die Echtzeitüberwachung und die schnelle visuelle Analyse zeigt.

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

Beigefügte Dateien |
ChartMiniTiles.mqh (38.64 KB)
MiniChartsEA.mq5 (9.85 KB)
NewsHeadlineEA.mq5 (68.81 KB)
TradingButtons.mqh (38.59 KB)
Automatisieren von Handelsstrategien in MQL5 (Teil 31): Erstellung eines Price Action 3 Drives Harmonic Pattern Systems Automatisieren von Handelsstrategien in MQL5 (Teil 31): Erstellung eines Price Action 3 Drives Harmonic Pattern Systems
In diesem Artikel entwickeln wir ein 3 Drives Pattern System in MQL5, das steigende und fallende harmonische Muster der 3 Drives mit Umkehrpunkten und Fibonacci-Verhältnissen identifiziert und Handelsgeschäfte mit anpassbaren Einstiegs-, Stop-Loss- und Take-Profit-Levels basierend auf vom Nutzer ausgewählten Optionen ausführt. Wir verbessern den Einblick des Händlers mit visuellem Feedback durch Chart-Objekte.
Selbstoptimierende Expert Advisors in MQL5 (Teil 13): Eine sanfte Einführung in die Kontrolltheorie mit Hilfe der Matrixfaktorisierung Selbstoptimierende Expert Advisors in MQL5 (Teil 13): Eine sanfte Einführung in die Kontrolltheorie mit Hilfe der Matrixfaktorisierung
Die Finanzmärkte sind unberechenbar, und Handelsstrategien, die in der Vergangenheit profitabel erschienen, brechen unter realen Marktbedingungen oft zusammen. Das liegt daran, dass die meisten Strategien, wenn sie einmal eingeführt sind, nicht mehr angepasst werden oder aus ihren Fehlern lernen können. Mit Hilfe von Ideen aus der Kontrolltheorie können wir mit Hilfe von Rückkopplungsreglern beobachten, wie unsere Strategien mit den Märkten interagieren und ihr Verhalten auf Rentabilität ausrichten. Unsere Ergebnisse zeigen, dass das Hinzufügen eines Feedback-Controllers zu einer einfachen gleitenden Durchschnittsstrategie die Gewinne verbessert, das Risiko reduziert und die Effizienz erhöht, was beweist, dass dieser Ansatz ein großes Potenzial für Handelsanwendungen hat.
Aufbau eines professionellen Handelssystems mit Heikin Ashi (Teil 1): Entwickeln eines nutzerdefinierten Indikators Aufbau eines professionellen Handelssystems mit Heikin Ashi (Teil 1): Entwickeln eines nutzerdefinierten Indikators
Dieser Artikel ist der erste Teil einer zweiteiligen Serie, die praktische Fähigkeiten und Best Practices für das Schreiben von nutzerdefinierten Indikatoren in MQL5 vermitteln soll. Anhand des Heikin Ashi als Arbeitsbeispiel untersucht der Artikel die Theorie hinter den Heikin Ashi-Charts, erklärt, wie Heikin Ashi-Kerzen berechnet werden, und demonstriert ihre Anwendung in der technischen Analyse. Das Herzstück ist eine schrittweise Anleitung zur Entwicklung eines voll funktionsfähigen Heikin Ashi-Indikators von Grund auf, mit klaren Erklärungen, die dem Leser helfen zu verstehen, was zu programmieren ist und warum. Dieses Grundwissen bildet die Grundlage für den zweiten Teil, in dem wir einen Expert Advisor erstellen werden, der auf der Grundlage der Heikin Ashi-Logik handelt.
Automatisieren von Handelsstrategien in MQL5 (Teil 30): Erstellen eines harmonischen AB-CD-Preisaktionsmusters mit visuellem Feedback Automatisieren von Handelsstrategien in MQL5 (Teil 30): Erstellen eines harmonischen AB-CD-Preisaktionsmusters mit visuellem Feedback
In diesem Artikel entwickeln wir einen AB=CD Pattern EA in MQL5, der harmonische Auf- und Abwärtsmuster von AB=CD mit Hilfe von Umkehrpunkten und Fibonacci-Ratios identifiziert und Trades mit präzisen Einstiegs-, Stop-Loss- und Take-Profit-Levels ausführt. Wir verbessern den Einblick des Händlers mit visuellem Feedback durch Chart-Objekte.