English Русский
preview
Vom Einsteiger zum Experten: Statistische Validierung von Angebots- und Nachfragezonen

Vom Einsteiger zum Experten: Statistische Validierung von Angebots- und Nachfragezonen

MetaTrader 5Beispiele |
30 0
Clemence Benjamin
Clemence Benjamin

Inhalt:

  1. Einführung 
  2. Implementierung
  3. Ergebnisse
  4. Schlussfolgerung
  5. Wichtige Erkenntnisse
  6. Anlagen



Einführung

Die Analyse von Angebots- und Nachfragezonen ist ein Eckpfeiler des Price-Action-Trading, der auf dem zeitlosen ökonomischen Prinzip des Marktungleichgewichts beruht. Im diskretionären Handel werden diese Zonen durch visuelle Mustererkennung identifiziert – eine Fähigkeit, die durch Erfahrung verfeinert wird. Diese Abhängigkeit von subjektiven Einschätzungen stellt jedoch ein erhebliches Problem für die Reproduzierbarkeit von Ergebnissen dar und ist das Haupthindernis für eine effektive Automatisierung. Während die theoretische Logik dieser Zonen gut bekannt ist, bleibt ihre Implementierung in präzise, formal definierte Regeln schwer fassbar, da oft willkürliche numerische Schwellenwerte verwendet werden.

In diesem Artikel wird eine strukturierte Forschungsmethodik vorgestellt, um diese Lücke zu schließen. Wir beschreiben eine vollständige, reproduzierbare Pipeline, die das qualitative Konzept eines „impulsiven Ausbruchs“ aus der Zone in eine quantifizierte, statistisch validierte Handelsregel umwandelt. Unser Ansatz führt eine wichtige methodische Vereinfachung ein, indem er einzelne HTF-Kerzen als grundlegende Analyseeinheit verwendet. Auf diese Weise können wir das Wesen einer Angebots- oder Nachfragezone klar erfassen und ihr bestimmendes Merkmal messen: die Dynamik.

Durch den Einsatz einer Python-basierten Forschungsumgebung in einem Jupyter-Notebook ermitteln wir systematisch die statistische Signatur einer Zone mit hoher Wahrscheinlichkeit. Die abgeleiteten Parameter werden dann in einem MQL5 Expert Advisor kodiert, wodurch ein transparentes, evidenzbasiertes Handelsinstrument entsteht. Bei diesem Prozess geht es nicht mehr um die Frage: „Sieht das stark aus?“, sondern um die Frage: „Erfüllt es die statistisch definierten Kriterien für Stärke?“

Konzeptionelle Grundlagen: Die Anatomie eines Marktungleichgewichts

Grundprinzip: Preisungleichgewicht

Eine Angebots- oder Nachfragezone markiert ein Preisniveau, bei dem das Gleichgewicht zwischen Käufern und Verkäufern entscheidend gestört ist. Ein aggressiver Zustrom von Aufträgen von einer Seite überwältigt die andere, sodass die Preise das Gebiet schnell verlassen. Dieser schnelle Ausbruch – der impulsive Ausbruch – hinterlässt eine theoretische Konzentration von nicht ausgeführten Gegenorders. Diese Zone des Ungleichgewichts wird dann zu einem künftig relevanten Bereich, da der Kurs bei einer Rückkehr typischerweise reagiert.

Definition der strukturellen Komponenten

Durch eine Synthese der Handelsliteratur und eine umfangreiche persönliche Chartanalyse kann die Anatomie einer klassischen Zone herausgearbeitet werden:

Angebotszone: Ein Bereich, in dem der Verkaufsdruck das Kaufinteresse überwiegt. Optisch erkennt man ihn an einer Konsolidierungsbasis (eine Reihe von Kerzen mit sich überlappenden Bereichen), gefolgt von einer starken, impulsiven Abwärtskerze, die unter dem Tiefpunkt der Basis schließt.

Konzepte zu Angebot und Nachfrage

Nachfragezone: Die bullische Umkehrung, bei der aggressive Käufe eine bullische, impulsive Kerze auslösen, die über dem Hoch einer Konsolidierungsbasis schließt.

Die impulsive Ausbruchskerze ist die entscheidende Komponente. Es ist die Signatur des Marktes, die das Ungleichgewicht bestätigt. Im diskretionären Trading wird die „Stärke“ visuell beurteilt, was zu Unstimmigkeiten führt. Daher wird die Größe dieser Kerze zur primären Variable für unsere quantitative Forschung.

Der komplette Lebenszyklus der Zone: Impuls, Fortsetzung und Retest

Das Verständnis des ersten Ausbruchs ist nur die erste Phase. Der gesamte Lebenszyklus einer gültigen Zone verläuft häufig in zwei Hauptbewegungen:

  • Phase 1 – Anfänglicher impulsiver Ausbruch: Der Kurs bricht mit Schwung aus der Basis aus und bildet ein neues kurzfristiges Richtungsextrem.
  • Phase 2 – Test und Reaktion: Der Kurs kehrt häufig in die Ursprungszone zurück und testet erneut den Bereich des Ungleichgewichts. Dieser erneute Test führt häufig zu einer zweiten, reaktiven Bewegung weg von der Zone, wenn die verbleibenden nicht ausgeführten Gegenorders auftauchen.

Nachfragezone

Nachfragezone (Konsolidierung bei A, Ausbruch bis nach B und Rückkehr in die Nachfragezone bei C)

 Die folgende Abbildung zeigt einen klaren Lebenszyklus der Angebotszone, der mit den entsprechenden rückläufigen Phasen versehen ist.

Angebotszone

Einzelkerzen-Angebotszone (S), Impuls von A nach B. Rückkehr in die Zone bei C.

In dieser Untersuchung konzentrieren wir uns auf die genaue Quantifizierung von Phase 1, dem ersten impulsiven Ausbruch. Dies ist das am klarsten definierte und messbare Ereignis, das als grundlegender Auslöser dient. Eine statistisch robuste Definition dieses Ausbruchs ermöglicht direkt die Identifizierung von Zonen mit hoher Wahrscheinlichkeit, auf denen sich Retest-Strategien zuverlässig aufbauen lassen.

Methodische Rechtfertigung: Das Modell der einzelnen Kerze mit höherem Zeithorizont

Um von visuellen Mustern zu quantifizierbaren Daten zu gelangen, gehen wir von einer zielgerichteten und robusten methodischen Prämisse aus: Der gesamte Prozess des Gleichgewichts und des Ungleichgewichts lässt sich oft effizient in der Struktur einer einzigen Kerze mit höherem Zeitrahmen (HTF) zusammenfassen.

Nachfragezone einer einzelnen Kerze (kleine Basiskerze und eine große Ausbruchskerze)

Angebot und Nachfrage finden sich auch in Fortsetzungsmustern wieder.

Konzepttreue: Eine starke, direktionale HTF-Kerze an einem Swing-Punkt ist das direkte Ergebnis des Ungleichgewichts, das wir untersuchen. Eine Analyse seiner internen Struktur im unteren Zeitrahmen würde typischerweise die klassische Sequenz einer Basis, gefolgt von einer impulsiven Bewegung, aufzeigen. Die HTF-Kerze ist die aggregierte Signatur dieser Mikrostruktur.

Vorteile für die quantitative Forschung:

  • Klarheit der Signale: Sie isoliert das entscheidende Marktereignis und filtert langwierige, zweideutige Konsolidierungen heraus.
  • Reduzierte parametrische Komplexität: Damit entfällt die Notwendigkeit, mehrere Parameter zur Definition einer Mehrkerzenbasis zu verwenden (z. B. Anzahl der Kerzen, zulässige Überlappung). Die Grenzen einer einzelnen Kerze (Eröffnung, Höchststand, Tiefststand, Schlussstand) sind unzweideutig.
  • Fraktale Gültigkeit: Das Prinzip ist über alle Zeitrahmen hinweg einheitlich, sodass die für einen HTF (z. B. H4) durchgeführte Forschung auch auf einen niedrigeren Handelszeitrahmen (z. B. M15) angewendet werden kann.

