English 日本語
preview
Entwicklung des Price Action Analysis Toolkit (Teil 40): Markt-DNA-Pass

Entwicklung des Price Action Analysis Toolkit (Teil 40): Markt-DNA-Pass

MetaTrader 5Beispiele |
40 2
Christian Benjamin
Christian Benjamin

Inhalt



Einführung

In der Biologie ist die Desoxyribonukleinsäure (DNA) das Molekül, das den genetischen Bauplan eines jeden Organismus kodiert. Die DNA bestimmt die biologische Identität und wird über Generationen weitergegeben. Ich habe einmal einen Fall beobachtet, in dem ein Mann die Vaterschaft bestritt, bis ein DNA-Test – der nach der Geburt des Kindes durchgeführt wurde – bewies, dass er tatsächlich der Vater war. Sie fragen sich vielleicht, was das mit der Preisaktionsanalyse zu tun hat: Die Verbindung ist die Idee eines dauerhaften, identifizierbaren Fingerabdrucks.

Bei meinen Untersuchungen habe ich festgestellt, dass jedes Währungspaar seine eigene charakteristische Preis-Aktions-Signatur aufweist. Einige Paare können sich unter gemeinsamen Einflüssen ähnlich verhalten (z. B. EURUSD und GBPUSD), während andere ein unterschiedliches Verhalten zeigen. Um diese Muster zu erfassen, habe ich ein automatisiertes System entwickelt, das jedes Instrument scannt und eine Markt-DNAerstellt – einen kompakten Fingerabdruck, der sich aus Volatilität, fraktaler Struktur, Sitzungsrhythmen und Retracement-Verhalten ableitet. Der Markt-DNA-Passquantifiziert diese Merkmale und ermöglicht es Ihnen, Instrumente zu vergleichen, strukturelle Verschiebungen (Mutationen) zu erkennen und Strategien auszuwählen oder an die vorherrschenden Marktbedingungen anzupassen.

Eine Mutation ist eine signifikante Änderung im Markt-Fingerabdruck des EA, die gekennzeichnet wird, wenn der Kosinus- oder normalisierte L2-Abstand zwischen der vorherigen und der aktuellen DNA-Metrik die festgelegten Schwellenwerte überschreitet – und bedeutet in der Regel einen Regimewechsel (z. B. ATR, Spikes, Session-Dominanz oder Retracement-Verhalten geändert). Behandeln Sie es als Frühwarnung: Prüfen Sie, welche Kennzahlen sich verändert haben, straffen Sie die Ausführung oder pausieren Sie sie (kleinere Größe, breitere ATR-Stopps, höhere Signalschwelle), und validieren Sie das neue Profil mit einigen Neuberechnungen oder dem Papierhandel, bevor Sie den Live-Handel wieder aufnehmen.

// Show top N metric changes when a mutation is detected.
// Call: ShowMutationDetails(gDNA_prev, gDNA, 3);
void ShowMutationDetails(const DNAMetrics &prev_in, const DNAMetrics &cur_in, int topN=3)
{
   // make local copies because DNAVector expects a non-const reference
   DNAMetrics prev = prev_in;
   DNAMetrics cur  = cur_in;

   // metric names must follow the order in DNAVector()
   string names[] = {
     "wick_body_ratio_avg",
     "pct_close_near_high",
     "pct_close_near_low",
     "pct_doji",
     "atr_norm",
     "pct_spikes",
     "vol_clustering",
     "swing_cycle_bars_avg",
     "fractal_density",
     "breakout_follow_through",
     "retr_38_freq",
     "retr_50_freq",
     "retr_62_freq",
     "asia_range_share",
     "london_range_share",
     "ny_range_share",
     "smoothness_index"
   };

   double va[], vb[];
   DNAVector(cur, va);
   DNAVector(prev, vb);

   int n = ArraySize(va);
   if(n != ArraySize(names))
   {
      Print("[ShowMutationDetails] vector/name-size mismatch");
      return;
   }

   // diffs and indices
   double diffs[]; int idxs[];
   ArrayResize(diffs, n);
   ArrayResize(idxs, n);
   for(int i=0; i<n; ++i) { diffs[i] = va[i] - vb[i]; idxs[i] = i; }

   // simple selection sort by absolute diff (descending)
   for(int i=0; i<n-1; ++i)
   {
      int best = i;
      for(int j=i+1; j<n; ++j)
         if(MathAbs(diffs[j]) > MathAbs(diffs[best])) best = j;

      // swap diffs
      double td = diffs[i]; diffs[i] = diffs[best]; diffs[best] = td;
      int ti = idxs[i]; idxs[i] = idxs[best]; idxs[best] = ti;
   }

   int show = MathMin(topN, n);
   string out = "";
   for(int k=0; k<show; ++k)
   {
      int id = idxs[k];
      double d = diffs[k];
      double prevVal = vb[id];
      double pct = (MathAbs(prevVal) < 1e-12 ? 0.0 : (d / MathAbs(prevVal) * 100.0));
      string sign = (d >= 0.0 ? "+" : "-");
      string line = StringFormat("%d) %s %s%.4f (%.1f%%)", k+1, names[id], sign, MathAbs(d), MathAbs(pct));
      out += line + "\\n";
      PrintFormat("[MarketDNA][Mutation] %s", line);
   }

   // show on-panel (adjust offsets/sizes if needed)
   int w = 360;
   int h = 18 * (show + 1);
   CreateOrSetRect("mut_detail_bg", InpCorner, InpX + 380, InpY + 340, w, h, BgColor());
   CreateOrSetLabel("mut_detail_lbl", InpCorner, InpX + 388, InpY + 344, SafeText(out, 800), 9, MakeColor(200,120,40));
}

In den folgenden Abschnitten beschreibe ich die verwendeten Metriken, die MQL5-Implementierung und praktische Beispiele, die zeigen, wie der Pass robuste Analysen unterstützt.



Konzeptionelle Metriken

Market DNA Pass komprimiert Hunderte von Balken roher Kursbewegungen in stabile, erklärbare Metriken – Spitzen, fraktale Schwankungen, Retracement-Frequenzen, ATR-normalisierte Volatilität, Anteile an der Sitzungsspanne, Glattheit und mehr – damit Händler, die mit Kursbewegungen zu tun haben, sehen können, wie sich der Markt strukturell verhält (und nicht nur, wo der Kurs gerade steht), und schnellere, konsistentere Entscheidungen treffen können.

Warum diese Metriken für Preis-Aktions-Händler wichtig sind:

