MQL5-Handelswerkzeuge (Teil 5): Erstellen eines Ticker-Laufbands für eine Symbolüberwachung in Echtzeit
Einführung
In unserem vorherigen Artikel (Teil 4) haben wir das Multi-Timeframe-Scanner-Dashboard mit dynamischen Positionierungs- und Toggle-Funktionen in MetaQuotes Language 5 (MQL5) verbessert, die bewegliche und minimierbare Anzeigen für eine bessere Nutzerfreundlichkeit ermöglichen. In Teil 5 erstellen wir ein t ein Tool zur Anzeige von Echtzeitdaten für mTicker-Laufbandband für die Echtzeit-Überwachung mehrerer Symbole, mit scrollenden Geldkursen, Spreads, täglichen prozentualen Veränderungen und anpassbaren Grafiken, um Händler auf einen Blick zu informieren. Wir werden die folgenden Themen behandeln:
Am Ende werden Sie ein vielseitiges MQL5-Ticker-Tool haben, das Sie anpassen und in Ihr Trading-Setup integrieren können – legen wir los!
Verstehen der Architektur des Ticker-Laufbands
Das von uns erstellte Ticker-Laufband ist ein Tool zur Anzeige von Echtzeitdaten für mehrere Symbole in einem scrollenden Format, das Geldkurse, Spreads und tägliche prozentuale Veränderungen anzeigt, damit wir auf einen Blick auf dem Laufenden bleiben. Diese Funktion ist wichtig, da sie einen kompakten, dynamischen Überblick über die Marktbewegungen bietet, der Preistrends und Volatilität hervorhebt, ohne das Chart zu überfrachten, was für eine schnelle Entscheidungsfindung beim schnelllebigen Handel unerlässlich ist.
Wir erreichen dies, indem wir die Anzeige in separate Bildlaufzeilen für Symbole, Preise, Spreads und Veränderungen strukturieren und dabei anpassbare Geschwindigkeiten und Farben verwenden, um Auf- oder Abwärtsbewegungen anzuzeigen. Wir planen, Arrays für die Symboldaten und Timer für einen reibungslosen Bildlauf zu verwenden, um sicherzustellen, dass sich der Ticker an die Präferenzen der Nutzer anpasst und gleichzeitig effizient im Hintergrund läuft. Schauen wir uns an, wie wir das zum Leben erwecken können! Im Folgenden finden Sie eine Visualisierung dessen, was wir erreichen wollen.

Implementation in MQL5
Um das Programm in MQL5 zu erstellen, müssen wir die Metadaten des Programms definieren und dann einige Eingaben festlegen, die es uns ermöglichen, die Funktionsweise des Programms leicht zu ändern, ohne direkt in den Code einzugreifen.
//+------------------------------------------------------------------+ //| ROLLING TICKER TIMER EA.mq5 | //| Copyright 2025, Allan Munene Mutiiria. | //| https://t.me/Forex_Algo_Trader | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, Allan Munene Mutiiria." #property link "https://t.me/Forex_Algo_Trader" #property version "1.00" #include <Arrays\ArrayString.mqh> //--- Include ArrayString library for string array operations //--- Input parameters input string Symbols = "EURUSDm,GBPUSDm,USDJPYm,USDCHFm,AUDUSDm,BTCUSDm,TSLAm"; // Symbols to display input int UpdateInterval = 50; // Update interval (milliseconds) input int SymbolFontSize = 10; // Symbol font size (first line) input string SymbolFont = "Arial Bold"; // Symbol font input int AskFontSize = 10; // Ask font size (second line) input string AskFont = "Arial"; // Ask font input int SpreadFontSize = 10; // Spread font size (third line) input string SpreadFont = "Calibri"; // Spread font input int SectionFontSize = 10; // Section currency, bid, and percent change font size input string SectionFont = "Arial"; // Section currency, bid, and percent change font input color FontColor = clrWhite; // Base font color input color UpColor = clrLime; // Color for price increase (Bid text and positive % change) input color DownColor = clrRed; // Color for price decrease (Bid text and negative % change) input color ArrowUpColor = clrBlue; // Color for up arrow input color ArrowDownColor = clrRed; // Color for down arrow input int Y_Position = 30; // Starting Y position (pixels) input int SymbolHorizontalSpacing = 160; // Horizontal spacing for Symbol line (pixels) input int AskHorizontalSpacing = 150; // Horizontal spacing for Ask line (pixels) input int SpreadHorizontalSpacing = 200; // Horizontal spacing for Spread line (pixels) input int SectionHorizontalSpacing = 170; // Horizontal spacing for Section line (pixels) input double SymbolScrollSpeed = 3.0; // Symbol line scroll speed (pixels per update) input double AskScrollSpeed = 1.3; // Ask line scroll speed (pixels per update) input double SpreadScrollSpeed = 10.0; // Spread line scroll speed (pixels per update) input double SectionScrollSpeed = 2.7; // Section scroll speed (pixels per update) input bool ShowSpread = true; // Show spread line input color BackgroundColor = clrBlack; // Background rectangle color input int BackgroundOpacity = 100; // Background opacity (0-255, limited effect)
Hier beginnen wir mit der Implementierung unseres Ticker-Laufbands für die Echtzeit-Symbolüberwachung in MQL5, indem wir die Bibliothek „<Arrays\ArrayString.mqh>“ einbinden und die Eingabeparameter für die Anpassung definieren. Wir binden „<Arrays\ArrayString.mqh>“ ein, um effiziente String-Array-Operationen zu ermöglichen, die für die Bearbeitung und Aufteilung der Liste der anzuzeigenden Symbole unerlässlich sind. Die Eingabe „Symbols“ ist eine Zeichenkette, die auf „EURUSDm, GBPUSDm, USDJPYm, USDCHFm, AUDUSDm, BTCUSDm, TSLAm“ gesetzt ist, um die zu überwachenden Symbole zu spezifizieren, sodass wir konfigurieren können, welche Vermögenswerte im Ticker erscheinen. Wir setzen „UpdateInterval“ auf 50 Millisekunden für die Aktualisierungsrate, um einen Ausgleich zwischen Reaktionsfähigkeit und Leistung zu schaffen.
Zur visuellen Anpassung definieren wir „SymbolFontSize“ auf 10, „SymbolFont“ als „Arial Bold“ für die Symbollinie, „AskFontSize“ auf 10, „AskFont“ als „Arial“ für die Briefkurslinie, „SpreadFontSize“ auf 10, „SpreadFont“ als „Calibri“ für die Spread-Zeile, „SectionFontSize“ auf 10 und „SectionFont“ als „Arial“ für den Währungs-, Geldkurs- und Prozentänderungsabschnitt.
Wir stellen „FontColor“ als clrWhite für den Basistext, „UpColor“ als „clrLime“ und „DownColor“ als „clrRed“ für Preisänderungen, „ArrowUpColor“ als „clrBlue“ und „ArrowDownColor“ als „clrRed“ für Richtungspfeile. Die Eingaben für die Positionierung und die Abstände umfassen „Y_Position“ mit 30 Pixeln für die vertikale Startposition, „SymbolHorizontalSpacing“ mit 160 Pixeln, „AskHorizontalSpacing“ mit 150 Pixeln, „SpreadHorizontalSpacing“ mit 200 Pixeln und „SectionHorizontalSpacing“ mit 170 Pixeln zur Steuerung des Layouts.
Die Bildlaufgeschwindigkeiten sind mit „SymbolScrollSpeed“ auf 3,0 Pixel pro Aktualisierung, „AskScrollSpeed“ auf 1,3, „SpreadScrollSpeed“ auf 10,0 und „SectionScrollSpeed“ auf 2,7 für eine unabhängige Zeilenbewegung eingestellt. Wir setzen „ShowSpread“ auf true, um die Spread-Linie zu aktivieren, „BackgroundColor“ auf „clrBlack“ und „BackgroundOpacity“ auf 100 für das Hintergrundrechteck. Diese Eingaben ermöglichen es uns, Aussehen, Verhalten und Inhalt des Tickers für eine optimale Echtzeitüberwachung anzupassen. Nach der Kompilierung erhalten wir die folgenden Eingaben.