Dieses Modell verlagert unsere Hauptmetrik vom Vergleich zweier separater Kerzen (Basis vs. Ausbruch) zur Analyse des internen Momentums einer Kerze. Wir definieren dies als das „Impulse Ratio“: (Schließen-Öffnen)/(Hoch-Tief). Ein hohes „Impulse Ratio“ (z. B. > 0,7) weist auf eine Kerze mit einem starken Richtungskörper und minimalen Dochten hin – der genaue statistische Fingerabdruck eines entscheidenden Ausbruchs.

Unsere zentrale Forschungsfrage wird daher verfeinert: Was sind die statistisch optimalen Schwellenwerte für das Impulse Ratio und die minimale absolute Größe (in Pips), die eine Zone mit hoher Wahrscheinlichkeit definieren, die eine Kerze mit höherem Zeitrahmen erzeugt?

Die Forschungs- und Implementierungspipeline

Um diese Frage zu beantworten, führen wir eine klare dreistufige Pipeline aus, die sicherstellt, dass jede algorithmische Regel auf empirischen Erkenntnissen beruht.

Stufe 1: Systematisches Sammeln von Daten (MQL5)

Wir entwickeln ein eigenes MQL5-Skript, das als systematischer Scanner fungiert. Es identifiziert HTF-Kandidaten an Swing-Punkten und exportiert ihre Kernmetriken in eine CSV-Datei. Die Datenpunkte für jeden Kandidaten umfassen:

  • Zeitstempel, Symbol, Zeitrahmen
  • Kerzenkörpergröße (pips), Gesamtspanne (pips), berechnete „Impulse Ratio“
  • Volatilitätskontext (z. B. ATR-Wert bei Kerzenschlusskurs)

Kennzeichnung auf der Grundlage der nachfolgenden Kursentwicklung zur Bestimmung des „Erfolgs“ für die spätere Analyse.

Stufe 2: Statistische Entdeckung und Schwellenwert-Optimierung (Python/Jupyter Notebook)

Im Jupyter Notebook führen wir eine explorative Datenanalyse des gesammelten Datensatzes durch.

  • Deskriptive Statistik: Wir analysieren die Verteilung von Impulse Ratio und der Körpergröße über alle Kandidaten.
  • Erfolgsanalyse: Wir segmentieren die Daten danach, ob die Kandidatenkerze zu einer erfolgreichen Kursreaktion geführt hat, und vergleichen dann die statistischen Eigenschaften der „erfolgreichen“ mit denen der „erfolglosen“ Gruppen.
  • Optimierung der Schwellenwerte: Wir bestimmen die optimalen Schwellenwerte (z. B. minimales Impulse Ratio von 0,65, minimale Körpergröße von 1,2 * ATR), die den Unterschied in den Erfolgsraten maximieren, und definieren damit unsere statistisch validierte Handelsregel.

Stufe 3: Modellimplementierung und -validierung (MQL5 Expert Advisor)

Der letzte, entscheidende Schritt ist die Implementierung der statistischen Erkenntnisse in eine ausführbare Handelslogik. Die optimierten Parameter sind in einem MQL5 Expert Advisor fest kodiert. Dieser EA sucht nach HTF-Kerzen, die die statistisch validierten Kriterien erfüllen, projiziert automatisch die Zonengrenzen und kann erweitert werden, um Trades auf dem unteren Zeitrahmen zu verwalten, wodurch sich der Kreislauf von der Recherche bis zur automatischen Ausführung schließt.



Implementierung

Systematisches Sammeln von Daten (MQL5)

Die erste und kritischste Phase unserer Forschung ist die systematische Sammlung von qualitativ hochwertigen, detaillierten Marktdaten. Dieser Prozess geht deutlich über eine rein nachträgliche Chartanalyse hinaus. Wir entwickeln ein spezielles MQL5-Skript, das als unvoreingenommener Daten-Scout fungiert und programmatisch die historische Preisentwicklung scannt, um jedes Auftreten unseres definierten Zwei-Kerzen-Musters zu erfassen – eine „kleine“ Kerze, gefolgt von einer größeren „Ausbruchskerze“ in derselben Richtung. Die Kernfunktion des Skripts besteht darin, visuelle Preisstrukturen in einen strukturierten Datensatz (CSV) zu übersetzen, der präzise Metriken wie Körpergrößen in Pips, ihr Verhältnis und volatilitätsbereinigte Werte unter Verwendung der Average True Range (ATR) aufzeichnet.

Indem wir Tausende dieser Beobachtungen unter verschiedenen Marktbedingungen sammeln, schaffen wir die wesentliche empirische Grundlage. Diese Rohdaten sind der Input für unsere statistische Analyse, die sicherstellt, dass jeder nachfolgende Einblick und Parameter aus objektivem Marktverhalten und nicht aus subjektiven Einschätzungen abgeleitet ist.

Das Skript zur Datenerhebung

Die folgende Aufschlüsselung erläutert die Logik und den Zweck der einzelnen Codeabschnitte in unserem Datenerfassungsskript (SD_BaseExit_Research.mq5). Ich werde die vollständige Quelle am Ende des Artikels anfügen.

1. Skript-Kopfzeilen und Konfiguration (Eingaben)

Dieser Abschnitt definiert die Identität des Skripts und vor allem die einstellbaren Parameter, die sein Verhalten steuern.

//--- Inputs: Define what "small" and "bigger" mean
input int    BarsToProcess    = 20000;     // Total bars to scan
input int    ATR_Period       = 14;        // For volatility context
input double MaxBaseBodyATR   = 0.5;       // Base candle max size (e.g., 0.5 * ATR)
input double MinExitBodyRatio = 2.0;       // Exit must be at least this many times bigger than base
input bool   CollectAllData   = true;      // TRUE=log all pairs, FALSE=use above filters now
input string OutFilePrefix    = "SD_BaseExit";

Diese Eingaben machen das Skript zu einem flexiblen Rechercheinstrument. Für die erste Erkennung sollte CollectAllData wahr sein, um eine breite Stichprobe zu sammeln. Später können Sie ihn auf false setzen, um bestimmte Größenschwellen (MaxBaseBodyATR, MinExitBodyRatio) direkt im MetaTrader 5 zu testen.

2. Kerninitialisierung (OnStart-Funktion)

In diesem Teil werden die erforderlichen Werkzeuge für die Datenverarbeitung und -speicherung eingerichtet: Abruf der ATR-Daten und Erstellung der CSV-Ausgabedatei.

  • Erstellen des ATR-Handles: Holt Average True Range-Daten ab, die für das Verständnis des Volatilitätskontexts entscheidend sind.
  • Erstellung von CSV-Dateien: Öffnet eine neue Datei zum Schreiben von Daten. Der Dateiname enthält das Symbol und den Zeitrahmen für eine klare Organisation.
  • CSV-Kopfzeile: Schreibt die Spaltentitel, die die Struktur des Datensatzes definieren.

// 1. INITIALIZATION: Get ATR data and open the data log (CSV file)
atrHandle = iATR(_Symbol, _Period, ATR_Period);
if(atrHandle == INVALID_HANDLE) {
   Print("Error: Could not get ATR data.");
   return;
}

string tf = PeriodToString(_Period);
string fileName = StringFormat("%s_%s_%s.csv", OutFilePrefix, _Symbol, tf);
int fileHandle = FileOpen(fileName, FILE_WRITE|FILE_CSV|FILE_ANSI);

