Vom Neuling zum Experten: Animierte Nachrichtenüberschrift mit MQL5 (I)
Inhalt:
Einführung
Heute möchten wir eine häufige Einschränkung beim Zugriff auf Wirtschaftsnachrichten und Kalenderereignisse innerhalb des MetaTrader 5-Terminals beheben – insbesondere bei der aktiven Chartanalyse.
Im MetaTrader 5 sind sowohl die Registerkarten Nachrichten als auch Wirtschaftskalender im Fenster Toolbox verfügbar. Diese Registerkarten enthalten wichtige Informationen, die von seriösen Nachrichtenanbietern stammen. Es ist jedoch wichtig, den Unterschied zwischen den beiden zu verstehen:
- Registerkarte Nachrichten: Zeigt Schlagzeilen und Updates an, die bereits veröffentlicht wurden.
- Wirtschaftskalender: Hier finden Sie eine Übersicht über anstehende wirtschaftliche Ereignisse, geordnet nach Datum, Uhrzeit und Wichtigkeit – nützlich für die Planung im Voraus.
Beide Instrumente sind für die Marktanalyse unerlässlich. Erfahrene Händler wissen, dass einige Wirtschaftsveröffentlichungen – wie z. B. Zinsentscheidungen oder Lohn- und Gehaltsabrechnungen außerhalb der Landwirtschaft – den Markt erheblich beeinflussen können. Mit der richtigen Vorbereitung bieten solche Ereignisse profitable Handelsmöglichkeiten. Sie bergen jedoch auch ein erhebliches Risiko, wenn die Handelsgeschäfte entgegen den Erwartungen verlaufen.

Zugriff auf die Nachrichten und den Kalender im MetaTrader 5.
Auf dem oben gezeigten Screenshot sehen Sie, dass der MetaTrader 5 sowohl auf die Nachrichten als auch auf den Wirtschaftskalender in einer einzigen integrierten Umgebung zugreifen kann. Dabei wird jedoch eine wichtige Einschränkung deutlich: Um eine dieser Funktionen anzuzeigen, muss der Nutzer manuell zum Toolbox-Fenster navigieren.
In der Toolbox werden die Informationen in tabellarischer Form dargestellt – in Zeilen und Spalten werden verschiedene Nachrichten und geplante Ereignisse zusammen mit den entsprechenden Details angezeigt. Die Nutzer können durch den Nachrichten-Feed blättern, um Schlagzeilen zu lesen, oder den Kalender durchstöbern, um sich über anstehende wirtschaftliche Veröffentlichungen zu informieren. Das Toolbox-Panel kann zwar erweitert werden, um mehr Inhalte anzuzeigen, doch geht dies mit einer Verkleinerung des Chart-Fensters einher, wodurch möglicherweise Preisaktionen, Indikatoren oder grafische Objekte im Chart verdeckt werden.
Die von uns vorgeschlagene Lösung behebt diese Einschränkung, indem sie Schlagzeilen und Kalenderereignisse direkt auf das Chart projiziert, wobei die volle Sichtbarkeit beibehalten wird, ohne in den Chart-Raum einzudringen oder Handelsobjekte zu beeinträchtigen. Ziel ist es, die Zugänglichkeit und das Situationsbewusstsein zu verbessern und gleichzeitig eine saubere und funktionale Chart-Umgebung zu bewahren.
In diesem einleitenden Abschnitt unserer Miniserie werde ich zunächst den MQL5-Wirtschaftskalender implementieren, um eine Schlagzeile mit den anstehenden Ereignissen anzuzeigen. Die Lösung lehnt sich an die Art und Weise an, wie Schlagzeilen normalerweise am unteren Rand eines Fernsehbildschirms angezeigt werden oder wie Werbung in sozialen Medien normalerweise auf diese Weise ausgestrahlt wird.
Im folgenden Abschnitt stellen wir den Ansatz vor, mit dem der Nachrichtenschlagzeilen-EA unter Verwendung von MQL5 erstellt werden soll. Wir skizzieren die Designstrategie, gehen die wichtigsten Implementierungsentscheidungen durch und gehen dann im Detail auf die Codebasis ein.
Abschließend werden die Testergebnisse und Beobachtungen vorgestellt, die einen vollständigen Überblick über den Lebenszyklus der Entwicklung dieses Echtzeit-Nachrichtenanzeigesystems in MetaTrader 5 geben.
Konzept
Um diese Idee in die Tat umzusetzen, werden wir die MQL5-Standardbibliothek nutzen, die robuste Werkzeuge für die Entwicklung grafischer Schnittstellen bietet. Konkret verwenden wir die CCanvas-Klasse, die sich in der Datei MQL5\Include\Canvas\Canvas.mqh befindet. Mit dieser Klasse können wir rechteckige, transparente Zeichenflächen erstellen – ideal, um dynamische Inhalte wie Schlagzeilen und aktuelle Wirtschaftsereignisse direkt in das Chart einzublenden.
Im Mittelpunkt unserer Implementierung steht ein scrollendes Tickersystem, das kontinuierlich relevante Informationen anzeigt, ohne die Chart-Funktionalität zu unterbrechen. Dieses Konzept ist inspiriert von realen Oberflächen, wie sie in Nachrichtensendungen, Finanzwebsites und sogar in sozialen Medien zu sehen sind, wo sich aufmerksamkeitsstarke Schlagzeilen über den Bildschirm bewegen, um Echtzeit-Updates zu liefern.