Nachdem wir die Eingaben definiert haben, können wir nun einige globale Variablen und Strukturen definieren, die wir im gesamten Programm verwenden werden und die dazu dienen, wiederkehrende Informationen für das Ticker-Laufband zu speichern.
//--- Global variables string symbolArray[]; //--- Array to store symbol names int totalSymbols; //--- Total number of symbols struct SymbolData //--- Structure to hold symbol price data { double bid; //--- Current bid price double ask; //--- Current ask price double spread; //--- Current spread double prev_bid; //--- Previous bid price double daily_open; //--- Daily opening price color bid_color; //--- Color for bid price display double percent_change; //--- Daily percentage change color percent_color; //--- Color for percentage change string arrow_char; //--- Arrow character for price direction color arrow_color; //--- Color for arrow }; SymbolData prices[]; //--- Array of symbol data structures string dashboardName = "TickerDashboard"; //--- Name for dashboard objects string backgroundName = "TickerBackground"; //--- Name for background object CArrayString objManager; //--- Object manager for text and image objects datetime lastDay = 0; //--- Track last day for daily open update
Hier definieren wir globale Variablen und eine Struktur zur Verwaltung von Symboldaten und Dashboard-Elementen. Wir deklarieren „symbolArray“ als ein Array von Strings, um die Namen der Symbole aus der Eingabe „Symbols“ zu speichern. Die Ganzzahl „totalSymbols“ gibt die Anzahl der Symbole nach der Aufteilung der Eingabezeichenfolge an. Wir definieren die Struktur „SymbolData“, um Preisinformationen für jedes Symbol zu speichern, einschließlich „bid“ für den aktuellen Geldkurs, „ask“ für den aktuellen Briefkurs, „spread“ für die berechnete Spanne, „prev_bid“ für das vorherige Gebot zur Erkennung von Änderungen, „daily_open“ für den Eröffnungskurs des Tages, „bid_color“ zur Einfärbung der Bid-Anzeige, „percent_change“ für die tägliche prozentuale Verschiebung, „percent_color“ zur Einfärbung der Veränderung, „arrow_char“ für Richtungspfeile und „arrow_color“ zur Einfärbung der Pfeile.
Wir erstellen „prices“ als ein Array der Struktur vom Typ „SymbolData“, um Daten für alle Symbole zu speichern. Die Zeichenfolge „dashboardName“ wird auf „TickerDashboard“ für die Benennung von Dashboard-Objekten und „backgroundName“ auf „TickerBackground“ für das Hintergrundrechteck gesetzt. Wir verwenden „CArrayString objManager“, um alle Text- und Bildobjektnamen zu verwalten und so die Bereinigung zu erleichtern. Schließlich wird mit „lastDay“ als Datumswert der letzte Tag für die Aktualisierung der täglichen Eröffnungen erfasst. Diese Globals organisieren die Symboldaten und die Objektverwaltung und ermöglichen effiziente Echtzeitaktualisierungen und Scrolling. Als Nächstes werden wir einige globale Hilfsfunktionen für die Erstellung des zentralen Ticker-Panels wie folgt definieren.
//+------------------------------------------------------------------+ //| Utility Functions | //+------------------------------------------------------------------+ void LogError(string message) // Log error messages { Print(message); //--- Output message to log } //+------------------------------------------------------------------+ //| Create Text Label Function | //+------------------------------------------------------------------+ bool createText(string objName, string text, int x, int y, color clrTxt, int fontsize, string font) { ResetLastError(); //--- Clear last error code if(ObjectFind(0, objName) < 0) //--- Check if object does not exist { if(!ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0)) //--- Create text label object { LogError(__FUNCTION__ + ": Failed to create label: " + objName + ", Error: " + IntegerToString(GetLastError())); //--- Log creation failure return false; //--- Return failure } objManager.Add(objName); //--- Add object name to manager } ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, x); //--- Set x-coordinate ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, y); //--- Set y-coordinate ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); //--- Set corner alignment ObjectSetString(0, objName, OBJPROP_TEXT, text); //--- Set text content ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); //--- Set text color ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontsize); //--- Set font size ObjectSetString(0, objName, OBJPROP_FONT, font); //--- Set font type ObjectSetInteger(0, objName, OBJPROP_BACK, false); //--- Disable background ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); //--- Disable selection ObjectSetInteger(0, objName, OBJPROP_ZORDER, 0); //--- Set z-order return true; //--- Return success } //+------------------------------------------------------------------+ //| Create Panel Function | //+------------------------------------------------------------------+ bool createPanel(string objName, int y, int width, int height, color clr) { ResetLastError(); //--- Clear last error code if(ObjectFind(0, objName) < 0) //--- Check if panel does not exist { if(!ObjectCreate(0, objName, OBJ_RECTANGLE_LABEL, 0, 0, 0)) //--- Create rectangle panel { LogError(__FUNCTION__ + ": Failed to create panel: " + objName + ", Error: " + IntegerToString(GetLastError())); //--- Log creation failure return false; //--- Return failure } objManager.Add(objName); //--- Add panel to object manager } ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, 0); //--- Set x-coordinate to 0 ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, y); //--- Set y-coordinate ObjectSetInteger(0, objName, OBJPROP_XSIZE, width); //--- Set panel width ObjectSetInteger(0, objName, OBJPROP_YSIZE, height); //--- Set panel height ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clr); //--- Set background color ObjectSetInteger(0, objName, OBJPROP_FILL, true); //--- Enable fill ObjectSetInteger(0, objName, OBJPROP_COLOR, clr); //--- Set border color ObjectSetInteger(0, objName, OBJPROP_STYLE, STYLE_SOLID); //--- Set border style ObjectSetInteger(0, objName, OBJPROP_WIDTH, 1); //--- Set border width ObjectSetInteger(0, objName, OBJPROP_BACK, false); //--- Enable background drawing ObjectSetInteger(0, objName, OBJPROP_ZORDER, -1); //--- Set z-order behind other objects return true; //--- Return success }
Wir implementieren Hilfsfunktionen für die Fehlerprotokollierung, die Erstellung von Textbeschriftungen und die Einrichtung von Bedienfeldern, um zuverlässige Elemente der Nutzeroberfläche und für das Debugging zu haben. Wir beginnen mit der Funktion „LogError“, die eine Zeichenkette „message“ entgegennimmt und sie mit der Funktion Print in das Protokoll ausgibt. Als Nächstes erstellen wir die Funktion „createText“, um Textbeschriftungen für die Ticker-Anzeige zu erzeugen. Sie nimmt „objName“, „text“, „x“, „y“, „clrTxt“, „fontsize“ und „font“ als Parameter.
Wir löschen den letzten Fehler mit ResetLastError und prüfen mit der Funktion ObjectFind, ob das Objekt existiert. Ist dies nicht der Fall, wird mit der Funktion ObjectCreate ein Kennzeichung als OBJ_LABEL erstellt, Fehler protokolliert und false zurückgegeben. Wir fügen „objName“ zu „objManager“ für die Verwaltung hinzu, setzen dann Eigenschaften mit ObjectSetInteger für OBJPROP_XDISTANCE und alle anderen Integer-Eigenschaften und „ObjectSetString“ für „OBJPROP_TEXT“ und „OBJPROP_FONT“. Diese Funktion gewährleistet eine einheitliche Textdarstellung für Symbole, Preise und Änderungen.
Anschließend definieren wir die Funktion „createPanel“, um das Hintergrundpanel zu erstellen. Sie nimmt „objName“, „y“, „width“, „height“ und „clr“ als Parameter entgegen und verwendet dieselbe Struktur wie die Funktion „createText“, die einen anpassbaren Hintergrund für die Laufschrift bereitstellt und durch die Wahl der Farbe deckungsähnliche Effekte unterstützt. Wir können nun zur Erstellung des Panels für das Laufband übergehen, aber zuerst müssen wir die notwendigen Daten organisieren, was die Aufteilung der Zeichenfolge der Symbole in separate, unabhängige Symbole, die wir verwenden können, und die Initialisierung der Preis- und Farbdaten beinhaltet. Wir werden dies in OnInit tun.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Split symbols string into array totalSymbols = StringSplit(Symbols, ',', symbolArray); //--- Split input symbols into array ArrayResize(prices, totalSymbols); //--- Resize prices array to match symbol count //--- Verify symbols exist and initialize data for(int i = 0; i < totalSymbols; i++) //--- Iterate through all symbols { if(!SymbolSelect(symbolArray[i], true)) //--- Select symbol for market watch { LogError("OnInit: Symbol " + symbolArray[i] + " not found"); //--- Log symbol not found return(INIT_FAILED); //--- Return initialization failure } prices[i].bid = 0; //--- Initialize bid price prices[i].ask = 0; //--- Initialize ask price prices[i].spread = 0; //--- Initialize spread prices[i].prev_bid = 0; //--- Initialize previous bid prices[i].daily_open = iOpen(symbolArray[i], PERIOD_D1, 0); //--- Set daily opening price prices[i].bid_color = FontColor; //--- Set initial bid color prices[i].percent_change = 0; //--- Initialize percentage change prices[i].percent_color = FontColor; //--- Set initial percent color prices[i].arrow_char = CharToString(236); //--- Set default up arrow prices[i].arrow_color = FontColor; //--- Set initial arrow color } ArrayPrint(symbolArray); ArrayPrint(prices); }
In OnInit initialisieren wir unser Programm, indem wir Symbole und Datenstrukturen einrichten. Zunächst wird die eingegebene Zeichenkette „Symbols“ mit der Funktion StringSplit mit einem Komma als Trennzeichen in „symbolArray“ aufgeteilt und die Anzahl der Symbole in „totalSymbols“ gespeichert. Wenn Sie ein anderes Begrenzungszeichen definiert haben, verwenden Sie es einfach hier. Anschließend wird die Größe von „prices“ mit ArrayResize an „totalSymbols“ angepasst, um die Anzahl der Symbole zu ermitteln. Dann durchlaufen wir eine Schleife durch jedes Symbol in „symbolArray“, wählen es für die Marktbeobachtung mit SymbolSelect aus und protokollieren einen Fehler mit „LogError“, wenn es fehlschlägt, und geben „INIT_FAILED“ zurück.
Für jedes Symbol initialisieren wir „prices[i].bid“, „prices[i].ask“, „prices[i].spread“ und „prices[i].prev_bid“ auf 0, setzen „prices[i].daily_open“ auf den täglichen Eröffnungskurs mit iOpen auf „PERIOD_D1“ und weisen „prices[i].bid_color“, „prices[i].percent_change“, „prices[i].percent_color“, „prices[i].arrow_char“ (mit CharToString für einen Aufwärtspfeil) und „prices[i].arrow_color“. Wir drucken „symbolArray“ und „Preise“ mit der Funktion ArrayPrint zur Fehlersuche. Dadurch wird sichergestellt, dass alle Symbole gültig sind und die Daten für Echtzeit-Aktualisierungen vorbereitet sind. Nach dem Kompilieren erhalten wir die folgende Ausgabe.