if(fileHandle == INVALID_HANDLE) {
   Print("Failed to create file: ", fileName);
   return;
}

// Write the header. Each row will be one observed "base-exit" candle pair.
FileWrite(fileHandle,
   "Pattern", "Symbol", "Timeframe", "Timestamp",
   "Base_BodyPips", "Exit_BodyPips", "ExitToBaseRatio",
   "ATR_Pips", "Base_BodyATR", "Exit_BodyATR",
   "Base_Open", "Base_Close", "Exit_Open", "Exit_Close"
);

3. Hauptabtastschleife: Die Mustererkennung

Diese for-Schleife ist das Herzstück des Skripts, das jedes aufeinanderfolgende Paar geschlossener Kerzen in der Historie untersucht.

Logischer Ablauf:

  1. Kerzenpaarung und Datenextraktion: Für jede Kerze i ist die Kerze i die potenzielle Basis, und die Kerze i-1 ist der potenzielle Ausbruch. Das Skript extrahiert Preise und berechnet Körpergrößen und ATR-Verhältnisse.
  2. Logik der Muster: Es wird geprüft, ob die beiden Kerzen aufeinanderfolgen und in dieselbe Richtung zeigen.

  • Bullish Pair → Wird als Kandidat für ein „Nachfragemuster“ eingestuft.
  • Bearish Pair → Wird als Kandidat für ein „Angebotsmuster“ eingestuft.
  • Nicht eindeutige Richtungen werden verworfen.

// 2. MAIN SCANNING LOOP: Look at every consecutive pair of candles
for(int i = 1; i < barsToCheck; i++) {
   int baseIdx = i;      // The older candle (potential base)
   int exitIdx = i - 1;  // The newer candle (potential exit)

   // ... (Data extraction for base and exit candles) ...

   // 3. PATTERN IDENTIFICATION: Determine direction and type
   string patternType = "None";
   bool isBullishBase = baseClose > baseOpen;
   bool isBullishExit = exitClose > exitOpen;
   bool isBearishBase = baseClose < baseOpen;
   bool isBearishExit = exitClose < exitOpen;

   // The core logic: A valid pattern requires consecutive candles in the SAME direction.
   if(isBullishBase && isBullishExit) {
      patternType = "Demand";
   } else if(isBearishBase && isBearishExit) {
      patternType = "Supply";
   }
   if(patternType == "None") continue; // Skip mixed-direction pairs

4. Strategische Filterung: Gleichgewicht zwischen Datenmenge und -qualität

Dies ist ein entscheidender Punkt bei der Recherche, der durch das CollectAllData-Flag gesteuert wird. Sie bestimmt, ob eine breite Stichprobe für die Entdeckung gesammelt oder sofort strenge Filter angewendet werden sollen.

   // 4. DATA FILTERING (Optional): Apply size rules if not collecting everything
   if(!CollectAllData) {
      // Rule: Base candle must be relatively small compared to market noise
      bool isBaseSmallEnough = baseBodyATR < MaxBaseBodyATR;
      // Rule: Exit candle must be significantly larger than the base
      bool isExitLargeEnough = exitToBaseRatio >= MinExitBodyRatio;

      if(!isBaseSmallEnough || !isExitLargeEnough) {
         continue; // Skip this pair, it doesn't meet our current test filters
      }
   }
   // If CollectAllData is TRUE, we log EVERY same-direction pair, regardless of size.
   // This is best for initial research.

5. Datenerfassung und -bereinigung

Für jedes gültige Muster wird eine detaillierte Zeile in die CSV-Datei geschrieben. Schließlich werden die Ressourcen ordnungsgemäß freigegeben.

   // 5. DATA LOGGING: Write all details of this pair to our CSV file
   datetime exitTime = iTime(_Symbol, _Period, exitIdx);
   MqlDateTime dtStruct; TimeToStruct(exitTime, dtStruct);
   string timeStamp = StringFormat("%04d-%02d-%02dT%02d:%02d:%02d",
                                   dtStruct.year, dtStruct.mon, dtStruct.day,
                                   dtStruct.hour, dtStruct.min, dtStruct.sec);

   FileWrite(fileHandle,
      patternType, _Symbol, tf, timeStamp,
      DoubleToString(baseBodyPips, 2),
      DoubleToString(exitBodyPips, 2),
      DoubleToString(exitToBaseRatio, 2),
      DoubleToString(atrExit / _Point, 2),
      DoubleToString(baseBodyATR, 3),
      DoubleToString(exitBodyATR, 3),
      DoubleToString(baseOpen, _Digits),
      DoubleToString(baseClose, _Digits),
      DoubleToString(exitOpen, _Digits),
      DoubleToString(exitClose, _Digits)
   );
   dataRowsWritten++;
}
// 6. CLEANUP: Close the file and release the indicator handle
FileClose(fileHandle);
IndicatorRelease(atrHandle);

Mit den von unserem MQL5-Skript erfassten Rohdaten besteht der nächste wichtige Schritt darin, diesen Datensatz nahtlos in unsere statistische Analyseumgebung zu übertragen. Dazu muss die Ausgabedatei gefunden und der Python-Forschungsarbeitsbereich gestartet werden.

Auffinden der gesammelten Daten

Nach der Fertigstellung speichert das Skript die CSV-Datei im Standardverzeichnis MQL5/Files/ in Ihrem MetaTrader 5 Terminal-Datenordner. Der genaue Pfad lautet in der Regel nach diesem Muster:

C:\Users\[IhrName]\AppData\Roaming\MetaQuotes\Terminal\[TerminalID]\MQL5\Files.

Die Datei wird entsprechend der Konvention unseres Skripts benannt, zum Beispiel SD_BaseExit_EURUSD_H1.csv. Diese Datei enthält alle mit einem Zeitstempel versehenen „Base-Exit“-Kerzenpaare und ihre berechneten Metriken, die für eine weitere Analyse bereitstehen.

Starten der Python-Analyseumgebung

Um mit der Analyse zu beginnen, öffnen wir eine Befehlszeilenschnittstelle (Eingabeaufforderung oder Terminal), navigieren zu diesem Verzeichnis und starten Jupyter Notebook. Das lässt sich mit wenigen Befehlen effizient bewerkstelligen:

# Navigate to the directory containing your CSV file
cd "C:\Users\[YourUserName]\AppData\Roaming\MetaQuotes\Terminal\[TerminalID]\MQL5\Files"

# Launch the Jupyter Notebook server
jupyter notebook

Diese Sequenz öffnet die JupyterLab-Oberfläche in Ihrem Webbrowser und schafft ein direktes Portal zu Ihren Daten. Von hier aus können Sie ein neues Notizbuch (z. B. Supply_and_demand_Research.ipynb) speziell für dieses Forschungsprojekt erstellen.

Stufe 2: Statistische Entdeckung und Schwellenwert-Optimierung (Python/Jupyter Notebook)

Zelle 1: Einrichtung und Dateneingabe

Diese Zelle bereitet die Python-Forschungsumgebung vor und lädt den vom MetaTrader 5 exportierten Datensatz zur Analyse.

Zunächst importiert es die erforderlichen wissenschaftlichen und Visualisierungsbibliotheken. Diese Bibliotheken bieten Werkzeuge zur Datenmanipulation (pandas, numpy), zur statistischen Analyse (scipy) und zur grafischen Erkundung (matplotlib, seaborn). Warnhinweise werden unterdrückt, um ein sauberes und lesbares Forschungsergebnis zu gewährleisten, was besonders wichtig ist, wenn die Ergebnisse in einem Artikel präsentiert werden.

Als Nächstes wird der visuelle Stil für Charts konfiguriert, um konsistente darstellungsfähige Plots zu erzeugen. Dadurch wird sichergestellt, dass alle später im Notizbuch erstellten Diagramme einem einheitlichen Design folgen, wodurch Verteilungen und Trends leichter zu interpretieren sind.

