English 日本語
preview
MQL5-Handelswerkzeuge (Teil 6): Dynamisches holografisches Dashboard mit Impulsanimationen und Steuerelementen

MQL5-Handelswerkzeuge (Teil 6): Dynamisches holografisches Dashboard mit Impulsanimationen und Steuerelementen

MetaTrader 5Handel |
89 0
Allan Munene Mutiiria
Allan Munene Mutiiria

Einführung

In unserem vorigen Artikel (Teil 5) haben wir ein Laufband mit Tickermeldungen in MetaQuotes Language 5 (MQL5) für die Überwachung von Symbolen in Echtzeit mit scrollenden Preisen, Spreads und Änderungen erstellt, um Händler effizient zu informieren. In Teil 6 entwickeln wir ein dynamisches holografisches Dashboard, das Multi-Symbol- und Zeitrahmen-Indikatoren wie den Relative Strength Index (RSI) und die Volatilität (basierend auf dem Average True Range (ATR)) mit Impulsanimationen, Sortierung und interaktiven Steuerelementen anzeigt und so ein ansprechendes Analysetool schafft. Wir werden die folgenden Themen behandeln:

  1. Verständnis der holografischen Dashboard-Architektur
  2. Implementation in MQL5
  3. Backtests
  4. Schlussfolgerung

Am Ende haben Sie ein anpassbares holografisches Dashboard für Ihr Trading-Setup – legen wir los!


Verständnis der holografischen Dashboard-Architektur

Das holografische Dashboard, das wir entwickeln, ist ein visuelles Tool, das mehrere Symbole und Zeitrahmen überwacht und Indikatoren wie RSI und Volatilität sowie Sortier- und Warnhinweise anzeigt, um uns dabei zu helfen, Chancen schnell zu erkennen. Diese Architektur ist wichtig, weil sie Echtzeitdaten mit interaktiven Steuerelementen und Animationen kombiniert und so die Analyse in einer unübersichtlichen Chart-Umgebung interessanter und effizienter macht.

Dazu verwenden wir Arrays für die Datenverwaltung, Handles für Indikatoren wie ATR und RSI sowie Funktionen für Sortier- und Pulseffekte mit Schaltflächen zum Umschalten der Sichtbarkeit und zum Umschalten der Ansichten. Wir planen, die Aktualisierungen in einer Schleife zu zentralisieren, die die Nutzeroberfläche (UI) dynamisch aktualisiert, um sicherzustellen, dass das Dashboard für den strategischen Handel anpassungsfähig und reaktionsschnell bleibt. Sehen Sie sich die nachstehende Visualisierung an, um zu verstehen, was wir erreichen wollen, bevor wir mit der Implementierung beginnen.

VOLLSTÄNDIGE ARCHITEKTUR


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.

//+------------------------------------------------------------------+
//|                                  Holographic Dashboard 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
#include <Files\FileTxt.mqh>      //--- Include FileTxt library for text file operations

// Input Parameters
input int BaseFontSize = 9;           // Base Font Size
input string FontType = "Calibri";    // Font Type (Professional)
input int X_Offset = 30;              // X Offset
input int Y_Offset = 30;              // Y Offset
input color PanelColor = clrDarkSlateGray; // Panel Background Color
input color TitleColor = clrWhite;    // Title/Symbol Color
input color DataColor = clrLightGray; // Bid/Neutral Color
input color ActiveColor = clrLime;    // Active Timeframe/Symbol Color
input color UpColor = clrDeepSkyBlue; // Uptrend Color
input color DownColor = clrCrimson;   // Downtrend Color
input color LineColor = clrSilver;    // Grid Line Color
input bool EnableAnimations = true;   // Enable Pulse Animations
input int PanelWidth = 730;           // Panel Width (px)
input int ATR_Period = 14;            // ATR Period for Volatility
input int RSI_Period = 14;            // RSI Period
input double Vol_Alert_Threshold = 2.0; // Volatility Alert Threshold (%)
input color GlowColor = clrDodgerBlue; // Glow Color for holographic effect
input int AnimationSpeed = 30; // Animation delay in ms for pulse
input int PulseCycles = 3; // Number of pulse cycles for animations

Wir beginnen mit der Einbindung von Bibliotheken für String-Arrays und Textdateiprotokollierung sowie der Einrichtung von Eingaben zur Anpassung der Nutzeroberfläche und der Indikatoren. Wir fügen „<Arrays\ArrayString.mqh>“ für die Behandlung von Symbollisten und „<Files\FileTxt.mqh>“ für die Protokollierung von Fehlern in einer Datei ein. Die Eingaben ermöglichen es uns, die Grundschriftgröße auf 9 einzustellen, eine professionelle Schriftart wie Calibri zu wählen, Offsets für die x- und y-Positionierung auf jeweils 30 Pixel festzulegen und Farben wie dunkles Schiefergrau für den Panelhintergrund, Weiß für Titel, Hellgrau für Daten, Limette für aktive Elemente, tiefes Himmelblau für Aufwärtstrends, Karmesinrot für Abwärtstrends und Silber für Rasterlinien auszuwählen.

Wir aktivieren die Impulsanimationen standardmäßig, legen die Breite des Panels auf 730 Pixel fest, setzen die ATR- und RSI-Perioden für die Volatilitäts- und Momentum-Berechnungen auf 14, legen einen Schwellenwert von 2,0 % für Volatilitätswarnungen fest, wählen Dodger Blue für das holografische Glühen und konfigurieren die Animationsgeschwindigkeit auf 30 ms mit 3 Impulszyklen. Diese Einstellungen machen das Dashboard in hohem Maße anpassungsfähig an visuelle und funktionale Präferenzen. Dann müssen wir einige globale Variablen definieren, die wir im gesamten Programm verwenden werden.

// Global Variables
double prices_PrevArray[];            //--- Array for previous prices
double volatility_Array[];            //--- Array for volatility values
double bid_array[];                   //--- Array for bid prices
long spread_array[];                  //--- Array for spreads
double change_array[];                //--- Array for percentage changes
double vol_array[];                   //--- Array for volumes
double rsi_array[];                   //--- Array for RSI values
int indices[];                        //--- Array for sorted indices
ENUM_TIMEFRAMES periods[] = {PERIOD_M1, PERIOD_M5, PERIOD_H1, PERIOD_H2, PERIOD_H4, PERIOD_D1, PERIOD_W1}; //--- Array of timeframes
string logFileName = "Holographic_Dashboard_Log.txt"; //--- Log file name
int sortMode = 0;                     //--- Current sort mode
string sortNames[] = {"Name ASC", "Vol DESC", "Change ABS DESC", "RSI DESC"}; //--- Sort mode names
int atr_handles_sym[];                //--- ATR handles for symbols
int rsi_handles_sym[];                //--- RSI handles for symbols
int atr_handles_tf[];                 //--- ATR handles for timeframes
int rsi_handles_tf[];                 //--- RSI handles for timeframes
int totalSymbols;                     //--- Total number of symbols
bool dashboardVisible = true;         //--- Dashboard visibility flag

Hier definieren wir globale Variablen, um Daten und Indikatoren in unserem Programm zu verwalten und Echtzeitüberwachung, Sortierung und Animationen zu unterstützen. Wir erstellen Arrays wie „prices_PrevArray“ für frühere Preise zur Berechnung von Änderungen, „volatility_array“ für Volatilitätswerte, „bid_array“ für aktuelle Gebote, „spread_array“ für Spreads als Long-Positionen, „change_array“ für prozentuale Veränderungen, „vol_array“ für Volumina, „rsi_array“ für RSI-Werte und „indices“ für die Sortierung von Indizes. Wir setzen „periods“ als ein Array von Zeitrahmen von PERIOD_M1 bis PERIOD_W1, „logFileName“ auf „Holographic_Dashboard_Log.txt“ für die Fehlerprotokollierung, „sortMode“ auf 0 für die erste Sortierung, „sortNames“ als Strings für Sortieroptionen wie „Name ASC“ oder „Vol DESC“und Arrays für ATR- und RSI-Handles („atr_handles_sym“, „rsi_handles_sym“ für Symbole, „atr_handles_tf“, „rsi_handles_tf“ für Timeframes).

Der Integerwert „totalSymbols“ gibt die Anzahl der Symbole an, und „dashboardVisible“ ist true, was den Zustand des Dashboards steuert. Um Objekte besser zu verwalten, werden wir eine Klasse erstellen.

// Object Manager Class
class CObjectManager : public CArrayString {
public:
   void AddObject(string name) {      //--- Add object name to manager
      if (!Add(name)) {               //--- Check if add failed
         LogError(__FUNCTION__ + ": Failed to add object name: " + name); //--- Log error
      }
   }
   
   void DeleteAllObjects() {          //--- Delete all managed objects
      for (int i = Total() - 1; i >= 0; i--) { //--- Iterate through objects
         string name = At(i);         //--- Get object name
         if (ObjectFind(0, name) >= 0) { //--- Check if object exists
            if (!ObjectDelete(0, name)) { //--- Delete object
               LogError(__FUNCTION__ + ": Failed to delete object: " + name + ", Error: " + IntegerToString(GetLastError())); //--- Log deletion failure
            }
         }
         Delete(i);                   //--- Remove from array
      }
      ChartRedraw(0);                 //--- Redraw chart
   }
};