Aus dem Bild ist ersichtlich, dass wir alle Symbole und Datenträger erfolgreich initialisiert haben, d. h. alles ist jetzt bereit. Jetzt können wir den Hintergrund des Dashboards erstellen.
//+------------------------------------------------------------------+ //| Create background function | //+------------------------------------------------------------------+ void CreateBackground() { int width = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS); //--- Get chart width int height = (ShowSpread ? 4 : 3) * (MathMax(MathMax(MathMax(SymbolFontSize, AskFontSize), SpreadFontSize), SectionFontSize) + 2) + 40; //--- Calculate panel height createPanel(backgroundName, Y_Position - 5, width, height, BackgroundColor); //--- Create background panel }
Hier implementieren wir die Funktion „CreateBackground“ und richten das Hintergrundpanel für die Tickeranzeige ein. Wir beginnen mit der Abfrage der Chart-Breite mit der Funktion ChartGetInteger unter Verwendung von CHART_WIDTH_IN_PIXELS und der Umwandlung in eine Ganzzahl in „width“. Wir berechnen die Panelhöhe in „height“ mit einem ternären Operator auf „ShowSpread“, um festzustellen, ob es 4 oder 3 Zeilen gibt, multiplizieren mit der maximalen Schriftgröße aus „SymbolFontSize“, „AskFontSize“, „SpreadFontSize“ und „SectionFontSize“ (plus 2 für die Auffüllung) und addieren 40 für zusätzlichen Raum. Schließlich rufen wir die Funktion „createPanel“ mit „backgroundName“, „Y_Position - 5“ für die vertikale Ausrichtung, „width“, „height“ und „BackgroundColor“ auf, um das Hintergrundrechteck zu zeichnen, das eine einheitliche Basis für die Lauftextelemente bildet. Wenn wir die Funktion bei der Initialisierung aufrufen, erhalten wir das folgende Ergebnis.