Die Zelle lädt dann die vom MQL5-Datensammlungsskript erzeugte CSV-Datei. Da die Datei als tabulatorgetrennte Datei exportiert wird, wird das entsprechende Trennzeichen explizit angegeben, um ein korrektes Parsing der Daten zu gewährleisten. Dieser Schritt ist entscheidend für die Wahrung der numerischen Integrität, insbesondere bei Pip-Werten, Verhältnissen und Zeitstempeln.

# %% [markdown]
#
# 
# **Objective:** Analyze the harvested candlestick data to discover statistically significant thresholds for a valid "impulsive exit."
# **Data:** `SD_BaseExit_XAUUSDr_5.csv`
# **Method:** Exploratory Data Analysis (EDA), Distribution Analysis, and Success Rate Correlation.

# %% [markdown]
# ## 1. Setup & Data Ingestion (Corrected)
# Loading tab-delimited data

# %%
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
import warnings
warnings.filterwarnings('ignore')

# Set visual style
plt.style.use('seaborn-v0_8-darkgrid')
sns.set_palette("husl")

# Load the data with TAB as delimiter
file_path = "SD_BaseExit_XAUUSDr_5.csv"
df = pd.read_csv(file_path, sep='\t')  # Tab-separated

print("✅ Data loaded successfully (tab-delimited).")
print(f"Dataset shape: {df.shape}")
print("\n🔍 Column names:")
print(list(df.columns))
print("\n📊 First 3 rows:")
print(df.head(3))

Ergebnis 1:

✅ Data loaded successfully (tab-delimited).
Dataset shape: (9663, 14)

🔍 Column names:
['Pattern', 'Symbol', 'Timeframe', 'Timestamp', 'Base_BodyPips', 'Exit_BodyPips', 'ExitToBaseRatio', 'ATR_Pips', 'Base_BodyATR', 'Exit_BodyATR', 'Base_Open', 'Base_Close', 'Exit_Open', 'Exit_Close']

📊 First 3 rows:
  Pattern   Symbol  Timeframe            Timestamp  Base_BodyPips  \
0  Demand  XAUUSDr          5  2026-01-12T06:45:00          194.0   
1  Demand  XAUUSDr          5  2026-01-12T06:40:00          226.0   
2  Supply  XAUUSDr          5  2026-01-12T06:30:00          104.0   

   Exit_BodyPips  ExitToBaseRatio  ATR_Pips  Base_BodyATR  Exit_BodyATR  \
0          155.0             0.80    311.64         0.545         0.497   
1          194.0             0.86    355.64         0.632         0.545   
2          477.0             4.59    365.79         0.273         1.304   

   Base_Open  Base_Close  Exit_Open  Exit_Close  
0    4566.03     4567.97    4567.96     4569.51  
1    4563.80     4566.06    4566.03     4567.97  
2    4569.60     4568.56    4568.61     4563.84  
🤝

Zelle 2: Erste Datenprüfung und -bereinigung

In diesem Schritt prüften wir den Datensatz, um seine Struktur, die Datentypen und die allgemeine Qualität zu bestätigen, bevor wir mit der statistischen Analyse fortfuhren. Wir überprüften das Vorhandensein aller kritischen Messfelder, suchten nach fehlenden Werten und stellten sicher, dass die Schlüsselspalten in Bezug auf die Kerzengröße, die ATR und das Exit-to-Base-Verhältnis korrekt als numerische Daten interpretiert wurden. Alle Zeilen mit unvollständigen oder ungültigen Werten in diesen wichtigen Feldern wurden entfernt, sodass ein sauberer und zuverlässiger Datensatz entstand, der eine solide Grundlage für alle nachfolgenden explorativen und statistischen Analysen bildet.

# %% [markdown]
# ## 2. Initial Data Inspection & Cleaning

# %%
print("📊 Dataset Info:")
print(df.info())
print("\n🧹 Checking for missing values:")
print(df.isnull().sum())

# Ensure numeric columns are correctly typed
numeric_cols = ['Base_BodyPips', 'Exit_BodyPips', 'ExitToBaseRatio', 'ATR_Pips', 'Base_BodyATR', 'Exit_BodyATR']
for col in numeric_cols:
    if col in df.columns:
        df[col] = pd.to_numeric(df[col], errors='coerce')
    else:
        print(f"⚠️ Warning: Column '{col}' not found in data")

# Remove any rows with missing critical data
df_clean = df.dropna(subset=numeric_cols).copy()
print(f"\n🧽 Data cleaned. Original: {df.shape}, Cleaned: {df_clean.shape}")

Ergebnis 2:

📊 Dataset Info:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 9663 entries, 0 to 9662
Data columns (total 14 columns):
 #   Column           Non-Null Count  Dtype  
---  ------           --------------  -----  
 0   Pattern          9663 non-null   object 
 1   Symbol           9663 non-null   object 
 2   Timeframe        9663 non-null   int64  
 3   Timestamp        9663 non-null   object 
 4   Base_BodyPips    9663 non-null   float64
 5   Exit_BodyPips    9663 non-null   float64
 6   ExitToBaseRatio  9663 non-null   float64
 7   ATR_Pips         9663 non-null   float64
 8   Base_BodyATR     9663 non-null   float64
 9   Exit_BodyATR     9663 non-null   float64
 10  Base_Open        9663 non-null   float64
 11  Base_Close       9663 non-null   float64
 12  Exit_Open        9663 non-null   float64
 13  Exit_Close       9663 non-null   float64
dtypes: float64(10), int64(1), object(3)
memory usage: 1.0+ MB
None

🧹 Checking for missing values:
Pattern            0
Symbol             0
Timeframe          0
Timestamp          0
Base_BodyPips      0
Exit_BodyPips      0
ExitToBaseRatio    0
ATR_Pips           0
Base_BodyATR       0
Exit_BodyATR       0
Base_Open          0
Base_Close         0
Exit_Open          0
Exit_Close         0
dtype: int64

🧽 Data cleaned. Original: (9663, 14), Cleaned: (9663, 14)

Zelle 3: Vorläufige statistische Untersuchung von Metriken zum Ausbruch aus Angebot und Nachfrage

In dieser Phase führten wir eine explorative Datenanalyse durch, um ein erstes statistisches Verständnis der gesammelten Messungen zu gewinnen. Für alle numerischen Schlüsselvariablen wurden deskriptive Statistiken erstellt, um ihre zentralen Tendenzen, ihre Streuung und ihre Gesamtverteilung aufzuzeigen, was uns hilft, die typische Größe und Variabilität sowohl der Basis- als auch der Ausbruchskerzen zu beurteilen. Darüber hinaus untersuchten wir die Verteilung von Angebots- und Nachfragemustern innerhalb des Datensatzes und visualisierten ihre Häufigkeit, um sicherzustellen, dass die Untersuchungsstichprobe einigermaßen ausgewogen und repräsentativ war, bevor wir uns eingehender mit der Analyse der Größenschwellen befassten.

# %% [markdown]
# ## 3. Exploratory Data Analysis (EDA)

# %%
print("🧮 Descriptive Statistics of Key Metrics:")
print(df_clean[numeric_cols].describe().round(2))

# Pattern Distribution
print(f"\n📈 Pattern Type Distribution:")
if 'Pattern' in df_clean.columns:
    pattern_counts = df_clean['Pattern'].value_counts()
    print(pattern_counts)
    
    # Simple Visualization: Pattern Count
    plt.figure(figsize=(8,5))
    sns.barplot(x=pattern_counts.index, y=pattern_counts.values)
    plt.title('Count of Supply vs. Demand Patterns Collected')
    plt.ylabel('Count')
    plt.show()
else:
    print("⚠️ 'Pattern' column not found")