Um die Dashboard-Objekte effizient zu verwalten, erstellen wir die Klasse „CObjectManager“, die die Klasse CArrayString erweitert. In der Methode „AddObject“ fügen wir das Objekt „name“ mit „Add“ zum Array hinzu und protokollieren Fehler über „LogError“, wenn sie nicht erfolgreich waren. Wir verwenden die Methode „deleteallobjects“, indem wir das Array mit „Total“ rückwärts durchlaufen, jeden „name“ mit „At“ abrufen, das Vorhandensein mit der Funktion ObjectFind prüfen, mit ObjectDelete löschen und bei einem Fehlschlag den Fehler protokollieren, es mit „Delete“ aus dem Array entfernen und das Chart mit der Funktion ChartRedraw neu zeichnen. Mit der Klassenerweiterung können wir einige Hilfsfunktionen erstellen, die wir im gesamten Programm zur Wiederverwendung aufrufen werden.

CObjectManager objManager;            //--- Object manager instance

//+------------------------------------------------------------------+
//| Utility Functions                                                |
//+------------------------------------------------------------------+
void LogError(string message) {
   CFileTxt file;                     //--- Create file object
   if (file.Open(logFileName, FILE_WRITE | FILE_TXT | FILE_COMMON, true) >= 0) { //--- Open log file
      file.WriteString(message + "\n"); //--- Write message
      file.Close();                   //--- Close file
   }
   Print(message);                    //--- Print message
}

string Ask(string symbol) {
   double value;                      //--- Variable for ask price
   if (SymbolInfoDouble(symbol, SYMBOL_ASK, value)) { //--- Get ask price
      return DoubleToString(value, (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS)); //--- Return formatted ask
   }
   LogError(__FUNCTION__ + ": Failed to get ask price for " + symbol + ", Error: " + IntegerToString(GetLastError())); //--- Log error
   return "N/A";                      //--- Return N/A on failure
}

string Bid(string symbol) {
   double value;                      //--- Variable for bid price
   if (SymbolInfoDouble(symbol, SYMBOL_BID, value)) { //--- Get bid price
      return DoubleToString(value, (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS)); //--- Return formatted bid
   }
   LogError(__FUNCTION__ + ": Failed to get bid price for " + symbol + ", Error: " + IntegerToString(GetLastError())); //--- Log error
   return "N/A";                      //--- Return N/A on failure
}

string Spread(string symbol) {
   long value;                        //--- Variable for spread
   if (SymbolInfoInteger(symbol, SYMBOL_SPREAD, value)) { //--- Get spread
      return IntegerToString(value);  //--- Return spread as string
   }
   LogError(__FUNCTION__ + ": Failed to get spread for " + symbol + ", Error: " + IntegerToString(GetLastError())); //--- Log error
   return "N/A";                      //--- Return N/A on failure
}

string PercentChange(double current, double previous) {
   if (previous == 0) return "0.00%"; //--- Handle zero previous value
   return StringFormat("%.2f%%", ((current - previous) / previous) * 100); //--- Calculate and format percentage
}

string TruncPeriod(ENUM_TIMEFRAMES period) {
   return StringSubstr(EnumToString(period), 7); //--- Truncate timeframe string
}

Um Objekte und Daten zu verwalten, instanziieren wir „objManager“ als „CObjectManager“, um UI-Elemente zu verfolgen. Wir erstellen die Funktion „LogError“, um Fehler zu protokollieren, öffnen „logFileName“ mit „CFileTxt“ unter Verwendung von „FILE_WRITE | FILE_TXT | FILE_COMMON“, schreiben die „Nachricht“ mit „WriteString“, schließen die Datei und drucken sie aus. Die Funktion „Ask“ ruft den Briefkurs für ein „Symbol“ mit SymbolInfoDouble ab, formatiert ihn mit DoubleToString unter Verwendung von „SymbolInfoInteger“ für die Dezimalstellen, protokolliert Fehler mit „LogError“, wenn sie fehlgeschlagen sind, und gibt bei Fehlschlag „N/A“ zurück. In ähnlicher Weise holt die Funktion „Bid“ den Geldkurs, formatiert ihn und behandelt eventuelle Fehler.

Die Funktion „Spread“ ermittelt die Spanne mit „SymbolInfoInteger“ und gibt sie als String mit IntegerToString oder „N/A“ bei Fehlschlag zurück. Die Funktion „PercentChange“ berechnet die prozentuale Veränderung zwischen „aktuellem“ und „vorherigem“ Preis unter Verwendung des StringFormats und gibt „0.00%“ zurück, wenn „vorheriger“ gleich Null ist. Die Funktion „TruncPeriod“ schneidet die Zeichenkette ENUM_TIMEFRAMES mit StringSubstr ab, um eine übersichtliche Anzeige des Zeitrahmens zu gewährleisten und saubere Ausgaben zu erhalten. Jetzt können wir die Funktion für die holografischen Impulse erstellen.

//+------------------------------------------------------------------+
//| Holographic Animation Function                                   |
//+------------------------------------------------------------------+
void HolographicPulse(string objName, color mainClr, color glowClr) {
   if (!EnableAnimations) return;     //--- Exit if animations disabled
   int cycles = PulseCycles;          //--- Set pulse cycles
   int delay = AnimationSpeed;        //--- Set animation delay
   for (int i = 0; i < cycles; i++) { //--- Iterate through cycles
      ObjectSetInteger(0, objName, OBJPROP_COLOR, glowClr); //--- Set glow color
      ChartRedraw(0);                 //--- Redraw chart
      Sleep(delay);                   //--- Delay
      ObjectSetInteger(0, objName, OBJPROP_COLOR, mainClr); //--- Set main color
      ChartRedraw(0);                 //--- Redraw chart
      Sleep(delay / 2);               //--- Shorter delay
   }
}

Hier implementieren wir die Funktion „HolographicPulse“, um einen Puls-Animationseffekt für Dashboard-Elemente zu erzeugen. Wir beenden das Programm vorzeitig, wenn „EnableAnimations“ falsch ist, um Animationen zu überspringen. Wir setzen „cycles“ auf „PulseCycles“ und „delay“ auf „AnimationSpeed“ und durchlaufen dann die „cycles“ mit einer for-Schleife. Bei jeder Iteration wird die Farbe des Objekts mit ObjectSetInteger für OBJPROP_COLOR auf „glowClr“ gesetzt, das Chart mit ChartRedraw neu gezeichnet, mit „Sleep“ für „delay“ pausiert, wieder auf „mainClr“ umgeschaltet, erneut neu gezeichnet und für einen kürzeren Effekt für „delay / 2“ pausiert. Dadurch wird der holografische Impuls hinzugefügt, um aktive oder warnende Elemente visuell hervorzuheben. Mit diesen Funktionen bewaffnet, können wir mit der Erstellung des Kerninitialisierungs-Dashboards fortfahren. Dazu benötigen wir einige Hilfsfunktionen, um das Programm modular zu halten.

//+------------------------------------------------------------------+
//| Create Text Label Function                                       |
//+------------------------------------------------------------------+
bool createText(string objName, string text, int x, int y, color clrTxt, int fontsize, string font, bool animate = false, double opacity = 1.0) {
   ResetLastError();                  //--- Reset error code
   if (ObjectFind(0, objName) < 0) {  //--- Check if object exists
      if (!ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0)) { //--- Create label
         LogError(__FUNCTION__ + ": Failed to create label: " + objName + ", Error: " + IntegerToString(GetLastError())); //--- Log error
         return false;                //--- Return failure
      }
      objManager.AddObject(objName);  //--- Add 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
   ObjectSetString(0, objName, OBJPROP_TEXT, text); //--- Set text
   ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); //--- Set color
   ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontsize); //--- Set font size
   ObjectSetString(0, objName, OBJPROP_FONT, font); //--- Set font
   ObjectSetInteger(0, objName, OBJPROP_BACK, false); //--- Set foreground
   ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); //--- Disable selection
   ObjectSetInteger(0, objName, OBJPROP_ZORDER, StringFind(objName, "Glow") >= 0 ? -1 : 0); //--- Set z-order

   if (animate && EnableAnimations) { //--- Check for animation
      ObjectSetInteger(0, objName, OBJPROP_COLOR, DataColor); //--- Set temporary color
      ChartRedraw(0);                 //--- Redraw chart
      Sleep(50);                      //--- Delay
      ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); //--- Set final color
   }

   ChartRedraw(0);                    //--- Redraw chart
   return true;                       //--- Return success
}

