English 日本語
preview
Aufbau eines nutzerdefinierten Systems zur Erkennung von Marktregimen in MQL5 (Teil 1): Der Indikator

Aufbau eines nutzerdefinierten Systems zur Erkennung von Marktregimen in MQL5 (Teil 1): Der Indikator

MetaTrader 5Handel |
133 5
Sahil Bagdi
Sahil Bagdi
  1. Einführung
  2. Das Verständnis von Marktregimen
  3. Schaffung der statistischen Grundlage
  4. Implementierung des Marktregime-Detektors
  5. Erstellen eines nutzerdefinierten Indikators für die Regime-Visualisierung
  6. Schlussfolgerung


Einführung

Die Finanzmärkte befinden sich in einem ständigen Wandel und wechseln zwischen Phasen starker Trends, seitwärts gerichteter Konsolidierung und chaotischer Volatilität. Für algorithmische Händler stellt dies eine große Herausforderung dar: Eine Strategie, die in Trendmärkten außergewöhnlich gut abschneidet, versagt oft kläglich bei schwankenden Märkten, während Ansätze, die für eine geringe Volatilität konzipiert sind, bei einem Anstieg der Volatilität das Konto sprengen können. Trotz dieser Tatsache werden die meisten Handelssysteme unter der impliziten Annahme entwickelt, dass das Marktverhalten im Laufe der Zeit gleich bleibt.

Diese grundlegende Diskrepanz zwischen der Marktrealität und dem Design des Handelssystems führt zu dem nur allzu bekannten Muster der Verschlechterung der Strategieperformance. Ein System funktioniert während der Backtests und der anfänglichen Einführung hervorragend, gerät aber ins Wanken, wenn sich die Marktbedingungen unweigerlich ändern. Der Händler steht dann vor einer schwierigen Entscheidung: die Strategie aufgeben und neu beginnen oder Drawdowns hinnehmen und darauf hoffen, dass die Marktbedingungen seinen Ansatz wieder begünstigen.

Was wäre, wenn es einen besseren Weg gäbe? Was wäre, wenn Ihr Handelssystem objektiv das aktuelle Marktregime erkennen und seine Strategie entsprechend anpassen könnte? Genau das werden wir in diesem Artikel aufbauen: ein umfassendes System zur Erkennung von Marktregimen in MQL5, das die Marktbedingungen in verschiedene Regime einteilen kann und einen Rahmen für adaptive Handelsstrategien bietet.

Am Ende dieser Artikelserie werden Sie ein komplettes System zur Erkennung von Marktregimen implementiert haben, das Folgendes umfasst:
  1. Eine solide statistische Grundlage für eine objektive Marktklassifizierung
  2. Eine nutzerdefinierte Marktregime-Detektorklasse, die Trends, Schwankungen und volatile Marktbedingungen identifiziert
  3. Ein nutzerdefinierter Indikator, der Regimewechsel direkt auf Ihren Charts visualisiert
  4. Ein anpassungsfähiger Expert Advisor, der automatisch geeignete Strategien auf der Grundlage des aktuellen Systems auswählt (Teil 2)
  5. Praktische Beispiele für die Implementierung und Optimierung des Systems für Ihre spezifischen Handelsanforderungen (Teil 2)

Ganz gleich, ob Sie ein erfahrener algorithmischer Händler sind, der seine bestehenden Systeme verbessern möchte, oder ein Neuling, der von Anfang an robustere Strategien entwickeln möchte, dieses System zur Erkennung von Marktregimen wird Ihnen leistungsstarke Werkzeuge an die Hand geben, um sich in der sich ständig verändernden Landschaft der Finanzmärkte zurechtzufinden.


Das Verständnis von Marktregimen

Bevor wir uns mit den Einzelheiten der Umsetzung befassen, ist es wichtig zu verstehen, was Marktregelungen sind und warum sie für Händler wichtig sind. Die Märkte verhalten sich im Laufe der Zeit nicht einheitlich, sondern sie wechseln zwischen verschiedenen Verhaltenszuständen oder „Regimen“. Diese Systeme haben einen erheblichen Einfluss auf die Preisentwicklung und folglich auch auf die Performance der Handelsstrategien.

Was sind Marktregime?

Marktregime sind bestimmte Muster des Marktverhaltens, die durch spezifische statistische Eigenschaften der Preisbewegungen gekennzeichnet sind. Es gibt zwar verschiedene Möglichkeiten, Marktregime zu klassifizieren, aber wir werden uns auf drei Haupttypen konzentrieren, die für die Entwicklung von Handelsstrategien am wichtigsten sind:
  1. Trend-Regime: Die Märkte weisen starke Richtungsbewegungen mit minimaler Mittelwertumkehr auf. Der Preis neigt dazu, sich beständig in eine Richtung zu bewegen, wobei es zu flachen Rücksetzern kommt. Statistisch gesehen weisen tendenzielle Märkte eine positive Autokorrelation der Renditen auf, was bedeutet, dass Kursbewegungen in eine Richtung wahrscheinlich von Bewegungen in dieselbe Richtung gefolgt werden.
  2. Reichweitenregime: Die Märkte oszillieren zwischen Unterstützungs- und Widerstandsniveaus mit starken Tendenzen zur Rückkehr zum Mittelwert. Der Preis neigt dazu, zwischen definierten Grenzen zu pendeln, anstatt in eine der beiden Richtungen auszubrechen. Statistisch gesehen weisen die Renditen von Wertpapiermärkten eine negative Autokorrelation auf, was bedeutet, dass auf Aufwärtsbewegungen wahrscheinlich Abwärtsbewegungen folgen und umgekehrt.
  3. Volatile Regime: An den Märkten kommt es zu großen, sprunghaften Kursbewegungen mit unklarer Richtung. Diese Regime treten häufig in Zeiten der Unsicherheit, der Nachrichtenlage oder des Marktstresses auf. Statistisch gesehen weisen die volatilen Regimes eine hohe Standardabweichung der Renditen mit unvorhersehbaren Autokorrelationsmustern auf.

Zu verstehen, in welchem Regime sich der Markt derzeit befindet, ist für Handelsentscheidungen von entscheidender Bedeutung. Eine Strategie, die für Märkte mit einem Trend optimiert ist, wird wahrscheinlich unter schwankenden Bedingungen schlecht abschneiden, während Strategien der Rückkehr zum Mittelwert, die für schwankende Märkte entwickelt wurden, während starker Trends katastrophale Folgen haben können.

Warum greifen traditionelle Indikatoren zu kurz?

Die meisten technischen Indikatoren wurden entwickelt, um bestimmte Preismuster oder Bedingungen zu erkennen und nicht, um Marktregime zu klassifizieren. Zum Beispiel:
  • Gleitende Durchschnitte und MACD können bei der Erkennung von Trends helfen, unterscheiden aber nicht zwischen Trend- und Volatilitätstendenzen.
  • RSI- und Stochastik-Oszillatoren funktionieren gut in schwankenden Märkten, erzeugen aber falsche Signale in Trendbedingungen.
  • Bollinger Bänder passen sich der Volatilität an, identifizieren aber nicht explizit Regimeübergänge.
Diese Beschränkungen stellen eine erhebliche Lücke in den meisten Handelssystemen dar. Ohne die aktuellen Marktbedingungen zu kennen, wenden die Händler ihre Strategien im Wesentlichen blind an und hoffen, dass die Marktbedingungen den Annahmen ihrer Strategie entsprechen.