Ergebnis 3:

🧮 Descriptive Statistics of Key Metrics:
       Base_BodyPips  Exit_BodyPips  ExitToBaseRatio  ATR_Pips  Base_BodyATR  \
count        9663.00        9663.00          9663.00   9663.00       9663.00   
mean          237.15         247.71             4.13    473.72          0.62   
std           253.53         268.18            17.92    230.17          0.82   
min             1.00           1.00             0.00     99.50          0.00   
25%            74.00          75.00             0.42    316.64          0.16   
50%           168.00         173.00             1.04    421.00          0.38   
75%           314.00         325.50             2.55    568.36          0.78   
max          3441.00        3441.00           770.00   2156.36         22.79   

       Exit_BodyATR  
count       9663.00  
mean           0.64  
std            0.85  
min            0.00  
25%            0.16  
50%            0.39  
75%            0.81  
max           22.79  

📈 Pattern Type Distribution:
Pattern
Demand    5131
Supply    4532
Name: count, dtype: int64

Ergebnis 3

Zelle 4: Isolierung der Ausgänge von Angebot und Nachfrage mit hoher Dynamik

In diesem Schritt haben wir den Datensatz bewusst eingegrenzt, um uns auf Angebots- und Nachfrageszenarien mit hoher Dynamik zu konzentrieren, indem wir die Fälle herausgefiltert haben, in denen die Ausbruchskerze die Basiskerze deutlich überstieg. Indem wir nur Muster mit einem Verhältnis von Ausbruch zu Grundkörper von mehr als 1,5 berücksichtigen, isolieren wir Kandidaten, die visuell und strukturell mit dem übereinstimmen, was Händler typischerweise als „impulsive“ Ausbrüche aus einer Zone beschreiben. Durch diese Verfeinerung wird das Rauschen von geringfügigen Bewegungen reduziert und die anschließende statistische Analyse kann sich auf die Abgänge konzentrieren, die am ehesten eine echte institutionelle Verlagerung darstellen.

# Add this after creating df_clean, BEFORE the clustering cell
# Filter to only look at patterns where exit was at least 1.5x the base
df_strong = df_clean[df_clean['ExitToBaseRatio'] > 1.5].copy()
print(f"Analyzing strong candidates: {df_strong.shape[0]} patterns (>{df_clean.shape[0]} total)")

Ergebnis 4:

Analyzing strong candidates: 3725 patterns (>9663 total)

Zelle 5: Statistische Verteilung und Schwellenwertanalyse des Verhältnisses von Ausbruchskerze zu Basiskerze 

Anhand von Verteilungsdiagrammen und Boxplots haben wir untersucht, wie die Ausbruchsstärke insgesamt verteilt ist und wie sie sich zwischen Angebots- und Nachfragestrukturen unterscheidet. Mittelwert, Median und Perzentilgrenzen wurden berechnet, um über die visuelle Beurteilung hinauszugehen und datengestützte Benchmarks zu erhalten, die es uns ermöglichen, Verhältnisbereiche zu bestimmen, die konsequent zwischen gewöhnlichen Preisbewegungen und statistisch signifikanten Verschiebungen unterscheiden.

# %% [markdown]
# ## 4. Core Analysis: Distribution of Exit-to-Base Ratio

# %%
if 'ExitToBaseRatio' in df_clean.columns:
    plt.figure(figsize=(12, 5))
    
    # Histogram with KDE
    plt.subplot(1, 2, 1)
    sns.histplot(data=df_clean, x='ExitToBaseRatio', bins=50, kde=True)
    plt.axvline(x=df_clean['ExitToBaseRatio'].median(), color='red', linestyle='--', 
                label=f'Median: {df_clean["ExitToBaseRatio"].median():.2f}')
    plt.axvline(x=df_clean['ExitToBaseRatio'].mean(), color='green', linestyle='--', 
                label=f'Mean: {df_clean["ExitToBaseRatio"].mean():.2f}')
    plt.title('Distribution of Exit-to-Base Size Ratio')
    plt.xlabel('Exit Body Pips / Base Body Pips')
    plt.legend()
    
    # Box plot by Pattern type
    if 'Pattern' in df_clean.columns:
        plt.subplot(1, 2, 2)
        sns.boxplot(data=df_clean, x='Pattern', y='ExitToBaseRatio')
        plt.title('Ratio Distribution: Supply vs. Demand')
        plt.ylabel('Exit-to-Base Ratio')
    
    plt.tight_layout()
    plt.show()
    
    # Critical Percentile Analysis
    print("📐 Key Percentiles for ExitToBaseRatio:")
    percentiles = [5, 25, 50, 75, 90, 95, 99]
    for p in percentiles:
        value = df_clean['ExitToBaseRatio'].quantile(p/100)
        print(f"  {p}th percentile: {value:.2f}")
else:
    print("⚠️ 'ExitToBaseRatio' column not found")

Ergebnis 5:

Key Percentiles for ExitToBaseRatio:
  5th percentile: 0.08
  25th percentile: 0.42
  50th percentile: 1.04
  75th percentile: 2.55
  90th percentile: 6.67
  95th percentile: 13.41
  99th percentile: 61.57

Zelle 6: Normalisierung der Ausbruchsstärke anhand der Volatilität (ATR-Kontext) 

In diesem Schritt haben wir die Kerzengröße kontextualisiert, indem wir sowohl die Basis- als auch die Ausbruchskörper mit der Marktvolatilität unter Verwendung der Average True Range (ATR) in Beziehung gesetzt haben. Anstatt die Größenordnung nur in Pips zu bewerten, haben wir beurteilt, wie klein die Basiskerze im Verhältnis zur Volatilität ist und wie stark die Ausbruchskerze ist, wenn sie durch ATR normalisiert wird. Die sich daraus ergebenden Streudiagramme zeigen, wie sich impulsive Ausbrüche um bestimmte volatilitätsbereinigte Schwellenwerte gruppieren, was die Idee untermauert, dass gültige Ausbrüche der Angebots- und Nachfragezonen besser durch relative Stärke als durch absolute Größe definiert sind und eine robustere Grundlage für symbol- und zeitrahmenübergreifende Automatisierung bieten.

# %% [markdown]
# ## 5. Contextualizing Size: The Role of Volatility (ATR)

# %%
if all(col in df_clean.columns for col in ['Base_BodyATR', 'Exit_BodyATR', 'ExitToBaseRatio', 'Pattern']):
    fig, axes = plt.subplots(1, 2, figsize=(14, 5))
    
    # Base Body vs. ATR
    sns.scatterplot(data=df_clean, x='Base_BodyATR', y='ExitToBaseRatio', hue='Pattern', alpha=0.6, ax=axes[0])
    axes[0].axvline(x=0.5, color='gray', linestyle=':', label='Typical Filter (0.5)')
    axes[0].set_title('Exit Ratio vs. Base "Smallness" (Base_BodyATR)')
    axes[0].set_xlabel('Base Candle Body / ATR')
    axes[0].legend()
    
    # Exit Body vs. ATR
    sns.scatterplot(data=df_clean, x='Exit_BodyATR', y='ExitToBaseRatio', hue='Pattern', alpha=0.6, ax=axes[1])
    axes[1].axvline(x=1.0, color='gray', linestyle=':', label='1x ATR Reference')
    axes[1].set_title('Exit Ratio vs. Exit "Strength" (Exit_BodyATR)')
    axes[1].set_xlabel('Exit Candle Body / ATR')
    axes[1].legend()
    
    plt.tight_layout()
    plt.show()
else:
    print("⚠️ Missing required columns for ATR analysis")

Ergebnis 6:

Zelle 7: Clustering starker Ausbrüche