Bedeutung Erklärung
Objektive Erkennung von Marktordnungen Anstatt zu raten, ob es sich um einen Trend oder einen Bereich handelt, quantifiziert der EA die Glattheit, die fraktale Dichte und die Ausbruchsverfolgung, sodass Sie die Taktik anhand der Daten ändern können (Trendverfolgung vs. Mittelwertumkehr).
Bessere Einstiegschancen
Metriken wie „Breakout Follow-Through“ und „Close-Near-High/Low“ geben eine Bestätigung für Preisaktions-Setups auf hohem Niveau (Kerzen der Breakout-Fortsetzung versus einer „Failed-Break/Reversal“).
Risikobewusste Dimensionierung und Filterung
ATR-normalisierte Messwerte und Spike-Häufigkeit helfen bei der Festlegung der Stopps und der Entscheidung, wann man aussetzen sollte (hohe ATR oder häufige Spikes = breitere Stopps oder weniger Handelsgeschäfte).
Mustervalidierung und Erwartungshaltung
Retracement-Histogramme zeigen, wie tief Korrekturen nach Impulsen auf dem Symbol/Zeitrahmen typischerweise sind – wichtig, um realistische Ziele zu setzen und zu entscheiden, ob ein „Rücksetzer auf 50 %“ möglich ist.
Effizienz der Handelsauswahl
Der EA kondensiert eine Menge der Hausaufgaben vor der Eröffnung eines Handelsgeschäfts in einem Pass auf einen Blick, sodass Sie Symbole/Zeitrahmen schnell scannen und nur diejenigen auswählen können, die Ihrem Preis-Aktions-Vorteil entsprechen.
Erklärbarkeit
Für jedes Signal werden numerische Gründe protokolliert (z. B. „hohes Follow-Through + niedrige Spikes + glatter Markt“), sodass Sie überprüfen können, warum Sie einen Handel getätigt haben, und das Regelwerk iterativ verbessern können.

Metriken der Kerzen- und Volatilitätsanalyse

1. Kerzen-Struktur und Abschluss

docht_body_ratio_avg – das durchschnittliche Verhältnis zwischen der Gesamtlänge der Schatten und der Größe des Kerzenkörpers.

  • Hoher Wert → lange Schatten → Zeichen einer Umkehr (Pin Bar, Shooting Star).
  • Niedriger Wert → saubere Trendkerzen → stetiger Kauf-/Verkaufsdruck.
  • Um Verzerrungen zu vermeiden, wurde eine Mindestschwelle für den Kerzenkörper eingeführt.

pct_close_near_high – Prozentsatz der Kerzen, die in den oberen 20% des Bereichs geschlossen wurden.

  • Hoher Wert → starke Nachfrage, Aufwärtstrend.
  • Auf dünnen Märkten kann es falsche Signale geben.

pct_close_near_low – Prozentsatz der Kerzen, die in den unteren 20% des Bereichs geschlossen wurden.

  • Hoher Wert → dominanter Verkaufsdruck, Abwärtstrend.
  • Sitzungen mit speziellen Mustern können das Ergebnis verfälschen.

pct_doji – der Anteil der Doji-Kerzen (Körper < ~10% des Bereichs).

  • Hoher Wert → Marktunsicherheit.
  • Doji-Serien können starken Ausbrüchen vorausgehen.

nearHigh_count / nearLow_count – die Anzahl der Kerzen, die in der Nähe des Hochs/Tiefs geschlossen wurden.

  • Wird verwendet, um die Verschiebung des Gleichgewichts zwischen Angebot und Nachfrage zu bewerten.

doji_count – absolute Anzahl der Dojis.

  • Es hilft, die Phasen der Antizipation vor der Bewegung zu erkennen.

2. Volatilität und Momentum

atr_mean – durchschnittliche ATR (absolute Volatilität in Preiseinheiten).

  • Wird für Anschläge und Ziele verwendet.

atr_pips – ATR umgerechnet in Pips.

  • Praktisch für die Vereinheitlichung von verschiedenen Werkzeugen.

atr_norm – ATR normiert auf den Preis (ATR / Close).

  • Liefert ein relatives Maß für die Volatilität.
  • Sehr empfindlich für billige Instrumente.

pct_spikes – der Anteil der Kerzen, bei denen der Bereich > ATR-Multiplikator ist.

  • Hoher Wert → häufige Impulse/Rauschen.

spikes_count – die absolute Anzahl der Impulskerzen.

bigTotal_count – Gesamtzahl der großen Kerzen (> ATR).

bigThenBig_count – die Anzahl der Fälle, in denen auf eine große Kerze eine weitere folgt.

  • Hoch → Volatilitätscluster, Tendenz steigend.

vol_clustering – der Anteil der großen Kerzen, auf die eine weitere große Kerze folgt.

  • Ein Maß für die Persistenz der erhöhten Volatilität.

3. Fraktale und Zyklen

swing_cycle_bars_avg – die durchschnittliche Anzahl der Balken zwischen den Veränderungen der fraktalen Extrema.

  • Länge des Schwingungszyklus.
  • In seitlicher Richtung kann sie stark reduziert werden.

fractal_density – fraktale Dichte (% der Kerzen mit Umkehrungen).

  • Hoch → der Markt ist zerklüftet, seitlich.
  • Niedrig → Trend.

sw_count – Gesamtzahl der fraktalen Punkte.

breakout_follow_through – der Anteil der fraktalen Ebenen, die durch einen Ausbruch bestätigt wurden (um ≥ ATR).

  • Hoch → Rücksetzer sind zuverlässig.
  • Niedrig → viele falsche Signale.

4. Korrekturen und Rücksetzer

retr_38_freq – die Häufigkeit eines Rücksetzers beträgt etwa 38 %.

  • Typisch sind flache Korrekturen.

retr_50_freq – Häufigkeit eines Rücksetzers beträgt etwa 50 % (44-56%).

  • Klassische Korrekturstufe.

retr_62_freq – Häufigkeit von tiefen Korrekturen (~62%).

  • Weist oft auf eine Veränderung der Volatilität/des Regimes hin.

retr_gt70_freq – Die Rate eines Rücksetzers >70%.

  • Hoher Wert → schwache Impulse, Rückkehr zum Bereich.

avg_max_retr – durchschnittlicher maximaler Rücksetzer nach Impulsen.

  • Hilft bei der Festlegung realistischer Stopps/Ziele.