Statistische Grundlagen der Regime-Erkennung

Um ein effektives System zur Erkennung von Regimen zu entwickeln, müssen wir statistische Maße nutzen, die das Marktverhalten objektiv klassifizieren können. Zu den wichtigsten statistischen Konzepten, die wir verwenden werden, gehören:
  1. Autokorrelation: Misst die Korrelation zwischen einer Zeitreihe und einer verzögerten Version ihrer selbst. Eine positive Autokorrelation könnte einen Trend bedeuten, während eine negative Autokorrelation auf ein (schwankendes) Verhalten mit einer Rückkehr zum Mittelwert hindeutet.
  2. Volatilität: Misst die Streuung der Renditen, in der Regel anhand der Standardabweichung. Plötzliche Anstiege der Volatilität signalisieren oft Regimewechsel.
  3. Trendstärke: Kann mit verschiedenen Methoden quantifiziert werden, darunter der absolute Wert der Autokorrelation, die Steigung der linearen Regression oder spezielle Indikatoren wie der ADX.

Durch die Kombination dieser statistischen Maße können wir einen robusten Rahmen für die objektive Klassifizierung von Marktregimen schaffen. Im nächsten Abschnitt werden wir diese Konzepte in MQL5-Code implementieren, um unser System zur Erkennung von Marktregimen aufzubauen.


Schaffung der statistischen Grundlage

In diesem Abschnitt werden wir die wichtigsten statistischen Komponenten implementieren, die für unser System zur Erkennung von Marktregimen benötigt werden. Wir werden eine robuste Klasse CStatistics erstellen, die alle für die Regimeklassifizierung erforderlichen mathematischen Berechnungen durchführen wird.

Die Klasse CStatistics

Die Grundlage unseres Systems zur Erkennung von Regimen ist eine leistungsstarke Statistikklasse, die verschiedene Berechnungen mit Preisdaten durchführen kann. Schauen wir uns die wichtigsten Komponenten dieser Klasse an:

//+------------------------------------------------------------------+
//| Class for statistical calculations                               |
//+------------------------------------------------------------------+
class CStatistics
{
private:
    double      m_data[];           // Data array for calculations
    int         m_dataSize;         // Size of the data array
    bool        m_isSorted;         // Flag indicating if data is sorted
    double      m_sortedData[];     // Sorted copy of data for percentile calculations
    
public:
    // Constructor and destructor
    CStatistics();
    ~CStatistics();
    
    // Data management methods
    bool        SetData(const double &data[], int size);
    bool        AddData(double value);
    void        Clear();
    
    // Basic statistical methods
    double      Mean() const;
    double      StandardDeviation() const;
    double      Variance() const;
    
    // Range and extremes
    double      Min() const;
    double      Max() const;
    double      Range() const;
    
    // Time series specific methods
    double      Autocorrelation(int lag) const;
    double      TrendStrength() const;
    double      MeanReversionStrength() const;
    
    // Percentile calculations
    double      Percentile(double percentile);
    double      Median();
};

Diese Klasse bietet eine umfassende Reihe von statistischen Funktionen, die es uns ermöglichen, Preisdaten zu analysieren und das aktuelle Marktregime zu bestimmen. Schauen wir uns einige der wichtigsten Methoden im Detail an.

Konstruktor und Destruktor

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CStatistics::CStatistics()
{
    m_dataSize = 0;
    m_isSorted = false;
    ArrayResize(m_data, 0);
    ArrayResize(m_sortedData, 0);
}

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CStatistics::~CStatistics()
{
    Clear();
}

Konstruktor und Destruktor helfen bei der Initialisierung der Klasse und der Deinitialisierung der Klasse. Der Konstruktor initialisiert unsere Mitgliedsvariablen und Arrays, während der Destruktor durch den Aufruf der Methode Clear() für eine ordnungsgemäße Bereinigung sorgt. Dieses Muster der ordnungsgemäßen Initialisierung und Bereinigung ist in MQL5 wichtig, um Speicherlecks zu vermeiden und einen zuverlässigen Betrieb zu gewährleisten.

Methoden der Datenverwaltung


Als Nächstes implementieren wir die Datenverwaltungsmethoden, mit denen wir Daten setzen, hinzufügen und löschen können:

bool CStatistics::SetData(const double &data[], int size)
{
    if(size <= 0)
        return false;
        
    m_dataSize = size;
    ArrayResize(m_data, size);
    
    for(int i = 0; i < size; i++)
        m_data[i] = data[i];
        
    m_isSorted = false;
    return true;
}

bool CStatistics::AddData(double value)
{
    m_dataSize++;
    ArrayResize(m_data, m_dataSize);
    m_data[m_dataSize - 1] = value;
    m_isSorted = false;
    return true;
}

void CStatistics::Clear()
{
    m_dataSize = 0;
    ArrayResize(m_data, 0);
    ArrayResize(m_sortedData, 0);
    m_isSorted = false;
}
                        

Mit der Methode SetData() kann der gesamte Datensatz durch ein neues Array ersetzt werden, was bei der Verarbeitung historischer Kursdaten nützlich ist. Die Methode AddData() fügt einen einzelnen Wert an die vorhandenen Daten an, was für inkrementelle Aktualisierungen praktisch ist, wenn neue Preisdaten verfügbar werden. Die Methode Clear() setzt das Objekt in seinen Ausgangszustand zurück und gibt den zugewiesenen Speicher frei.

Beachten Sie, dass wir m_isSorted = false setzen, wenn sich die Daten ändern. Dieses Flag hilft uns, die Leistung zu optimieren, indem wir die Daten nur dann sortieren, wenn dies für die Berechnung der Prozentsätze erforderlich ist.

Grundlegende statistische Methoden

Lassen Sie uns nun die grundlegenden statistischen Methoden zur Berechnung von Mittelwert, Standardabweichung und Varianz anwenden:

double CStatistics::Mean() const
{
    if(m_dataSize <= 0)
        return 0.0;
        
    double sum = 0.0;
    for(int i = 0; i < m_dataSize; i++)
        sum += m_data[i];
        
    return sum / m_dataSize;
}

double CStatistics::StandardDeviation() const
{
    if(m_dataSize <= 1)
        return 0.0;
        
    double mean = Mean();
    double sum = 0.0;
    
    for(int i = 0; i < m_dataSize; i++)
        sum += MathPow(m_data[i] - mean, 2);
        
    return MathSqrt(sum / (m_dataSize - 1));
}

double CStatistics::Variance() const
{
    if(m_dataSize <= 1)
        return 0.0;
        
    double stdDev = StandardDeviation();
    return stdDev * stdDev;
}

Bei diesen Methoden werden statistische Standardformeln verwendet. Mit der Methode Mean() wird der Durchschnitt aller Datenpunkte berechnet. Die Methode StandardDeviation() misst die Streuung der Datenpunkte um den Mittelwert, was für die Identifizierung volatiler Marktregimes entscheidend ist. Die Methode Variance() gibt das Quadrat der Standardabweichung zurück und liefert damit ein weiteres Maß für die Streuung der Daten.

Beachten Sie, wie wir Randfälle, wie leere Datensätze oder einzelne Datenpunkte, behandeln, indem wir Null zurückgeben. Dieser defensive Programmieransatz verhindert Fehler bei der Arbeit mit unzureichenden Daten.

Bereichs- und Extremwertmethoden