In diesem abschließenden Analyseschritt wurde mittels K-Means-Clustering ermittelt, ob sich die stärksten Ausbruchskerzen auf natürliche Weise in verschiedene Kategorien einteilen lassen, z. B. in „moderate“ und „starke“ Impulse. Durch Clustering auf der Grundlage des Verhältnisses von Ausbruch zu Basis und der volatilitätsbereinigten Ausbruchsgröße (Ausbruchskörper/ATR) wollten wir statistisch aussagekräftige Untergruppen innerhalb unseres Datensatzes mit hohem Momentum identifizieren. Die Ellbogenmethode diente als Leitfaden für die Auswahl einer angemessenen Anzahl von Clustern, während Streudiagramme und Clusterprofile es uns ermöglichten, die Unterschiede zwischen den Gruppen zu visualisieren und zu quantifizieren. Dieser Ansatz bietet eine datengestützte Grundlage für die Definition von Schwellenwertkriterien, die später in MQL5 für die automatische Erkennung von gültigen Angebots- und Nachfrageausgängen implementiert werden können, um über die visuelle Beurteilung hinaus zu reproduzierbaren, algorithmischen Handelsregeln zu gelangen.

# %% [markdown]
# ## 6. Statistical Clustering: Finding Natural "Impulsive Exit" Groups
# **Objective:** Use K-Means clustering to see if our strong candidates (`df_strong`) naturally group into categories like "Moderate" and "Strong" impulses based on their size ratio and volatility-adjusted strength.

# %%
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

# --- Step 1: Prepare Features for Clustering ---
# We will cluster based on TWO dimensions:
# 1. ExitToBaseRatio (How much bigger is the exit?)
# 2. Exit_BodyATR (How significant is the exit in current market noise?)
print("Preparing features for clustering...")
cluster_features = df_strong[['ExitToBaseRatio', 'Exit_BodyATR']].copy()

# Check for any missing values (should be none after our cleaning)
print(f"Features shape: {cluster_features.shape}")

# Standardize the features (critical for K-Means)
scaler = StandardScaler()
features_scaled = scaler.fit_transform(cluster_features)
print("Features scaled (standardized).\n")

# --- Step 2: The Elbow Method (Optional but Recommended) ---
# Helps suggest a reasonable number of clusters (K).
print("Running Elbow Method to suggest optimal K...")
inertias = []
K_range = range(1, 8)  # Test from 1 to 7 clusters

for k in K_range:
    kmeans = KMeans(n_clusters=k, random_state=42, n_init='auto')  # n_init='auto' for newer scikit-learn
    kmeans.fit(features_scaled)
    inertias.append(kmeans.inertia_)  # Inertia = sum of squared distances to cluster center

# Plot the Elbow Curve
plt.figure(figsize=(8,5))
plt.plot(K_range, inertias, 'bo-')
plt.xlabel('Number of Clusters (K)')
plt.ylabel('Inertia (Lower is Better)')
plt.title('Elbow Method for Optimal K: Where the line "bends"')
plt.grid(True, alpha=0.3)
plt.show()

print("Inertia values:", [f"{i:.0f}" for i in inertias])
print("Look for a 'kink' or elbow in the plot above. Often K=2 or K=3 works well.\n")

# --- Step 3: Apply K-Means Clustering ---
# YOU NEED TO CHOOSE K based on the elbow plot and your research goal.
# For distinguishing "Strong" vs "Very Strong" impulses, start with K=2 or 3.
chosen_k = 3  # <-- CHANGE THIS based on the elbow plot. Try 2 or 3.
print(f"Applying K-Means clustering with K = {chosen_k}...")

kmeans = KMeans(n_clusters=chosen_k, random_state=42, n_init='auto')
cluster_labels = kmeans.fit_predict(features_scaled)

# Add the cluster labels back to our main dataframe
df_strong['Cluster'] = cluster_labels
print(f"Clustering complete. Cluster labels added to 'df_strong'.\n")

# --- Step 4: Visualize the Clusters ---
print("Visualizing clusters...")
plt.figure(figsize=(11, 6))

# Create a scatter plot, coloring points by their assigned cluster
scatter = plt.scatter(df_strong['ExitToBaseRatio'], 
                      df_strong['Exit_BodyATR'],
                      c=df_strong['Cluster'], 
                      cmap='viridis', 
                      alpha=0.6,
                      s=30)  # s is point size

plt.xlabel('Exit-to-Base Ratio', fontsize=12)
plt.ylabel('Exit Body / ATR', fontsize=12)
plt.title(f'K-Means Clustering of Strong Impulses (K={chosen_k})\nEach color is a distinct group', fontsize=14)

# Add a colorbar and grid
plt.colorbar(scatter, label='Cluster ID')
plt.grid(True, alpha=0.3)
plt.show()

# --- Step 5: Analyze and Profile Each Cluster ---
print("="*60)
print("CLUSTER PROFILE ANALYSIS")
print("="*60)

# 5.1 Basic Counts
print("\n📊 1. Number of patterns per cluster:")
cluster_counts = df_strong['Cluster'].value_counts().sort_index()
for clus_id, count in cluster_counts.items():
    percentage = (count / len(df_strong)) * 100
    print(f"   Cluster {clus_id}: {count:4d} patterns ({percentage:.1f}% of strong candidates)")

# 5.2 Mean (Center) of each cluster
print("\n📈 2. Cluster Centers (MEAN values):")
# Get the original feature means for each cluster
cluster_profile = df_strong.groupby('Cluster')[['ExitToBaseRatio', 'Exit_BodyATR', 'Base_BodyATR']].mean().round(3)
print(cluster_profile)

# 5.3 Key Percentiles within each cluster (more robust than mean)
print("\n📐 3. Key PERCENTILES for ExitToBaseRatio in each cluster:")
for clus_id in range(chosen_k):
    cluster_data = df_strong[df_strong['Cluster'] == clus_id]
    print(f"\n   Cluster {clus_id}:")
    for p in [25, 50, 75, 90]:  # 25th, Median (50th), 75th, 90th percentiles
        value = cluster_data['ExitToBaseRatio'].quantile(p/100)
        print(f"     {p}th percentile: {value:.2f}")

# 5.4 Pattern Type distribution within clusters
if 'Pattern' in df_strong.columns:
    print("\n🧩 4. Pattern Type (Supply/Demand) mix per cluster:")
    pattern_mix = pd.crosstab(df_strong['Cluster'], df_strong['Pattern'], normalize='index') * 100
    print(pattern_mix.round(1).astype(str) + ' %')

print("\n" + "="*60)
print("ANALYSIS COMPLETE")

Ergebnis 7: 

============================================================
CLUSTER PROFILE ANALYSIS
============================================================

📊 1. Number of patterns per cluster:
   Cluster 0: 3153 patterns (84.6% of strong candidates)
   Cluster 1:   62 patterns (1.7% of strong candidates)
   Cluster 2:  510 patterns (13.7% of strong candidates)

📈 2. Cluster Centers (MEAN values):
         ExitToBaseRatio  Exit_BodyATR  Base_BodyATR
Cluster                                             
0                  5.845         0.670         0.216
1                  9.649         6.391         1.541
2                 34.023         2.264         0.566

📐 3. Key PERCENTILES for ExitToBaseRatio in each cluster:

   Cluster 0:
     25th percentile: 2.11
     50th percentile: 3.21
     75th percentile: 6.21
     90th percentile: 12.73

   Cluster 1:
     25th percentile: 2.99
     50th percentile: 4.80
     75th percentile: 10.63
     90th percentile: 19.45

   Cluster 2:
     25th percentile: 2.75
     50th percentile: 5.75
     75th percentile: 32.23
     90th percentile: 98.36

🧩 4. Pattern Type (Supply/Demand) mix per cluster:
Pattern  Demand  Supply
Cluster                
0        52.6 %  47.4 %
1        41.9 %  58.1 %
2        48.4 %  51.6 %