//+------------------------------------------------------------------+
//| Create Button Function                                           |
//+------------------------------------------------------------------+
bool createButton(string objName, string text, int x, int y, int width, int height, color textColor, color bgColor, color borderColor, bool animate = false) {
   ResetLastError();                  //--- Reset error code
   if (ObjectFind(0, objName) < 0) {  //--- Check if object exists
      if (!ObjectCreate(0, objName, OBJ_BUTTON, 0, 0, 0)) { //--- Create button
         LogError(__FUNCTION__ + ": Failed to create button: " + objName + ", Error: " + IntegerToString(GetLastError())); //--- Log error
         return false;                //--- Return failure
      }
      objManager.AddObject(objName);  //--- Add to manager
   }
   ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, x); //--- Set x-coordinate
   ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, y); //--- Set y-coordinate
   ObjectSetInteger(0, objName, OBJPROP_XSIZE, width); //--- Set width
   ObjectSetInteger(0, objName, OBJPROP_YSIZE, height); //--- Set height
   ObjectSetString(0, objName, OBJPROP_TEXT, text); //--- Set text
   ObjectSetInteger(0, objName, OBJPROP_COLOR, textColor); //--- Set text color
   ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, bgColor); //--- Set background color
   ObjectSetInteger(0, objName, OBJPROP_BORDER_COLOR, borderColor); //--- Set border color
   ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, BaseFontSize + (StringFind(objName, "SwitchTFBtn") >= 0 ? 3 : 0)); //--- Set font size
   ObjectSetString(0, objName, OBJPROP_FONT, FontType); //--- Set font
   ObjectSetInteger(0, objName, OBJPROP_ZORDER, 1); //--- Set z-order
   ObjectSetInteger(0, objName, OBJPROP_STATE, false); //--- Reset state

   if (animate && EnableAnimations) { //--- Check for animation
      ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrLightGray); //--- Set temporary background
      ChartRedraw(0);                 //--- Redraw chart
      Sleep(50);                      //--- Delay
      ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, bgColor); //--- Set final background
   }

   ChartRedraw(0);                    //--- Redraw chart
   return true;                       //--- Return success
}

//+------------------------------------------------------------------+
//| Create Panel Function                                            |
//+------------------------------------------------------------------+
bool createPanel(string objName, int x, int y, int width, int height, color clr, double opacity = 1.0) {
   ResetLastError();                  //--- Reset error code
   if (ObjectFind(0, objName) < 0) {  //--- Check if object exists
      if (!ObjectCreate(0, objName, OBJ_RECTANGLE_LABEL, 0, 0, 0)) { //--- Create panel
         LogError(__FUNCTION__ + ": Failed to create panel: " + objName + ", Error: " + IntegerToString(GetLastError())); //--- Log error
         return false;                //--- Return failure
      }
      objManager.AddObject(objName);  //--- Add to manager
   }
   ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, x); //--- Set x-coordinate
   ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, y); //--- Set y-coordinate
   ObjectSetInteger(0, objName, OBJPROP_XSIZE, width); //--- Set width
   ObjectSetInteger(0, objName, OBJPROP_YSIZE, height); //--- Set height
   ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clr); //--- Set background color
   ObjectSetInteger(0, objName, OBJPROP_BORDER_TYPE, BORDER_FLAT); //--- Set border type
   ObjectSetInteger(0, objName, OBJPROP_ZORDER, -1); //--- Set z-order
   ChartRedraw(0);                    //--- Redraw chart
   return true;                       //--- Return success
}

//+------------------------------------------------------------------+
//| Create Line Function                                             |
//+------------------------------------------------------------------+
bool createLine(string objName, int x1, int y1, int x2, int y2, color clrLine, double opacity = 1.0) {
   ResetLastError();                  //--- Reset error code
   if (ObjectFind(0, objName) < 0) {  //--- Check if object exists
      if (!ObjectCreate(0, objName, OBJ_RECTANGLE_LABEL, 0, 0, 0)) { //--- Create line as rectangle
         LogError(__FUNCTION__ + ": Failed to create line: " + objName + ", Error: " + IntegerToString(GetLastError())); //--- Log error
         return false;                //--- Return failure
      }
      objManager.AddObject(objName);  //--- Add to manager
   }
   ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, x1); //--- Set x1
   ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, y1); //--- Set y1
   ObjectSetInteger(0, objName, OBJPROP_XSIZE, x2 - x1); //--- Set width
   ObjectSetInteger(0, objName, OBJPROP_YSIZE, StringFind(objName, "Glow") >= 0 ? 3 : 1); //--- Set height
   ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrLine); //--- Set color
   ObjectSetInteger(0, objName, OBJPROP_ZORDER, StringFind(objName, "Glow") >= 0 ? -1 : 0); //--- Set z-order
   ChartRedraw(0);                    //--- Redraw chart
   return true;                       //--- Return success
}

Hier definieren wir die Funktion „createText“, um eine Textbeschriftung zu erzeugen. Wir beginnen mit dem Aufruf von ResetLastError, um alle vorherigen Fehler zu löschen. Wenn das Objekt nicht existiert (geprüft über „ObjectFind(0, objName) < 0“), wird es mit ObjectCreate vom Typ OBJ_LABEL erstellt. Bei einem Fehlschlag wird der Fehler protokolliert und false zurückgegeben. Wir fügen es dem „objManager“ über „AddObject“ hinzu. Wir legen Eigenschaften fest: OBJPROP_XDISTANCE auf „x“, „OBJPROP_YDISTANCE“ auf „y“, und das Gleiche für die anderen. Wenn „animate“ und „EnableAnimations“ wahr sind, setzen wir „OBJPROP_COLOR“ vorübergehend auf „DataColor“, zeichnen neu, verzögern mit „Sleep(50)“ und setzen dann auf die Farbe des Textes. Zum Schluss wird neu gezeichnet und true zurückgegeben.

Als Nächstes definieren wir „createButton“ auf ähnliche Weise: Fehler zurücksetzen, Existenz prüfen, bei Bedarf mit OBJ_BUTTON erstellen, bei Fehlschlag protokollieren und zum Manager hinzufügen. Dann werden die Objekteigenschaften eingestellt und, falls Animationen aktiviert sind, OBJPROP_BGCOLOR vorübergehend auf „clrLightGray“ gesetzt, neu gezeichnet, 50ms schlafen, dann auf „bgColor“ gesetzt. Neu zeichnen und true zurückgeben. Für „createPanel“ verwenden wir einen ähnlichen Ansatz.

Die Funktion „createLine“ schließlich verwendet ein ähnliches Muster: zurücksetzen, prüfen, als OBJ_RECTANGLE_LABEL (der eine Linie simuliert) erstellen, bei Fehlschlag protokollieren und zum Manager hinzufügen. Setze „OBJPROP_XDISTANCE“ auf „x1“, „OBJPROP_YDISTANCE“ auf „y1“, „OBJPROP_XSIZE“ auf „x2-x1“, „OBJPROP_YSIZE“ auf 3 wenn „Glow“ im Namen sonst 1, „OBJPROP_BGCOLOR“ auf „clrLine“, OBJPROP_ZORDER auf -1 wenn „Glow“ sonst 0. Neu zeichnen und true zurückgeben. Wir verwenden diese Funktionen nun, um die Kernfunktion zu erstellen, mit der wir das Haupt-Dashboard wie folgt gestalten können.