//+------------------------------------------------------------------+
//| Calculate minimum value in the data                              |
//+------------------------------------------------------------------+
double CStatistics::Min() const
{
    if(m_dataSize <= 0)
        return 0.0;
        
    double min = m_data[0];
    for(int i = 1; i < m_dataSize; i++)
        if(m_data[i] < min)
            min = m_data[i];
            
    return min;
}

//+------------------------------------------------------------------+
//| Calculate maximum value in the data                              |
//+------------------------------------------------------------------+
double CStatistics::Max() const
{
    if(m_dataSize <= 0)
        return 0.0;
        
    double max = m_data[0];
    for(int i = 1; i < m_dataSize; i++)
        if(m_data[i] > max)
            max = m_data[i];
            
    return max;
}

//+------------------------------------------------------------------+
//| Calculate range (max - min) of the data                          |
//+------------------------------------------------------------------+
double CStatistics::Range() const
{
    return Max() - Min();
}
                            

Diese Methoden liefern zusätzliche Erkenntnisse über die Datenverteilung. Die Methoden Min() und Max() ermitteln den kleinsten und den größten Wert im Datensatz, während die Methode Range() die Differenz zwischen ihnen berechnet. Diese Maßstäbe können nützlich sein, um Preisgrenzen auf schwankenden Märkten zu ermitteln.

Zeitreihenspezifische Methoden

Nun wollen wir die zeitreihenspezifischen Methoden implementieren, die für die Erkennung von Regimen entscheidend sind:

double CStatistics::Autocorrelation(int lag) const
{
    if(m_dataSize <= lag || lag <= 0)
        return 0.0;
        
    double mean = Mean();
    double numerator = 0.0;
    double denominator = 0.0;
    
    for(int i = 0; i < m_dataSize - lag; i++)
    {
        numerator += (m_data[i] - mean) * (m_data[i + lag] - mean);
    }
    
    for(int i = 0; i < m_dataSize; i++)
    {
        denominator += MathPow(m_data[i] - mean, 2);
    }
    
    if(denominator == 0.0)
        return 0.0;
        
    return numerator / denominator;
}

double CStatistics::TrendStrength() const
{
    // Use lag-1 autocorrelation as a measure of trend strength
    double ac1 = Autocorrelation(1);
    
    // Positive autocorrelation indicates trending behavior
    return ac1;
}

double CStatistics::MeanReversionStrength() const
{
    // Negative autocorrelation indicates mean-reverting behavior
    double ac1 = Autocorrelation(1);
    
    // Return the negative of autocorrelation, so positive values
    // indicate stronger mean reversion
    return -ac1;
}

Die Methode Autokorrelation() berechnet die Korrelation zwischen der Datenreihe und einer verzögerten Version ihrer selbst. Dies ist ein aussagekräftiges Maß für die Unterscheidung zwischen tendenziellen und schwankenden Märkten. Eine positive Autokorrelation (Werte größer als Null) deutet auf einen Trend hin, während eine negative Autokorrelation (Werte kleiner als Null) auf ein Rückkehr zum Mittelwert oder Seitwärtsbewegung schließen lässt.

Die Methode TrendStrength() verwendet die Lag-1-Autokorrelation als direktes Maß für die Trendstärke. Höhere positive Werte bedeuten stärkere Trends. Die Methode MeanReversionStrength() gibt das Negativ der Autokorrelation zurück, sodass positive Werte stärkere Tendenzen zu einer Rückkehr zum Mittelwert anzeigen.

Diese Methoden bilden das statistische Rückgrat unseres Systems zur Erkennung von Regimen und liefern objektive Maßstäbe für das Marktverhalten, die wir zur Klassifizierung von Regimen verwenden werden.

Perzentil-Berechnungen

Abschließend wollen wir Methoden zur Berechnung von Perzentilen und des Medians implementieren:

double CStatistics::Percentile(double percentile)
{
    if(m_dataSize <= 0 || percentile < 0.0 || percentile > 100.0)
        return 0.0;
        
    // Sort data if needed
    if(!m_isSorted)
    {
        ArrayResize(m_sortedData, m_dataSize);
        for(int i = 0; i < m_dataSize; i++)
            m_sortedData[i] = m_data[i];
            
        ArraySort(m_sortedData);
        m_isSorted = true;
    }
    
    // Calculate position
    double position = (percentile / 100.0) * (m_dataSize - 1);
    int lowerIndex = (int)MathFloor(position);
    int upperIndex = (int)MathCeil(position);
    
    // Handle edge cases
    if(lowerIndex == upperIndex)
        return m_sortedData[lowerIndex];
        
    // Interpolate
    double fraction = position - lowerIndex;
    return m_sortedData[lowerIndex] + fraction * (m_sortedData[upperIndex] - m_sortedData[lowerIndex]);
}

double CStatistics::Median()
{
    return Percentile(50.0);
}

Die Methode Percentile() berechnet den Wert, unter den ein bestimmter Prozentsatz der Beobachtungen fällt. Zunächst werden die Daten sortiert (sofern nicht bereits sortiert) und dann durch lineare Interpolation der genaue Perzentilwert ermittelt. Die Methode Median() ist eine Komfortfunktion, die das 50. Perzentil zurückgibt, das den mittleren Wert des Datensatzes darstellt.

Beachten Sie die Optimierung mit dem Flag m_isSorted, das sicherstellt, dass die Daten nur einmal sortiert werden, auch wenn mehrere Perzentile berechnet werden. Dies ist ein Beispiel dafür, wie eine sorgfältige Implementierung die Leistung von MQL5-Code verbessern kann.

Mit der Vervollständigung unserer Klasse CStatistics verfügen wir nun über ein leistungsstarkes Instrumentarium zur Analyse von Preisdaten und zur Erkennung von Marktregimen. Im nächsten Abschnitt bauen wir auf dieser Grundlage auf und erstellen die Klasse Market Regime Detector.


Implementierung des Marktregime-Detektors

Nachdem wir nun unsere statistische Grundlage geschaffen haben, können wir die Kernkomponente unseres Systems aufbauen: den Marktregime-Detektor. In diesem Kurs werden wir die von uns eingeführten statistischen Maßnahmen nutzen, um die Marktbedingungen in bestimmte Regime einzuordnen.

Enumeration für die Marktregime

Definieren wir zunächst die Typen der Marktregime, die unser System identifizieren wird. Wir erstellen eine separate Datei mit dem Namen MarketRegimeEnum.mqh, um sicherzustellen, dass die Enum-Definition für alle Komponenten unseres Systems verfügbar ist:

// Define market regime types
enum ENUM_MARKET_REGIME
{
    REGIME_TRENDING_UP = 0,    // Trending up regime
    REGIME_TRENDING_DOWN = 1,  // Trending down regime
    REGIME_RANGING = 2,        // Ranging/sideways regime
    REGIME_VOLATILE = 3,       // Volatile/chaotic regime
    REGIME_UNDEFINED = 4       // Undefined regime (default) 
};

Diese Erkennen definiert die fünf möglichen Marktregime, die unser System erkennen kann. Wir werden diese Werte in unserer gesamten Implementierung verwenden, um den aktuellen Marktzustand darzustellen.

Die Klasse CMarketRegimeDetector

Die Detektorklasse des Marktregimes kombiniert unsere statistischen Werkzeuge mit einer Logik zur Klassifizierung von Marktregimen. Schauen wir uns seine Struktur an:

class CMarketRegimeDetector
{
private:
    // Configuration
    int         m_lookbackPeriod;       // Period for calculations
    int         m_smoothingPeriod;      // Period for smoothing regime transitions
    double      m_trendThreshold;       // Threshold for trend detection
    double      m_volatilityThreshold;  // Threshold for volatility detection
    
    // Data buffers
    double      m_priceData[];          // Price data buffer
    double      m_returns[];            // Returns data buffer
    double      m_volatility[];         // Volatility buffer
    double      m_trendStrength[];      // Trend strength buffer
    double      m_regimeBuffer[];       // Regime classification buffer
    
    // Statistics objects
    CStatistics m_priceStats;           // Statistics for price data
    CStatistics m_returnsStats;         // Statistics for returns data
    CStatistics m_volatilityStats;      // Statistics for volatility data
    
    // Current state
    ENUM_MARKET_REGIME m_currentRegime; // Current detected regime
    
    // Helper methods
    void        CalculateReturns();
    void        CalculateVolatility();
    void        CalculateTrendStrength();
    ENUM_MARKET_REGIME DetermineRegime();
    
public:
    // Constructor and destructor
    CMarketRegimeDetector(int lookbackPeriod = 100, int smoothingPeriod = 10);
    ~CMarketRegimeDetector();
    
    // Configuration methods
    void        SetLookbackPeriod(int period);
    void        SetSmoothingPeriod(int period);
    void        SetTrendThreshold(double threshold);
    void        SetVolatilityThreshold(double threshold);
    
    // Processing methods
    bool        Initialize();
    bool        ProcessData(const double &price[], int size);
    
    // Access methods
    ENUM_MARKET_REGIME GetCurrentRegime() const { return m_currentRegime; }
    string      GetRegimeDescription() const;
    double      GetTrendStrength() const;
    double      GetVolatility() const;
    
    // Buffer access for indicators
    bool        GetRegimeBuffer(double &buffer[]) const;
    bool        GetTrendStrengthBuffer(double &buffer[]) const;
    bool        GetVolatilityBuffer(double &buffer[]) const;
};

Diese Klasse kapselt alle Funktionen, die zur Erkennung von Marktregimen erforderlich sind. Lassen Sie uns jede Methode im Detail implementieren.

Konstruktor und Destruktor

Implementieren wir zunächst den Konstruktor und den Destruktor:

CMarketRegimeDetector::CMarketRegimeDetector(int lookbackPeriod, int smoothingPeriod)
{
    // Set default parameters
    m_lookbackPeriod = (lookbackPeriod > 20) ? lookbackPeriod : 100;
    m_smoothingPeriod = (smoothingPeriod > 0) ? smoothingPeriod : 10;
    m_trendThreshold = 0.2;
    m_volatilityThreshold = 1.5;
    
    // Initialize current regime
    m_currentRegime = REGIME_UNDEFINED;
    
    // Initialize buffers
    ArrayResize(m_priceData, m_lookbackPeriod);
    ArrayResize(m_returns, m_lookbackPeriod - 1);
    ArrayResize(m_volatility, m_lookbackPeriod - 1);
    ArrayResize(m_trendStrength, m_lookbackPeriod - 1);
    ArrayResize(m_regimeBuffer, m_lookbackPeriod);
    
    // Initialize buffers with zeros
    ArrayInitialize(m_priceData, 0.0);
    ArrayInitialize(m_returns, 0.0);
    ArrayInitialize(m_volatility, 0.0);
    ArrayInitialize(m_trendStrength, 0.0);
    ArrayInitialize(m_regimeBuffer, (double)REGIME_UNDEFINED);
}

CMarketRegimeDetector::~CMarketRegimeDetector()
{
    // Free memory (not strictly necessary in MQL5, but good practice)
    ArrayFree(m_priceData);
    ArrayFree(m_returns);
    ArrayFree(m_volatility);
    ArrayFree(m_trendStrength);
    ArrayFree(m_regimeBuffer);
}

Der Konstruktor initialisiert alle Mitgliedsvariablen und Arrays mit Standardwerten. Es beinhaltet eine Parametervalidierung, um sicherzustellen, dass der Rückblickzeitraum mindestens 20 Balken beträgt (für statistische Signifikanz) und der Glättungszeitraum positiv ist. Der Destruktor gibt den für die Arrays zugewiesenen Speicher frei, was eine gute Praxis ist, auch wenn MQL5 eine automatische Garbage Collection hat.

Konfigurationsmethoden

Als Nächstes implementieren wir die Konfigurationsmethoden, mit denen die Nutzer das Verhalten des Detektors anpassen können:

void CMarketRegimeDetector::SetLookbackPeriod(int period)
{
    if(period <= 20)
        return;
        
    m_lookbackPeriod = period;
    
    // Resize buffers
    ArrayResize(m_priceData, m_lookbackPeriod);
    ArrayResize(m_returns, m_lookbackPeriod - 1);
    ArrayResize(m_volatility, m_lookbackPeriod - 1);
    ArrayResize(m_trendStrength, m_lookbackPeriod - 1);
    ArrayResize(m_regimeBuffer, m_lookbackPeriod);
    
    // Re-initialize
    Initialize();
}

void CMarketRegimeDetector::SetSmoothingPeriod(int period)
{
    if(period <= 0)
        return;
        
    m_smoothingPeriod = period;
}

void CMarketRegimeDetector::SetTrendThreshold(double threshold)
{
    if(threshold <= 0.0)
        return;
        
    m_trendThreshold = threshold;
}

void CMarketRegimeDetector::SetVolatilityThreshold(double threshold)
{
    if(threshold <= 0.0)
        return;
        
    m_volatilityThreshold = threshold;
}

Mit diesen Methoden können die Nutzer die Parameter des Detektors an ihre spezifischen Handelsinstrumente und Zeitrahmen anpassen. Die Methode SetLookbackPeriod() ist besonders wichtig, da sie die Größe aller internen Puffer an den neuen Zeitraum anpasst. Bei den anderen Methoden werden die entsprechenden Parameter nach der Validierung der Eingabewerte einfach aktualisiert.

Initialisierungs- und Verarbeitungsmethoden

Lassen Sie uns nun die Initialisierungs- und Datenverarbeitungsmethoden implementieren:

bool CMarketRegimeDetector::Initialize()
{
    // Initialize buffers with zeros
    ArrayInitialize(m_priceData, 0.0);
    ArrayInitialize(m_returns, 0.0);
    ArrayInitialize(m_volatility, 0.0);
    ArrayInitialize(m_trendStrength, 0.0);
    ArrayInitialize(m_regimeBuffer, (double)REGIME_UNDEFINED);
    
    // Reset current regime
    m_currentRegime = REGIME_UNDEFINED;
    
    return true;
}

bool CMarketRegimeDetector::ProcessData(const double &price[], int size)
{
    if(size < m_lookbackPeriod)
        return false;
        
    // Copy the most recent price data
    for(int i = 0; i < m_lookbackPeriod; i++)
        m_priceData[i] = price[size - m_lookbackPeriod + i];
        
    // Calculate returns, volatility, and trend strength
    CalculateReturns();
    CalculateVolatility();
    CalculateTrendStrength();
    
    // Determine the current market regime
    m_currentRegime = DetermineRegime();
    
    // Update regime buffer for indicator display
    for(int i = 0; i < m_lookbackPeriod - 1; i++)
        m_regimeBuffer[i] = m_regimeBuffer[i + 1];
        
    m_regimeBuffer[m_lookbackPeriod - 1] = (double)m_currentRegime;
    
    return true;
}