============================================================
ANALYSIS COMPLETE


Ergebnisse

Die Anwendung des K-Means-Clustering auf den gefilterten Datensatz der starken Kandidaten (ExitToBaseRatio > 1,5) ergab drei verschiedene Verhaltensgruppen. Diese Segmentierung geht über eine monolithische Sicht des „Impulses“ hinaus und bietet eine statistisch fundierte Taxonomie für Marktbewegungen, die von einer kleinen Basis ausgehen.

Cluster 0: Der zentrale impulsive Ausbruch

Diese Gruppe stellt das dominante und relevanteste Muster dar und umfasst 84,6 % der validierten starken Kandidaten.

Statistisches Profil: Sie ist gekennzeichnet durch ein medianes ExitToBaseRatio von 3,21, was bestätigt, dass ein sinnvoller impulsiver Ausbruch im Durchschnitt mehr als dreimal so groß ist wie die vorangegangene Basis – ein Schwellenwert, der deutlich über dem allgemein angenommenen 2-fachen Multiplikator liegt. Der Cluster weist eine moderate absolute Größe mit einem mittleren Exit_BodyATR von 0,67 auf und bestätigt die Definition der „kleinen Basis“ mit einem mittleren Base_BodyATR von nur 0,22.

Interpretation als Handelssignal: Diese Gruppe ist das Hauptziel einer systematischen Strategie. Es handelt sich um ein klassisches Muster mit hoher Wahrscheinlichkeit, bei dem auf eine Konsolidierung eine entscheidende, handelbare Bewegung folgt, die sowohl im Verhältnis zur Basis als auch im Kontext der vorherrschenden Marktvolatilität signifikant ist.

Cluster 1: hoch volatile Ausreißer

Eine minimale Teilmenge (1,7 %) von Mustern bildete dieses eindeutige Cluster.

Statistisches Profil: Sie ist definiert durch eine extreme mittlere Exit_BodyATR von 6,39 und eine ungewöhnlich große mittlere Base_BodyATR von 1,54, gepaart mit einem hohen ExitToBaseRatio (Mittelwert: 9,65).

Interpretation als Handelssignal: Dieses Cluster wird so interpretiert, dass es atypische Marktereignisse erfasst, wie z. B. durch Nachrichten ausgelöste Gaps oder Volatilitätsspitzen. Die Basiskerze stellt keine Konsolidierung dar und verstößt damit gegen die Kernprämisse von Angebots-/Nachfragezonen. Folglich werden Muster in diesem Cluster als statistische Ausreißer mit geringer Zuverlässigkeit für eine wiederholbare Handelsstrategie betrachtet und ausdrücklich herausgefiltert.

Cluster 2: Ausreißer mit extremem Verhältnis

Auf dieses Cluster entfielen 13,7 % der starken Kandidaten.

Statistisches Profil: Es weist außerordentlich hohe ExitToBaseRatio-Werte auf (Median: 5,75, 90. Perzentil: 98,36) mit einer moderaten mittleren Exit_BodyATR von 2,26. Dies ergibt sich aus einer minimalen mittleren Basisgröße (Base_BodyATR: 0,57).

Interpretation als Handelssignal: Während das relative Verhältnis mathematisch extrem ist, ist die praktische Handelsbedeutung nicht proportional größer als die von Cluster 0. Das extreme Verhältnis ist häufig auf eine Basisgröße von nahezu null zurückzuführen, die möglicherweise nicht durchgängig einen gültigen Konsolidierungsbereich darstellt. Aufgrund des geringeren Stichprobenumfangs und der geringeren Interpretierbarkeit wird dieser Cluster ebenfalls zugunsten des größeren und robusteren Kern-Clusters zurückgestellt.

Basierend auf den 3.153 hochwertigen Mustern in Cluster 0 sind hier unsere optimierten, statistisch abgeleiteten Parameter:

ParameterUrsprünglicher (subjektiver) WertOptimierter (datengesteuerter) WertStatistische Begründung (basierend auf der Cluster-0-Analyse)
MinExitBodyRatio:
Exit muss X-mal größer sein als die Basis
2,03,0Der Median des Verhältnisses von Ausbruch zu Basis für zuverlässige Muster (Cluster 0) beträgt 3,21. Mit einem Schwellenwert von 3,0 wird die stärkere, bedeutendere Hälfte dieser Impulse erfasst.
MaxBaseBodyATR:
Maximale Größe der Basiskerze vs. Volatilität
0,50,3Die durchschnittliche Base_BodyATR in Cluster 0 beträgt 0,22. Eine Verschärfung dieses Filters auf 0,3 gewährleistet, dass die Basis eine echte Konsolidierung darstellt und größere, mehrdeutige Kerzen herausgefiltert werden.
MinExitBodyATR:
Minimale Signifikanz der Ausbruchskerze vs. Volatilität
nicht vorher definiert0,5Die mittlere Exit_BodyATR für Cluster 0 beträgt 0,67. Ein Mindestschwellenwert von 0,5 stellt sicher, dass der Ausbruch im Kontext des aktuellen Marktrauschens eine sinnvolle absolute Dynamik aufweist.



Schlussfolgerung

Diese Forschung hat die kritische erste Hälfte des Entwicklungszyklus eines quantitativen Handels erfolgreich abgeschlossen: den Übergang von einem visuellen Konzept zu einer statistisch validierten Definition. Durch die Anwendung einer rigorosen Datenerfassung und einer Pipeline für maschinelles Lernen auf das Konzept der impulsiven Ausbrüche aus den Angebots- und Nachfragezonen haben wir Vermutungen durch Beweise ersetzt.

Unsere wichtigste Erkenntnis ist, dass das zuverlässigste „kleine Basis, großer Ausbruch“-Muster des Marktes – Cluster 0 – am besten durch eine spezifische, messbare Signatur definiert ist: eine Ausbruchskerze, die in der Regel dreimal so groß ist wie eine wirklich kleine Basis, während sie gleichzeitig ein bedeutendes absolutes Momentum im Verhältnis zur Marktvolatilität aufweist. Die abgeleiteten Parameter (MinExitBodyRatio = 3,0, MaxBaseBodyATR = 0,3, MinExitBodyATR = 0,5) sind keine willkürlichen Optimierungen, sondern das empirische Profil eines hochwahrscheinlichen Ereignisses.

Diese Analyse liefert den wesentlichen Entwurf für die Automatisierung. Diese drei datengesteuerten Parameter lassen sich direkt in einen klaren, eindeutigen Logikblock für einen MQL5 Expert Advisor umsetzen.

Diese Funktion verkörpert die aus unserer Forschung hervorgegangene zentrale Handelsregel. Sie kann in einen umfassenden Expert Advisor integriert werden, der nach Zwei-Kerzen-Mustern sucht, sie durch diese statistische Linse validiert und Trades mit Präzision ausführt. Die nachfolgenden Schritte – Handelsmanagement, Risikokontrolle und Analyse mehrerer Zeitrahmen – sind technische Aufgaben, die auf dieser bewährten Grundlage aufbauen.

In der bevorstehenden Veröffentlichung werden wir diese Forschungsergebnisse in ein voll funktionsfähiges Handelssystem umsetzen. Wir werden ausführlich berichten:

  • Die Integration dieser Validierungslogik in ein robustes Erkennungsmodul.
  • Die Gestaltung des Einstiegs-, Stop-Loss- und Take-Profit-Mechanismus ist kongruent mit der zonenbasierten Strategie.
  • Backtest-Ergebnisse, die die Auswirkungen der Verwendung unserer aus den Daten abgeleiteten Parameter im Vergleich zu den üblichen Standardwerten auf die Leistung zeigen.