//+------------------------------------------------------------------+
//| Dashboard Creation Function with Holographic Effects             |
//+------------------------------------------------------------------+
void InitDashboard() {
   // Get chart dimensions
   long chartWidth, chartHeight;      //--- Variables for chart dimensions
   if (!ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0, chartWidth) || !ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0, chartHeight)) { //--- Get chart size
      LogError(__FUNCTION__ + ": Failed to get chart dimensions, Error: " + IntegerToString(GetLastError())); //--- Log error
      return;                         //--- Exit on failure
   }
   int fontSize = (int)(BaseFontSize * (chartWidth / 800.0)); //--- Calculate font size
   int cellWidth = PanelWidth / 8;    //--- Calculate cell width
   int cellHeight = 18;               //--- Set cell height
   int panelHeight = 70 + (ArraySize(periods) + 1) * cellHeight + 40 + (totalSymbols + 1) * cellHeight + 50; //--- Calculate panel height

   // Create Dark Panel
   createPanel("DashboardPanel", X_Offset, Y_Offset, PanelWidth, panelHeight, PanelColor); //--- Create dashboard panel

   // Create Header with Glow
   createText("Header", "HOLOGRAPHIC DASHBOARD", X_Offset + 10, Y_Offset + 10, TitleColor, fontSize + 4, FontType); //--- Create header text
   createText("HeaderGlow", "HOLOGRAPHIC DASHBOARD", X_Offset + 11, Y_Offset + 11, GlowColor, fontSize + 4, FontType, true); //--- Create header glow
   createText("SubHeader", StringFormat("%s | TF: %s", _Symbol, TruncPeriod(_Period)), X_Offset + 10, Y_Offset + 30, DataColor, fontSize, FontType); //--- Create subheader

   // Timeframe Grid
   int y = Y_Offset + 50;             //--- Set y-coordinate for timeframe grid
   createText("TF_Label", "Timeframe", X_Offset + 10, y, TitleColor, fontSize, FontType); //--- Create timeframe label
   createText("Trend_Label", "Trend", X_Offset + 10 + cellWidth, y, TitleColor, fontSize, FontType); //--- Create trend label
   createText("Vol_Label", "Vol", X_Offset + 10 + cellWidth * 2, y, TitleColor, fontSize, FontType); //--- Create vol label
   createText("RSI_Label", "RSI", X_Offset + 10 + cellWidth * 3, y, TitleColor, fontSize, FontType); //--- Create RSI label
   createLine("TF_Separator", X_Offset + 5, y + cellHeight + 2, X_Offset + PanelWidth - 5, y + cellHeight + 2, LineColor, 0.6); //--- Create separator line
   createLine("TF_Separator_Glow", X_Offset + 4, y + cellHeight + 1, X_Offset + PanelWidth - 4, y + cellHeight + 3, GlowColor, 0.3); //--- Create glow separator
   if (EnableAnimations) HolographicPulse("TF_Separator", LineColor, GlowColor); //--- Animate separator if enabled

   y += cellHeight + 5;               //--- Update y-coordinate
   for (int i = 0; i < ArraySize(periods); i++) { //--- Iterate through timeframes
      color periodColor = (periods[i] == _Period) ? ActiveColor : DataColor; //--- Set period color
      createText("Period_" + IntegerToString(i), TruncPeriod(periods[i]), X_Offset + 10, y, periodColor, fontSize, FontType); //--- Create period text
      createText("Trend_" + IntegerToString(i), "-", X_Offset + 10 + cellWidth, y, DataColor, fontSize, FontType); //--- Create trend text
      createText("Vol_" + IntegerToString(i), "0.00%", X_Offset + 10 + cellWidth * 2, y, DataColor, fontSize, FontType); //--- Create vol text
      createText("RSI_" + IntegerToString(i), "0.0", X_Offset + 10 + cellWidth * 3, y, DataColor, fontSize, FontType); //--- Create RSI text
      y += cellHeight;                //--- Update y-coordinate
   }

   // Symbol Grid
   y += 30;                           //--- Update y-coordinate for symbol grid
   createText("Symbol_Label", "Symbol", X_Offset + 10, y, TitleColor, fontSize, FontType); //--- Create symbol label
   createText("Bid_Label", "Bid", X_Offset + 10 + cellWidth, y, TitleColor, fontSize, FontType); //--- Create bid label
   createText("Spread_Label", "Spread", X_Offset + 10 + cellWidth * 2, y, TitleColor, fontSize, FontType); //--- Create spread label
   createText("Change_Label", "% Change", X_Offset + 10 + cellWidth * 3, y, TitleColor, fontSize, FontType); //--- Create change label
   createText("Vol_Label_Symbol", "Vol", X_Offset + 10 + cellWidth * 4, y, TitleColor, fontSize, FontType); //--- Create vol label
   createText("RSI_Label_Symbol", "RSI", X_Offset + 10 + cellWidth * 5, y, TitleColor, fontSize, FontType); //--- Create RSI label
   createText("UpArrow_Label", CharToString(236), X_Offset + 10 + cellWidth * 6, y, TitleColor, fontSize, "Wingdings"); //--- Create up arrow label
   createText("DownArrow_Label", CharToString(238), X_Offset + 10 + cellWidth * 7, y, TitleColor, fontSize, "Wingdings"); //--- Create down arrow label
   createLine("Symbol_Separator", X_Offset + 5, y + cellHeight + 2, X_Offset + PanelWidth - 5, y + cellHeight + 2, LineColor, 0.6); //--- Create separator line
   createLine("Symbol_Separator_Glow", X_Offset + 4, y + cellHeight + 1, X_Offset + PanelWidth - 4, y + cellHeight + 3, GlowColor, 0.3); //--- Create glow separator
   if (EnableAnimations) HolographicPulse("Symbol_Separator", LineColor, GlowColor); //--- Animate separator if enabled

   y += cellHeight + 5;               //--- Update y-coordinate
   for (int i = 0; i < totalSymbols; i++) { //--- Iterate through symbols
      string symbol = SymbolName(i, true); //--- Get symbol name
      string displaySymbol = (symbol == _Symbol) ? "*" + symbol : symbol; //--- Format display symbol
      color symbolColor = (symbol == _Symbol) ? ActiveColor : DataColor; //--- Set symbol color
      createText("Symbol_" + IntegerToString(i), displaySymbol, X_Offset + 10, y, symbolColor, fontSize, FontType); //--- Create symbol text
      createText("Bid_" + IntegerToString(i), Bid(symbol), X_Offset + 10 + cellWidth, y, DataColor, fontSize, FontType); //--- Create bid text
      createText("Spread_" + IntegerToString(i), Spread(symbol), X_Offset + 10 + cellWidth * 2, y, DataColor, fontSize, FontType); //--- Create spread text
      createText("Change_" + IntegerToString(i), "0.00%", X_Offset + 10 + cellWidth * 3, y, DataColor, fontSize, FontType); //--- Create change text
      createText("Vol_" + IntegerToString(i), "0.00%", X_Offset + 10 + cellWidth * 4, y, DataColor, fontSize, FontType); //--- Create vol text
      createText("RSI_" + IntegerToString(i), "0.0", X_Offset + 10 + cellWidth * 5, y, DataColor, fontSize, FontType); //--- Create RSI text
      createText("ArrowUp_" + IntegerToString(i), CharToString(236), X_Offset + 10 + cellWidth * 6, y, UpColor, fontSize, "Wingdings"); //--- Create up arrow
      createText("ArrowDown_" + IntegerToString(i), CharToString(238), X_Offset + 10 + cellWidth * 7, y, DownColor, fontSize, "Wingdings"); //--- Create down arrow
      y += cellHeight;                //--- Update y-coordinate
   }

   // Interactive Buttons with Pulse Animation
   createButton("ToggleBtn", "TOGGLE DASHBOARD", X_Offset + 10, y + 20, 150, 25, TitleColor, PanelColor, UpColor); //--- Create toggle button
   createButton("SwitchTFBtn", "NEXT TF", X_Offset + 170, y + 20, 120, 25, UpColor, PanelColor, UpColor); //--- Create switch TF button
   createButton("SortBtn", "SORT: " + sortNames[sortMode], X_Offset + 300, y + 20, 150, 25, TitleColor, PanelColor, UpColor); //--- Create sort button

   ChartRedraw(0);                    //--- Redraw chart
}

Hier initialisieren wir das Dashboard, indem wir zunächst die Abmessungen des Charts mithilfe der Variablen „chartWidth“ und „chartHeight“ abrufen. Wir erreichen dies, indem wir die Funktion ChartGetInteger zweimal aufrufen: einmal mit CHART_WIDTH_IN_PIXELS, um die Breite zu erhalten, und einmal mit „CHART_HEIGHT_IN_PIXELS“, um die Höhe zu erhalten. Als Nächstes berechnen wir die „fontSize“, indem wir die „BaseFontSize“ auf der Grundlage der Breite des Charts relativ zu 800 Pixel skalieren und das Ergebnis in eine Ganzzahl umwandeln. Wir bestimmen dann die „cellWidth“, indem wir „PanelWidth“ durch 8 teilen und „cellHeight“ auf einen festen Wert von 18 setzen. „panelHeight“ wird berechnet, indem 70, das Produkt aus („ArraySize(periods)“ + 1) und „cellHeight“, 40, das Produkt aus („totalSymbols“ + 1) und „cellHeight“, und 50 addiert werden – dies berücksichtigt das Gesamtlayout, einschließlich Zeitrahmen und Symbole.

Um den dunklen Hintergrund des Panels zu erstellen, rufen wir die Funktion „createPanel“ mit dem Namen „DashboardPanel“ auf, positionieren es an den Positionen „X_Offset“ und „Y_Offset“, mit den Abmessungen „PanelWidth“ und „panelHeight“ und färben es mit „PanelColor“. Für die Kopfzeile erstellen wir die Haupttextbeschriftung „Header“ mit der Zeichenfolge „HOLOGRAPHIC DASHBOARD“ mit der Funktion „createText“ an den Koordinaten „X_Offset“ + 10“ und „Y_Offset“ + 10“, gestylt mit „TitleColor“, einer Schriftgröße von „fontSize“ + 4“ und „FontType“. Um einen Glüheffekt hinzuzufügen, erstellen wir eine weitere Textbeschriftung „HeaderGlow“ mit der gleichen Zeichenfolge, aber um 1 Pixel in x- und y-Richtung versetzt, unter Verwendung von „GlowColor“, der gleichen Schriftgröße, „FontType“, und setzen das Deckkraft-Flag auf true.

Dann fügen wir eine Zwischenüberschrift „SubHeader“ hinzu, formatiert mit dem aktuellen Symbol _Symbol und einer abgeschnittenen Periode aus „TruncPeriod(_Period)“ mit „StringFormat“formatiert, bei „X_Offset“ + 10“ und „Y_Offset“ + 30“ positioniert und mit „DataColor“, „fontSize“ und „FontType“ eingefärbt.

Im Abschnitt für das Zeitraster setzen wir „y“ auf „Y_Offset“ + 50“. Wir erstellen Beschriftungen für „Timeframe“, „Trend“, „Vol“ und „RSI“ mit „createText“ für jede, horizontal positioniert mit Offsets basierend auf „cellWidth“, alle mit „TitleColor“, „fontSize“ und „FontType“. Darunter zeichnen wir eine Trennlinie „TF_Separator“ mit der Funktion „createLine“ von „X_Offset + 5“ bis „X_Offset + PanelWidth – 5“, in der Höhe „y + cellHeight + 2“, in der Farbe „LineColor“ mit der Deckkraft 0.6“. Für das Glühen fügen wir „TF_Separator_Glow“ als weitere, leicht versetzte und breitere Zeile mit „GlowColor“ und Deckkraft 0,3“ hinzu. Wenn „EnableAnimations“ wahr ist, wenden wir die Animation über „HolographicPulse“ mit „LineColor“ und „GlowColor“ an. Wir verwenden eine ähnliche Logik für alle anderen Etikettenobjekte.