Nachdem der Hintergrund erstellt wurde, können wir mit der Erstellung der anderen Dashboard-Elemente fortfahren. Wir erstellen eine Funktion, die alles wie folgt aufnimmt.
//+------------------------------------------------------------------+ //| Create dashboard function | //+------------------------------------------------------------------+ void CreateDashboard() { //--- Create text and image objects for each symbol for(int i = 0; i < totalSymbols; i++) //--- Iterate through all symbols { // Determine image based on symbol string imageFile; //--- Variable for image file path if(symbolArray[i] == "EURUSDm") //--- Check for EURUSDm imageFile = "\\Images\\euro.bmp"; //--- Set EURUSD image else if(symbolArray[i] == "GBPUSDm") //--- Check for GBPUSDm imageFile = "\\Images\\gbpusd.bmp"; //--- Set GBPUSD image else if(symbolArray[i] == "USDJPYm") //--- Check for USDJPYm imageFile = "\\Images\\usdjpy.bmp"; //--- Set USDJPY image else if(symbolArray[i] == "USDCHFm") //--- Check for USDCHFm imageFile = "\\Images\\usdchf.bmp"; //--- Set USDCHF image else if(symbolArray[i] == "AUDUSDm") //--- Check for AUDUSDm imageFile = "\\Images\\audusd.bmp"; //--- Set AUDUSD image else if(symbolArray[i] == "BTCUSDm") //--- Check for BTCUSDm imageFile = "\\Images\\btcusd.bmp"; //--- Set BTCUSD image else if(symbolArray[i] == "TSLAm") //--- Check for TSLAm imageFile = "\\Images\\tesla.bmp"; //--- Set Tesla image else imageFile = "\\Images\\euro.bmp"; //--- Set default image // Symbol line (first line) createText(dashboardName + "_Symbol_" + IntegerToString(i), "", (i * SymbolHorizontalSpacing), Y_Position, FontColor, SymbolFontSize, SymbolFont); //--- Create symbol text label // Ask line (second line) createText(dashboardName + "_Ask_" + IntegerToString(i), "", (i * AskHorizontalSpacing), Y_Position + SymbolFontSize + 2, FontColor, AskFontSize, AskFont); //--- Create ask price text label // Spread line (third line, if enabled) if(ShowSpread) //--- Check if spread display is enabled { createText(dashboardName + "_Spread_" + IntegerToString(i), "", (i * SpreadHorizontalSpacing), Y_Position + SymbolFontSize + 2 + AskFontSize + 2, FontColor, SpreadFontSize, SpreadFont); //--- Create spread text label } // Section: Image (left) string imageName = dashboardName + "_Image_" + IntegerToString(i); //--- Define image object name if(ObjectFind(0, imageName) < 0) //--- Check if image object does not exist { if(!ObjectCreate(0, imageName, OBJ_BITMAP_LABEL, 0, 0, 0)) //--- Create image object { LogError("CreateDashboard: Failed to create image: " + imageName + ", Error: " + IntegerToString(GetLastError())); //--- Log image creation failure return; //--- Exit function } objManager.Add(imageName); //--- Add image to object manager } ObjectSetInteger(0, imageName, OBJPROP_XDISTANCE, (i * SectionHorizontalSpacing)); //--- Set image x-coordinate ObjectSetInteger(0, imageName, OBJPROP_YDISTANCE, Y_Position + (ShowSpread ? SymbolFontSize + 2 + AskFontSize + 2 + SpreadFontSize + 14 : SymbolFontSize + 2 + AskFontSize + 14)); //--- Set image y-coordinate ObjectSetString(0, imageName, OBJPROP_BMPFILE, imageFile); //--- Set image file ObjectSetInteger(0, imageName, OBJPROP_CORNER, CORNER_LEFT_UPPER); //--- Set image corner alignment // Section: Currency (top, right of image) string currencyName = dashboardName + "_Currency_" + IntegerToString(i); //--- Define currency text object name createText(currencyName, StringFormat("%-10s", symbolArray[i]), (i * SectionHorizontalSpacing) + 35, Y_Position + (ShowSpread ? SymbolFontSize + 2 + AskFontSize + 2 + SpreadFontSize + 14 : SymbolFontSize + 2 + AskFontSize + 14), FontColor, SectionFontSize, SectionFont); //--- Create currency text label // Section: Percent Change (next to currency, horizontal) string percentChangeName = dashboardName + "_PercentChange_" + IntegerToString(i); //--- Define percent change object name string percentText = prices[i].percent_change >= 0 ? StringFormat("+%.2f%%", prices[i].percent_change) : StringFormat("%.2f%%", prices[i].percent_change); //--- Format percent change text createText(percentChangeName, percentText, (i * SectionHorizontalSpacing) + 105, Y_Position + (ShowSpread ? SymbolFontSize + 2 + AskFontSize + 2 + SpreadFontSize + 14 : SymbolFontSize + 2 + AskFontSize + 14), prices[i].percent_color, SectionFontSize, SectionFont); //--- Create percent change text label // Section: Arrow (below currency, right of image, Wingdings) string arrowName = dashboardName + "_Arrow_" + IntegerToString(i); //--- Define arrow object name createText(arrowName, prices[i].arrow_char, (i * SectionHorizontalSpacing) + 35, Y_Position + (ShowSpread ? SymbolFontSize + 2 + AskFontSize + 2 + SpreadFontSize + 14 : SymbolFontSize + 2 + AskFontSize + 14) + SectionFontSize + 2, prices[i].arrow_color, SectionFontSize, "Wingdings"); //--- Create arrow text label // Section: Bid Price (next to arrow, horizontal) string bidName = dashboardName + "_Bid_" + IntegerToString(i); //--- Define bid price object name createText(bidName, StringFormat("%.5f", prices[i].bid), (i * SectionHorizontalSpacing) + 50, Y_Position + (ShowSpread ? SymbolFontSize + 2 + AskFontSize + 2 + SpreadFontSize + 14 : SymbolFontSize + 2 + AskFontSize + 14) + SectionFontSize + 2, prices[i].bid_color, SectionFontSize, SectionFont); //--- Create bid price text label } }
Hier implementieren wir die Funktion „CreateDashboard“, um die visuellen Elemente der Ticker-Anzeige einzurichten, einschließlich Textbeschriftungen und Bilder für jedes Symbol. Wir beginnen mit einer Schleife durch „totalSymbols“ und bestimmen „imageFile“ auf der Grundlage von „symbolArray[i]“ mit if-else-Bedingungen, wobei wir spezifische Bitmap (BMP)-Dateien für Symbole wie „EURUSDm“ oder einen Standard für andere zuweisen. Wir erstellen den Text der Symbolzeile mit „createText“ für „dashboardName + "Symbol" + IntegerToString(i)“, positioniert bei „(i * SymbolHorizontalSpacing)“ und „Y_Position“.
Für die Ask-Line erstellen wir eine weitere Textbeschriftung mit „createText“ für „dashboardName + 'Ask' + IntegerToString(i)“, positioniert bei „(i * AskHorizontalSpacing)“ und „Y_Position + SymbolFontSize + 2“. Wenn „ShowSpread“ wahr ist, fügen wir mit „createText“ für „dashboardName + "Spread" + IntegerToString(i)“ einen entsprechend positionierten Spreadline-Text hinzu.
Für den Abschnitt erstellen wir ein Bildobjekt mit der Funktion ObjectCreate als OBJ_BITMAP_LABEL, falls nicht vorhanden, fügen es zu „objManager“ hinzu, setzen seine Position mit „ObjectSetInteger“, und weisen „imageFile“ mit der Funktion „ObjectSetString“ zu. Beachten Sie, dass Sie die Bilddateien als BMP-Dateien benötigen. Wir haben das Standardverzeichnis wie folgt verwendet, aber Sie können auch Ihr eigenes verwenden.