Die Methode Initialize() setzt alle Puffer und das aktuelle Regime auf ihre Standardwerte zurück. Die Methode ProcessData() ist das Herzstück des Detektors, das neue Preisdaten verarbeitet und die Regimeklassifizierung aktualisiert. Es kopiert zunächst die jüngsten Kursdaten, berechnet dann die Renditen, die Volatilität und die Trendstärke und bestimmt schließlich das aktuelle Marktregime. Außerdem wird der Regimepuffer für die Indikatoranzeige aktualisiert, wobei die Werte verschoben werden, um Platz für das neue Regime zu schaffen.

Berechnungsmethoden

Implementieren wir die Berechnungsmethoden, mit denen die statistischen Maße für die Regimeerkennung berechnet werden:

void CMarketRegimeDetector::CalculateReturns()
{
    for(int i = 0; i < m_lookbackPeriod - 1; i++)
    {
        // Calculate percentage returns
        if(m_priceData[i] != 0.0)
            m_returns[i] = (m_priceData[i + 1] - m_priceData[i]) / m_priceData[i] * 100.0;
        else
            m_returns[i] = 0.0;
    }
    
    // Update returns statistics
    m_returnsStats.SetData(m_returns, m_lookbackPeriod - 1);
}

void CMarketRegimeDetector::CalculateVolatility()
{
    // Use a rolling window for volatility calculation
    int windowSize = MathMin(20, m_lookbackPeriod - 1);
    
    for(int i = 0; i < m_lookbackPeriod - 1; i++)
    {
        if(i < windowSize - 1)
        {
            m_volatility[i] = 0.0;
            continue;
        }
        
        double sum = 0.0;
        double mean = 0.0;
        
        // Calculate mean
        for(int j = 0; j < windowSize; j++)
            mean += m_returns[i - j];
            
        mean /= windowSize;
        
        // Calculate standard deviation
        for(int j = 0; j < windowSize; j++)
            sum += MathPow(m_returns[i - j] - mean, 2);
            
        m_volatility[i] = MathSqrt(sum / (windowSize - 1));
    }
    
    // Update volatility statistics
    m_volatilityStats.SetData(m_volatility, m_lookbackPeriod - 1);
}

void CMarketRegimeDetector::CalculateTrendStrength()
{
    // Use a rolling window for trend strength calculation
    int windowSize = MathMin(50, m_lookbackPeriod - 1);
    
    for(int i = 0; i < m_lookbackPeriod - 1; i++)
    {
        if(i < windowSize - 1)
        {
            m_trendStrength[i] = 0.0;
            continue;
        }
        
        double window[];
        ArrayResize(window, windowSize);
        
        // Copy data to window
        for(int j = 0; j < windowSize; j++)
            window[j] = m_returns[i - j];
            
        // Create temporary statistics object
        CStatistics tempStats;
        tempStats.SetData(window, windowSize);
        
        // Calculate trend strength using autocorrelation
        m_trendStrength[i] = tempStats.TrendStrength();
    }
    
    // Update price statistics
    m_priceStats.SetData(m_priceData, m_lookbackPeriod);
}
Diese Methoden berechnen die wichtigsten statistischen Maße, die zur Erkennung von Regimen verwendet werden:
  1. CalculateReturns() berechnet aus den Kursdaten prozentuale Renditen, die für statistische Analysen besser geeignet sind als Rohkurse.
  2. CalculateVolatility() verwendet den Ansatz eines Rolling-Windows, um die Standardabweichung der Renditen zu jedem Zeitpunkt zu berechnen und so ein Maß für die Marktvolatilität zu erhalten.
  3. CalculateTrendStrength() verwendet ebenfalls den Ansatz eines Rolling-Windows, erstellt jedoch für jedes Fenster ein temporäres CStatistics-Objekt und verwendet dessen Methode TrendStrength() zur Berechnung der auf einer Autokorrelation basierenden Trendstärke.

Diese rollierenden Berechnungen ermöglichen eine reaktionsschnellere und genauere Bewertung der Marktbedingungen als die Verwendung des gesamten Rückblicks für jede Berechnung.

Regime-Klassifizierung

Das Herzstück unseres Systems ist die Methode DetermineRegime(), die den aktuellen Marktzustand auf der Grundlage statistischer Maße klassifiziert:

ENUM_MARKET_REGIME CMarketRegimeDetector::DetermineRegime()
{
    // Get the latest values
    double latestTrendStrength = m_trendStrength[m_lookbackPeriod - 2];
    double latestVolatility = m_volatility[m_lookbackPeriod - 2];
    
    // Get the average volatility for comparison
    double avgVolatility = 0.0;
    int count = 0;
    
    for(int i = m_lookbackPeriod - 22; i < m_lookbackPeriod - 2; i++)
    {
        if(i >= 0)
        {
            avgVolatility += m_volatility[i];
            count++;
        }
    }
    
    if(count > 0)
        avgVolatility /= count;
    else
        avgVolatility = latestVolatility;
    
    // Determine price direction
    double priceChange = m_priceData[m_lookbackPeriod - 1] - m_priceData[m_lookbackPeriod - m_smoothingPeriod - 1];
    
    // Classify the regime
    if(latestVolatility > avgVolatility * m_volatilityThreshold)
    {
        // Highly volatile market
        return REGIME_VOLATILE;
    }
    else if(MathAbs(latestTrendStrength) > m_trendThreshold)
    {
        // Trending market
        if(priceChange > 0)
            return REGIME_TRENDING_UP;
        else
            return REGIME_TRENDING_DOWN;
    }
    else
    {
        // Ranging market
        return REGIME_RANGING;
    }
}
Mit dieser Methode wird ein hierarchischer Klassifizierungsansatz umgesetzt:
  1. Zunächst wird geprüft, ob der Markt eine hohe Volatilität aufweist, indem die aktuelle Volatilität mit der durchschnittlichen Volatilität der letzten 20 Balken verglichen wird. Wenn die Volatilität den Schwellenwert überschreitet, wird der Markt als volatil eingestuft.
  2. Wenn der Markt nicht volatil ist, wird geprüft, ob ein signifikanter Trend vorliegt, indem die absolute Trendstärke mit der Trendschwelle verglichen wird. Wird ein Trend erkannt, wird die Richtung (aufwärts oder abwärts) auf der Grundlage der Kursveränderung während des Glättungszeitraums bestimmt.
  3. Wird weder eine Volatilität noch ein Trend festgestellt, wird der Markt als schwankend eingestuft.

Dieser hierarchische Ansatz gewährleistet, dass die Volatilität Vorrang vor der Trenderkennung hat, da Trendfolgestrategien in volatilen Märkten besonders anfällig sind.

Zugriffsmethoden

Zum Schluss wollen wir die Zugriffsmethoden implementieren, die Informationen über das aktuelle Marktregime liefern:

string CMarketRegimeDetector::GetRegimeDescription() const
{
    switch(m_currentRegime)
    {
        case REGIME_TRENDING_UP:
            return "Trending Up";
            
        case REGIME_TRENDING_DOWN:
            return "Trending Down";
            
        case REGIME_RANGING:
            return "Ranging";
            
        case REGIME_VOLATILE:
            return "Volatile";
            
        default:
            return "Undefined";
    }
}

double CMarketRegimeDetector::GetTrendStrength() const
{
    if(m_lookbackPeriod <= 2)
        return 0.0;
        
    return m_trendStrength[m_lookbackPeriod - 2];
}