Schließlich erstellen wir interaktive Schaltflächen: „ToggleBtn“ als „TOGGLE DASHBOARD“ bei „X_Offset“ + 10“, „y + 20“, Größe 150x25, mit „TitleColor“, „PanelColor“, „UpColor“; „SwitchTFBtn“ als „NEXT TF“ bei „X_Offset“ + 170“, gleiches y, Größe 120x25, mit „UpColor“, „PanelColor“, „UpColor“; und „SortBtn“ als „SORT: „ + sortNames[sortMode]“ bei „X_Offset“ + 300“, gleiches y, Größe 150x25, mit „TitleColor“, „PanelColor“, „UpColor“. Abschließend wird das Chart mit der Funktion „ChartRedraw(0)“ neu gezeichnet. Mit der Funktion können wir sie im Initialisierungs-Ereignishandler aufrufen, und wir können die schwere Arbeit erledigen.

//+------------------------------------------------------------------+
//| Expert Initialization Function                                   |
//+------------------------------------------------------------------+
int OnInit() {
   // Clear existing objects
   if (ObjectsDeleteAll(0, -1, -1) < 0) { //--- Delete all objects
      LogError(__FUNCTION__ + ": Failed to delete objects, Error: " + IntegerToString(GetLastError())); //--- Log error
   }
   objManager.DeleteAllObjects();     //--- Delete managed objects

   // Initialize arrays
   totalSymbols = SymbolsTotal(true); //--- Get total symbols
   if (totalSymbols == 0) {           //--- Check for symbols
      LogError(__FUNCTION__ + ": No symbols available"); //--- Log error
      return INIT_FAILED;             //--- Return failure
   }
   ArrayResize(prices_PrevArray, totalSymbols); //--- Resize previous prices array
   ArrayResize(volatility_Array, totalSymbols); //--- Resize volatility array
   ArrayResize(bid_array, totalSymbols); //--- Resize bid array
   ArrayResize(spread_array, totalSymbols); //--- Resize spread array
   ArrayResize(change_array, totalSymbols); //--- Resize change array
   ArrayResize(vol_array, totalSymbols); //--- Resize vol array
   ArrayResize(rsi_array, totalSymbols); //--- Resize RSI array
   ArrayResize(indices, totalSymbols);   //--- Resize indices array
   ArrayResize(atr_handles_sym, totalSymbols); //--- Resize ATR symbol handles
   ArrayResize(rsi_handles_sym, totalSymbols); //--- Resize RSI symbol handles
   ArrayResize(atr_handles_tf, ArraySize(periods)); //--- Resize ATR timeframe handles
   ArrayResize(rsi_handles_tf, ArraySize(periods)); //--- Resize RSI timeframe handles
   ArrayInitialize(prices_PrevArray, 0); //--- Initialize previous prices
   ArrayInitialize(volatility_Array, 0); //--- Initialize volatility

   // Create indicator handles for timeframes
   for (int i = 0; i < ArraySize(periods); i++) { //--- Iterate through timeframes
      atr_handles_tf[i] = iATR(_Symbol, periods[i], ATR_Period); //--- Create ATR handle
      if (atr_handles_tf[i] == INVALID_HANDLE) { //--- Check for invalid handle
         LogError(__FUNCTION__ + ": Failed to create ATR handle for TF " + EnumToString(periods[i])); //--- Log error
         return INIT_FAILED;          //--- Return failure
      }
      rsi_handles_tf[i] = iRSI(_Symbol, periods[i], RSI_Period, PRICE_CLOSE); //--- Create RSI handle
      if (rsi_handles_tf[i] == INVALID_HANDLE) { //--- Check for invalid handle
         LogError(__FUNCTION__ + ": Failed to create RSI handle for TF " + EnumToString(periods[i])); //--- Log error
         return INIT_FAILED;          //--- Return failure
      }
   }

   // Create indicator handles for symbols on H1
   for (int i = 0; i < totalSymbols; i++) { //--- Iterate through symbols
      string symbol = SymbolName(i, true); //--- Get symbol name
      atr_handles_sym[i] = iATR(symbol, PERIOD_H1, ATR_Period); //--- Create ATR handle
      if (atr_handles_sym[i] == INVALID_HANDLE) { //--- Check for invalid handle
         LogError(__FUNCTION__ + ": Failed to create ATR handle for symbol " + symbol); //--- Log error
         return INIT_FAILED;          //--- Return failure
      }
      rsi_handles_sym[i] = iRSI(symbol, PERIOD_H1, RSI_Period, PRICE_CLOSE); //--- Create RSI handle
      if (rsi_handles_sym[i] == INVALID_HANDLE) { //--- Check for invalid handle
         LogError(__FUNCTION__ + ": Failed to create RSI handle for symbol " + symbol); //--- Log error
         return INIT_FAILED;          //--- Return failure
      }
   }

   InitDashboard();                   //--- Initialize dashboard
   dashboardVisible = true;           //--- Set dashboard visible

   return INIT_SUCCEEDED;             //--- Return success
}

In der Funktion OnInit werden die vorhandenen Objekte mit der Funktion ObjectsDeleteAll für alle Charts und Typen gelöscht, wobei Fehler mit „LogError“ protokolliert werden, wenn sie nicht erfolgreich waren, und „objManager.DeleteAllObjects“ aufgerufen, um verwaltete Elemente zu entfernen. Wir erhalten „totalSymbols“ von SymbolsTotal mit true für Marktbeobachtungssymbole, wobei INIT_FAILED zurückgegeben wird, wenn es null ist, und mit „LogError“ protokolliert wird. Wir ändern die Größe von Arrays wie „prices_PrevArray“, „volatility_array“, „bid_array“, „spread_array“, „change_array“, „vol_array“, „rsi_array“, „indices“, „atr_handles_sym“, „rsi_handles_sym“, „atr_handles_tf“ und „rsi_handles_tf“ mit „totalSymbols“ oder „ArraySize(periods)“ unter Verwendung von ArrayResize angleichen und „prices_PrevArray“ und „volatility_Array“ mit der Funktion ArrayInitialize auf Null initialisieren.

Für Zeitrahmen durchlaufen wir „periods“ und erstellen „atr_handles_tf[i]“ mit iATR auf „_Symbol“, „periods[i]“ und „ATR_Period“ und „rsi_handles_tf[i]“ mit „iRSI“ auf „ _Symbol“, „periods[i]“, „RSI_Period“ und „PRICE_CLOSE“, wobei bei „INVALID_HANDLE“ INIT_FAILED protokolliert und zurückgegeben wird. Ähnlich verhält es sich bei den Symbolen: Wir durchlaufen „totalSymbols“, holen uns „symbol“ mit „SymbolName“ und true, erstellen „atr_handles_sym[i]“ mit „iATR“ auf „symbol“, „PERIOD_H1“und „ATR_Period“, und „rsi_handles_sym[i]“ mit iRSI auf „symbol“, „PERIOD_H1“, „RSI_Period“ und „PRICE_CLOSE“, Protokollierung und Rückgabe von „INIT_FAILED“, wenn ungültig. Wir rufen „InitDashboard“ auf, um die Nutzeroberfläche zu erstellen, setzen „dashboardVisible“ auf true und geben den Erfolg zurück. Wenn wir das Programm ausführen, erhalten wir das folgende Ergebnis.

ERSTES DASHBOARD

Aus dem Bild geht hervor, dass wir das Programm erfolgreich initialisiert haben. Wir können uns um die Deinitialisierung des Programms kümmern, bei der wir die erstellten Objekte löschen und die Indikator-Handles freigeben müssen.

//+------------------------------------------------------------------+
//| Expert Deinitialization Function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
   if (ObjectsDeleteAll(0, -1, -1) < 0) { //--- Delete all objects
      LogError(__FUNCTION__ + ": Failed to delete objects, Error: " + IntegerToString(GetLastError())); //--- Log error
   }
   objManager.DeleteAllObjects();     //--- Delete managed objects

   // Release indicator handles
   for (int i = 0; i < ArraySize(atr_handles_tf); i++) { //--- Iterate through timeframe ATR handles
      if (atr_handles_tf[i] != INVALID_HANDLE) IndicatorRelease(atr_handles_tf[i]); //--- Release handle
      if (rsi_handles_tf[i] != INVALID_HANDLE) IndicatorRelease(rsi_handles_tf[i]); //--- Release handle
   }
   for (int i = 0; i < ArraySize(atr_handles_sym); i++) { //--- Iterate through symbol ATR handles
      if (atr_handles_sym[i] != INVALID_HANDLE) IndicatorRelease(atr_handles_sym[i]); //--- Release handle
      if (rsi_handles_sym[i] != INVALID_HANDLE) IndicatorRelease(rsi_handles_sym[i]); //--- Release handle
   }
}

In OnDeinit werden die Ressourcen aufgeräumt, wenn der EA entfernt wird. Wir löschen alle Chart-Objekte mit ObjectsDeleteAll mit -1 für alle Charts und Typen und protokollieren Fehler mit „LogError“, wenn das Ergebnis negativ ist. Wir rufen „objManager.DeleteAllObjects“ auf, um verwaltete Elemente zu entfernen. Für Zeitrahmen-Handles werden die „atr_handles_tf“ und „rsi_handles_tf“ mit ArraySize durchlaufen und gültige Handles mit IndicatorRelease freigegeben, wenn sie nicht „INVALID_HANDLE“ sind. Ähnlich verhält es sich mit den Symbol-Handles in „atr_handles_sym“ und „rsi_handles_sym“. Dies gewährleistet eine vollständige Bereinigung der Objekte und Indikatoren. Hier ist eine Illustration.