Anschließend erstellen wir den Währungstext mit „createText“ für „dashboardName + "Currency" + IntegerToString(i)“, formatiert mit der Funktion StringFormat. Für die prozentuale Veränderung formatieren wir „percentText“ auf der Grundlage von „prices[i].percent_change“ und erstellen den Text mit „createText“. Wir fügen eine Kennzeichnung der Pfeile mit „createText“ unter Verwendung von „prices[i].arrow_char“ und der Schriftart „Wingdings" hinzu. Schließlich erstellen wir den Angebotstext mit „createText“ unter Verwendung von „StringFormat“ für „prices[i].bid“. Diese Funktion erstellt das mehrzeilige Ticker-Layout mit Bildern und dynamischem Text für das Scrollen von Echtzeitdaten. Nun rufen wir die Funktion bei der Initialisierung auf, und erhalten folgende Ausgabe.

Was wir erhalten, ist ein statisches Dashboard. Jetzt müssen wir nur noch das Dashboard aktualisieren. Für Echtzeit-Aktualisierungen wollen wir uns nicht auf Tick-basierte Aktualisierungen verlassen, da diese vollständig von der Tick-Frequenz des Symbols abhängen würden, an das das Programm angehängt ist. Wir wollen zeitgesteuerte Aktualisierungen verwenden, damit die Aktualisierungen häufig durchgeführt werden. Lassen Sie uns zunächst die Funktionen definieren, mit denen das Dashboard und der Hintergrund bei Bedarf aktualisiert werden.
//+------------------------------------------------------------------+ //| Update background function | //+------------------------------------------------------------------+ void UpdateBackground() { int width = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS); //--- Get current chart width int height = (ShowSpread ? 4 : 3) * (MathMax(MathMax(MathMax(SymbolFontSize, AskFontSize), SpreadFontSize), SectionFontSize) + 2) + 40; //--- Recalculate panel height ObjectSetInteger(0, backgroundName, OBJPROP_XSIZE, width); //--- Update panel width ObjectSetInteger(0, backgroundName, OBJPROP_YSIZE, height); //--- Update panel height } //+------------------------------------------------------------------+ //| Update dashboard function | //+------------------------------------------------------------------+ void UpdateDashboard() { static double symbolOffset = 0; //--- Track symbol line offset static double askOffset = 0; //--- Track ask line offset static double spreadOffset = 0; //--- Track spread line offset static double sectionOffset = 0; //--- Track section offset int totalWidthSymbol = totalSymbols * SymbolHorizontalSpacing; //--- Calculate total symbol line width int totalWidthAsk = totalSymbols * AskHorizontalSpacing; //--- Calculate total ask line width int totalWidthSpread = totalSymbols * SpreadHorizontalSpacing; //--- Calculate total spread line width int totalWidthSection = totalSymbols * SectionHorizontalSpacing; //--- Calculate total section width int rightEdge = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS); //--- Get chart right boundary //--- Update text and image objects for(int i = 0; i < totalSymbols; i++) //--- Iterate through all symbols { // Symbol line (first line) string symbolName = dashboardName + "_Symbol_" + IntegerToString(i); //--- Define symbol object name double symbolXPos = (i * SymbolHorizontalSpacing) - symbolOffset; //--- Calculate symbol x-position if(symbolXPos < -SymbolHorizontalSpacing) symbolXPos += totalWidthSymbol; //--- Wrap around if off-screen createText(symbolName, StringFormat("%-10s", symbolArray[i]), (int)symbolXPos, Y_Position, FontColor, SymbolFontSize, SymbolFont); //--- Update symbol text ObjectSetInteger(0, symbolName, OBJPROP_HIDDEN, symbolXPos > rightEdge || symbolXPos < 0); //--- Hide if off-screen // Ask line (second line) string askName = dashboardName + "_Ask_" + IntegerToString(i); //--- Define ask object name double askXPos = (i * AskHorizontalSpacing) - askOffset; //--- Calculate ask x-position if(askXPos < -AskHorizontalSpacing) askXPos += totalWidthAsk; //--- Wrap around if off-screen createText(askName, StringFormat("%.5f", prices[i].ask), (int)askXPos, Y_Position + SymbolFontSize + 2, clrMagenta, AskFontSize, AskFont); //--- Update ask text ObjectSetInteger(0, askName, OBJPROP_HIDDEN, askXPos > rightEdge || askXPos < 0); //--- Hide if off-screen // Spread line (third line) if(ShowSpread) //--- Check if spread display is enabled { string spreadName = dashboardName + "_Spread_" + IntegerToString(i); //--- Define spread object name double spreadXPos = (i * SpreadHorizontalSpacing) - spreadOffset; //--- Calculate spread x-position if(spreadXPos < -SpreadHorizontalSpacing) spreadXPos += totalWidthSpread; //--- Wrap around if off-screen createText(spreadName, StringFormat("%.1f", prices[i].spread), (int)spreadXPos, Y_Position + SymbolFontSize + 2 + AskFontSize + 2, clrAqua, SpreadFontSize, SpreadFont); //--- Update spread text ObjectSetInteger(0, spreadName, OBJPROP_HIDDEN, spreadXPos > rightEdge || spreadXPos < 0); //--- Hide if off-screen } // Section (Image, Currency, Percent Change, Arrow, Bid Price) double sectionXPos = (i * SectionHorizontalSpacing) - sectionOffset; //--- Calculate section x-position if(sectionXPos < -SectionHorizontalSpacing) sectionXPos += totalWidthSection; //--- Wrap around if off-screen // Image (left) string imageName = dashboardName + "_Image_" + IntegerToString(i); //--- Define image object name ObjectSetInteger(0, imageName, OBJPROP_XDISTANCE, (int)sectionXPos); //--- Update image x-coordinate ObjectSetInteger(0, imageName, OBJPROP_YDISTANCE, Y_Position + (ShowSpread ? SymbolFontSize + 2 + AskFontSize + 2 + SpreadFontSize + 14 : SymbolFontSize + 2 + AskFontSize + 14)); //--- Update image y-coordinate ObjectSetInteger(0, imageName, OBJPROP_HIDDEN, sectionXPos > rightEdge || sectionXPos < 0); //--- Hide if off-screen // Currency (top, right of image) string currencyName = dashboardName + "_Currency_" + IntegerToString(i); //--- Define currency object name createText(currencyName, StringFormat("%-10s", symbolArray[i]), (int)sectionXPos + 35, Y_Position + (ShowSpread ? SymbolFontSize + 2 + AskFontSize + 2 + SpreadFontSize + 14 : SymbolFontSize + 2 + AskFontSize + 14), FontColor, SectionFontSize, "Arial Bold"); //--- Update currency text // Percent Change (next to currency, horizontal) string percentChangeName = dashboardName + "_PercentChange_" + IntegerToString(i); //--- Define percent change object name string percentText = prices[i].percent_change >= 0 ? StringFormat("+%.2f%%", prices[i].percent_change) : StringFormat("%.2f%%", prices[i].percent_change); //--- Format percent change createText(percentChangeName, percentText, (int)sectionXPos + 105, Y_Position + (ShowSpread ? SymbolFontSize + 2 + AskFontSize + 2 + SpreadFontSize + 14 : SymbolFontSize + 2 + AskFontSize + 14), prices[i].percent_color, SectionFontSize, SectionFont); //--- Update percent change text // Arrow (below currency, right of image, Wingdings) string arrowName = dashboardName + "_Arrow_" + IntegerToString(i); //--- Define arrow object name createText(arrowName, prices[i].arrow_char, (int)sectionXPos + 35, Y_Position + (ShowSpread ? SymbolFontSize + 2 + AskFontSize + 2 + SpreadFontSize + 14 : SymbolFontSize + 2 + AskFontSize + 14) + SectionFontSize + 2, prices[i].arrow_color, SectionFontSize, "Wingdings"); //--- Update arrow text // Bid Price (next to arrow, horizontal) string bidName = dashboardName + "_Bid_" + IntegerToString(i); //--- Define bid object name createText(bidName, StringFormat("%.5f", prices[i].bid), (int)sectionXPos + 50, Y_Position + (ShowSpread ? SymbolFontSize + 2 + AskFontSize + 2 + SpreadFontSize + 14 : SymbolFontSize + 2 + AskFontSize + 14) + SectionFontSize + 2, prices[i].bid_color, SectionFontSize, SectionFont); //--- Update bid price text } //--- Increment offsets for scrolling effect symbolOffset = fmod(symbolOffset + SymbolScrollSpeed, totalWidthSymbol); //--- Update symbol line offset askOffset = fmod(askOffset + AskScrollSpeed, totalWidthAsk); //--- Update ask line offset spreadOffset = fmod(spreadOffset + SpreadScrollSpeed, totalWidthSpread); //--- Update spread line offset sectionOffset = fmod(sectionOffset + SectionScrollSpeed, totalWidthSection); //--- Update section offset //--- Redraw chart ChartRedraw(); //--- Refresh chart display }
Hier implementieren wir die Funktion „UpdateBackground“, um das Hintergrundpanel bei Größenänderungen des Charts anzupassen. Die aktuelle Chart-Breite wird mit der Funktion ChartGetInteger unter Verwendung von CHART_WIDTH_IN_PIXELS abgefragt und in eine Ganzzahl in „width“ umgewandelt. Wir berechnen die Panelhöhe in „height“ neu, indem wir einen ternären Operator auf „ShowSpread“ anwenden, um festzustellen, ob es 4 oder 3 Zeilen gibt, mit der maximalen Schriftgröße aus „SymbolFontSize“, „AskFontSize“, „SpreadFontSize“ und „SectionFontSize“ multiplizieren (plus 2 für die Auffüllung) und 40 für zusätzlichen Raum hinzufügen. Schließlich aktualisieren wir die Abmessungen des Panels mit ObjectSetInteger für „OBJPROP_XSIZE“ und OBJPROP_YSIZE auf „backgroundName“.
Als Nächstes implementieren wir die Funktion „UpdateDashboard“, um das Scrollen und Aktualisieren von Text- und Bildobjekten zu ermöglichen. Wir definieren statische Offsets „symbolOffset“, „askOffset“, „spreadOffset“ und „sectionOffset“, um Zeilenpositionen zu verfolgen. Wir berechnen die Gesamtbreiten „totalWidthSymbol“, „totalWidthAsk“, „totalWidthSpread“ und „totalWidthSection“ durch Multiplikation von „totalSymbols“ mit den jeweiligen Abstandsangaben. Den rechten Rand des Charts erhalten wir mit „ChartGetInteger“ unter Verwendung von „CHART_WIDTH_IN_PIXELS“. Wir durchlaufen eine Schleife durch „totalSymbols“ und aktualisieren die Position jedes Symbols mit „symbolXPos“, angepasst durch „symbolOffset“, wobei wir mit modulo umbrechen, wenn es außerhalb des Bildschirms liegt, und rufen „createText“ auf, um den Text zu aktualisieren, und verstecken ihn mit „ObjectSetInteger“ für „OBJPROP_HIDDEN“, wenn er außerhalb von „rightEdge“ liegt.
Ähnliche Aktualisierungen führen wir für Ask-, Spread- (wenn „ShowSpread“) und Section-Elemente durch, einschließlich Bilder mit „ObjectSetInteger“ für OBJPROP_XDISTANCE und „OBJPROP_YDISTANCE“, Währung, prozentuale Veränderung (formatiert mit StringFormat), Pfeil (mit „prices[i].arrow_char“) und Bid-Text. Wir erhöhen die Offsets mit „fmod“ anhand der Bildlaufgeschwindigkeit und rufen ChartRedraw auf, um die Anzeige zu aktualisieren. Diese Funktionen sorgen dafür, dass sich der Ticker an Veränderungen anpasst und reibungslos läuft, sodass er in Echtzeit überwacht werden kann. Wir können dann die Ereignisbehandlung OnTimer aufrufen, aber zuerst müssen wir das Timer-Intervall festlegen. Dies ist sehr wichtig.
//--- Set timer EventSetMillisecondTimer(UpdateInterval); //--- Set timer for updates //--- Initialize last day lastDay = TimeCurrent() / 86400; //--- Set current day for daily open tracking
Hier wird lediglich das Timer-Intervall durch Aufruf der Funktion EventSetMillisecondTimer und Übergabe des definierten Aktualisierungsintervalls festgelegt und schließlich die Variable „Letzter Tag“ für die Verfolgung des neuen Tages initialisiert. Jetzt können wir die Logik der Zeitschaltuhr definieren.
//+------------------------------------------------------------------+ //| Expert timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- Check for new day to update daily open datetime currentDay = TimeCurrent() / 86400; //--- Calculate current day if(currentDay > lastDay) //--- Check if new day { for(int i = 0; i < totalSymbols; i++) //--- Iterate through symbols { prices[i].daily_open = iOpen(symbolArray[i], PERIOD_D1, 0); //--- Update daily open price } lastDay = currentDay; //--- Update last day } //--- Update background size in case chart is resized UpdateBackground(); //--- Update background dimensions //--- Update dashboard display UpdateDashboard(); //--- Update dashboard visuals }
Hier implementieren wir die Ereignisbehandlung von OnTimer, um periodische Aktualisierungen in unserem Rolling Ticker Tape für die Echtzeit-Symbolüberwachung zu verwalten, die in dem durch „UpdateInterval“ festgelegten Intervall ausgelöst werden. Wir beginnen mit der Berechnung von „currentDay“ als TimeCurrent geteilt durch 86400, um den Tag in Sekunden zu erhalten, was 1 Tag * 24 Stunden * 60 Minuten * 60 Sekunden entspricht. Wenn „currentDay“ größer ist als „lastDay“, durchlaufen wir „totalSymbols“ und aktualisieren „prices[i].daily_open“ für jedes Symbol mit iOpen auf „PERIOD_D1“ mit Shift 0, dann setzen wir „lastDay“ auf „currentDay“, um den neuen Tag zu verfolgen. Dadurch wird sichergestellt, dass die täglichen prozentualen Änderungen um Mitternacht korrekt zurückgesetzt werden.
Als Nächstes rufen wir „UpdateBackground“ auf, um das Hintergrundfeld anzupassen, wenn die Größe des Charts geändert wird. Schließlich rufen wir „UpdateDashboard“ auf, um alle Text- und Bildobjekte mit den aktuellen Daten und Bildlaufpositionen zu aktualisieren, damit der Ticker dynamisch bleibt und auf zeitliche Änderungen reagiert. Wir kommen zu folgendem Ergebnis.