Ausschnitt aus der Definition der Überschrift aus Google-Suche.
An dieser Stelle werden Sie sich vielleicht fragen, warum wir diesen Expert Advisor speziell als „News headline“ (Nachrichtenschlagzeile) bezeichnen. Der Begriff „Schlagzeile“ bezieht sich auf eine kurze, auffällige Zusammenfassung der wichtigsten Informationen, die so gestaltet ist, dass sie leicht zu sehen und schnell zu verstehen ist. In unserem Fall dient sie als kompakte Möglichkeit, zeitkritische Marktdaten (z. B. Nachrichten oder Wirtschaftsmeldungen) in einem zugänglichen und visuell ansprechenden Format zu vermitteln.

Das Konzept: Rufen Sie Wirtschaftskalenderdaten über die MQL5-API ab und zeigen Sie anstehende Ereignisse direkt im Chart durch unseren nutzerdefinierten News Headline EA an.
Um diese Entwicklungsphase zu vereinfachen, werden wir uns zunächst auf zwei Kernkomponenten konzentrieren:
- Verstehen und Nutzen der CCanvas-Klasse in MQL5, die nutzerdefiniertes grafisches Zeichnen auf dem Chart ermöglicht.
- Implementierung des MQL5-Wirtschaftskalenders unter Verwendung eingebauter Funktionen zum Abrufen anstehender Ereignisse und deren Anzeige mit einem horizontalen Bildlaufeffekt.
Dieses horizontale Scrolling-Design ist beabsichtigt – es spart wertvollen vertikalen Platz auf dem Chart und bietet eine nicht aufdringliche Inline-Anzeige zeitkritischer Informationen.
Als zukunftsweisende Erweiterung planen wir auch die Integration einer externen Nachrichten-API in zukünftigen Iterationen. Dies ermöglicht es uns, Echtzeit-Marktnachrichten in einer separaten Scrollspur unterhalb der Kalenderereignisse anzuzeigen. Zunächst legen wir den Grundstein, indem wir einen Platzhaltertext einfügen, der den News-Feed darstellt.
Auf einen Blick kann ein Händler, der dieses System verwendet, Folgendes feststellen:- Erkennen wichtiger, bevorstehende Ereignisse sofort.
- Wie schnell sie eintreten werden (z. B. in Stunden oder Minuten).
- Erkennen des erwarteten Ausmaßes der Auswirkungen, sodass der Händler eine vorsichtigere oder informiertere Strategie wählen kann.
Nachdem wir uns mit den grundlegenden Konzepten beschäftigt haben, gehen wir nun zu einer tieferen Untersuchung der Implementierungsdetails über.
Umsetzung
Verstehen der Canvas-Kopfzeile
Die Klasse CCanvas in MQL5 ist ein leistungsstarkes und vielseitiges Dienstprogramm, das für die Erstellung und Verwaltung von nutzerdefinierten grafischen Oberflächen und visuellen Elementen direkt in MetaTrader 5-Charts entwickelt wurde. Im Kern ermöglicht CCanvas Entwicklern die Erstellung von speicherinternen Bitmap-Oberflächen, die durch Chart-Objekte wie OBJ_BITMAP und OBJ_BITMAP_LABEL gerendert werden. Dies ermöglicht das dynamische Zeichnen von grafischen Inhalten – einschließlich Linien, Formen, Polygonen und Text – über Charts, ohne die nativen Chart-Elemente zu beeinträchtigen. Die Klasse bietet Low-Level-Kontrolle über das Rendering durch einen Pixelpuffer (m_pixels[]), zusammen mit Funktionen wie CreateBitmapLabel() zur Initialisierung und Update() zur Aktualisierung der Ausgabe.
CCanvas bietet ein leistungsfähiges Ressourcenmanagement: Entwickler können Bitmaps laden oder speichern, Leinwände (canvas) an Charts anhängen oder von ihnen lösen und Pixel direkt mit PixelSet() oder PixelGet() manipulieren – ideal für leistungssensible Anwendungen. Seine Flexibilität erstreckt sich auf Farbformate (ARGB, XRGB, mit Transparenz), Polygon-Rendering (einschließlich nicht-konvexer Füllungen) und Chartschnittstellen mit Ebenen.
In der Praxis öffnet CCanvas die Tür für anspruchsvolle UI-Entwicklung in MetTrader 5. Es wird häufig für nutzerdefinierte Indikatoren (wie geglättete oder schattierte Overlays), interaktive Tools (wie Trendlinien mit nutzerdefinierten Caps), Dashboards zur Handelsvisualisierung und voll funktionsfähige Chart-Panels mit Schaltflächen, Schiebereglern oder sogar scrollenden Nachrichtentickern verwendet. Obwohl das CPU-gebundene Rendering es in Kontexten mit ultrahoher Auflösung einschränkt, machen seine Präzision auf Pixelebene und seine vollständige Anpassbarkeit es für High-End-Chart-Oberflächen unverzichtbar.
Verstehen des Wirtschaftskalender
Wenn Sie mit dem MetaTrader 5-Wirtschaftskalender arbeiten, müssen Sie zunächst verstehen, dass jedes Ereignis über eine eindeutige Länderkennung an ein bestimmtes Land (oder eine Wirtschaftsunion) gebunden ist. In MQL5 wird dies durch die Struktur MqlCalendarCountry dargestellt, die Felder wie id (den ISO 3166-1-Code), den Ländernamen, den Zwei-Buchstaben-Code, den Währungscode und das Währungssymbol und sogar den URL-freundlichen Ländernamen enthält. Indem Sie die Liste der MqlCalendarCountry-Einträge des Kalenders einmal abfragen, erhalten Sie Zugang zu allen Attributen, die Sie benötigen, um Ereignisse nach Regionen zu filtern oder zu gruppieren. Jedes Kalenderereignis verweist dann über das Feld country_id in der Struktur MqlCalendarEvent auf sein Land zurück.
Diese Struktur selbst beschreibt die allgemeinen Merkmale eines wiederkehrenden Ereignistyps – seinen Namen, seine Bedeutung, seinen Wirtschaftssektor (BIP, Arbeitsplätze, Preise usw.), seine Periodizität (täglich, monatlich, vierteljährlich) und die Einheiten, in denen seine Werte gemeldet werden. Entscheidend ist, dass es sich nicht um ein einzelnes Ereignis handelt, sondern um die „Vorlage“ oder Definition eines Ereignisses (z. B. „US CPI Release“), das der Kalenderdienst im Laufe seiner veröffentlichten Geschichte viele Male planen kann.
Die tatsächlich geplanten Ereignisse dieser Ereignistypen – komplett mit Zeitstempeln, tatsächlichen und prognostizierten Werten und etwaigen Revisionen – werden in einer separaten Tabelle mit MqlCalendarValue-Strukturen gespeichert. Jeder MqlCalendarValue-Datensatz enthält eine event_id (mit Rückverweis auf die Vorlage in MqlCalendarEvent), eine genaue Zeit und einen Zeitraum sowie vier numerische Felder (actual_value, forecast_value, prev_value, revised_prev_value), die bereits ausgefüllt sein können oder auch nicht. Hilfsmethoden wie HasActualValue() und GetActualValue() erleichtern die Überprüfung und den Abruf von realen Werten (die automatisch von der internen „ppm“-Darstellung des Kalenders zurückskaliert werden).
Dieser relationale Aufbau – Länder, Ereignistypen und dann Ereignisereignisse – stellt sicher, dass Daten nicht unnötig dupliziert werden: vierteljährliche VPI-Einträge zum Beispiel verweisen alle auf eine einzige VPI-Definition, die ihre Wichtigkeitsstufe, Einheiten und Häufigkeit enthält. Wenn wir diese Strukturen verstehen und wissen, wie sie aufeinander verweisen, können wir genau filtern, formatieren und nur die anstehenden Ereignisse anzeigen, die für uns von Bedeutung sind, während unser Code effizient und wartbar bleibt.
Die Nachrichten Schlagzeile EA
Einrichten von Nutzerkontrollen
Zunächst entscheiden wir, welche Parameter die Händler verändern können sollten. Wir legen die Scrollgeschwindigkeiten für jede Wichtigkeitsspur (InpSpeedHigh, InpSpeedMed, InpSpeedLow), die Geschwindigkeit des News-Tickers (InpNewsSpeed) und das Frame-Intervall (InpTimerMs) fest. Außerdem kann der Nutzer wählen, ob die Laufschrift oben oder unten angezeigt werden soll (InpPositionTop), wie weit sie vom Chart-Rand entfernt sein soll (InpTopOffset) und welche Spuren angezeigt werden sollen (ShowHigh, ShowMed, ShowLow). Durch die Isolierung dieser Funktionen in einem übersichtlichen Block „Nutzereingaben“ kann jeder das Verhalten schnell anpassen, ohne sich mit den Implementierungsdetails befassen zu müssen.
//+------------------------------------------------------------------+ //| 1) USER INPUTS | //+------------------------------------------------------------------+ input int InpSpeedHigh = 4; // px/frame for High-impact lane input int InpSpeedMed = 2; // px/frame for Medium-impact lane input int InpSpeedLow = 1; // px/frame for Low-impact lane input int InpNewsSpeed = 5; // px/frame for news ticker row input int InpTimerMs = 50; // ms between frames (~20 fps) input bool InpPositionTop = true; // true=top, false=bottom input int InpTopOffset = 50; // px offset from chart edge input bool ShowHigh = true; // toggle High lane input bool ShowMed = true; // toggle Medium lane input bool ShowLow = true; // toggle Low lane
Definieren von Layout-Konstanten
Als Nächstes legen wir feste Abstandsregeln fest, die das visuelle Layout bestimmen: wie viele Pixel die linke Zeitbeschriftung vom Währungssymbol trennen (GapTimeToSym), wie viel Platz wir um unser Inline-Bedeutungsfeld herum lassen (GapSymToRect, GapRectToName) und die Größe dieses Feldes (RectSize). Durch die Zentralisierung dieser Werte können wir die Feinabstimmung des Erscheinungsbildes an einer Stelle vornehmen, anstatt uns durch den Zeichencode zu kämpfen.
//+------------------------------------------------------------------+ //| 2) DEVELOPER CONSTANTS | //+------------------------------------------------------------------+ static const int GapTimeToSym = 10; // px gap after “[1h]” static const int GapSymToRect = 5; // px gap before inline box static const int RectSize = 8; // width & height of inline box static const int GapRectToName= 10; // px gap after inline box
Speichern des Status und Zeichnen von Puffern
Dann deklarieren wir globale Variablen für die Abmessungen des Charts (canvW), die Zeilenhöhe (lineH), den Platzhaltertext für die Nachrichtenspur und einen Zeitstempel, um wiederholte Kalenderabfragen zu vermeiden (lastReloadDay). Wir instanziieren auch zwei CCanvas-Objekte – eines für die drei Ereignisbahnen und eines für den Nachrichtenticker. Schließlich definieren wir unsere CEvent-Klasse und drei dynamische Arrays (highArr, medArr, lowArr), um eingehende Kalenderereignisse nach Wichtigkeit zu speichern. Der aktuelle Scroll-Offset jeder Spur (offHigh usw.) vervollständigt den Status, den wir beibehalten, wenn der EA läuft.
//+------------------------------------------------------------------+ //| 3) GLOBALS | //+------------------------------------------------------------------+ int lineH = 16; // row height in px int canvW; // chart width string placeholder = // news ticker text "News feed coming soon – stay tuned with the calendar"; datetime lastReloadDay = 0; // daily reload guard CCanvas eventsCanvas, newsCanvas; // two layers // Event struct and arrays class CEvent : public CObject { public: datetime time; string sym, name; int imp; CEvent(datetime t,const string &S,const string &N,int I) { time=t; sym=S; name=N; imp=I; } }; CEvent *highArr[], *medArr[], *lowArr[]; int offHigh, offMed, offLow, offNews;
Positionierungs- und Sortierungshelfer
Um unsere Hauptlogik sauber zu halten, werden zwei kleine Hilfsfunktionen ausgeklammert. SetCanvas() platziert ein Canvas-Objekt entweder am oberen oder unteren Rand des Charts, je nach den Einstellungen des Nutzers. SortArr() ist eine einfache Sortierfunktion, die jedes Wichtigkeits-Array nach dem Zeitpunkt des Ereignisses ordnet und so sicherstellt, dass unsere Fahrspuren die kommenden Ereignisse immer in der richtigen Reihenfolge anzeigen.
//+------------------------------------------------------------------+ //| Helper: position a canvas label | //+------------------------------------------------------------------+ void SetCanvas(string name,bool top,int yDist) { ObjectSetInteger(0,name,OBJPROP_CORNER, top?CORNER_LEFT_UPPER:CORNER_LEFT_LOWER); ObjectSetInteger(0,name,OBJPROP_XDISTANCE, 0); ObjectSetInteger(0,name,OBJPROP_YDISTANCE, yDist); } //+------------------------------------------------------------------+ //| Helper: sort events by time | //+------------------------------------------------------------------+ void SortArr(CEvent* &arr[]) { int n=ArraySize(arr); for(int i=0;i<n-1;i++) for(int j=i+1;j<n;j++) if(arr[i].time > arr[j].time) { CEvent *tmp=arr[i]; arr[i]=arr[j]; arr[j]=tmp; } }
Heutige Ereignisse abrufen
Die Funktion ReloadEvents() ist von zentraler Bedeutung für das Abrufen und Filtern von Daten. Es fragt den MetaTrader-Wirtschaftskalender nach Ereignissen ab, die zwischen heute Mitternacht und 24 Stunden später stattfinden. Wir überspringen jedes Ereignis, dessen Zeitstempel bereits abgelaufen ist. Jedes gültige Ereignis wird in ein CEvent-Objekt verpackt und dann entsprechend seiner Wichtigkeit in das Array high/medium/low eingeordnet. Am Ende wird jede Spur so sortiert, dass das früheste Ereignis zuerst in der jeweiligen Spur erscheint.
//+------------------------------------------------------------------+ //| ReloadEvents: load only *future* events for *today* | //+------------------------------------------------------------------+ void ReloadEvents() { datetime srv = TimeTradeServer(); // midnight today MqlDateTime dt; TimeToStruct(srv, dt); MqlDateTime m0 = {dt.year, dt.mon, dt.day,0,0,0}; datetime today = StructToTime(m0); if(today == lastReloadDay) return; lastReloadDay = today; // clear previous for(int i=0;i<ArraySize(highArr);i++) delete highArr[i]; for(int i=0;i<ArraySize(medArr); i++) delete medArr[i]; for(int i=0;i<ArraySize(lowArr); i++) delete lowArr[i]; ArrayResize(highArr,0); ArrayResize(medArr,0); ArrayResize(lowArr,0); // fetch events [today, today+24h) MqlCalendarValue vals[]; int cnt = CalendarValueHistory(vals, today, today+86400); for(int i=0;i<cnt;i++) { if(vals[i].time <= srv) continue; // skip past MqlCalendarEvent e; if(!CalendarEventById(vals[i].event_id, e)) continue; MqlCalendarCountry c; if(!CalendarCountryById(e.country_id, c)) continue; string sym = "[" + c.currency + "]"; CEvent *ev = new CEvent(vals[i].time, sym, e.name, e.importance); // classify if(e.importance==CALENDAR_IMPORTANCE_HIGH) { int s=ArraySize(highArr)+1; ArrayResize(highArr,s); highArr[s-1]=ev; } else if(e.importance==CALENDAR_IMPORTANCE_MODERATE) { int s=ArraySize(medArr)+1; ArrayResize(medArr,s); medArr[s-1]=ev; } else { int s=ArraySize(lowArr)+1; ArrayResize(lowArr,s); lowArr[s-1]=ev; } } SortArr(highArr); SortArr(medArr); SortArr(lowArr); }
Wenn ReloadEvents() ausgeführt wird, wird eine vollständige Liste der heutigen Kalendereinträge über CalendarValueHistory() abgerufen, aber jeder Roheintrag enthält nur eine event_id und eine country_id. Durch den Abgleich mit der Tabelle MqlCalendarEvent – in der jeder Ereignistyp mit seinem Namen, seiner Häufigkeit, seinem Sektor und vor allem seiner Bedeutung definiert ist – können wir nur die wirklich marktbewegenden Elemente darstellen. Die Struktur MqlCalendarCountry stellt sicher, dass jede Überschrift mit der richtigen Währung (z. B. [USD] für die Vereinigten Staaten) gekennzeichnet wird, die sich aus dem ISO-Code und dem Symbol ergibt. Durch diese zweistufige Suche (Wert → Ereignistyp → Land) ist unser EA sowohl lernfähig – er holt sich nur das, was benötigt wird – als auch genau, da wir Länder- oder Ereignisdetails nie fest codieren, sondern uns auf die eigene, ständig synchronisierte Datenbank des MetaTrader verlassen.
Die Wichtigkeitskonstanten (CALENDAR_IMPORTANCE_HIGH, ..._MODERATE, ..._LOW) sind das Herzstück unserer Gassenlogik. Durch die Auswahl der zu berücksichtigenden Wichtigkeitsstufen (ShowHigh/ShowMed/ShowLow) und die Einfärbung der einzelnen Inline-Boxen in Rot, Orange oder Weiß geben wir dem Händler einen sofortigen visuellen Hinweis: Rot markiert die Veröffentlichungen mit der größten Auswirkung (z. B. Zinsentscheidungen der US-Notenbank, Lohn- und Gehaltsabrechnungen außerhalb der Landwirtschaft), Orange die Veröffentlichungen mit mittlerer Auswirkung (Verbraucherpreisindex, Einzelhandelsumsätze) und Weiß die Veröffentlichungen mit geringerer Auswirkung (kleinere Reden, weniger wichtige Daten).
In der Praxis hilft dies dem Händler, auf einen Blick zu erkennen, ob er die Stopps nachziehen oder sogar die automatisierten Strategien anhalten muss, wenn ein wichtiges Ereignis bevorsteht. Ohne diesen Filter und die farbliche Kennzeichnung, die durch das Feld „Wichtigkeit“ in MqlCalendarEvent ermöglicht wird, würde eine durchlaufende Liste mit Dutzenden von Einträgen schnell zu einem Rauschen statt zu einem Signal werden.
Rendern einer bewegten Streifen
DrawLane() kapselt die Logik für einen horizontalen Streifen. Wir haben eine Schriftart mit einem Schriftschnitt („Courier New“) gewählt, sodass jedes Zeichen – einschließlich Klammern und Ziffern – die gleiche Breite hat und eine saubere Ausrichtung gewährleistet ist. Dann ziehen wir:
- Zeitangabe links (Stunden oder Minuten).
- Währungssymbol.
- Inline-Bedeutungsfeld (rot/orange/weiß gefärbt).
- Ereignisname, gefolgt von einem Trennzeichen, wenn weitere Ereignisse folgen.
Schließlich wird der Versatz der Spur um die Geschwindigkeit der Spur verringert, und wenn die gesamte Zeile über den linken Rand hinausgelaufen ist, wird sie wieder nach rechts verschoben.
//+------------------------------------------------------------------+ //| DrawLane: scroll one lane with inline importance box | //+------------------------------------------------------------------+ void DrawLane(CEvent* &arr[], int &offset, int y, int speed) { int n=ArraySize(arr); if(n==0) return; // monospaced for alignment eventsCanvas.FontNameSet("Courier New"); eventsCanvas.FontSizeSet(-100); int x = offset; datetime srv = TimeTradeServer(); for(int i=0;i<n;i++) { CEvent *e = arr[i]; // time-left “[1h]” or “[45m]” long diff = (long)e.time - (long)srv; string tl = (diff>=3600 ? IntegerToString(diff/3600)+"h" : IntegerToString(diff/60)+"m"); string part = "[" + tl + "]"; eventsCanvas.TextOut(x,y,part,XRGB(255,255,255),ALIGN_LEFT); x += eventsCanvas.TextWidth(part) -20; // symbol “[USD]” eventsCanvas.TextOut(x,y,e.sym,XRGB(255,255,255),ALIGN_RIGHT); x += eventsCanvas.TextWidth(e.sym) + GapSymToRect; // inline importance box uint col = (e.imp==CALENDAR_IMPORTANCE_HIGH ? XRGB(255,0,0) : e.imp==CALENDAR_IMPORTANCE_MODERATE? XRGB(255,165,0): XRGB(255,255,255)); eventsCanvas.FillRectangle(x, y + (lineH-RectSize)/2, x+RectSize, y + (lineH-RectSize)/2 + RectSize, col); x += RectSize + GapRectToName; // event name + separator eventsCanvas.TextOut(x,y,e.name,XRGB(255,255,255),ALIGN_RIGHT); x += eventsCanvas.TextWidth(e.name)+60; if(i+1<n) { eventsCanvas.TextOut(x,y,"|",XRGB(180,180,180),ALIGN_RIGHT); x += eventsCanvas.TextWidth("|") + 20; } } // scroll + wrap int totalW = x - offset; offset -= speed; if(offset + totalW < 0) offset = canvW; }
Orchestrierung aller Streifen und der Nachrichtenzeile
In DrawAll() werden die drei Ereignisspuren vertikal angeordnet, darunter (oder darüber, je nach Position) der Nachrichtenplatzhalter. Nach dem Zeichnen von Ereignissen auf eventsCanvas rufen wir Update(false) auf, um sie an das Chart-Objekt zu übertragen. Die Nachrichtenspur verwendet ihre eigene newsCanvas, mit einer einfacheren Nur-Text-Zeichnung, gefolgt von Update(true) zur synchronen Aktualisierung.
//+------------------------------------------------------------------+ //| DrawAll: render lanes + news row | //+------------------------------------------------------------------+ void DrawAll() { // clear events eventsCanvas.Erase(ARGB(180,0,0,0)); int y=0; if(ShowHigh) { DrawLane(highArr, offHigh, y, InpSpeedHigh); y += lineH; } if(ShowMed) { DrawLane(medArr, offMed, y, InpSpeedMed); y += lineH; } if(ShowLow) { DrawLane(lowArr, offLow, y, InpSpeedLow); y += lineH; } eventsCanvas.Update(false); // news placeholder newsCanvas.Erase(ARGB(170,0,0,0)); newsCanvas.FontNameSet("Tahoma"); newsCanvas.FontSizeSet(-120); int yOff = (lineH - newsCanvas.TextHeight(placeholder)) / 2; newsCanvas.TextOut(offNews, yOff, placeholder, XRGB(255,255,255), ALIGN_LEFT); offNews -= InpNewsSpeed; if(offNews + newsCanvas.TextWidth(placeholder) < -20) offNews = canvW; newsCanvas.Update(true); }
Initialisierung, Timer und Aufräumen
Schließlich erstellen und konfigurieren wir in OnInit() unsere Leinwände, rufen ReloadEvents() zum ersten Mal auf, setzen alle Offsets auf canvW und positionieren die beiden Leinwände anhand von InpPositionTop und InpTopOffset. Dann zeichnen wir das erste Bild und starten den Millisekunden-Timer.
OnTimer() positioniert einfach die Leinwände neu (damit die Nutzer InpPositionTop live umdrehen können), lädt die Ereignisse einmal pro Tag neu, passt die Größe des Charts an und ruft erneut DrawAll() auf. OnDeinit() räumt die Leinwände auf und löscht alle zugeordneten CEvent-Objekte.
//+------------------------------------------------------------------+ //| OnInit: setup canvases, initial load & position | //+------------------------------------------------------------------+ int OnInit() { // force reload Today lastReloadDay = 0; // clear arrays ArrayResize(highArr,0); ArrayResize(medArr,0); ArrayResize(lowArr,0); // chart width canvW = (int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS); // create events canvas (4 rows tall) eventsCanvas.CreateBitmapLabel("EvCanvas",0,0,canvW,4*lineH,COLOR_FORMAT_ARGB_RAW); eventsCanvas.TransparentLevelSet(150); // create news canvas (1 row tall) newsCanvas.CreateBitmapLabel("NwCanvas",0,0,canvW,lineH,COLOR_FORMAT_ARGB_RAW); newsCanvas.TransparentLevelSet(0); // load data + init offsets ReloadEvents(); offHigh = offMed = offLow = offNews = canvW; // initial positioning { int rows = (ShowHigh?1:0)+(ShowMed?1:0)+(ShowLow?1:0); int yOff = InpTopOffset + (InpPositionTop ? 0 : rows*lineH); SetCanvas("EvCanvas", InpPositionTop, InpTopOffset); SetCanvas("NwCanvas", InpPositionTop, yOff + (InpPositionTop ? rows*lineH : 0)); } // first draw & timer DrawAll(); EventSetMillisecondTimer(InpTimerMs); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| OnTimer: reposition, daily reload, redraw | //+------------------------------------------------------------------+ void OnTimer() { // reposition every tick int rows = (ShowHigh?1:0)+(ShowMed?1:0)+(ShowLow?1:0); if(InpPositionTop) { SetCanvas("EvCanvas", true, InpTopOffset); SetCanvas("NwCanvas", true, InpTopOffset + rows*lineH); } else { SetCanvas("EvCanvas", false, InpTopOffset); SetCanvas("NwCanvas", false, InpTopOffset + lineH); } // reload once per day ReloadEvents(); // adapt width int wNew = (int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS); if(wNew != canvW) { canvW = wNew; ObjectSetInteger(0,"EvCanvas",OBJPROP_WIDTH,canvW); ObjectSetInteger(0,"NwCanvas",OBJPROP_WIDTH,canvW); } // redraw DrawAll(); } //+------------------------------------------------------------------+ //| OnDeinit: cleanup | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { EventKillTimer(); eventsCanvas.Destroy(); ObjectDelete(0,"EvCanvas"); newsCanvas.Destroy(); ObjectDelete(0,"NwCanvas"); for(int i=0;i<ArraySize(highArr);i++) delete highArr[i]; for(int i=0;i<ArraySize(medArr); i++) delete medArr[i]; for(int i=0;i<ArraySize(lowArr); i++) delete lowArr[i]; }
Nachdem dieser Schritt abgeschlossen ist, können wir nun unseren Code im Chart testen. Während der Entwicklung habe ich viele der Kompilierungsfehler behoben, was zu einer sauberen und gut strukturierten Endversion führte. Durch die Zusammenstellung der oben genannten Komponenten haben wir nun einen voll funktionsfähigen Nachrichten-Schlagzeilen-EA, der für den Einsatz auf dem Chart bereit ist. Im nächsten Abschnitt erfahren Sie mehr über meine Testerfahrungen.
Tests
Navigieren Sie im MetaTrader 5-Terminal zum Bereich Expert Advisors und ziehen Sie den News Headline EA auf den Chart. Nach erfolgreichem Hinzufügen erscheint der EA standardmäßig am oberen Rand des Charts mit einem vertikalen Versatz von 50 Pixeln. Dieser Versatz verhindert, dass er die Schaltflächen Markttiefe und Handelsbereich sowie den EA-Namen in der oberen rechten Ecke überlappt.
Sie können diesen Versatz anpassen, um die Überschriftenleinwand an jeder gewünschten vertikalen Position im Chart zu positionieren. Der EA verfügt über vier Streifen, die jeweils für eine optimierte Headline-Geschwindigkeit mit einer Bildrate von 20 FPS ausgelegt sind. Anstehende Nachrichten werden in farblich gekennzeichneten Rechtecken angezeigt, die ihre Wichtigkeit angeben.