ENTFERNEN-GIF

Nachdem die erstellten Objekte vollständig erfasst wurden, können wir uns nun den Aktualisierungen zuwenden. Wir beabsichtigen, die Aktualisierungen in OnTick durchzuführen, um alles einfach zu halten, aber Sie könnten sie auch in der Ereignisbehandlung von OnTimer durchführen. Beginnen wir zunächst mit dem Abschnitt über den Zeitrahmen.

//+------------------------------------------------------------------+
//| Expert Tick Function with Holographic Updates                    |
//+------------------------------------------------------------------+
void OnTick() {
   if (!dashboardVisible) return;     //--- Exit if dashboard hidden

   long chartWidth;                   //--- Variable for chart width
   ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0, chartWidth); //--- Get chart width
   int fontSize = (int)(BaseFontSize * (chartWidth / 800.0)); //--- Calculate font size
   int cellWidth = PanelWidth / 8;    //--- Calculate cell width
   int cellHeight = 18;               //--- Set cell height
   int y = Y_Offset + 75;             //--- Set y-coordinate for timeframe data

   // Update Timeframe Data with Pulse
   for (int i = 0; i < ArraySize(periods); i++) { //--- Iterate through timeframes
      double open = iOpen(_Symbol, periods[i], 0); //--- Get open price
      double close = iClose(_Symbol, periods[i], 0); //--- Get close price
      double atr_buf[1];              //--- Buffer for ATR
      if (CopyBuffer(atr_handles_tf[i], 0, 0, 1, atr_buf) != 1) { //--- Copy ATR data
         LogError(__FUNCTION__ + ": Failed to copy ATR buffer for TF " + EnumToString(periods[i])); //--- Log error
         continue;                    //--- Skip on failure
      }
      double vol = (close > 0) ? (atr_buf[0] / close) * 100 : 0.0; //--- Calculate volatility
      double rsi_buf[1];              //--- Buffer for RSI
      if (CopyBuffer(rsi_handles_tf[i], 0, 0, 1, rsi_buf) != 1) { //--- Copy RSI data
         LogError(__FUNCTION__ + ": Failed to copy RSI buffer for TF " + EnumToString(periods[i])); //--- Log error
         continue;                    //--- Skip on failure
      }
      double rsi = rsi_buf[0];        //--- Get RSI value
      color clr = DataColor;          //--- Set default color
      string trend = "-";             //--- Set default trend
      if (rsi > 50) { clr = UpColor; trend = "↑"; } //--- Set up trend
      else if (rsi < 50) { clr = DownColor; trend = "↓"; } //--- Set down trend
      createText("Trend_" + IntegerToString(i), trend, X_Offset + 10 + cellWidth, y, clr, fontSize, FontType, EnableAnimations); //--- Update trend text
      createText("Vol_" + IntegerToString(i), StringFormat("%.2f%%", vol), X_Offset + 10 + cellWidth * 2, y, vol > Vol_Alert_Threshold ? UpColor : DataColor, fontSize, FontType, vol > Vol_Alert_Threshold && EnableAnimations); //--- Update vol text
      color rsi_clr = (rsi > 70 ? DownColor : (rsi < 30 ? UpColor : DataColor)); //--- Set RSI color
      createText("RSI_" + IntegerToString(i), StringFormat("%.1f", rsi), X_Offset + 10 + cellWidth * 3, y, rsi_clr, fontSize, FontType, (rsi > 70 || rsi < 30) && EnableAnimations); //--- Update RSI text
      HolographicPulse("Period_" + IntegerToString(i), (periods[i] == _Period) ? ActiveColor : DataColor, GlowColor); //--- Pulse period text
      y += cellHeight;                //--- Update y-coordinate
   }

   // Update Symbol Data with Advanced Glow
   y += 50;                           //--- Update y-coordinate for symbol data
   for (int i = 0; i < totalSymbols; i++) { //--- Iterate through symbols
      string symbol = SymbolName(i, true); //--- Get symbol name
      double bidPrice;                //--- Variable for bid price
      if (!SymbolInfoDouble(symbol, SYMBOL_BID, bidPrice)) { //--- Get bid price
         LogError(__FUNCTION__ + ": Failed to get bid for " + symbol + ", Error: " + IntegerToString(GetLastError())); //--- Log error
         continue;                    //--- Skip on failure
      }
      long spread;                    //--- Variable for spread
      if (!SymbolInfoInteger(symbol, SYMBOL_SPREAD, spread)) { //--- Get spread
         LogError(__FUNCTION__ + ": Failed to get spread for " + symbol + ", Error: " + IntegerToString(GetLastError())); //--- Log error
         continue;                    //--- Skip on failure
      }
      double change = (prices_PrevArray[i] == 0 ? 0 : (bidPrice - prices_PrevArray[i]) / prices_PrevArray[i] * 100); //--- Calculate change
      double close = iClose(symbol, PERIOD_H1, 0); //--- Get close price
      double atr_buf[1];              //--- Buffer for ATR
      if (CopyBuffer(atr_handles_sym[i], 0, 0, 1, atr_buf) != 1) { //--- Copy ATR data
         LogError(__FUNCTION__ + ": Failed to copy ATR buffer for symbol " + symbol); //--- Log error
         continue;                    //--- Skip on failure
      }
      double vol = (close > 0) ? (atr_buf[0] / close) * 100 : 0.0; //--- Calculate volatility
      double rsi_buf[1];              //--- Buffer for RSI
      if (CopyBuffer(rsi_handles_sym[i], 0, 0, 1, rsi_buf) != 1) { //--- Copy RSI data
         LogError(__FUNCTION__ + ": Failed to copy RSI buffer for symbol " + symbol); //--- Log error
         continue;                    //--- Skip on failure
      }
      double rsi = rsi_buf[0];        //--- Get RSI value
      bid_array[i] = bidPrice;        //--- Store bid
      spread_array[i] = spread;       //--- Store spread
      change_array[i] = change;       //--- Store change
      vol_array[i] = vol;             //--- Store vol
      rsi_array[i] = rsi;             //--- Store RSI
      volatility_Array[i] = vol;      //--- Store volatility
      prices_PrevArray[i] = bidPrice; //--- Update previous price
   }
}

In der Funktion OnTick werden Aktualisierungen bei jedem Markttick durchgeführt, sodass die Daten für Zeitrahmen und Symbole in Echtzeit aktualisiert werden. Wir brechen vorzeitig ab, wenn „dashboardVisible“ falsch ist, um unnötige Verarbeitung zu vermeiden. Wir rufen „chartWidth“ mit ChartGetInteger unter Verwendung von CHART_WIDTH_IN_PIXELS ab, berechnen „fontSize“ skaliert mit „chartWidth / 800.0“, „cellWidth“ als „PanelWidth / 8“, und „cellHeight“ als 18. Wir setzen „y“ auf „Y_Offset + 75“ für das Zeitraster und durchlaufen die „Perioden“ mit der Funktion ArraySize. Für jeden Zeitrahmen werden „open“ mit iOpen und „close“ mit „iClose“ bei Shift 0 ermittelt, „atr_buf“ mit CopyBuffer aus „atr_handles_tf[i]“ kopiert und „vol“ als prozentualer ATR über „close“ berechnet, falls positiv.

Wir kopieren „rsi_buf“ aus „rsi_handles_tf[i]“ und erhalten „rsi“, setzen „clr“ und „trend“ basierend auf RSI > 50 für Aufwärtsbewegungen („↑“ in „UpColor“) oder < 50 für Abwärtsbewegungen („↓“ in „DownColor“). Wir hätten auch die Pfeile aus Schriftarten verwenden können, aber diese handcodierten Pfeile fügen sich nahtlos ein und erhöhen den holografischen Reiz. Wir aktualisieren Texte mit „createText“ für Trend, Vol (gefärbt „UpColor“, wenn > „Vol_Alert_Threshold“ mit Animation) und RSI (gefärbt basierend auf überkauft/überverkauft mit Animation), und rufen „HolographicPulse“ auf den Perioden-Text mit „ActiveColor“ auf, wenn er mit _Period übereinstimmt. Wir erhöhen „y“ um „cellHeight“.

Wir aktualisieren „y“ um 50 für das Symbolgitter und durchlaufen die Schleife „totalSymbols“. Für jedes Symbol aus SymbolName mit true, holen wir „bidPrice“ mit „SymbolInfoDouble“ unter Verwendung von „SYMBOL_BID“ und „spread“ mit SymbolInfoInteger unter Verwendung von SYMBOL_SPREAD, protokollieren und überspringen bei Misserfolg. Wir berechnen „change“ als Prozentsatz über „prices_PrevArray[i]“, erhalten „close“ mit iClose auf „PERIOD_H1“ bei Shift 0, kopieren „atr_buf“ aus „atr_handles_sym[i]“, um „vol“ zu berechnen, und „rsi_buf“ aus „rsi_handles_sym[i]“, um „rsi“ zu erhalten. Wir speichern Werte in „bid_array“, „spread_array“, „change_array“, „vol_array“, „rsi_array“ und „volatility_array“ und aktualisieren „prices_PrevArray[i]“ auf „bidPrice“. Wir können nun zum Bereich der Symbole übergehen, wo wir sie sortieren und mit Effekten anzeigen müssen.