Dieser Weg von der manuellen Chartanalyse zur Python-Analyse und schließlich zum optimierten Code in MQL5 demonstriert einen modernen, evidenzbasierten Ansatz zur Strategieentwicklung. Indem wir unsere Algorithmen auf die statistische Realität abstützen, wollen wir Werkzeuge schaffen, die nicht nur automatisiert sind, sondern intelligent automatisiert.

Die wichtigsten Erkenntnisse aus dieser Untersuchung sind in der nachstehenden Tabelle zusammengefasst, zusammen mit den entsprechenden Anhängen. Sie sind herzlich eingeladen, Ihre Gedanken mitzuteilen und in den Kommentaren weiter zu diskutieren. Bleiben Sie dran für unsere nächste Publikation, in der wir auf diesen Ergebnissen aufbauen werden.


Wichtige Erkenntnisse

Wichtige LektionBeschreibung:
Subjektivität muss quantifiziert werdenDie größte Herausforderung bei der Automatisierung von Preisaktionskonzepten wie „impulsiven Ausbrüchen“ ist deren subjektiver, visueller Charakter. Die wichtigste Lektion ist, dass jedes Merkmal, das mit dem „Auge des Händlers“ beurteilt wird, in messbare, numerische Eigenschaften zerlegt werden muss (z. B. Candle-Body-Ratio, ATR-Multiple), um testbar und automatisierbar zu werden.
Datengestützte Parameter schlagen herkömmliche AnnahmenGängige heuristische Werte (z. B. ein Ausbruch, der doppelt so groß ist wie die Basis) sind oft ungeprüft. Die systematische Datenerfassung und -analyse ergaben, dass die statistisch signifikante Schwelle für unser Instrument höher lag, was zu robusteren, evidenzbasierten Regeln führte (`MinExitBodyRatio = 3,0`).
Die Forschungspipeline ist entscheidendEine strukturierte, zweistufige Pipeline – MQL5 (Datenerhebung) → Python (statistische Entdeckung) – ist unerlässlich. Sie schafft einen klaren, reproduzierbaren Weg von der Marktbeobachtung zur algorithmischen Logik und stellt sicher, dass der endgültige EA auf empirischen Erkenntnissen und nicht auf Vermutungen beruht.
Clustering zeigt die Mikrostruktur des MarktesDie Anwendung des statistischen Clustering (K-Means) auf die Daten filterte nicht nur das Rauschen heraus, sondern entdeckte aktiv die marktinterne Klassifizierung von Impulsen. Die Identifizierung des „Kern“-Clusters (Cluster 0) ermöglichte es uns, Parameter zu definieren, die auf dem häufigsten und kohärentesten Muster des Marktes basieren und nicht nur auf einem willkürlichen Grenzwert.
Der Kontext ist entscheidend.Für die Messung des Impulses sind sowohl relative als auch absolute Objektive erforderlich. Ein hoher Wert von ExitToBaseRatio bedeutet wenig, wenn die Kerzen im Verhältnis zur Marktvolatilität (ATR) winzig sind. Die Notwendigkeit, einen Mindestwert für Exit_BodyATR (0,5) festzulegen, ergab sich direkt aus dieser Erkenntnis, wodurch ein ganzheitlicherer Filter geschaffen wurde.
Brückenschlag zwischen Forschung und AusführungDas ultimative Ziel der quantitativen Forschung ist die Erstellung von ausführbarem Code. Die letzte, entscheidende Lektion besteht darin, statistische Erkenntnisse – wie die Eigenschaften von Cluster 0 – direkt in eine saubere Validierungsfunktion in MQL5 zu übersetzen und damit eine direkte Brücke vom Forschungsnotizbuch zu einem Live-Chart zu schlagen.



Anlagen

DateinameBeschreibung:
SD_BaseExit_Research.mq5Das Kernskript der MQL5-Datenerfassung. Es scannt systematisch historische Kursdaten, um Instanzen des definierten Zwei-Kerzen-Basis-Ausbruchsmusters zu finden. Es berechnet die wichtigsten Metriken (Körpergrößen in Pips, ATR-Verhältnisse) für jedes gültige Muster und exportiert sie in eine strukturierte CSV-Datei, wodurch der Rohdatensatz für die statistische Analyse entsteht.
Supply_and_demand_research.ipynb:Das Jupyter-Notebook, das den kompletten Python-Analyse-Workflow enthält. Es lädt die gesammelten CSV-Daten, führt eine explorative Datenanalyse (EDA) durch, visualisiert Verteilungen und wendet K-Means-Clustering an. Dieses Notebook ist die Umgebung, in der subjektive Kursmuster in objektive, statistisch ermittelte Handelsparameter übersetzt werden.
SD_BaseExit_XAUUSDr_5.csvIst eine vom MQL5-Skript erzeugte Beispiel-Ausgabedatei. Ihr Name folgt dem Muster [Präfix]_[Symbol]_[Zeitrahmen].csv. Diese Datei enthält den gesammelten Datensatz – Tausende von mit Zeitstempeln versehenen Musterbeobachtungen mit allen berechneten Metriken – und ist bereit für den Import in das Jupyter Notebook. Das Skript speichert die Dateien automatisch im “MQL5/Files“-Verzeichnis des MetaTrader 5-Terminals (z.B. .../MQL5/Files/), was eine direkte Kompatibilität und einen nahtlosen Dateipfad für die Python-Analyseskripte gewährleistet.

Zurück zum Inhalt

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

Entwicklung eines dynamischen Multi-Pair-EA (Teil 6): Adaptive Spread-Sensitivität für hochfrequente Symbolwechsel Entwicklung eines dynamischen Multi-Pair-EA (Teil 6): Adaptive Spread-Sensitivität für hochfrequente Symbolwechsel
In diesem Teil werden wir uns auf die Entwicklung einer intelligenten Ausführungsschicht konzentrieren, die die Spread-Bedingungen in Echtzeit über mehrere Symbole hinweg kontinuierlich überwacht und auswertet. Der EA passt seine Symbolauswahl dynamisch an, indem er den Handel auf der Grundlage der Spread-Effizienz und nicht nach festen Regeln aktiviert oder deaktiviert. Dieser Ansatz ermöglicht es Hochfrequenz-Multi-Pair-Systemen, kostengünstige Symbole zu priorisieren.
Erstellen von nutzerdefinierten Indikatoren in MQL5 (Teil 6): Weiterentwicklung der RSI-Berechnungen mit Glättung, Farbwechsel und Multi-Timeframe-Unterstützung Erstellen von nutzerdefinierten Indikatoren in MQL5 (Teil 6): Weiterentwicklung der RSI-Berechnungen mit Glättung, Farbwechsel und Multi-Timeframe-Unterstützung
In diesem Artikel erstellen wir einen vielseitigen RSI-Indikator in MQL5, der mehrere Varianten, Datenquellen und Glättungsmethoden für eine verbesserte Analyse unterstützt. Wir fügen Farbwechsel für farbliche Darstellungen, dynamische Grenzen für überkaufte/überverkaufte Zonen und Benachrichtigungen für Trendwarnungen hinzu. Es unterstützt mehrere Zeitrahmen mit Interpolation und bietet uns ein anpassbares RSI-Tool für verschiedene Strategien.
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.
Integration externer Anwendungen mit MQL5 Community OAuth Integration externer Anwendungen mit MQL5 Community OAuth
Erfahren Sie, wie Sie Ihrer Android-App mit dem OAuth-2.0-Autorisierungscodefluss die Funktion „Sign in with MQL5“ hinzufügen. Die Anleitung behandelt die App-Registrierung, Endpunkte, Redirect URI, Custom Tabs, Deep-Link-Handling und ein PHP-Backend, das den Code für ein Access-Token über HTTPS austauscht. Sie werden echte MQL5-Nutzer authentifizieren und auf Profildaten wie Rang und Ruf zugreifen.