double CMarketRegimeDetector::GetVolatility() const
{
    if(m_lookbackPeriod <= 2)
        return 0.0;
        
    return m_volatility[m_lookbackPeriod - 2];
}

bool CMarketRegimeDetector::GetRegimeBuffer(double &buffer[]) const
{
    if(ArraySize(buffer) < m_lookbackPeriod)
        ArrayResize(buffer, m_lookbackPeriod);
        
    for(int i = 0; i < m_lookbackPeriod; i++)
        buffer[i] = m_regimeBuffer[i];
        
    return true;
}

bool CMarketRegimeDetector::GetTrendStrengthBuffer(double &buffer[]) const
{
    int size = m_lookbackPeriod - 1;
    
    if(ArraySize(buffer) < size)
        ArrayResize(buffer, size);
        
    for(int i = 0; i < size; i++)
        buffer[i] = m_trendStrength[i];
        
    return true;
}

bool CMarketRegimeDetector::GetVolatilityBuffer(double &buffer[]) const
{
    int size = m_lookbackPeriod - 1;
    
    if(ArraySize(buffer) < size)
        ArrayResize(buffer, size);
        
    for(int i = 0; i < size; i++)
        buffer[i] = m_volatility[i];
        
    return true;
}
Diese Methoden ermöglichen den Zugriff auf das aktuelle Regime und seine Merkmale:
  1. GetRegimeDescription() gibt eine für den Menschen lesbare Beschreibung des aktuellen Regimes zurück.
  2. GetTrendStrength() und GetVolatility() geben die aktuellen Werte für Trendstärke und Volatilität zurück.
  3. GetRegimeBuffer(), GetTrendStrengthBuffer() und GetVolatilityBuffer() kopieren die internen Puffer in externe Arrays, was für die Anzeige von Indikatoren nützlich ist.

Mit der Fertigstellung unserer Klasse CMarketRegimeDetector verfügen wir nun über ein leistungsfähiges Instrument zur Erkennung von Marktregimen. Im nächsten Abschnitt werden wir einen nutzerdefinierten Indikator erstellen, der diese Regime direkt auf dem Kurschart visualisiert.


Erstellen eines nutzerdefinierten Indikators für die Regime-Visualisierung

Nachdem wir nun unsere Klasse „Market Regime Detector“ haben, können wir einen nutzerdefinierten Indikator erstellen, der die erkannten Regimes direkt im Preischart anzeigt. Dies bietet den Händlern eine intuitive Möglichkeit, Regimewechsel zu erkennen und ihre Strategien entsprechend anzupassen.

Der MarketRegimeIndicator

Unser nutzerdefinierter Indikator zeigt das aktuelle Marktregime, die Trendstärke und die Volatilität direkt auf dem Chart an. Hier ist die Umsetzung:
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots   3

// Include the Market Regime Detector
#include "MarketRegimeEnum.mqh"
#include "MarketRegimeDetector.mqh"

// Indicator input parameters
input int      LookbackPeriod = 100;       // Lookback period for calculations
input int      SmoothingPeriod = 10;       // Smoothing period for regime transitions
input double   TrendThreshold = 0.2;       // Threshold for trend detection (0.1-0.5) 
input double   VolatilityThreshold = 1.5;  // Threshold for volatility detection (1.0-3.0)

// Indicator buffers
double RegimeBuffer[];        // Buffer for regime classification
double TrendStrengthBuffer[]; // Buffer for trend strength
double VolatilityBuffer[];    // Buffer for volatility

// Global variables
CMarketRegimeDetector *Detector = NULL;
Der Indikator verwendet drei Puffer, um verschiedene Aspekte von Marktregimen zu speichern und anzuzeigen:
  1. RegimeBuffer - Speichert die numerische Darstellung des aktuellen Regimes
  2. TrendStrengthBuffer - Speichert die Werte der Trendstärke
  3. VolatilityBuffer - Speichert die Volatilitätswerte

Initialisierung des Indikators

Die Funktion OnInit() richtet die Indikatorpuffer ein und erstellt den Marktregime-Detektor:

int OnInit()
{
    // Set indicator buffers
    SetIndexBuffer(0, RegimeBuffer, INDICATOR_DATA);
    SetIndexBuffer(1, TrendStrengthBuffer, INDICATOR_DATA);
    SetIndexBuffer(2, VolatilityBuffer, INDICATOR_DATA);
    
    // Set indicator labels
    PlotIndexSetString(0, PLOT_LABEL, "Market Regime");
    PlotIndexSetString(1, PLOT_LABEL, "Trend Strength");
    PlotIndexSetString(2, PLOT_LABEL, "Volatility");
    
    // Set indicator styles
    PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
    PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE);
    PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_LINE);
    
    // Set line colors
    PlotIndexSetInteger(1, PLOT_LINE_COLOR, clrBlue);
    PlotIndexSetInteger(2, PLOT_LINE_COLOR, clrRed);
    
    // Set line styles
    PlotIndexSetInteger(1, PLOT_LINE_STYLE, STYLE_SOLID);
    PlotIndexSetInteger(2, PLOT_LINE_STYLE, STYLE_SOLID);
    
    // Set line widths
    PlotIndexSetInteger(1, PLOT_LINE_WIDTH, 1);
    PlotIndexSetInteger(2, PLOT_LINE_WIDTH, 1);
    
    // Create and initialize the Market Regime Detector
    Detector = new CMarketRegimeDetector(LookbackPeriod, SmoothingPeriod);
    if(Detector == NULL)
    {
        Print("Failed to create Market Regime Detector");
        return INIT_FAILED;
    }
    
    // Configure the detector
    Detector.SetTrendThreshold(TrendThreshold);
    Detector.SetVolatilityThreshold(VolatilityThreshold);
    Detector.Initialize();
    
    // Set indicator name
    IndicatorSetString(INDICATOR_SHORTNAME, "Market Regime Detector");
    
    return INIT_SUCCEEDED;
}
Diese Funktion erfüllt mehrere wichtige Aufgaben:
  1. Sie bindet die Indikatorpuffer an die entsprechenden Arrays
  2. Sie legt die visuellen Eigenschaften des Indikators fest (Beschriftungen, Stile, Farben)
  3. Sie erstellt und konfiguriert den Market Regime Detector mit den vom Nutzer angegebenen Parametern

Die Verwendung von SetIndexBuffer() und verschiedenen PlotIndexSetXXX()-Befehlen ist Standardpraxis bei der Entwicklung von MQL5-Indikatoren. Diese Funktionen konfigurieren, wie der Indikator im Chart angezeigt werden soll.

Berechnung des Indikators