// Sort indices
for (int i = 0; i < totalSymbols; i++) indices[i] = i; //--- Initialize indices
bool swapped = true;               //--- Swap flag
while (swapped) {                  //--- Loop until no swaps
   swapped = false;                //--- Reset flag
   for (int j = 0; j < totalSymbols - 1; j++) { //--- Iterate through indices
      bool do_swap = false;        //--- Swap decision
      int a = indices[j], b = indices[j + 1]; //--- Get indices
      if (sortMode == 0) {         //--- Sort by name ASC
         string na = SymbolName(a, true), nb = SymbolName(b, true); //--- Get names
         if (na > nb) do_swap = true; //--- Swap if needed
      } else if (sortMode == 1) {  //--- Sort by vol DESC
         if (vol_array[a] < vol_array[b]) do_swap = true; //--- Swap if needed
      } else if (sortMode == 2) {  //--- Sort by change ABS DESC
         if (MathAbs(change_array[a]) < MathAbs(change_array[b])) do_swap = true; //--- Swap if needed
      } else if (sortMode == 3) {  //--- Sort by RSI DESC
         if (rsi_array[a] < rsi_array[b]) do_swap = true; //--- Swap if needed
      }
      if (do_swap) {               //--- Perform swap
         int temp = indices[j];    //--- Temporary store
         indices[j] = indices[j + 1]; //--- Swap
         indices[j + 1] = temp;    //--- Complete swap
         swapped = true;           //--- Set flag
      }
   }
}

// Display sorted symbols with pulse on high vol
for (int j = 0; j < totalSymbols; j++) { //--- Iterate through sorted indices
   int i = indices[j];                   //--- Get index
   string symbol = SymbolName(i, true);  //--- Get symbol
   double bidPrice = bid_array[i];       //--- Get bid
   long spread = spread_array[i];        //--- Get spread
   double change = change_array[i];      //--- Get change
   double vol = vol_array[i];            //--- Get vol
   double rsi = rsi_array[i];            //--- Get RSI
   color clr_s = (symbol == _Symbol) ? ActiveColor : DataColor; //--- Set symbol color
   color clr_p = DataColor, clr_sp = DataColor, clr_ch = DataColor, clr_vol = DataColor, clr_rsi = DataColor; //--- Set default colors
   color clr_a1 = DataColor, clr_a2 = DataColor; //--- Set arrow colors

   // Price Change
   if (change > 0) {               //--- Check positive change
      clr_p = UpColor; clr_ch = UpColor; clr_a1 = UpColor; clr_a2 = DataColor; //--- Set up colors
   } else if (change < 0) {        //--- Check negative change
      clr_p = DownColor; clr_ch = DownColor; clr_a1 = DataColor; clr_a2 = DownColor; //--- Set down colors
   }

   // Volatility Alert
   if (vol > Vol_Alert_Threshold) { //--- Check high volatility
      clr_vol = UpColor;            //--- Set vol color
      clr_s = (symbol == _Symbol) ? ActiveColor : UpColor; //--- Set symbol color
   }

   // RSI Color
   clr_rsi = (rsi > 70 ? DownColor : (rsi < 30 ? UpColor : DataColor)); //--- Set RSI color

   // Update Texts
   string displaySymbol = (symbol == _Symbol) ? "*" + symbol : symbol; //--- Format display symbol
   createText("Symbol_" + IntegerToString(j), displaySymbol, X_Offset + 10, y, clr_s, fontSize, FontType, vol > Vol_Alert_Threshold && EnableAnimations); //--- Update symbol text
   createText("Bid_" + IntegerToString(j), Bid(symbol), X_Offset + 10 + cellWidth, y, clr_p, fontSize, FontType, EnableAnimations); //--- Update bid text
   createText("Spread_" + IntegerToString(j), Spread(symbol), X_Offset + 10 + cellWidth * 2, y, clr_sp, fontSize, FontType); //--- Update spread text
   createText("Change_" + IntegerToString(j), StringFormat("%.2f%%", change), X_Offset + 10 + cellWidth * 3, y, clr_ch, fontSize, FontType); //--- Update change text
   createText("Vol_" + IntegerToString(j), StringFormat("%.2f%%", vol), X_Offset + 10 + cellWidth * 4, y, clr_vol, fontSize, FontType, vol > Vol_Alert_Threshold && EnableAnimations); //--- Update vol text
   createText("RSI_" + IntegerToString(j), StringFormat("%.1f", rsi), X_Offset + 10 + cellWidth * 5, y, clr_rsi, fontSize, FontType, (rsi > 70 || rsi < 30) && EnableAnimations); //--- Update RSI text
   createText("ArrowUp_" + IntegerToString(j), CharToString(236), X_Offset + 10 + cellWidth * 6, y, clr_a1, fontSize, "Wingdings"); //--- Update up arrow
   createText("ArrowDown_" + IntegerToString(j), CharToString(238), X_Offset + 10 + cellWidth * 7, y, clr_a2, fontSize, "Wingdings"); //--- Update down arrow

   // Pulse on high volatility
   if (vol > Vol_Alert_Threshold) { //--- Check high volatility
      HolographicPulse("Symbol_" + IntegerToString(j), clr_s, GlowColor); //--- Pulse symbol text
   }

   y += cellHeight;                //--- Update y-coordinate
}

ChartRedraw(0);                    //--- Redraw chart
}

Hier sortieren wir die Indizes, indem wir zunächst das Array „indices“ in einer Schleife von 0 bis „totalSymbols“ – 1 initialisieren. Wir verwenden einen Bubble-Sort-Ansatz, bei dem das „Swapped“-Flag anfangs auf „true“ gesetzt ist, und gehen in eine while-Schleife, bis keine Swaps mehr auftreten. Darin setzen wir „swapped“ auf false zurück, fahren dann eine Schleife von 0 bis „totalSymbols“ – 2, setzen „do_swap“ auf false und erhalten „a“ und „b“ als „indices[j]“ und „indices[j+1]“. Abhängig von „sortMode“: für 0 (name ASC), wir erhalten Namen über „SymbolName(a, true)“ und „SymbolName(b, true)“, tauschen wenn „na > nb“; für 1 (vol DESC), tauschen wenn „vol_array[a] < vol_array[b]“; for 2 (change ABS DESC), swap if „MathAbs(change_array[a]) < MathAbs(change_array[b])“; for 3 (RSI DESC), swap if „rsi_array[a] < rsi_array[b]“. Wenn „do_swap“, tauschen wir „indices[j]“ und „indices[j+1]“ unter Verwendung einer „temp“-Variablen und setzen „swapped“ auf true.

Als Nächstes zeigen wir sortierte Symbole an, indem wir eine Schleife über „totalSymbols“ ziehen, „i“ als „indices[j]“ erhalten und dann „symbol“ über „SymbolName(i, true)“, „bidPrice“ aus „bid_array[i]“, „spread“ aus „spread_array[i]“, „change“ aus „change_array[i]“, „vol“ aus „vol_array[i]“, und „rsi“ aus „rsi_array[i]“. Wir setzen „clr_s“ auf „ActiveColor“, wenn es mit „_Symbol“ übereinstimmt, sonst auf „DataColor“; andere Farben werden standardmäßig auf „DataColor“ gesetzt. Für Preisänderung: wenn „change > 0“, „clr_p“, „clr_ch“, „clr_a1“ auf „UpColor“ und „clr_a2“ auf „DataColor“; wenn < 0, auf „DownColor“ mit „clr_a1“ als „DataColor“ einstellen. Für Volatilitätsalarm: wenn „vol > Vol_Alert_Threshold“, setzen wir „clr_vol“ auf „UpColor“ und aktualisieren „clr_s“, wenn es nicht das aktuelle Symbol ist. Für RSI: Wir setzen „clr_rsi“ auf „DownColor“ wenn >70, „UpColor“ wenn <30, sonst „DataColor“.

Wir formatieren „displaySymbol“ mit „*“, wenn es mit „_Symbol“ übereinstimmt. Texte über „createText“ aktualisieren: symbol („Symbol_j“) mit „displaySymbol“, „clr_s“, animieren wenn hohe Volumina und aktiviert; bid („Bid_j“) mit „Bid(symbol)“, „clr_p“, animiert wenn aktiviert; spread („Spread_j“) mit „Spread(symbol)“, „clr_sp“; change („Change_j“) formatiert „%.2f%%“ über „StringFormat“, „clr_ch“; vol („Vol_j“) formatiert „%.2f%%“, „clr_vol“, animiert wenn hohe Vol und aktiviert; RSI („RSI_j“) formatiert „%.1f“, „clr_rsi“, Animation, wenn überkauft/überverkauft und aktiviert; Pfeil nach oben („ArrowUp_j“) mit „CharToString(236)“, „clr_a1“, „Wingdings“; Pfeil nach unten („ArrowDown_j“) mit „CharToString(238)“, „clr_a2“, „Wingdings“. Bei hohen Volumina „HolographicPulse“ mit „clr_s“ und „GlowColor“ auf Symboltext anwenden. Bei jeder Iteration wird „y“ um „cellHeight“ erhöht und schließlich neu gezeichnet. Wenn wir kompilieren, erhalten wir das folgende Ergebnis.