Testen des News Headline EA
Das obige Bild zeigt einen erfolgreichen Einsatz des News Headline EA. Sie erscheint wie vorgesehen und zeigt alle bevorstehenden Nachrichtenereignisse mit einer flüssigen und nahtlosen Animation an.
Schlussfolgerung
Dies markiert das Ende einer weiteren spannenden Entwicklungsdiskussion, an deren Ende ein praktisches und aufschlussreiches Instrument für Händler und Entwickler steht. Wir haben die Leistungsfähigkeit der Canvas-Klasse erfolgreich genutzt, um ein effizientes Rendering und visuelle Klarheit zu erreichen – ein Ansatz, der auch als wertvolle Abkürzung bei der Entwicklung von Schnittstellen dient.
Im Laufe dieses Projekts haben wir gelernt, wie man Wirtschaftskalenderdaten abruft und sie in einem aussagekräftigen, handelsfreundlichen Format darstellt. Das Ergebnis ist eine übersichtliche, minimalistische Ansicht bevorstehender Nachrichtenereignisse direkt auf dem Chart – und damit die Lösung einer langjährigen Herausforderung bei nachrichtenbasierten Handelsinstrumenten.
Die zweite Version dieses EA wird einen API-Zugang für Echtzeit-Nachrichtenfeeds beinhalten, der noch dynamischere Updates ermöglicht. Darüber hinaus kann die Leinwand zur Anzeige anderer handelsrelevanter Daten umfunktioniert werden, was diesen Ansatz äußerst vielseitig macht.
Wenn die wichtigsten Nachrichten klar auf dem Chart zu sehen sind, können Händler besser informierte Entscheidungen treffen – ob sie am Markt teilnehmen oder an der Seitenlinie bleiben. Es wird allgemein empfohlen, den Handel einige Stunden vor und nach wichtigen Nachrichten zu vermeiden, um das Risiko zu verringern und Volatilitätsspitzen zu vermeiden.
Sie sind herzlich eingeladen, uns Ihre Gedanken mitzuteilen oder Fragen im Kommentarbereich zu stellen. Sie finden die angehängten Dateien auch direkt unter diesem Artikel.
| Dateiname | Beschreibung |
|---|---|
| NewsTicker.mq5 | Die Hauptquelle des Expert Advisors implementiert den dreispurig scrollenden Wirtschaftskalender und den Nachrichten-Platzhalter-Ticker direkt auf dem Chart unter Verwendung der CCanvas-Klasse, mit Geschwindigkeiten pro Spur, Inline-Bedeutungsfeldern und Echtzeit-Countdowns. |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/18299
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Datenwissenschaft und ML (Teil 43): Erkennen verborgener Muster in Indikatordaten unter Verwendung Latenter Gaußscher Mischmodelle (LGMM)
Umstellung auf MQL5 Algo Forge (Teil 3): Verwendung externer Repositories für die eigenen Projekte
Vom Neuling zum Experten: Animierte Nachrichtenüberschrift mit MQL5 (II)
Erstellen eines Handelsadministrator-Panels in MQL5 (Teil XII): Integration eines Rechners für Forex-Werte
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.