Die Funktion OnCalculate() verarbeitet Kursdaten und aktualisiert die Indikatorpuffer:

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
    // Check if there's enough data
    if(rates_total < LookbackPeriod)
        return 0;
    
    // Process data with the detector
    if(!Detector.ProcessData(close, rates_total))
    {
        Print("Failed to process data with Market Regime Detector");
        return 0;
    }
    
    // Get the regime buffer
    Detector.GetRegimeBuffer(RegimeBuffer);
    
    // Get the trend strength buffer
    Detector.GetTrendStrengthBuffer(TrendStrengthBuffer);
    
    // Get the volatility buffer
    Detector.GetVolatilityBuffer(VolatilityBuffer);
    
    // Display current regime in the chart corner
    string regimeText = "Current Market Regime: " + Detector.GetRegimeDescription();
    string trendText = "Trend Strength: " + DoubleToString(Detector.GetTrendStrength(), 4);
    string volatilityText = "Volatility: " + DoubleToString(Detector.GetVolatility(), 4);
    
    Comment(regimeText + "\n" + trendText + "\n" + volatilityText);
    
    // Return the number of calculated bars
    return rates_total;
}
Diese Funktion:
  1. Prüft, ob genügend Daten für die Berechnung vorhanden sind.
  2. Verarbeitet die Preisdaten mit dem Market Regime Detector.
  3. Ruft die Puffer für Regime, Trendstärke und Volatilität ab.
  4. Zeigt die Informationen zum aktuellen Regime in der Chartecke an.
  5. Gibt die Anzahl der berechneten Balken zurück.

Die Funktion OnCalculate() wird von der Plattform immer dann aufgerufen, wenn neue Kursdaten verfügbar sind oder wenn das Chart gescrollt wird. Er ist für die Aktualisierung der Indikatorpuffer zuständig, die dann auf dem Chart angezeigt werden.

Indikator Cleanup

Die Funktion OnDeinit() sorgt für eine ordnungsgemäße Bereinigung, wenn der Indikator entfernt wird:

void OnDeinit(const int reason)
{
    // Clean up
    if(Detector != NULL)
    {
        delete Detector;
        Detector = NULL;
    }
    
    // Clear the comment
    Comment("");
}

Diese Funktion löscht das Market Regime Detector-Objekt, um Speicherlecks zu vermeiden, und löscht alle Kommentare aus dem Chart. Eine ordnungsgemäße Bereinigung ist bei der MQL5-Programmierung unerlässlich, um sicherzustellen, dass die Ressourcen freigegeben werden, wenn sie nicht mehr benötigt werden.

Interpretation des Indikators

Bei der Verwendung des Market Regime Indicator sollten Händler auf Folgendes achten:
  1. Regime Line: Diese Linie stellt die derzeitige Marktordnung dar. Die Zahlenwerte entsprechen den verschiedenen Regimen:
    • 0: Trending Up
    • 1: Trending Down
    • 2: Ranging
    • 3: Volatile
    • 4: Undefined
  2. Trendstärke-Linie: Diese blaue Linie zeigt die Stärke des Trends. Höhere positive Werte weisen auf stärkere Aufwärtstrends hin, während niedrigere negative Werte stärkere Abwärtstrends anzeigen. Werte nahe Null deuten auf einen schwachen oder keinen Trend hin.
  3. Volatilitätslinie: Diese rote Linie zeigt das aktuelle Volatilitätsniveau. Ausschläge in dieser Linie gehen häufig Regimewechsel voraus und können potenzielle Handelschancen oder -risiken signalisieren.
  4. Kommentar zur Tabelle: Der Indikator zeigt das aktuelle Regime, die Trendstärke und die Volatilitätswerte in der oberen linken Ecke des Charts an, um eine einfache Referenz zu ermöglichen.

Durch die Beobachtung dieser Elemente können die Händler das aktuelle Marktregime schnell erkennen und ihre Strategien entsprechend anpassen. So sollten beispielsweise Trendfolgestrategien während Trendphasen eingesetzt werden, während Strategien der Rückkehr zum Mittelwert in Schwankungsphasen besser geeignet sind. In Zeiten hoher Volatilität könnten Händler erwägen, die Positionsgrößen zu reduzieren oder sich ganz vom Markt fernzuhalten.


Hier können wir deutlich sehen, dass sich der aktuelle Markt in einer Schwankungsbreite befindet, wie wir auch auf dem Chart deutlich erkennen können.


Schlussfolgerung

In diesem Artikel haben wir uns auf den Weg gemacht, um eines der schwierigsten Probleme im algorithmischen Handel zu lösen: die Anpassung an sich ändernde Marktbedingungen. Wir begannen mit der Erkenntnis, dass sich die Märkte im Laufe der Zeit nicht gleichförmig verhalten, sondern zwischen verschiedenen Verhaltenszuständen oder „Regimen“ wechseln. Diese Erkenntnis hat uns dazu veranlasst, ein umfassendes System zur Erkennung von Marktregimen zu entwickeln, mit dem diese Übergänge erkannt werden können. Im nächsten Teil werden wir sehen, wie man Handelsstrategien entsprechend unserer Erkennung von Regimen anpassen kann.

Der Weg vom Problem zur Lösung

Als wir anfingen, stellten wir eine kritische Lücke in den meisten Handelssystemen fest: die Unfähigkeit, Marktbedingungen objektiv zu klassifizieren und sich an sie anzupassen. Herkömmliche Indikatoren und Strategien sind in der Regel für bestimmte Marktbedingungen optimiert, was zu einer uneinheitlichen Performance führt, wenn sich die Märkte weiterentwickeln. Das ist das Problem, mit dem Händler täglich konfrontiert sind - Strategien, die in einem Marktumfeld hervorragend funktionieren, können in einem anderen spektakulär scheitern.

Unsere Lösung für dieses Problem bestand darin, ein robustes System zur Erkennung von Marktregimen von Grund auf zu entwickeln. Wir begannen mit einer soliden statistischen Grundlage und implementierten Schlüsselmaße wie Autokorrelation und Volatilität, die das Marktverhalten objektiv klassifizieren können. Anschließend haben wir eine umfassende Market Regime Detector-Klasse entwickelt, die diese statistischen Maße zur Identifizierung von Trends, Schwankungen und volatilen Marktbedingungen nutzt.

Um dieses System praktisch und zugänglich zu machen, haben wir einen nutzerdefinierten Indikator entwickelt, der Regimewechsel direkt auf dem Preischart anzeigt und Händlern ein unmittelbares visuelles Feedback zu den aktuellen Marktbedingungen gibt. Anschließend haben wir gezeigt, wie man einen adaptiven Expert Advisor erstellt, der automatisch verschiedene Handelsstrategien auf der Grundlage des erkannten Systems auswählt und anwendet.

Im nächsten Teil des Artikels werden wir uns mit praktischen Überlegungen zur Implementierung und Optimierung des Systems befassen, einschließlich der Optimierung von Parametern, der Handhabung von Regimeübergängen und der Integration in bestehende Handelssysteme. Diese praktischen Einblicke werden Ihnen helfen, das Market Regime Detection System effektiv und automatisch in Ihrem eigenen Handel einzusetzen. In der Zwischenzeit spielen Sie mit dem manuellen Ansatz des Indikators herum.


Datei-Übersicht

Hier finden Sie eine Zusammenfassung aller in diesem Artikel erstellten Dateien:
Dateiname Beschreibung
MarketRegimeEnum.mqh
Definiert die im gesamten System verwendeten Aufzählungstypen der Marktordnung
CStatistics.mqh Klasse der statistischen Berechnungen zur Erkennung von Marktordnungen
MarketRegimeDetector.mqh Umsetzung der Kernmarktregelung
MarketRegimeIndicator.mq5 Nutzerdefinierter Indikator zur Visualisierung von Regimen in Charten

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

Letzte Kommentare | Zur Diskussion im Händlerforum (5)
Robert Angers
Robert Angers | 27 Apr. 2025 in 21:12
Ihr Code lässt sich nicht kompilieren.... fehlt IsStrongSignal(value) ...
Sahil Bagdi
Sahil Bagdi | 28 Apr. 2025 in 06:19
Robert Angers #:
Ihr Code lässt sich nicht kompilieren.... fehlt IsStrongSignal(value) ...