retr_count – die Anzahl der Impulse, nach denen Rollbacks gezählt wurden (wichtig für die Zuverlässigkeit).

5. Aktivität der Sitzung

asia_range_share / london_range_share / ny_range_share – der Anteil der in der entsprechenden Sitzung erzeugten Gesamtreichweite.

  • Zeigt an, welche Sitzung am meisten zur Bewegung beiträgt.

asia_range / london_range / ny_range – absolute Spanne (Hoch-Tief) innerhalb einer Sitzung.

  • Kennzeichnet die Volatilität zu einer bestimmten Tageszeit.

6. Zusammengesetzte Indizes und Leistungsparameter

smoothness_index (0-1) – Glättungsindex.

  • Hoch → Trend, geringes Rauschen.
  • Niedrig → seitwärts laufender, zerklüfteter Markt.

atr_cache_used – Kennzeichen für die Verwendung zwischengespeicherter ATR-Daten (Dienst).

sample_bars – Stichprobenumfang (Anzahl der Balken).

  • Große Stichproben → stabiler, aber weniger sensitiv für Veränderungen.


    MQL5-Implementierung

    Wir implementieren die MQL5 Market DNA-Engine als kompaktes System, das historische Balken für ein ausgewähltes Symbol und einen Zeitrahmen liest, einen Fingerabdruck der Preisanatomie und -struktur (Kerzen, ATR, fraktale Schwankungen, Retracements und Session-Range-Aktien) berechnet, einen beschrifteten „DNA-Pass“ auf dem Chart ausgibt, optional ein zweites Symbol vergleicht, Metriken und Signale im CSV-Format protokolliert und leichtgewichtige regelbasierte KAUFEN/VERKAUFEN-Vorschläge sowie Mutationswarnungen ausgibt, wenn sich der Fingerabdruck signifikant ändert. Dieser eine Satz fasst das Ziel zusammen: Der folgende Code konzentriert sich auf die Erstellung reproduzierbarer, erklärbarer Metriken, die Sie überprüfen oder in weitere Analysen einfließen lassen können.

    Um Sie bei der Implementierung zu unterstützen, erklärt dieser Abschnitt die Build- und Laufzeitannahmen, empfiehlt sinnvolle Starteingaben und hebt die wichtigsten Hilfsprogramme und Lebenszyklus-Hooks hervor, die Sie in der Datei finden werden – zum Beispiel OnInit, OnTimer, Recalculate, BuildDNA und DrawPass. Wenn Sie diese Grundlagen kennen, sind Sie besser darauf vorbereitet, den folgenden fünf Schritten zu folgen, ohne sich in Details zu verlieren.

    Bevor Sie beginnen, sollten Sie sicherstellen, dass Ihre Umgebung einige Voraussetzungen erfüllt. Sie benötigen MetaTrader 5 mit Berechtigung zum Kompilieren und Ausführen von EAs (#property strict und Trade/Trade.mqh werden verwendet). Der EA schreibt in den gemeinsamen Datei-Ordner des Terminals, sodass die Dateieingabe und -ausgabe erlaubt ist. Wählen Sie schließlich ein Symbol/Zeitrahmen mit mindestens ~300 historischen Balken; 1200 Balken werden für stabile Statistiken empfohlen. Wenn Sie nicht über eine ausreichende Historie verfügen, wird der EA Sie warnen, und die Ergebnisse werden verrauscht sein.

    #property copyright "Copyright 2025, MetaQuotes Ltd."
    #property link      "https://www.mql5.com/en/users/lynnchris"
    #property version   "1.0"
    #property strict
    
    #include <Trade/Trade.mqh>

    Wenn Sie ihn am schnellsten ausprobieren möchten, kopieren Sie Market DNA Pass.mq5 in Ihren MQL5/Experts-Ordner, kompilieren Sie ihn im MetaEditor, starten Sie den kompilierten EA an einen Chart an, setzen Sie InpTF und InpBars (Standardwerte sind PERIOD_H1 und 1200) und aktivieren Sie optional InpLogCSV, um Metriken zu erhalten. Der EA verwendet einen Timer und baut bei jedem neuen geschlossenen Balken neu auf. Prüfen Sie nach einem kurzen Durchlauf Files\Common auf MarketDNA_log.csv und MarketDNA_signals.csv, um die aufgezeichneten Ausgaben zu untersuchen.

    Eine gute Grundlage für die empfohlenen Eingaben ist InpTF = PERIOD_H1, InpBars = 1200, InpATRPeriod = 14, InpSpikeATRMult = 2.0, InpDojiBodyPct = 0.10, InpFractalDepth = 5, InpRetrWindowBars = 50 und InpFT_ATR_Mult = 0.5. Für eine gute Reaktionsfähigkeit und eine moderate CPU-Auslastung setzen Sie InpRecalcSeconds = 10 und InpCacheATR = true. Betrachten Sie diese als Ausgangspunkte für die Abstimmung pro Symbol und Handelshorizont.

    //============================== INPUTS ==============================//
    input ENUM_TIMEFRAMES InpTF              = PERIOD_H1;    // Analysis timeframe
    input int              InpBars           = 1200;         // Bars to analyze (>= 300 recommended)
    input int              InpATRPeriod      = 14;           // ATR period
    input double           InpSpikeATRMult   = 2.0;          // Spike threshold in ATR multiples
    input double           InpDojiBodyPct    = 0.10;         // Doji body <= % of candle range
    input int              InpFractalDepth   = 5;            // Fractal depth (ZigZag-like swings)
    input int              InpRetrLookbackSwings = 80;       // Max impulses to evaluate retracements
    input int              InpRetrWindowBars = 50;           // How many bars forward to scan for retracement
    input double           InpFT_ATR_Mult    = 0.5;          // Breakout follow-through threshold (in ATR multiples)
    input string           InpCompareSymbol  = "";           // Optional second symbol to compare
    input int              InpRecalcSeconds  = 10;           // Recalc cadence (seconds)
    input int              InpCorner         = 0;            // Panel corner (0-3)
    input int              InpX              = 12;           // Panel X offset
    input int              InpY              = 24;           // Panel Y offset
    input bool             InpDarkTheme      = true;         // Dark panel theme
    input int              InpMetricPalette  = 1;            // Metric color palette (0=Warm Brown,1=DarkGray,2=NearBlack,3=Lilac,4=RichBrown,5=HighContrast)
    input bool             InpAlertsOnMutation = true;       // Alert on DNA shifts
    input double           InpMutationThresh = 0.12;         // Cosine distance to flag change
    input double           InpMutationL2Thresh = 0.05;       // Normalized L2 change to flag mutation
    input bool             InpLogCSV         = false;        // Append results to CSV in common Files folder
    input string           InpCSVFileName    = "MarketDNA_log.csv"; // CSV filename (FILE_COMMON)
    input bool             InpCacheATR       = true;         // Cache ATR array between runs
    input bool             InpSelfTest       = false;        // Run small synthetic self-test at init
    input int              InpAsiaStart      = 0;            // Session hour boundaries (server hours)
    input int              InpAsiaEnd        = 7;
    input int              InpLondonStart    = 8;
    input int              InpLondonEnd      = 15;
    input int              InpNYStart        = 16;
    input int              InpNYEnd          = 23;
    input bool             InpDebugRetr      = false;        // Print retracement debug lines to Experts

    Praktische Hinweise zu Namensgebung, Sicherheit und Leistung: EA stellt den Chart-Objekten das Präfix MDNA_<Symbol>_<TF>_ voran, um Kollisionen zu vermeiden; CSVs befinden sich im Ordner FILE_COMMON unter festen Dateinamen. Aus Sicherheits- und Leistungsgründen erzwingt der EA eine minimale Timer-Kadenz (≥5s) und vermeidet schwerwiegende Änderungen, es sei denn, der neueste geschlossene Balken wurde geändert. Wenn Sie viele Instanzen oder massive Rückblicke (z. B. >5k Balken) ausführen, erhöhen Sie das Zeitintervall oder reduzieren Sie InpBars, um die CPU- und Speichernutzung zu begrenzen. Beachten Sie auch, dass mehrere EA-Instanzen, die dieselbe CSV-Datei schreiben, zu Wettlaufbedingungen führen können – für eine robuste Multi-Chart-Protokollierung sollten Sie eindeutige Dateinamen pro Symbol/Zeitrahmen in Betracht ziehen.

    Mit dieser Orientierung gehen wir zur Implementierung über: Datenerfassung und -vorverarbeitung, Kerzenanatomie und Volatilitätsmetriken, Strukturanalyse von Schwankungen/Retracements/Ausbrüchen, Snapshot-Vergleich und Signalerzeugung und schließlich die Nutzeroberfläche, Persistenz und Lebenszykluskontrollen. Jeder Teil ist direkt den Funktionen und logischen Blöcken in der .mq5-Datei zugeordnet, sodass Sie den Code nachvollziehen, die Ergebnisse lokal reproduzieren und die Engine für Ihre Forschungs- oder Handelsabläufe anpassen können

    Datenerfassung und -vorverarbeitung

    Zunächst laden wir die Kurshistorie mit CopyRates über LoadRates(sym, tf, bars) mit einer Sicherheitsmarge, damit zukunftsorientierte Scans (ATR-Fenster, Retracement-Fenster) einen Kontext haben. Wir berechnen die True Range pro Bar mit BarTR() und eine einfache SMA ATR für jeden Index mit CalcATR(r, period, idx). Wenn InpCacheATR aktiviert ist und die gespeicherten Parameter übereinstimmen, wird der globale g_atrs[]-Cache wiederverwendet, um eine Neuberechnung der ATRs zu vermeiden (siehe die Cache-Prüfung in BuildDNA). Wir bereinigen Eingaben und Zwischenwerte mit Helfern wie SafeDiv, Clamp und LTrim, konvertieren ATR in Pips/normalisierte Einheiten (atr_pips, atr_norm) und stellen sicher, dass wir eine Mindestanzahl von Balken haben – wenn N < 300 ist, kennzeichnet die Funktion D.valid = false und stoppt. Die wichtigsten Ergebnisse dieser Stufe sind ein Zeitreihen-Array MqlRates r[] und ein nachgeschaltetes ATR-Array.

    // Load rates with safety margin
    bool LoadRates(string sym, ENUM_TIMEFRAMES tf, int bars, MqlRates &rates[])
    {
       ArraySetAsSeries(rates, true);
       int need = MathMax(300, bars + 200); // safety margin for forward scans
       int got  = CopyRates(sym, tf, 0, need, rates);
       if(got <= 0) return false;
       return (got >= bars);
    }
    
    // True Range (series layout: 0 newest)
    double BarTR(MqlRates &r[], int i)
    {
       if(i >= ArraySize(r)-1) return 0.0;
       double prevC = r[i+1].close;
       double tr1 = r[i].high - r[i].low;
       double tr2 = MathAbs(r[i].high - prevC);
       double tr3 = MathAbs(r[i].low  - prevC);
       return MathMax(tr1, MathMax(tr2, tr3));
    }
    
    // Simple SMA ATR computed over 'period' TRs starting at idx
    double CalcATR(MqlRates &r[], int period, int idx)
    {
       double tr_sum = 0.0;
       int count = 0;
       for(int i = idx; i < idx + period && i < ArraySize(r)-1; ++i)
       {
          tr_sum += BarTR(r, i);
          ++count;
       }
       return (count > 0 ? tr_sum / count : 0.0);
    }
    

    Anatomie der Kerze und Volatilitätsmetriken

    Anschließend werden die bereinigten Zeitreihen iteriert, um Deskriptoren auf Kerzenebene und Volatilitätswerte zu erstellen. Die Schleife in BuildDNA berechnet ein durchschnittliches Docht-zu-Körper-Verhältnis (wick_body_ratio_avg), zählt Abschlüsse in der Nähe von Hoch/Tief (pct_close_near_high, pct_close_near_low), erkennt Doji-Kerzen (pct_doji) anhand von InpDojiBodyPct und markiert ATR-Spikes, wenn TR > InpSpikeATRMult * atr_i. Wir identifizieren auch „große“ ATR-Balken und aufeinanderfolgende „big-then-big“-Ereignisse, um vol_clustering zu schätzen. Alle Akkumulatoren pro Balken werden zu begrenzten Metriken und Rohwerten (z. B. nearHigh_count, spikes_count, bigThenBig_count) aggregiert, die die DNAMetrics-Struktur auffüllen. Diese Felder werden absichtlich geklammert und normalisiert, damit sie robuste Bausteine für Ähnlichkeitsvergleiche und Signalheuristiken bilden.

    // Example loop computing candle descriptors (place inside BuildDNA after rates & atrs ready)
    int nearHigh=0, nearLow=0, doji=0, spikes=0;
    double wickBodyAccum = 0.0;
    int bigTotal=0, bigThenBig=0;
    
    for(int i = 0; i < N; ++i)
    {
       double high = r[i].high, low = r[i].low, open = r[i].open, close = r[i].close;
       double range = high - low;
       if(range <= 0.0) continue;
    
       double body = MathAbs(close - open);
       if(body < 1e-9) body = 1e-9;
       double upper = (close >= open ? high - close : high - open);
       double lower = (close >= open ? open - low : close - low);
    
       double minBody = MathMax(body, range * 0.02); // floor to avoid tiny-body noise
       double wickRatio = (upper + lower) / minBody;
       wickRatio = MathMin(MathMax(wickRatio, 0.0), 50.0);
       wickBodyAccum += wickRatio;
    
       double pos = (close - low) / range;
       if(pos >= 0.80) ++nearHigh;
       else if(pos <= 0.20) ++nearLow;
    
       if(body <= InpDojiBodyPct * range) ++doji;
    
       double tr = BarTR(r, i);
       double atr_i = atrs[i];
       if(atr_i > 0 && tr > InpSpikeATRMult * atr_i) ++spikes;
    
       bool big = (atr_i > 0 && tr > 1.0 * atr_i);
       if(big)
       {
          ++bigTotal;
          if(i > 0)
          {
             double trPrev = BarTR(r, i-1);
             double atrPrev = atrs[i-1];
             if(atrPrev > 0 && trPrev > 1.0 * atrPrev) ++bigThenBig;
          }
       }
    }
    
    // Aggregate into DNAMetrics fields (example assignments)
    D.wick_body_ratio_avg = (N > 0 ? wickBodyAccum / N : 0.0);
    D.pct_close_near_high = SafeDiv(nearHigh, N);
    D.pct_close_near_low  = SafeDiv(nearLow, N);
    D.pct_doji            = SafeDiv(doji, N);
    D.pct_spikes          = SafeDiv(spikes, N);
    D.vol_clustering      = (bigTotal > 0 ? SafeDiv(bigThenBig, bigTotal) : 0.0);
    D.nearHigh_count = nearHigh; D.spikes_count = spikes; D.bigThenBig_count = bigThenBig;
    

    Strukturelle Analyse: Schwankungen, Rückschritte und Ausbrüche nach einem Durchbruch

    Wir erkennen fraktale Schwingungspunkte mit BuildSwings (r, InpFractalDepth, sw[]), das lokale Hochs und Tiefs unter Verwendung der konfigurierten Tiefen-Nachbarschaft findet. Anschließend werden die Statistiken für den Swing-Zyklus berechnet (durchschnittliche Balken pro Impuls, swing_cycle_bars_avg und fractal_density). Für das Retracement-Verhalten rufen wir ComputeRetracementHistogram (r, sw, swN, ...): Für jeden gegenläufigen Impuls wird bis zu InpRetrWindowBars vorwärts gescannt und das maximale Retracement-Verhältnis relativ zum Impuls aufgezeichnet; die Maxima werden in die Bänder 38 % / 50 % / 62 % / >70 % eingeteilt und gemittelt (avg_max_retr), um retr_38_freq, retr_50_freq, retr_62_freq und retr_gt70_freq zu erzeugen.

    Getrennt davon scannt ComputeBreakoutFollowThrough die Swing-Ereignisse und prüft, ob ein Ausbruch über das Swing-Extrem hinaus ein ATR-skaliertes Ziel (InpFT_ATR_Mult * atr) erreicht, wobei breakout_follow_through als der Anteil der Ereignisse, denen gefolgt wird, ermittelt wird. Zusammen quantifizieren diese strukturellen Metriken den Trendrhythmus, typische Pullback-Größen und die Zuverlässigkeit von Ausbrüchen.

    // Fractal swing builder (returns newest-first series layout)
    struct Swing { int index; double price; bool isHigh; };
    
    int BuildSwings(MqlRates &r[], int depth, Swing &sw[])
    {
       ArrayResize(sw, 0);
       int N = ArraySize(r);
       for(int i = depth; i < N - depth; ++i)
       {
          bool highP = true, lowP = true;
          double h = r[i].high, l = r[i].low;
          for(int k = 1; k <= depth; ++k)
          {
             if(r[i-k].high >= h || r[i+k].high >= h) highP = false;
             if(r[i-k].low <= l || r[i+k].low <= l) lowP = false;
             if(!highP && !lowP) break;
          }
          if(highP) { int n = ArraySize(sw); ArrayResize(sw, n+1); sw[n].index = i; sw[n].price = h; sw[n].isHigh = true; }
          if(lowP)  { int n = ArraySize(sw); ArrayResize(sw, n+1); sw[n].index = i; sw[n].price = l; sw[n].isHigh = false; }
       }
       // sort by index ascending (newest first in series layout)
       for(int a=0;a<ArraySize(sw);++a)
          for(int b=a+1;b<ArraySize(sw);++b)
             if(sw[a].index > sw[b].index) { Swing t = sw[a]; sw[a] = sw[b]; sw[b] = t; }
       return ArraySize(sw);
    }
    
    // Retracement histogram (core loop)
    void ComputeRetracementHistogram(MqlRates &r[], Swing &sw[], int swN,
                                     double &f38, double &f50, double &f62, double &f70,
                                     double &avgRetr, int &counted_out)
    {
       int counted=0, c38=0, c50=0, c62=0, c70=0;
       double sumMaxRetr = 0.0;
    
       for(int i=0; i < swN-1 && counted < InpRetrLookbackSwings; ++i)
       {
          Swing a = sw[i], b = sw[i+1];
          if(a.isHigh == b.isHigh) continue;
    
          Swing older = (a.index > b.index ? a : b);
          Swing newer = (a.index > b.index ? b : a);
          double impulse = MathAbs(older.price - newer.price);
          int start = newer.index - 1;
          int end   = MathMax(0, newer.index - InpRetrWindowBars);
          double maxRetr = 0.0;
    
          if(impulse > 0 && start >= 0 && start >= end)
          {
             if(older.isHigh && !newer.isHigh)
             {
                for(int k = start; k >= end; --k)
                {
                   double retr = SafeDiv(r[k].high - newer.price, impulse);
                   if(retr > maxRetr) maxRetr = retr;
                }
             }
             else if(!older.isHigh && newer.isHigh)
             {
                for(int k = start; k >= end; --k)
                {
                   double retr = SafeDiv(newer.price - r[k].low, impulse);
                   if(retr > maxRetr) maxRetr = retr;
                }
             }
          }
    
          counted++;
          if(impulse > 0)
          {
             sumMaxRetr += maxRetr;
             if(maxRetr < 0.44) ++c38;
             else if(maxRetr < 0.56) ++c50;
             else if(maxRetr < 0.70) ++c62;
             else ++c70;
          }
       }
    
       if(counted > 0)
       {
          f38 = double(c38) / counted;
          f50 = double(c50) / counted;
          f62 = double(c62) / counted;
          f70 = double(c70) / counted;
          avgRetr = sumMaxRetr / counted;
       }
       else { f38 = f50 = f62 = f70 = avgRetr = 0.0; }
       counted_out = counted;
    }
    
    // Breakout follow-through check
    double ComputeBreakoutFollowThrough(MqlRates &r[], Swing &sw[], int swN, int atrPeriod, double ftAtrMult)
    {
       if(swN < 2) return 0.0;
       int events = 0, success = 0;
       for(int i=0; i < swN-1 && events < 80; ++i)
       {
          int s_index = sw[i].index;
          double s_price = sw[i].price;
          bool s_isHigh = sw[i].isHigh;
          int start = s_index - 1;
          if(start < 0) continue;
          double atr = CalcATR(r, atrPeriod, s_index);
          double target = ftAtrMult * atr;
          if(target <= 0) continue;
    
          bool broke = false, followed = false;
          for(int k = start; k >= 0; --k)
          {
             if(s_isHigh)
             {
                if(r[k].high > s_price) { broke = true; if((r[k].high - s_price) >= target) { followed = true; break; } }
             }
             else
             {
                if(r[k].low < s_price) { broke = true; if((s_price - r[k].low) >= target) { followed = true; break; } }
             }
          }
          if(broke) { ++events; if(followed) ++success; }
       }
       return (events > 0 ? double(success) / events : 0.0);
    }
    

    Vergleich von Schnappschüssen, Mutationserkennung und Signalerzeugung

    Sobald wir eine neue DNAMetrics-Instanz haben, verwandeln wir ausgewählte Felder in einen festen 17-dimensionalen Vektor mit DNAVector (D, vec[]). Wir vergleichen die aktuelle und die vorherige Version mit Hilfe von CosineDistance (A,B) und NormalizedL2Distance (A,B). Wenn einer der beiden Abstände InpMutationThresh / InpMutationL2Thresh überschreitet, wird ein Mutationsbanner angezeigt und (falls aktiviert) Alert() aufgerufen; der Code färbt dieses Banner auch nach Schweregrad.

    Parallel zur Mutationserkennung setzt GenerateSignal(constDNAMetrics &D) Kauf- und Verkaufsbewertungen aus Breakout-Follow-Through, Glättungsindex, Spike-Häufigkeit, Nähe zu Tief/Hoch und Retracement-Buckets zusammen; es wendet eine von der ATR abgeleitete Strafe an, klammert Bewertungen und gibt nur BUY/SELL aus, wenn die Bewertung InpSignalThreshold erfüllt und die gegenüberliegende Bewertung um InpSignalGap übersteigt. MaybeNotify erzwingt einen Cooldown (15 Minuten) für Benachrichtigungen; Signale und ihre vollständigen Diagnosegründe werden zur Offline-Überprüfung an MarketDNA_signals.csv angehängt.

    // Build vector for comparison (17-dim)
    void DNAVector(DNAMetrics &D, double &vec[])
    {
       int n = 17;
       ArrayResize(vec, n);
       vec[0]  = D.wick_body_ratio_avg;
       vec[1]  = D.pct_close_near_high;
       vec[2]  = D.pct_close_near_low;
       vec[3]  = D.pct_doji;
       vec[4]  = D.atr_norm;
       vec[5]  = D.pct_spikes;
       vec[6]  = D.vol_clustering;
       vec[7]  = D.swing_cycle_bars_avg;
       vec[8]  = D.fractal_density;
       vec[9]  = D.breakout_follow_through;
       vec[10] = D.retr_38_freq;
       vec[11] = D.retr_50_freq;
       vec[12] = D.retr_62_freq;
       vec[13] = D.asia_range_share;
       vec[14] = D.london_range_share;
       vec[15] = D.ny_range_share;
       vec[16] = D.smoothness_index;
    }
    
    // Cosine distance and normalized L2
    double CosineDistance(DNAMetrics &A, DNAMetrics &B)
    {
       double va[], vb[];
       DNAVector(A, va); DNAVector(B, vb);
       double dot=0, na=0, nb=0;
       for(int i=0;i<ArraySize(va);++i) { dot += va[i]*vb[i]; na += va[i]*va[i]; nb += vb[i]*vb[i]; }
       double denom = MathSqrt(na)*MathSqrt(nb);
       if(denom <= 0) return 1.0;
       double cos = dot / denom;
       return 1.0 - MathMax(-1.0, MathMin(1.0, cos));
    }
    
    double NormalizedL2Distance(DNAMetrics &A, DNAMetrics &B)
    {
       double va[], vb[];
       DNAVector(A, va); DNAVector(B, vb);
       double num=0.0, denom=0.0;
       for(int i=0;i<ArraySize(va);++i) { double d = va[i] - vb[i]; num += d*d; denom += va[i]*va[i]; }
       double l2 = MathSqrt(num);
       double scale = MathSqrt(denom) + 1e-9;
       return l2 / scale;
    }
    
    // Signal generation (rule-based)
    Signal GenerateSignal(const DNAMetrics &D)
    {
       Signal s; s.type = SIGNAL_NONE; s.score = 0.0; s.reason = "";
    
       double cFT = Clamp(D.breakout_follow_through, 0.0, 1.0);
       double cSmooth = Clamp(D.smoothness_index, 0.0, 1.0);
       double cNotSpikes = 1.0 - Clamp(D.pct_spikes, 0.0, 1.0);
       double cRetr38 = Clamp(D.retr_38_freq, 0.0, 1.0);
       double cRetrGT70 = Clamp(D.retr_gt70_freq, 0.0, 1.0);
    
       // weights
       double wFT = 0.50, wSmooth = 0.25, wNotSpikes = 0.15, wRetr38 = 0.10;
       double wSellNearLow = 0.30, wSellSpikes = 0.25, wSellSmoothInv = 0.25, wSellRetrGT70 = 0.20;
    
       double buyScore = wFT*cFT + wSmooth*cSmooth + wNotSpikes*cNotSpikes + wRetr38*cRetr38;
       double sellScore = wSellNearLow*Clamp(D.pct_close_near_low,0,1) + wSellSpikes*Clamp(D.pct_spikes,0,1)
                          + wSellSmoothInv*(1.0 - cSmooth) + wSellRetrGT70*cRetrGT70;
    
       double atrPenalty = Clamp(D.atr_norm * 10.0, 0.0, 0.5);
       double buyScorePen = Clamp(buyScore * (1.0 - atrPenalty), 0.0, 1.0);
       double sellScorePen = Clamp(sellScore * (1.0 - atrPenalty * 0.5), 0.0, 1.0);
    
       double minThreshold = InpSignalThreshold;
       double minGap = InpSignalGap;
    
       s.reason = StringFormat("buy_raw=%.3f sell_raw=%.3f buy=%.3f sell=%.3f", buyScore, sellScore, buyScorePen, sellScorePen);
    
       if(buyScorePen - sellScorePen >= minGap && buyScorePen >= minThreshold) { s.type = SIGNAL_BUY; s.score = buyScorePen; }
       else if(sellScorePen - buyScorePen >= minGap && sellScorePen >= minThreshold) { s.type = SIGNAL_SELL; s.score = sellScorePen; }
       else { s.type = SIGNAL_NONE; s.score = MathMax(buyScorePen, sellScorePen); }
       return s;
    }
    
    // Notification cooldown
    void MaybeNotify(const Signal &s, string sym)
    {
       if(s.type == SIGNAL_NONE) return;
       if(TimeCurrent() - gLastSignalTime < 60*15) return; // 15-minute cooldown
       string text = StringFormat("MarketDNA %s %s signal score=%.2f reason=%s", sym, SignalTypeToString(s.type), s.score, s.reason);
       SendNotification(text); Alert(text);
       gLastSignalTime = TimeCurrent();
    }
    

    Anzeige, Persistenz und Lebenszykluskontrolle

    Schließlich werden die Ausgaben über On-Chart-Objekte dargestellt. DrawPass (title, D, x, y) erstellt eine rechteckige Tafel (ObjectCreate mit OBJ_RECTANGLE_LABEL) und zahlreiche beschriftete Linien (OBJ_LABEL), die jede Metrik, Warnungen und Zeitstempel zeigen; DrawComparison zeichnet eine kompakte Ähnlichkeitsüberschrift, wenn ein Vergleichssymbol vorhanden ist. Die Ergebnisse werden mit WriteCSV (D, sym) und WriteSignalCSV (s, sym) in Dateien in DATEI_COMMON gespeichert (Dateikopfzeilen werden erstellt, wenn die Datei neu ist).

    Der EA-Lebenszyklus verwendet OnInit, um EventSetTimer (sec) zu setzen (wodurch sec >= 5 erzwungen wird), OnTimer, um Recalculate() aufzurufen, und Recalculate() ist so optimiert, dass schwere Rebuilds übersprungen werden, wenn sich die letzte geschlossene Barzeit nicht geändert hat (CopyRates(..., 0, 1) check). OnDeinit beendet den Timer, und ClearObjects() entfernt die vorangestellten UI-Objekte. Die optionalen Modi InpSelfTest und InpDebugRetr ermöglichen die Validierung der Swing/Retracement-Logik und den Ausdruck von Debug-Spuren.

    // Create or update label helper
    void CreateOrSetLabel(string name, int corner, int x, int y, string text, int fontsize=11, color clr=(color)(-1))
    {
       string obj = Pref()+name;
       color useclr = (clr == (color)(-1) ? TextColor() : clr);
       if(ObjectFind(0,obj) == -1)
       {
          ObjectCreate(0,obj,OBJ_LABEL,0,0,0);
          ObjectSetInteger(0,obj,OBJPROP_CORNER,corner);
          ObjectSetInteger(0,obj,OBJPROP_XDISTANCE,x);
          ObjectSetInteger(0,obj,OBJPROP_YDISTANCE,y);
          ObjectSetInteger(0,obj,OBJPROP_FONTSIZE,fontsize);
          ObjectSetInteger(0,obj,OBJPROP_COLOR,useclr);
          ObjectSetString(0,obj,OBJPROP_FONT,"Arial");
       }
       ObjectSetString(0,obj,OBJPROP_TEXT,text);
    }
    
    // Minimal DrawPassport example (truncated)
    void DrawPassport(string title, DNAMetrics &D, int x, int y)
    {
       CreateOrSetRect(title+"_bg", InpCorner, x, y, 360, 460, BgColor());
       CreateOrSetLabel(title+"_hdr", InpCorner, x+10, y+8, title, 12, Accent());
       CreateOrSetLabel(title+"_ATR", InpCorner, x+10, y+32, StringFormat("ATR: %.1f pips (%.3f%%)", D.atr_pips, D.atr_norm*100.0), 10, TextColor());
       CreateOrSetLabel(title+"_WB", InpCorner, x+10, y+50, StringFormat("Wick/Body avg: %.2f", D.wick_body_ratio_avg), 10, TextColor());
       // ... add more labels for other metrics
    }
    
    // CSV writing (append, creates header when empty)
    void WriteCSV(DNAMetrics &D, string sym)
    {
       if(!InpLogCSV) return;
       string fname = InpCSVFileName;
       int handle = FileOpen(fname, FILE_READ|FILE_WRITE|FILE_CSV|FILE_COMMON|FILE_ANSI);
       if(handle == INVALID_HANDLE) { PrintFormat("Unable to open CSV '%s'", fname); return; }
       if(FileSize(handle) == 0)
          FileWrite(handle, "timestamp","symbol","tf","sample_bars","wick_body_avg","pct_close_high","pct_close_low","pct_doji","atr_mean","atr_pips");
       FileSeek(handle, 0, SEEK_END);
       FileWrite(handle, TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS), sym, TFToString(InpTF), D.sample_bars, D.wick_body_ratio_avg, D.pct_close_near_high, D.pct_close_near_low, D.pct_doji, D.atr_mean, D.atr_pips);
       FileClose(handle);
    }
    
    // Lifecycle hooks (skeleton)
    int OnInit()
    {
       EventSetTimer(MathMax(5, InpRecalcSeconds)); // enforce minimal cadence
       CreateOrSetLabel("status", InpCorner, InpX, InpY + 380, "Idle: waiting first calculation...", 10, TextColor());
       if(InpSelfTest) SelfTest();
       Recalculate(); // initial build
       return INIT_SUCCEEDED;
    }
    
    void OnTimer()
    {
       Recalculate(); // optimized to rebuild only on new closed bar
    }
    
    void OnDeinit(const int reason)
    {
       EventKillTimer();
       ClearObjects(); // cleanup
    }
    


    Ergebnisse

    Als wir den EA mit dem EURUSD-H1-Chart verbunden haben, hat er sofort das Market-DNA-Panel erstellt und die Metriken des Instruments über die gewählte Stichprobe berechnet. Das Panel fasst Volatilität, Spike- und Retracement-Profile, Session-Beiträge und andere strukturelle Signale zusammen. Auf der Grundlage dieser normalisierten Metriken berechnet der EA separate Kauf- und Verkaufs-Scores und gibt ein KAUF-Signal aus, weil der Kauf-Score den Verkaufs-Score um den konfigurierten Gap übersteigt und den Schwellenwert überschreitet. Der Zeitstempel des Panels, die Punktzahl und die Diagnoselinie erklären, warum der Trend gestiegen ist (hohe Ausbruchsfolge, niedrige Spike-Frequenz, mäßige Glattheit), sodass das visuelle Chart den Entscheidungsprozess dokumentiert und nicht nur einen isolierten Handelsvorschlag zeigt.

    In der Stichprobe mit 1.200 Balken fanden wir 171 Schwankungen und 80 Rücksetzer (etwa 44,2 % der Schwankungen führten zu einem messbaren Rücksetzer). Die Londoner Sitzung hat den größten Anteil an der Handelsspanne. Wenn Sie also auf starke Bewegungen setzen wollen, sollten Sie sich auf die Londoner Stunden konzentrieren. Die Schwingungszyklen liegen im Durchschnitt bei 9,62 Takten, was angibt, wie regelmäßig die Schwankungen auftreten. Am wichtigsten ist, dass der Durchbruch extrem hoch ist (≈98%).


    Das entsprechende Chart bezieht sich auf GBPUSD, ein Paar, das mit EURUSD korreliert. Der Market-DNA weist im Vergleich zum EURUSD eine größere Schwankungsbreite auf: Er verzeichnete 161 Ausschläge und 80 Rücksetzer, mit einem durchschnittlichen Ausschlagszyklus von 11,28 Balken. Die Durchbruchsquote ist hoch (≈94 %), und die Londoner Sitzung liefert den größten Anteil der Spanne (≈46 %).


    Schlussfolgerung

    Nachdem wir Sie durch den gesamten Prozess geführt haben – von der anfänglichen Idee über die Implementierung bis hin zum Testen mit ermutigenden Ergebnissen – können wir nun feststellen, dass dieses Tool das einzigartige „Make-up“ jedes Paares auf der Grundlage seiner Preisbewegung effektiv erfasst. Sie können mit den Eingaben experimentieren, einen Backtest oder einen Demotest durchführen, um die für Ihre Strategie am besten geeigneten Werte zu finden. Beachten Sie jedoch, dass dieser EA in erster Linie zu Lehrzwecken entwickelt wurde, insbesondere um die Identität jedes Paares anhand seiner historischen Kursentwicklung zu erkennen. Es sollte nicht für den Live-Handel mit echtem Geld verwendet werden, sondern eher als unterstützendes Werkzeug neben Ihren bestehenden Strategien.

    Siehe meine anderen Artikel.

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

    Beigefügte Dateien |
    Letzte Kommentare | Zur Diskussion im Händlerforum (2)
    Mustafa Nail Sertoglu
    Mustafa Nail Sertoglu | 18 Sept. 2025 in 07:35
    Wieder eine schöne Idee und Arbeit von C. Benjamin, vielen Dank und gesunde Tage für dich und deine Lieben.
    Christian Benjamin
    Christian Benjamin | 18 Sept. 2025 in 08:45
    Mustafa Nail Sertoglu #:
    Wieder eine schöne Idee und Arbeit von C. Benjamin, danke und gesunde Tage für dich und deine Lieben.
    Die Freude ist ganz meinerseits.
    Die Übertragung der Trading-Signale in einem universalen Expert Advisor. Die Übertragung der Trading-Signale in einem universalen Expert Advisor.
    In diesem Artikel wurden die verschiedenen Möglichkeiten beschrieben, um die Trading-Signale von einem Signalmodul des universalen EAs zum Steuermodul der Positionen und Orders zu übertragen. Es wurden die seriellen und parallelen Interfaces betrachtet.
    Aufbau von KI-gesteuerten Handelssystemen in MQL5 (Teil 2): Entwicklung eines ChatGPT-integrierten Programms mit Nutzeroberfläche Aufbau von KI-gesteuerten Handelssystemen in MQL5 (Teil 2): Entwicklung eines ChatGPT-integrierten Programms mit Nutzeroberfläche
    In diesem Artikel entwickeln wir ein in ChatGPT integriertes Programm in MQL5 mit einer Nutzeroberfläche, das das JSON-Parsing-Framework aus Teil 1 nutzt, um Prompts an die API von OpenAI zu senden und die Antworten auf einem MetaTrader 5-Chart anzuzeigen. Wir implementieren ein Dashboard mit einem Eingabefeld, einer Übermittlungsschaltfläche und einer Antwortanzeige, wobei wir die API-Kommunikation und den Textumbruch für die Nutzerinteraktion übernehmen.
    Eine alternative Log-datei mit der Verwendung der HTML und CSS Eine alternative Log-datei mit der Verwendung der HTML und CSS
    In diesem Artikel werden wir eine sehr einfache, aber leistungsfähige Bibliothek zur Erstellung der HTML-Dateien schreiben, dabei lernen wir auch, wie man eine ihre Darstellung einstellen kann (nach seinem Geschmack) und sehen wir, wie man es leicht in seinem Expert Advisor oder Skript hinzufügen oder verwenden kann.
    Vom Neuling zum Experten: Animierte Nachrichtenüberschrift mit MQL5 (XI) – Korrelation im Nachrichtenhandel Vom Neuling zum Experten: Animierte Nachrichtenüberschrift mit MQL5 (XI) – Korrelation im Nachrichtenhandel
    In diesem Beitrag werden wir untersuchen, wie das Konzept der Finanzkorrelation angewendet werden kann, um die Entscheidungseffizienz beim Handel mit mehreren Symbolen während der Ankündigung wichtiger wirtschaftlicher Ereignisse zu verbessern. Der Schwerpunkt liegt dabei auf der Bewältigung des erhöhten Risikos, das durch die erhöhte Volatilität bei der Veröffentlichung von Nachrichten entsteht.