Anhand der Visualisierung können wir sehen, dass wir ein effektives Laufband haben, das rollt. Wir müssen nun die Preise aktualisieren, und das ist alles. Wir sollten diese Aktualisierungslogik auch in einer Funktion haben.
//+------------------------------------------------------------------+ //| Update prices function | //+------------------------------------------------------------------+ void UpdatePrices() { for(int i = 0; i < totalSymbols; i++) //--- Iterate through all symbols { double bid = SymbolInfoDouble(symbolArray[i], SYMBOL_BID); //--- Retrieve current bid price double ask = SymbolInfoDouble(symbolArray[i], SYMBOL_ASK); //--- Retrieve current ask price //--- Validate prices if(bid == 0 || ask == 0) //--- Check for invalid prices { LogError("UpdatePrices: Failed to retrieve prices for " + symbolArray[i]); //--- Log price retrieval failure continue; //--- Skip to next symbol } //--- Update color and arrow based on price change (tick-to-tick for bid and arrow) if(bid > prices[i].prev_bid && prices[i].prev_bid != 0) //--- Check if bid increased { prices[i].bid_color = UpColor; //--- Set bid color to up color prices[i].arrow_char = CharToString(236); //--- Set up arrow character prices[i].arrow_color = ArrowUpColor; //--- Set arrow to up color } else if(bid < prices[i].prev_bid && prices[i].prev_bid != 0) //--- Check if bid decreased { prices[i].bid_color = DownColor; //--- Set bid color to down color prices[i].arrow_char = CharToString(238); //--- Set down arrow character prices[i].arrow_color = ArrowDownColor; //--- Set arrow to down color } else //--- Handle no change or first tick { prices[i].bid_color = FontColor; //--- Set bid color to default prices[i].arrow_char = CharToString(236); //--- Set default up arrow prices[i].arrow_color = FontColor; //--- Set arrow to default color } //--- Calculate daily percentage change prices[i].percent_change = prices[i].daily_open != 0 ? ((bid - prices[i].daily_open) / prices[i].daily_open) * 100 : 0; //--- Compute percentage change prices[i].percent_color = prices[i].percent_change >= 0 ? UpColor : DownColor; //--- Set percent color based on change //--- Update data prices[i].bid = bid; //--- Store current bid prices[i].ask = ask; //--- Store current ask prices[i].spread = (ask - bid) * MathPow(10, SymbolInfoInteger(symbolArray[i], SYMBOL_DIGITS)); //--- Calculate spread prices[i].prev_bid = bid; //--- Update previous bid } }
Wir implementieren die Funktion „UpdatePrices“ zur Aktualisierung der Symboldaten. Wir durchlaufen eine Schleife durch „totalSymbols“ und rufen „bid“ und „ask“ für jedes „symbolArray[i]“ mit Hilfe der Funktion „SymbolInfoDouble“ mit SYMBOL_BID und „SYMBOL_ASK“ ab. Wenn „bid“ oder „ask“ gleich 0 ist, protokollieren wir einen Fehler mit „LogError“ und gehen zum nächsten Symbol über. Wir aktualisieren „bid_color“, „arrow_char“ (mit der Funktion CharToString für Auf- oder Abwärtspfeile) und „arrow_color“ je nachdem, ob „bid“ größer, kleiner oder gleich „prev_bid“ ist (ohne Berücksichtigung der anfänglichen 0). Die Pfeile sind in der Standardstruktur von MQL5 Wingdings, die wie folgt aussieht.