Auf welche Datei beziehen Sie sich?

Rau Heru
Rau Heru | 21 Mai 2025 in 12:48

Der Marktregime-Indikator weist 24 Fehler und 1 Warnung auf, wenn ich versuche, ihn zu kompilieren:

'MarketRegimeIndicator.mq5' 1

Datei 'C:\Users\rauma\AppData\Roaming\MetaQuotes\Terminal\10CE948A1DFC9A8C27E56E827008EBD4\MQL5\Include\MarketRegimeEnum.mqh' nicht gefunden MarketRegimeIndicator.mq5 14 11

Datei 'C:\Benutzer\rauma\AppData\Roaming\MetaQuotes\Terminal\10CE948A1DFC9A8C27E56E827008EBD4\MQL5\Include\MarketRegimeDetector.mqh' nicht gefunden MarketRegimeIndicator.mq5 15 11

'CMarketRegimeDetector' - unerwartetes Token, wahrscheinlich fehlt der Typ? MarketRegimeIndicator.mq5 29 1

'*' - Semikolon erwartet MarketRegimeIndicator.mq5 29 23

'Detector' - nicht deklarierter Bezeichner MarketRegimeIndicator.mq5 64 5

'CMarketRegimeDetector' - Deklaration ohne Typ MarketRegimeIndicator.mq5 64 20

CMarketRegimeDetector' - Klassentyp erwartet MarketRegimeIndicator.mq5 64 20

Funktion nicht definiert MarketRegimeIndicator.mq5 64 20

'new' - Ausdruck vom Typ 'void' ist illegal MarketRegimeIndicator.mq5 64 16

'=' - Verwendung einer illegalen Operation MarketRegimeIndicator.mq5 64 14

'Detector' - nicht deklarierter Bezeichner MarketRegimeIndicator.mq5 65 8

'==' - illegale Operation MarketRegimeIndicator.mq5 65 17

Detector' - nicht deklarierter Bezeichner MarketRegimeIndicator.mq5 72 5

Detektor' - nicht deklarierter Bezeichner MarketRegimeIndicator.mq5 73 5

Detektor' - nicht deklarierter Bezeichner MarketRegimeIndicator.mq5 74 5

Detektor' - nicht deklarierter Bezeichner MarketRegimeIndicator.mq5 101 9

';' - unerwartetes Token MarketRegimeIndicator.mq5 103 68

'(' - unausgewogene linke Klammer MarketRegimeIndicator.mq5 101 7

leere kontrollierte Anweisung gefunden MarketRegimeIndicator.mq5 103 68

'Detector' - nicht deklarierter Bezeichner MarketRegimeIndicator.mq5 133 8

'!=' - illegale Operation MarketRegimeIndicator.mq5 133 17

'Detector' - nicht deklarierter Bezeichner MarketRegimeIndicator.mq5 135 16

'Detector' - Objektzeiger erwartet MarketRegimeIndicator.mq5 135 16

Detektor' - nicht deklarierter Bezeichner MarketRegimeIndicator.mq5 136 9

'=' - unzulässige Verwendung einer Operation MarketRegimeIndicator.mq5 136 18

24 Fehler, 1 Warnung 25 2


Rashid Umarov
Rashid Umarov | 21 Mai 2025 in 13:02
Rau Heru #:

Der Marktregime-Indikator hat 24 Fehler und 1 Warnung, wenn ich versuche, ihn zu kompilieren:

'MarketRegimeIndicator.mq5' 1

Datei 'C:\Benutzer\rauma\AppData\Roaming\MetaQuotes\Terminal\10CE948A1DFC9A8C27E56E827008EBD4\MQL5\Include\MarketRegimeEnum.mqh' nicht gefunden MarketRegimeIndicator.mq5 14 11

Datei 'C:\Benutzer\rauma\AppData\Roaming\MetaQuotes\Terminal\10CE948A1DFC9A8C27E56E827008EBD4\MQL5\Include\MarketRegimeDetector.mqh' nicht gefunden MarketRegimeIndicator.mq5 15 11

Der Indikator sucht nach diesen Dateien im Ordner C:\Users\rauma\AppData\Roaming\MetaQuotes\Terminal\10CE948A1DFC9A8C27E56E827008EBD4\MQL5\Include\

#property copyright "Sahil Bagdi"
#property link      "https://www.mql5.com/de/users/sahilbagdi"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots   3

// Den Marktregime-Detektor einbeziehen
#include <MarketRegimeEnum.mqh>
#include <MarketRegimeDetector.mqh>
Yoshiteru Taneda
Yoshiteru Taneda | 17 Juli 2025 in 10:56
Sahil Bagdi #:

Auf welche Datei beziehen Sie sich?

MarketRegimeDetector.mqh

bei Zeile 472

Ich nehme an, Sie beziehen sich auf

IsStrongSignal' - nicht deklarierter Bezeichner MarketRegimeDetector.mqh 472 16

'strategySignal' - irgendein Operator erwartet MarketRegimeDetector.mqh 472 31

Websockets für MetaTrader 5: Asynchrone Client-Verbindungen mit dem Windows-API Websockets für MetaTrader 5: Asynchrone Client-Verbindungen mit dem Windows-API
Dieser Artikel beschreibt die Entwicklung einer nutzerdefinierten, dynamisch gelinkten Bibliothek, die asynchrone Websocket-Client-Verbindungen für MetaTrader-Programme ermöglicht.
Datenwissenschaft und ML (Teil 36): Der Umgang mit verzerrten Finanzmärkten Datenwissenschaft und ML (Teil 36): Der Umgang mit verzerrten Finanzmärkten
Die Finanzmärkte sind nicht vollkommen ausgeglichen. Einige Märkte steigen, andere fallen, und wieder andere zeigen ein gewisses Schwankungsverhalten, das auf Unsicherheit in beide Richtungen hindeutet. Diese unausgewogenen Informationen können beim Trainieren von Machine-Learning-Modellen irreführend sein, da sich die Märkte häufig ändern. In diesem Artikel werden wir verschiedene Möglichkeiten erörtern, dieses Problem zu lösen.
Datenwissenschaft und ML (Teil 37): Mit Kerzenmustern und AI den Markt schlagen Datenwissenschaft und ML (Teil 37): Mit Kerzenmustern und AI den Markt schlagen
Kerzenmuster helfen Händlern, die Marktpsychologie zu verstehen und Trends auf den Finanzmärkten zu erkennen. Sie ermöglichen fundiertere Handelsentscheidungen, die zu besseren Ergebnissen führen können. In diesem Artikel werden wir untersuchen, wie man Kerzenmuster mit KI-Modellen nutzen kann, um eine optimale Handelsperformance zu erzielen.
Erstellen von dynamischen MQL5-Grafikschnittstellen durch ressourcengesteuerte Bildskalierung mit bikubischer Interpolation auf Handelscharts Erstellen von dynamischen MQL5-Grafikschnittstellen durch ressourcengesteuerte Bildskalierung mit bikubischer Interpolation auf Handelscharts
In diesem Artikel erforschen wir dynamische MQL5-Grafikschnittstellen, die bikubische Interpolation für hochwertige Bildskalierung auf Handelscharts verwenden. Wir stellen flexible Positionierungsoptionen vor, die eine dynamische Zentrierung oder Eckverankerung mit nutzerdefinierten Versätzen ermöglichen.