PULSIERENDE AKTUALISIERUNGEN IM ONTICK

Aus der Visualisierung geht hervor, dass die Aktualisierungen bei jedem Markttick wirksam werden. Jetzt können wir den von uns erstellten Schaltflächen Leben einhauchen. Dies wird über die Ereignisbehandlung durch OnChartEvent erreicht.

//+------------------------------------------------------------------+
//| Chart Event Handler                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {
   if (id == CHARTEVENT_OBJECT_CLICK) { //--- Handle click event
      if (sparam == "ToggleBtn") {    //--- Check toggle button
         dashboardVisible = !dashboardVisible; //--- Toggle visibility
         objManager.DeleteAllObjects(); //--- Delete objects
         if (dashboardVisible) {      //--- Check if visible
            InitDashboard();          //--- Reinitialize dashboard
         } else {
            createButton("ToggleBtn", "TOGGLE DASHBOARD", X_Offset + 10, Y_Offset + 10, 150, 25, TitleColor, PanelColor, UpColor); //--- Create toggle button
         }
      }
      else if (sparam == "SwitchTFBtn") { //--- Check switch TF button
         int currentIdx = -1;         //--- Initialize current index
         for (int i = 0; i < ArraySize(periods); i++) { //--- Find current timeframe
            if (periods[i] == _Period) { //--- Match found
               currentIdx = i;        //--- Set index
               break;                 //--- Exit loop
            }
         }
         int nextIdx = (currentIdx + 1) % ArraySize(periods); //--- Calculate next index
         if (!ChartSetSymbolPeriod(0, _Symbol, periods[nextIdx])) { //--- Switch timeframe
            LogError(__FUNCTION__ + ": Failed to switch timeframe, Error: " + IntegerToString(GetLastError())); //--- Log error
         }
         createButton("SwitchTFBtn", "NEXT TF", X_Offset + 170, (int)ObjectGetInteger(0, "SwitchTFBtn", OBJPROP_YDISTANCE), 120, 25, UpColor, PanelColor, UpColor, EnableAnimations); //--- Update button
      }
      else if (sparam == "SortBtn") { //--- Check sort button
         sortMode = (sortMode + 1) % 4; //--- Cycle sort mode
         createButton("SortBtn", "SORT: " + sortNames[sortMode], X_Offset + 300, (int)ObjectGetInteger(0, "SortBtn", OBJPROP_YDISTANCE), 150, 25, TitleColor, PanelColor, UpColor, EnableAnimations); //--- Update button
      }
      ObjectSetInteger(0, sparam, OBJPROP_STATE, false); //--- Reset button state
      ChartRedraw(0);                 //--- Redraw chart
   }
}

Wir implementieren die Ereignishandler durch OnChartEvent, um interaktive Ereignisse zu behandeln und auf Schaltflächenklicks zu reagieren, um die Sichtbarkeit umzuschalten, den Zeitrahmen zu wechseln und den Sortiermodus zu wechseln. Für CHARTEVENT_OBJECT_CLICK prüfen wir „sparam“ gegen „ToggleBtn“, schalten „dashboardVisible“ um, löschen Objekte mit „objManager.DeleteAllObjects“, und Reinitialisierung mit „InitDashboard“, wenn sichtbar, oder Erstellung eines neuen „ToggleBtn“ mit „createButton“, wenn versteckt. Wenn „sparam“ „SwitchTFBtn“ ist, finden wir den aktuellen Zeitrahmenindex in „periods“ mit einer Schleife, berechnen „nextIdx“ als „(currentIdx + 1) % ArraySize(periods)“, wechseln den Chart mit „ChartSetSymbolPeriod“ unter Verwendung von „periods[nextIdx]“, protokollieren Fehler mit „LogError“ und aktualisieren den Button mit „createButton“ inklusive Animation, wenn „EnableAnimations“.

Für „SortBtn“ setzen wir „sortMode“ mit „(sortMode + 1) % 4“ und aktualisieren den Schaltflächentext zu "SORT: " + "sortNames[sortMode]" unter Verwendung von „createButton“ mit Animation. Wir setzen den Schaltflächenstatus mit ObjectSetInteger für OBJPROP_STATE auf false zurück und zeichnen das Chart mit der Funktion ChartRedraw neu. Dies ermöglicht die Kontrolle über die Anzeige und die Datenorganisation des Dashboards. Nach dem Kompilieren erhalten wir die folgende Ausgabe.

REAKTIVE SCHALTFLÄCHEN

Wir sehen, dass wir das Dashboard bei jedem Markttick aktualisieren können und auf die Schaltflächenklicks für die Umschaltung des Dashboards, den Wechsel des Zeitrahmens und die Sortierung der Indizes für die Symbolmetriken reagieren und somit unsere Ziele erreichen. 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.

BACKTESTS


Schlussfolgerung

Abschließend haben wir ein dynamisches holografisches Dashboard in MQL5 erstellt, das Symbole und Zeitrahmen mit RSI, Volatilitätswarnungen und Sortierung überwacht und mit Impulsanimationen und interaktiven Schaltflächen für ein immersives Handelserlebnis sorgt. Wir haben die Architektur und Implementierung detailliert beschrieben und verwenden Klassenkomponenten wie „CObjectManager“ und Funktionen wie „HolographicPulse“, um visuell ansprechende Einblicke in Echtzeit zu liefern. Sie können dieses Dashboard an Ihre Handelsbedürfnisse anpassen und Ihre Analyse mit holografischen Effekten und Kontrollen aufwerten.

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

Beigefügte Dateien |
Entwicklung des Price Action Analysis Toolkit (Teil 34): Umwandlung von Marktrohdaten in Prognosemodellen mithilfe einer fortschrittlichen Pipeline der Datenerfassung Entwicklung des Price Action Analysis Toolkit (Teil 34): Umwandlung von Marktrohdaten in Prognosemodellen mithilfe einer fortschrittlichen Pipeline der Datenerfassung
Haben Sie schon einmal einen plötzlichen Marktanstieg verpasst oder wurden Sie von einem solchen überrascht? Der beste Weg, aktuelle Ereignisse zu antizipieren, besteht darin, aus historischen Mustern zu lernen. Mit dem Ziel, ein ML-Modell zu trainieren, zeigt Ihnen dieser Artikel zunächst, wie Sie ein Skript in MetaTrader 5 erstellen, das historische Daten aufnimmt und sie zur Speicherung an Python sendet. Lesen Sie weiter, um die einzelnen Schritte in Aktion zu sehen.
Datenwissenschaft und ML (Teil 46): Aktienmarktprognosen mit N-BEATS in Python Datenwissenschaft und ML (Teil 46): Aktienmarktprognosen mit N-BEATS in Python
N-BEATS ist ein revolutionäres Deep-Learning-Modell, das für die Prognose von Zeitreihen entwickelt wurde. Es wurde veröffentlicht, um die klassischen Modelle für Zeitreihenprognosen wie ARIMA, PROPHET, VAR usw. zu übertreffen. In diesem Artikel werden wir dieses Modell erörtern und es für die Vorhersage des Aktienmarktes verwenden.
Klassische Strategien neu interpretieren (Teil 14): Analyse mehrerer Strategien Klassische Strategien neu interpretieren (Teil 14): Analyse mehrerer Strategien
In diesem Artikel setzen wir unsere Erforschung der Erstellung eines Ensembles von Handelsstrategien und der Verwendung des MT5 genetischen Optimierers zur Abstimmung der Strategieparameter fort. Heute haben wir die Daten in Python analysiert. Dabei hat sich gezeigt, dass unser Modell besser vorhersagen kann, welche Strategie besser abschneiden wird, und eine höhere Genauigkeit erreicht als die direkte Vorhersage der Marktrenditen. Als wir unsere Anwendung jedoch mit ihren statistischen Modellen testeten, fielen unsere Leistungswerte drastisch ab. In der Folge stellten wir fest, dass der genetische Optimierer leider stark korrelierte Strategien bevorzugte, was uns dazu veranlasste, unsere Methode zu überarbeiten, um die Stimmgewichte fest zu halten und die Optimierung stattdessen auf Indikatoreinstellungen zu konzentrieren.
Entwicklung des Price Action Analysis Toolkit (Teil 33): Candle-Range Theory Tool Entwicklung des Price Action Analysis Toolkit (Teil 33): Candle-Range Theory Tool
Verbessern Sie Ihr Marktverständnis mit der Candle-Range Theory Suite für MetaTrader 5, einer vollständig MQL5-nativen Lösung, die rohe Preisbalken in Echtzeit-Volatilitätsinformationen umwandelt. Die leichtgewichtige Bibliothek CRangePattern vergleicht die „True Range“ jeder Kerze mit einer adaptiven ATR und klassifiziert sie in dem Moment, in dem sie schließt. Der CRT-Indikator projiziert diese Klassifizierungen dann als scharfe, farbkodierte Rechtecke und Pfeile auf Ihr Chart, die sich verengende Konsolidierungen, explosive Ausbrüche und Verengungen der gesamten Spanne in dem Moment anzeigen, in dem sie auftreten.