Sie können jedoch jeden Pfeilcode verwenden, der Sie glücklich macht. Wir berechnen dann „percent_change“ anhand von „daily_open“ und setzen „percent_color“ mit einem ternären Operator für aufwärts oder abwärts. Schließlich aktualisieren wir „prices[i].bid“, „prices[i].ask“, „spread“ (berechnet mit MathPow und SymbolInfoInteger für „SYMBOL_DIGITS“ und „prev_bid“, um aktuelle Daten für die Anzeige und Änderungen zu gewährleisten und die Preise und Indikatoren des Tickers bei jedem Tick aktuell zu halten. Wir rufen die Funktion nun bei jedem Tick auf, um die Preisänderungen zu verarbeiten, oder Sie könnten sie auch in der Funktion OnTimer aufrufen. Sie haben wieder die Wahl.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Update prices on every tick for live changes UpdatePrices(); //--- Update symbol prices } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Clean up objects for(int i = objManager.Total() - 1; i >= 0; i--) //--- Iterate through all managed objects { string name = objManager.At(i); //--- Get object name if(ObjectFind(0, name) >= 0) //--- Check if object exists { if(!ObjectDelete(0, name)) //--- Delete object LogError("OnDeinit: Failed to delete object: " + name + ", Error: " + IntegerToString(GetLastError())); //--- Log deletion failure } objManager.Delete(i); //--- Remove object from manager } EventKillTimer(); //--- Stop timer }
In OnTick rufen wir „UpdatePrices“ auf, um Bid-, Ask-, Spread- und Änderungsdaten für alle Symbole zu aktualisieren und sicherzustellen, dass der Ticker aktuelle Marktbewegungen zeitnah wiedergibt. Als Nächstes implementieren wir die Funktion OnDeinit, um aufzuräumen, wenn das Programm entfernt wird. Wir durchlaufen den „objManager“ in einer Schleife rückwärts mit „Total“ und erhalten den „Namen“ jedes Objekts mit „At“. Wenn das Objekt über ObjectFind existiert, löschen wir es mit der Funktion ObjectDelete, wobei wir Fehler mit „LogError“ protokollieren, wenn sie nicht erfolgreich waren. Wir entfernen den Namen aus „objManager“ mit dem Operator Delete. Schließlich stoppen wir den Timer mit EventKillTimer, um die periodischen Aktualisierungen zu beenden. Dies ist sehr wichtig. Dadurch wird sichergestellt, dass alle Objekte ordnungsgemäß gelöscht werden und keine Elemente auf dem Chart zurückbleiben. Wenn wir das Programm ausführen, erhalten wir das folgende Ergebnis.

Anhand der Visualisierung können wir sehen, dass alles wie erwartet funktioniert und wir unsere Ziele erreicht haben. Nun bleibt nur noch die Prüfung der Durchführbarkeit des Projekts, die im vorangegangenen Abschnitt behandelt wurde.
Backtests
Wir haben die Tests durchgeführt, und unten sehen Sie die kompilierte Visualisierung in einem einzigen Graphics Interchange Format (GIF) Bitmap-Bildformat.

Schlussfolgerung
Abschließend haben wir eine laufende Tickeranzeige in MQL5 für die Überwachung von Symbolen in Echtzeit entwickelt, das scrollende Linien für Geldkurse, Spreads und tägliche Änderungen mit anpassbaren Schriftarten, Farben und Geschwindigkeiten enthält, um Marktbewegungen effektiv hervorzuheben. Wir haben die Architektur und Implementierung demonstriert, von Datenstrukturen wie „SymbolData“ bis hin zu Funktionen wie „UpdateDashboard“ und „UpdatePrices“, die einen reibungslosen Bildlauf und präzise Aktualisierungen für effiziente Handelseinblicke gewährleisten. Sie können diesen Ticker an Ihre Bedürfnisse anpassen und so Ihre Möglichkeiten, mehrere Symbole zu verfolgen und auf Preistrends in Echtzeit zu reagieren, erheblich verbessern.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/18844
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.
Singuläre Spektralanalyse in MQL5
Umstellung auf MQL5 Algo Forge (Teil 4): Arbeiten mit Versionen und Releases
Einführung in MQL5 (Teil 18): Einführung in das Muster der Wolfe-Wellen
MQL5-Assistenz-Techniken, die Sie kennen sollten (Teil 73): Verwendung von Ichimoku-Mustern und ADX-Wilder
- 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.
Funktioniert nicht
Haben Sie den Artikel überhaupt gelesen?