English 日本語
preview
Der MQL5-Standardbibliotheks-Explorer (Teil 9): Verwendung von ALGLIB zur Filterung übermäßiger MA-Crossover-Signale

Der MQL5-Standardbibliotheks-Explorer (Teil 9): Verwendung von ALGLIB zur Filterung übermäßiger MA-Crossover-Signale

MetaTrader 5Beispiele |
20 0
Clemence Benjamin
Clemence Benjamin

Inhalt:


Einführung

Das Kreuzen zweier gleitender Durchschnitte ist wahrscheinlich die erste Strategie, die jeder Händler ausprobiert. Ein schneller MA, der einen langsamen MA nach oben kreuzt, signalisiert „Kauf“, und die umgekehrte Konstellation signalisiert „Verkauf“. Es ist einfach, intuitiv und in Trendmärkten überraschend effektiv. Das Problem tritt auf, wenn sich der Markt seitwärts bewegt: Der Kurs oszilliert um die Durchschnitte, die Linien kreuzen sich wiederholt, und wir erhalten eine Reihe von Verlustgeschäften – die berüchtigten Whipsaws.

Viele Händler versuchen, dies durch eine Erhöhung der Perioden (was die Durchschnitte glatter, aber langsamer macht) oder durch das Hinzufügen von Filtern (RSI, ADX usw.) zu beheben. Diese Ansätze können helfen, bleiben aber heuristische Anpassungen, die auf die ursprüngliche Struktur aufgesetzt sind.

ALGLIB ist eine plattformübergreifende Bibliothek für numerische Analyse, die fortgeschrittene mathematische Berechnungen direkt in MetaTrader 5 Indikatoren und Expert Advisors bringt. Ursprünglich für C++, C# und Python entwickelt, wurde ALGLIB als Teil der Standardbibliothek von MQL5 portiert und bietet uns Zugriff auf Hunderte von optimierten Algorithmen für lineare Algebra, Optimierung, Signalverarbeitung und Datenanalyse.

Für diejenigen, die sich von fortgeschrittener Mathematik eingeschüchtert fühlen könnten, besteht kein Grund zur Sorge. Wir beginnen mit einfachen Konzepten und bauen schrittweise darauf auf. ALGLIB übernimmt die schweren numerischen Berechnungen intern – wir müssen nur konzeptionell verstehen, was jede Funktion bewirkt. Stellen Sie es sich wie das Fahren eines Autos vor: Sie müssen keine Thermodynamik verstehen können, um das Gaspedal zu drücken.

In diesem Artikel werden wir einen einfachen gleitenden Durchschnitts-Crossover in ein mathematisch vorverarbeitetes System umwandeln, wobei wir drei ALGLIB-Techniken verwenden:

  • grundlegende statistische Filter,
  • Singuläre Spektralanalyse (SSA) und
  • splinebasierte Ableitungsanalyse.

Am Ende werden Sie sehen, wie mathematische Vorverarbeitung die Signalfrequenz in Seitwärtsmärkten reduzieren kann, während die Reaktionsfähigkeit bei Trends erhalten bleibt.


Konzept

ALGLIB ist eine Bibliothek für numerische Analyse, die über Jahrzehnte entwickelt wurde. Sie bietet optimierte Implementierungen von Algorithmen, deren Programmierung von Grund auf erhebliche Zeit in Anspruch nehmen würde. In ihrem umfangreichen Funktionsspektrum finden Sie Werkzeuge für:

  • Lineare Algebra – Matrixoperationen, Zerlegungen, Gleichungslöser
  • Optimierung – eingeschränkte und uneingeschränkte Minimierung
  • Interpolation und Anpassung – Splines, kleinste Quadrate, rationale Approximationen
  • Datenanalyse – Clustering, Hauptkomponentenanalyse
  • Signalverarbeitung – FFT, Faltung, Filterung
  • Statistik – Verteilungen, Hypothesentests, Korrelationsanalyse

ALGLIB arbeitet primär mit spezialisierten Strukturen wie CRowDouble für eindimensionale Arrays und CMatrixDouble für Matrizen. Diese können in native MQL5-Vektor- und Matrixtypen und zurück konvertiert werden.

Grundlegende Filter (SMA, EMA, LRMA)

ALGLIB bietet gebrauchsfertige Filterfunktionen, die effizienter und numerisch stabiler sind als manuelle Implementierungen. FilterSMA berechnet einen einfachen gleitenden Durchschnitt unter Verwendung laufender Summen mit Überlaufschutz. FilterEMA implementiert den exponentiellen gleitenden Durchschnitt mit präziser Koeffizientenhandhabung. FilterLRMA führt über ein gleitendes Fenster eine lineare Regression aus – im Wesentlichen wird eine gerade Linie an die letzten K Punkte angepasst und der Wert am aktuellen Datenpunkt zurückgegeben. 

Die Mathematik hinter LRMA ist besonders interessant: Für jedes Fenster wird eine einfache lineare Regression y = a + b*x berechnet, wobei x die Position innerhalb des Fensters darstellt. Der Wert am aktuellen Datenpunkt ist dann a + b*(window‑1). Dies ergibt einen Filter, der schneller auf lineare Trends reagiert als ein einfacher Durchschnitt.

Der Ausgabewert am jüngsten Datenpunkt wird aus der Regressionsgeraden berechnet, wodurch er reaktionsschneller auf Trends reagiert als ein einfacher gleitender Durchschnitt.

Singuläre Spektralanalyse (SSA)

SSA zerlegt eine Zeitreihe in strukturelle Komponenten wie Trend, Zyklen und Rauschen. Dies funktioniert durch den Aufbau einer Trajektorienmatrix, die Durchführung einer Singulärwertzerlegung (SVD) und die Rekonstruktion ausgewählter Komponenten. Konzeptionell trennt sie längerfristige Strukturen von kurzfristigen Schwankungen.

Das CSSAModel von ALGLIB verwaltet den Prozess intern durch die Angabe einer Fenstergröße und eines Rekonstruktionsrangs.

Spline-Interpolation und Ableitungen

Ein kubischer Spline ist ein glattes stückweises Polynom, das durch Datenpunkte mit stetigen ersten und zweiten Ableitungen verläuft. Die erste Ableitung stellt die momentane Änderungsrate dar. Nulldurchgänge der Ableitung können auf Richtungswechsel hinweisen.

Wir vergleichen vier Ansätze:

  • Baseline – EMA-Crossover auf Basis der Rohkursen
  • Grundlegend gefiltert – EMA-Crossover von vorgeglätteten Kursen
  • SSA-gefiltert – EMA-Crossover auf Basis des SSA-Trends
  • Spline-Ableitung – Nulldurchgänge als Richtungssignale

Durch die Implementierung aller vier in einem einzigen Indikator können wir ihr Verhalten visuell vergleichen und sehen, wie sich die Vorverarbeitung auf das Signal-Timing und die Zuverlässigkeit auswirkt.


Umsetzung

Jetzt erstellen wir unseren Indikator Schritt für Schritt. Starten Sie den MetaEditor, erstellen Sie einen neuen Indikator und lassen Sie uns in den Code eintauchen. Wir nennen ihn ALGLIB_FilterDemo.mq5. Dieser Indikator wurde entwickelt, um mehrere fortschrittliche Filtertechniken zu demonstrieren, die von der numerischen Bibliothek ALGLIB bereitgestellt werden. Durch die Anwendung verschiedener Filter auf dieselbe Kursreihe können wir deren Glättungseigenschaften und deren Auswirkung auf ein einfaches Crossover-Handelssystem vergleichen. Das endgültige Chart zeigt mehrere Linien – jede repräsentiert eine andere gefilterte Version des Kurses – zusammen mit Crossover-Signalen, die sowohl aus den auf Rohkursen berechneten gleitenden Durchschnitten als auch aus den gefilterten Zeitreihen generiert werden.

Schritt 1: Einrichtung des Frameworks

Zuerst müssen wir die ALGLIB-Bibliothek einbinden und unsere Indikatoreigenschaften definieren. Die #include <Math/Alglib/alglib.mqh> Direktive bindet alle notwendigen ALGLIB-Funktionen für Filterung, SSA, Splines und lineare Algebra ein. Die #property Anweisungen legen das grundlegende Verhalten des Indikators fest: Er wird im Hauptchartfenster ( indicator_chart_window ) gezeichnet, und wir weisen zehn Puffer und zehn Plots zu. Die Zuweisung von zehn Puffern ermöglicht es uns, den ursprünglichen Kurs, drei Baseline-EMAs (obwohl wir nur zwei für das Crossover verwenden), fünf gefilterte Reihen und zwei Sätze von Crossover-Signalen zu speichern und anzuzeigen. All diese Linien gleichzeitig im Chart zu haben, mag überladen wirken, aber es ermöglicht einen unmittelbaren visuellen Vergleich, wie jeder Filter die Kursdaten aufbereitet.

//+------------------------------------------------------------------+
//|                                            ALGLIB_FilterDemo.mq5 |
//|                                Copyright 2026, Clemence Benjamin |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 10
#property indicator_plots   10

//--- include ALGLIB
#include <Math/Alglib/alglib.mqh>

Die Einstellung von indicator_buffers und indicator_plots auf 10 bedeutet, dass wir zehn Linien oder Markierungen in unserem Chart haben werden. Das ist eine Menge, aber wir möchten zum Vergleich alles auf einmal sehen.

Schritt 2: Definition der Plot-Eigenschaften

Jeder Plot benötigt eine Kennzeichnung, einen Typ, eine Farbe und einen Stil. Wir verwenden Linien für die kontinuierlichen Reihen und Pfeile für Crossover-Signale. Die Kennzeichnungen erscheinen im Datenfenster und helfen dabei, jede Linie zu identifizieren. Durch die Zuweisung unterschiedlicher Farben – Schwarz für den ungefilterten Schlusskurs, Blau/Rot für die Baseline-EMAs, Grün für SMA-gefiltert, Dodger-Blau für EMA-gefiltert, Orange für LRMA-gefiltert, Magenta für den SSA-Trend und Braun für die skalierte Spline-Ableitung – machen wir den Chart lesbar. Die Plots 9 und 10 sind Pfeil-Plots; sie erscheinen nur dort, wo ein Crossover auftritt, und markieren potenzielle Kauf- (unter der Bar) und Verkaufspunkte (über der Bar). Der Pfeil-Code und der leere Wert werden später in OnInit festgelegt.

//--- plot definitions
#property indicator_label1  "Close"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrBlack
#property indicator_width1  1

#property indicator_label2  "Baseline Fast EMA"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrBlue
#property indicator_width2  1

#property indicator_label3  "Baseline Slow EMA"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrRed
#property indicator_width3  1

#property indicator_label4  "SMA Filtered"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrGreen
#property indicator_width4  1

#property indicator_label5  "EMA Filtered"
#property indicator_type5   DRAW_LINE
#property indicator_color5  clrDodgerBlue
#property indicator_width5  1

#property indicator_label6  "LRMA Filtered"
#property indicator_type6   DRAW_LINE
#property indicator_color6  clrOrange
#property indicator_width6  1

#property indicator_label7  "SSA Trend"
#property indicator_type7   DRAW_LINE
#property indicator_color7  clrMagenta
#property indicator_width7  1

#property indicator_label8  "Spline Derivative (scaled)"
#property indicator_type8   DRAW_LINE
#property indicator_color8  clrBrown
#property indicator_width8  1

#property indicator_label9  "Baseline Crossover Signals"
#property indicator_type9   DRAW_ARROW
#property indicator_color9  clrBlue
#property indicator_width9  1

#property indicator_label10 "Filtered Crossover Signals"
#property indicator_type10  DRAW_ARROW
#property indicator_color10 clrRed
#property indicator_width10 1

Beachten Sie, dass die Plots 9 und 10 Pfeile sind. Wir verwenden diese, um Kauf- und Verkaufssignale zu markieren.

Schritt 3: Eingabe-Parameter

Wir möchten, dass Benutzer alle wichtigen Parameter anpassen können. Definieren wir sie:

//--- input parameters
input int      FastMAPeriod   = 5;           // Fast MA period
input int      SlowMAPeriod   = 20;          // Slow MA period
input int      FilterWindow   = 14;          // Window for SMA/LRMA and EMA alpha (alpha=2/(period+1))
input int      SSAWindow       = 30;          // Window for SSA (must be < data length)
input int      SSARank         = 5;           // Number of SSA components to keep (rank)
input double   SplineDerivScale= 10.0;        // Scaling factor for spline derivative (for visibility)
input int      LookbackBars    = 500;         // Number of recent bars to process (speed optimization)

Der Parameter LookbackBars ist entscheidend für die Performance. ALGLIB-Operationen, insbesondere SSA, können bei Tausenden Bars rechenintensiv sein. Indem wir nur die aktuellsten Bars verarbeiten (standardmäßig 500), halten wir den Indikator reaktionsfähig und zeigen dennoch ausreichend Historie an. Jeder Eingabeparameter steuert einen spezifischen Aspekt des Indikators: Der Baseline-Crossover verwendet FastMAPeriod und SlowMAPeriod; FilterWindow bestimmt die Länge der einfachen, exponentiellen und linearen gleitenden Durchschnitte, die auf den Kurs angewendet werden; SSAWindow legt die Fensterlänge für die Trajektorienmatrix bei der singulären Spektralanalyse fest, und SSARank wählt aus, wie viele der größten Eigenwerte für die Rekonstruktion des Trends beibehalten werden; SplineDerivScale multipliziert einfach die Ableitung, damit sie beim Plotten sichtbar wird; und LookbackBars begrenzt die Anzahl der Bars, die den ALGLIB-Routinen zugeführt werden.

Schritt 4: Deklaration der Puffer

Wir benötigen zehn Puffer, um unsere Daten zu speichern:

//--- indicator buffers
double closeBuffer[];
double baselineFastBuffer[];
double baselineSlowBuffer[];
double smaFilteredBuffer[];
double emaFilteredBuffer[];
double lrmaFilteredBuffer[];
double ssaTrendBuffer[];
double splineDerivBuffer[];
double baselineSignalBuffer[];
double filteredSignalBuffer[];

Jeder Puffer entspricht einem der zuvor definierten Plots. Der closeBuffer enthält die ungefilterten Schlusskurse; baselineFastBuffer und baselineSlowBuffer werden durch die integrierte iMA-Funktion gefüllt; smaFilteredBuffer, emaFilteredBuffer und lrmaFilteredBuffer enthalten die Ergebnisse der Anwendung der jeweiligen ALGLIB-Filter; ssaTrendBuffer speichert den SSA-rekonstruierten Trend; splineDerivBuffer speichert den Kurs zuzüglich einer skalierten Ableitung; und die beiden Signalpuffer enthalten die Pfeilpositionen für Crossover. Alle Puffer werden als dynamische Arrays deklariert; ihre Größe wird vom Terminal verwaltet.

Schritt 5: Handles für integrierte gleitende Durchschnitte

Für den Baseline-Crossover verwenden wir die integrierte iMA-Funktion von MQL5. Diese ist bereits optimiert und dient als unsere Referenz:

//--- handles for built-in iMA (for baseline)
int fastMAHandle, slowMAHandle;

Die Verwendung von iMA-Handles ist effizient, da das Terminal die gleitenden Durchschnitte intern berechnet und die Ergebnisse zwischenspeichert. Diese Handles werden in OnInit erstellt und in OnDeinit freigegeben.

Schritt 6: Initialisierungsfunktion

In OnInit() richten wir unsere Puffer ein, konfigurieren die Pfeilstile und erstellen die MA-Handles:

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   //--- set index buffers
   SetIndexBuffer(0, closeBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, baselineFastBuffer, INDICATOR_DATA);
   SetIndexBuffer(2, baselineSlowBuffer, INDICATOR_DATA);
   SetIndexBuffer(3, smaFilteredBuffer, INDICATOR_DATA);
   SetIndexBuffer(4, emaFilteredBuffer, INDICATOR_DATA);
   SetIndexBuffer(5, lrmaFilteredBuffer, INDICATOR_DATA);
   SetIndexBuffer(6, ssaTrendBuffer, INDICATOR_DATA);
   SetIndexBuffer(7, splineDerivBuffer, INDICATOR_DATA);
   SetIndexBuffer(8, baselineSignalBuffer, INDICATOR_DATA);
   SetIndexBuffer(9, filteredSignalBuffer, INDICATOR_DATA);

   //--- set arrow codes (159 = small circle)
   PlotIndexSetInteger(8, PLOT_ARROW, 159);
   PlotIndexSetInteger(9, PLOT_ARROW, 159);
   PlotIndexSetDouble(8, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(9, PLOT_EMPTY_VALUE, EMPTY_VALUE);

   //--- indicator short name
   IndicatorSetString(INDICATOR_SHORTNAME, "ALGLIB Filter Demo (Optimized)");

   //--- get handles for baseline MAs
   fastMAHandle = iMA(_Symbol, _Period, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   slowMAHandle = iMA(_Symbol, _Period, SlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   if(fastMAHandle == INVALID_HANDLE || slowMAHandle == INVALID_HANDLE)
      return(INIT_FAILED);

   return(INIT_SUCCEEDED);
}

Der Pfeilcode 159 ergibt einen kleinen Kreis. Wir setzen leere Werte für die Signalpuffer, damit sie nur dann gezeichnet werden, wenn wir explizit einen Wert festlegen. Durch die Zuweisung von INDICATOR_DATA an jeden Puffer teilen wir dem Terminal mit, dass diese Arrays die anzuzeigenden Werte enthalten. Die Handles für die exponentiellen gleitenden Durchschnitte der Baseline werden mit den vom Benutzer gewählten Perioden unter Verwendung des aktuellen Symbols und Zeitrahmens erstellt. Wenn eines der Handles fehlschlägt, wird die Indikatorinitialisierung abgebrochen.

Schritt 7: Deinitialisierung

Geben Sie die Handles nach der Verwendung stets frei:

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   if(fastMAHandle != INVALID_HANDLE)  IndicatorRelease(fastMAHandle);
   if(slowMAHandle != INVALID_HANDLE)  IndicatorRelease(slowMAHandle);
}

Das Freigeben der Handles ist eine bewährte Methode, um die vom Terminal zugewiesenen Ressourcen freizugeben. Obwohl das Terminal dies automatisch tut, wenn der Indikator entfernt wird, macht eine explizite Freigabe den Code robust und portabel.

Schritt 8: Hilfsfunktionen für Filter

Um unseren Code sauber zu halten, erstellen wir Hilfsfunktionen, die die Konvertierung zwischen MQL5-Vektoren und ALGLIBs CRowDouble kapseln:

//+------------------------------------------------------------------+
//| Helper to convert vector to CRowDouble and back after filter     |
//+------------------------------------------------------------------+
void ApplySMA(vector<double> &data, int window)
{
   CRowDouble row(data);
   CAlglib::FilterSMA(row, (int)data.Size(), window);
   data = row.ToVector();
}

void ApplyEMA(vector<double> &data, int window)
{
   double alpha = 2.0 / (window + 1.0);
   CRowDouble row(data);
   CAlglib::FilterEMA(row, (int)data.Size(), alpha);
   data = row.ToVector();
}

void ApplyLRMA(vector<double> &data, int window)
{
   CRowDouble row(data);
   CAlglib::FilterLRMA(row, (int)data.Size(), window);
   data = row.ToVector();
}

Diese Funktionen nehmen einen Vektor als Referenz entgegen, konvertieren ihn in ein CRowDouble, wenden den Filter an und konvertieren ihn zurück. Dieses Muster ist essenziell, da ALGLIB mit CRowDouble-Objekten arbeitet, wir aber den Komfort des MQL5-Vektortyps nutzen möchten. Die Funktionen modifizieren den ursprünglichen Vektor direkt, was unnötiges Kopieren vermeidet und den Hauptcode lesbarer macht. Beachten Sie, dass der EMA-Filter die Glättungskonstante Alpha erfordert, die mithilfe der Standardformel Alpha = 2/(Periode+1) aus der Fensterlänge abgeleitet wird.

Schritt 9: Die Hauptschleife der Berechnung

Nun zum Herzstück unseres Indikators – der OnCalculate-Funktion. Hier geschieht die gesamte ALGLIB-Magie. Ich werde sie abschnittsweise erläutern.

Bestimmung des Verarbeitungsbereichs

Zuerst entscheiden wir basierend auf LookbackBars, welche Bars verarbeitet werden sollen:

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
{
   //--- Determine the range of bars we need to process
   int startIdx = (rates_total > LookbackBars) ? rates_total - LookbackBars : 0;
   int len = rates_total - startIdx;

Diese elegante Zeile berechnet den Startindex. Wenn wir mehr Bars als LookbackBars haben, beginnen wir LookbackBars vom Ende an; andernfalls beginnen wir bei Bar 0. Dies stellt sicher, dass wir nur eine überschaubare Anzahl von Bars in die ALGLIB-Routinen übergeben. Die Länge len ist die Anzahl der Bars, die wir tatsächlich mit Filtern verarbeiten werden.

Validierung der Daten

Wir müssen sicherstellen, dass wir genügend Bars für den längsten Zeitraum haben, den wir verwenden werden:

   //--- Need enough data for the longest period
   int maxPeriod = MathMax(SlowMAPeriod, MathMax(FilterWindow, SSAWindow));
   if(len < maxPeriod)
   {
      // Not enough bars in the lookback window – fill with EMPTY and return
      for(int i = startIdx; i < rates_total; i++)
      {
         smaFilteredBuffer[i] = EMPTY_VALUE;
         emaFilteredBuffer[i] = EMPTY_VALUE;
         lrmaFilteredBuffer[i] = EMPTY_VALUE;
         ssaTrendBuffer[i]    = EMPTY_VALUE;
         splineDerivBuffer[i] = EMPTY_VALUE;
      }
      ArrayInitialize(baselineSignalBuffer, EMPTY_VALUE);
      ArrayInitialize(filteredSignalBuffer, EMPTY_VALUE);
      return(rates_total);
   }

Wenn das Lookback-Fenster zu kurz ist, füllen wir alles mit leeren Werten und kehren zurück. Dies verhindert, dass der Indikator unvollständige oder falsche Daten darstellt. Der maxPeriod nimmt den größten der drei Schlüsselzeiträume (langsamer MA, Filterfenster, SSA-Fenster), um zu garantieren, dass alle Filter über genügend Daten verfügen, um ein aussagekräftiges Ergebnis zu liefern.

Grundlegende Datenkopierung

Wir kopieren die Schlusskurse in unseren ersten Puffer (zur Anzeige) und rufen die Baseline-MAs ab:

   //--- Copy close prices to buffer 0 (for plotting)
   for(int i = 0; i < rates_total; i++)
      closeBuffer[i] = close[i];

   //--- Get baseline MAs (they already cover all bars)
   if(CopyBuffer(fastMAHandle, 0, 0, rates_total, baselineFastBuffer) <= 0) return(0);
   if(CopyBuffer(slowMAHandle, 0, 0, rates_total, baselineSlowBuffer) <= 0) return(0);

Die Schlusskurse werden einfach in den ersten Puffer gespiegelt. Die beiden Baseline-EMA-Puffer werden durch Kopieren aus den iMA-Handles gefüllt. Da diese Handles Werte für jede Bar enthalten, kopieren wir den gesamten Bereich. Wenn das Kopieren fehlschlägt (gibt <= 0 zurück), beenden wir den Vorgang vorzeitig.

Aufbereitung des Datenvektors

Wir erstellen einen Vektor, der nur die Kurse enthält, die wir verarbeiten werden:

   //--- Create a vector of close prices for the lookback window
   vector<double> vecClose(len);
   for(int i = 0; i < len; i++)
      vecClose[i] = close[startIdx + i];

Dieser Vektor, vecClose, enthält die Kursdaten, die in alle ALGLIB-Filter eingespeist werden. Durch die Arbeit an einem zusammenhängenden Segment des Kurs-Arrays vermeiden wir die Übergabe riesiger Arrays und reduzieren den Speicher- und Rechenaufwand.

Anwendung grundlegender Filter

Nun wenden wir jeden Filter mithilfe unserer Hilfsfunktionen an:

   //--- 1) SMA Filter
   vector<double> vecSMA = vecClose;
   ApplySMA(vecSMA, FilterWindow);
   for(int i = 0; i < len; i++)
      smaFilteredBuffer[startIdx + i] = vecSMA[i];

   //--- 2) EMA Filter
   vector<double> vecEMA = vecClose;
   ApplyEMA(vecEMA, FilterWindow);
   for(int i = 0; i < len; i++)
      emaFilteredBuffer[startIdx + i] = vecEMA[i];

   //--- 3) LRMA Filter
   vector<double> vecLRMA = vecClose;
   ApplyLRMA(vecLRMA, FilterWindow);
   for(int i = 0; i < len; i++)
      lrmaFilteredBuffer[startIdx + i] = vecLRMA[i];

Beachten Sie, wie jeder Filter seine eigene Kopie der Daten modifiziert. Der ursprüngliche vecClose bleibt für nachfolgende Operationen unverändert. Die gefilterten Ergebnisse werden dann an den korrekten Indizes ( startIdx + i ) in die entsprechenden Puffer platziert. Der einfache gleitende Durchschnitt (SMA) gewichtet alle Kurse im Fenster gleich; der exponentielle gleitende Durchschnitt (EMA) gewichtet aktuelle Kurse stärker; und der lineare Regressions-Gleitdurchschnitt (LRMA) passt eine gerade Linie an die Daten an und verwendet den Endpunkt als gefilterten Wert. Diese drei Filter sind etablierte und dienen als Basis für den Vergleich mit den fortgeschritteneren SSA- und Spline-Methoden.

Singuläre Spektralanalyse

Dies ist der anspruchsvollste Teil. Wir erstellen ein SSA-Modell, fügen unsere Daten hinzu, konfigurieren es und extrahieren den Trend:

   //--- 4) SSA Trend
   CSSAModel ssa;
   CAlglib::SSACreate(ssa);
   CRowDouble priceRow(vecClose);                     // convert once
   CAlglib::SSAAddSequence(ssa, priceRow);
   CAlglib::SSASetAlgoTopKRealtime(ssa, SSARank);
   CAlglib::SSASetWindow(ssa, SSAWindow);
   CRowDouble trend, noise;
   CAlglib::SSAAnalyzeLast(ssa, len, trend, noise);

   if(trend.Size() == len)
   {
      vector<double> vecTrend = trend.ToVector();
      for(int i = 0; i < len; i++)
         ssaTrendBuffer[startIdx + i] = vecTrend[i];
   }
   else
   {
      for(int i = 0; i < len; i++)
         ssaTrendBuffer[startIdx + i] = EMPTY_VALUE;
   }

Die entscheidende Zeile ist SSASetAlgoTopKRealtime(ssa, SSARank). Dies weist SSA an, die führenden SSARank-Komponenten (größte Eigenwerte) für die Rekonstruktion zu verwenden. Indem wir nur die größten Komponenten beibehalten, filtern wir im Wesentlichen das Rauschen heraus. Die Fenstergröße SSAWindow bestimmt, wie viele vergangene Punkte beim Aufbau der Trajektorienmatrix berücksichtigt werden – ein größeres Fenster erfasst längerfristige Muster, erfordert jedoch mehr Daten. Nach der Analyse prüfen wir, ob der Trend die erwartete Länge aufweist. Falls SSA fehlschlägt (was bei unzureichenden Daten oder numerischen Problemen vorkommen kann), füllen wir mit leeren Werten auf. Die resultierende Trendlinie sollte glatter sein als jeder der einfachen gleitenden Durchschnitte und kann zugrunde liegende zyklische Komponenten aufdecken.

Berechnung der Spline-Ableitung

Für die Spline-Ableitung benötigen wir eine x-Achse, die die Barindizes repräsentiert:

   //--- 5) Spline derivative
   // X axis = bar index within the lookback window (0..len-1)
   vector<double> xVec(len);
   for(int i = 0; i < len; i++) xVec[i] = i;

   vector<double> priceVec = priceRow.ToVector();   // already from vecClose

   double xArr[], priceArr[];
   ArrayResize(xArr, len);
   ArrayResize(priceArr, len);
   for(int i = 0; i < len; i++)
   {
      xArr[i] = xVec[i];
      priceArr[i] = priceVec[i];
   }

   CSpline1DInterpolantShell spline;
   CAlglib::Spline1DBuildCubic(xArr, priceArr, len, 0, 0.0, 0, 0.0, spline);

Wir konvertieren unsere Vektoren in einfache Arrays, da Spline1DBuildCubic double-Parameter erwartet. Die Randbedingungsparameter (0, 0.0, 0, 0.0) spezifizieren einen natürlichen kubischen Spline mit verschwindenden zweiten Ableitungen an den Enden – eine Standardwahl, die für die meisten Kursreihen gut funktioniert. Der Spline-Interpolant wird dann in spline gespeichert.

Nun berechnen wir die Ableitung an jedem Punkt:

   for(int i = 0; i < len; i++)
   {
      double val, deriv, deriv2;
      CAlglib::Spline1DDiff(spline, i, val, deriv, deriv2);
      splineDerivBuffer[startIdx + i] = close[startIdx + i] + deriv * SplineDerivScale;
   }

Wir addieren die skalierte Ableitung zum tatsächlichen Kurs, sodass die Linie in der Nähe des Kursniveaus gezeichnet wird. Ohne diese Verschiebung läge die Ableitung nahe bei null und wäre schwer zu erkennen. Die Ableitung gibt die Änderungsrate der geglätteten Kurve an; positive Werte deuten auf Aufwärtsmomentum hin, negative Werte auf Abwärtsmomentum. Der Skalierungsfaktor macht diese Schwankungen als eine Linie sichtbar, die um den Kurs oszilliert.

Crossover-Signalerkennung

Nun generieren wir unsere Handelssignale. Zuerst initialisieren wir die Signalpuffer mit leeren Werten:

   //--- 6) Crossover signals (only within lookback window)
   ArrayInitialize(baselineSignalBuffer, EMPTY_VALUE);
   ArrayInitialize(filteredSignalBuffer, EMPTY_VALUE);

Für den gefilterten Crossover benötigen wir schnelle und langsame exponentielle gleitende Durchschnitte der EMA-gefilterten Reihe (vecEMA). Wir berechnen diese rekursiv in Vektoren:

   double alphaFast = 2.0 / (FastMAPeriod + 1.0);
   double alphaSlow = 2.0 / (SlowMAPeriod + 1.0);

   vector<double> fastFilteredVec(len);
   vector<double> slowFilteredVec(len);

   if(len > 0)
   {
      fastFilteredVec[0] = vecEMA[0];
      slowFilteredVec[0] = vecEMA[0];
   }
   for(int i = 1; i < len; i++)
   {
      fastFilteredVec[i] = alphaFast * vecEMA[i] + (1 - alphaFast) * fastFilteredVec[i-1];
      slowFilteredVec[i] = alphaSlow * vecEMA[i] + (1 - alphaSlow) * slowFilteredVec[i-1];
   }

Diese rekursive Formel ist die Standard-EMA-Berechnung. Durch die Vorberechnung der gesamten Reihe vermeiden wir eine Neuberechnung bei jedem Tick und machen den Code übersichtlicher. Beachten Sie, dass wir dieselben schnellen und langsamen Perioden wie bei der Baseline verwenden, diese jedoch auf den EMA-gefilterten Kurs (vecEMA) anwenden und nicht auf den ungefilterten Schlusskurs. Dies erzeugt ein Crossover-Signal, das potenziell weniger verrauscht ist, da die zugrunde liegende Reihe bereits geglättet ist.

Nun suchen wir nach Crossovers:

   for(int i = 1; i < len; i++)
   {
      int idx = startIdx + i;

      // Baseline crossover signals (using the built‑in MA buffers)
      if(baselineFastBuffer[idx] > baselineSlowBuffer[idx] && baselineFastBuffer[idx-1] <= baselineSlowBuffer[idx-1])
         baselineSignalBuffer[idx] = low[idx] - 10 * _Point; // buy arrow below price
      if(baselineFastBuffer[idx] < baselineSlowBuffer[idx] && baselineFastBuffer[idx-1] >= baselineSlowBuffer[idx-1])
         baselineSignalBuffer[idx] = high[idx] + 10 * _Point; // sell arrow above price

      // Filtered crossover signals
      if(fastFilteredVec[i] > slowFilteredVec[i] && fastFilteredVec[i-1] <= slowFilteredVec[i-1])
         filteredSignalBuffer[idx] = low[idx] - 20 * _Point; // buy
      if(fastFilteredVec[i] < slowFilteredVec[i] && fastFilteredVec[i-1] >= slowFilteredVec[i-1])
         filteredSignalBuffer[idx] = high[idx] + 20 * _Point; // sell
   }

Für Käufe platzieren wir den Pfeil unter dem Tief der Bar; für Verkäufe über dem Hoch. Die gefilterten Pfeile werden 20 Punkte entfernt platziert (im Vergleich zu 10 bei der Baseline), damit sie visuell unterscheidbar sind. Die Bedingung prüft auf einen Crossover, indem sie die aktuellen und vorherigen Werte der schnellen und langsamen Linie vergleicht. Diese Standardlogik erzeugt ein Signal genau dann, wenn die schnelle Linie die langsame Linie kreuzt.

Aufräumen

Schließlich füllen wir alle Bars vor dem Lookback-Fenster mit leeren Werten für die gefilterten Linien:

   //--- Fill any bars before the lookback window with EMPTY_VALUE for the filtered lines
   for(int i = 0; i < startIdx; i++)
   {
      smaFilteredBuffer[i] = EMPTY_VALUE;
      emaFilteredBuffer[i] = EMPTY_VALUE;
      lrmaFilteredBuffer[i] = EMPTY_VALUE;
      ssaTrendBuffer[i]    = EMPTY_VALUE;
      splineDerivBuffer[i] = EMPTY_VALUE;
   }

   //--- return value of prev_calculated for next call
   return(rates_total);
}

Und das war's! Unser Indikator ist fertig.

Nach dem Kompilieren im MetaEditor lädt der Indikator fehlerfrei. Bei Anwendung auf USDJPY M15 mit Standardparametern ist die Initialisierung dank der LookbackBars-Optimierung effizient. Auf dem Chart sehen Sie den ungefilterten Schlusskurs (schwarz), die beiden Baseline-EMAs (blau und rot) und die fünf gefilterten Linien (grün, dodger-blau, orange, magenta und braun). Die blauen Pfeile markieren Crossovers der Baseline-EMAs, während die roten Pfeile (weiter vom Kurs entfernt) die Crossovers der gefilterten EMAs markieren. Durch den Vergleich der beiden Signalsets können Sie beurteilen, ob die zusätzliche Glättung hilft, übermäßige Signale zu reduzieren, oder ob sie zu viel Verzögerung einführt.

Die Implementierung umfasst:

  • Baseline-EMA-Crossover-Puffer – die standardmäßigen schnellen und langsamen EMAs, die vom Terminal berechnet werden und eine vertraute Referenz bieten.
  • Gefilterte Serienpuffer (SMA, EMA, LRMA) – drei klassische gleitende Durchschnitte, die über ALGLIB angewendet werden und zeigen, wie jeder den Kurs glättet.
  • SSA-Trendrekonstruktion – eine moderne, datenadaptive Methode, die die Serie in Trend und Rauschen zerlegt und zugrunde liegende Muster aufdeckt.
  • Spline-Ableitungsberechnung – ein kontinuierliches Maß für die Änderungsrate des geglätteten Kurses, skaliert für die Sichtbarkeit.
  • Signalvisualisierungslogik – zwei Sätze von Crossover-Signalen (Baseline und gefiltert), die als Pfeile dargestellt werden und einen direkten Vergleich von Handelszeitpunkt und -häufigkeit ermöglichen.

Die Leistungsoptimierung konzentriert sich auf die Minimierung von Neuberechnungen und die Begrenzung von SSA- und Spline-Berechnungen auf aktuelle Bars. Der Parameter LookbackBars ermöglicht es Ihnen, zwischen Geschwindigkeit und historischer Tiefe abzuwägen. Mit diesen Bausteinen können Sie mit verschiedenen Filterparametern experimentieren und sogar den EMA-gefilterten Crossover durch eine der anderen gefilterten Serien ersetzen, um zu sehen, wie sie sich auf die Signalerzeugung auswirken.


Tests

Nachdem unser Indikator erfolgreich kompiliert wurde, ist es an der Zeit, ihn in Aktion zu sehen. Wenn Sie neu in diesem Prozess sind, machen Sie sich keine Sorgen – wir gehen jeden Schritt gemeinsam durch. Das Ziel hier ist nicht die Bewertung der Rentabilität (denken Sie daran, dies ist ein visuelles Werkzeug, kein Handelsroboter). Stattdessen wollen wir beobachten, wie sich die mathematische Vorverarbeitung auf das Verhalten von gleitenden Durchschnitts-Crossovers auswirkt – insbesondere in Seitwärtsmärkten.

Schritt 1: Den Indikator auf Ihren Chart bringen

Nach dem Kompilieren des Codes im MetaEditor erscheint der Indikator ALGLIB_FilterDemo.ex5 in Ihrem Navigator-Fenster (Ansicht → Navigator oder Strg+N) im Ordner „Indikatoren“. Wenn Sie ihn nicht sehen, klicken Sie mit der rechten Maustaste in den Navigator und wählen Sie „Aktualisieren“.

Um ihn auf einen Chart anzuwenden:

  • Öffnen Sie einen neuen Chart – wir verwenden USDJPY, M15 (15-Minuten) als Beispiel.
  • Ziehen Sie den Indikator aus dem Navigator auf den Chart oder doppelklicken Sie darauf.
  • Das Fenster mit den Eingabeparametern des Indikators wird angezeigt. Belassen Sie vorerst alles bei den Standardwerten:
    • Fast MA Period: 5
    • Slow MA Period: 20
    • Filter Window: 14
    • SSA Window: 30
    • SSA Rank: 5
    • Spline Derivative Scale: 10.0
    • Lookback Bars: 500
  • Klicken Sie auf OK.

Der Indikator zeichnet sofort mehrere Linien in Ihren Chart. Machen Sie sich keine Sorgen, wenn es zunächst unübersichtlich aussieht – jede Linie hat einen Zweck, und wir werden sie jetzt identifizieren.

Schritt 2: Beobachtung des Indikators in Aktion (Live-Chart)

Nehmen Sie sich einen Moment Zeit, um zu untersuchen, was in Ihrem Chart erscheint. Sie sollten Folgendes sehen:

  • Schwarze Linie: Der ungefilterte Schlusskurs (Ihre Referenz).
  • Blaue und rote Linien: Der schnelle (5) und der langsame (20) exponentielle gleitende Durchschnitt als Basis – der klassische Crossover, den wir alle kennen.
  • Grüne Linie: Kurs gefiltert mit einem einfachen gleitenden Durchschnitt (SMA) unter Verwendung von ALGLIB.
  • Dodger-blaue Linie: Kurs gefiltert mit einem exponentiellen gleitenden Durchschnitt (EMA) unter Verwendung von ALGLIB.
  • Orangefarbene Linie: Kurs gefiltert mit einem gleitenden Durchschnitt der linearen Regression (LRMA) unter Verwendung von ALGLIB.
  • Magentafarbene Linie: Die Trendkomponente, extrahiert durch singuläre Spektralanalyse (SSA).
  • Braune Linie: Die Spline-Ableitung – ein Maß für die Änderungsrate des geglätteten Kurses, skaliert und zum Kurs addiert, damit sie im Chart sichtbar ist.
  • Blaue Pfeile: Crossover-Signale der Baseline-EMAs (unter den Bars für Käufe, darüber für Verkäufe platziert).
  • Rote Pfeile: Crossover-Signale der gefilterten EMAs (etwas weiter entfernt platziert, damit sie sich unterscheiden).

Betrachten Sie nun einen Seitwärtsabschnitt des Charts – der Kurs bewegt sich horizontal ohne klaren Trend. Beobachten Sie, was passiert:

  • Die Baseline-EMAs (blau und rot) kreuzen sich wiederholt in kurzen Abständen. Jedes Kreuzen erzeugt einen blauen Pfeil. In einem Seitwärtsmarkt erscheinen diese Pfeile oft mehrmals kurz hintereinander. Dies ist das Problem der „exzessiven Signale“, das wir zuvor besprochen haben.
  • Betrachten Sie nun die gefilterten Linien. Beachten Sie, wie die grüne (SMA), die dodger-blau (EMA) und die orangefarbene (LRMA) Linie glatter sind als der ungefilterte Kurs. Sie reagieren nicht auf jede kleine Schwankung.
  • Achten Sie besonders auf die roten Pfeile (gefilterte Kreuzungen). Zählen Sie diese in demselben Seitwärtsabschnitt. Sie werden wahrscheinlich weniger rote Pfeile sehen als blaue. Die Vorverarbeitung hat viele der falschen Signale herausgefiltert.
  • Die magentafarbene SSA-Linie ist oft die glatteste von allen – sie bewegt sich in Seitwärtsphasen kaum und führt nur selten zu Kreuzungen.
  • Die braune Spline-Ableitungslinie oszilliert um den Kurs. Wenn sie nach oben oder unten kreuzt, signalisiert dies Veränderungen im Momentum. Sie werden vielleicht bemerken, dass sie reagiert, bevor die eigentliche Kreuzung stattfindet – das ist die Ableitung, die Steigungsänderungen frühzeitig erkennt.

Auf einem Live-Chart

Abb. 1. Live-Chart USDJPY M15

Schritt 3: Testen mit dem Strategietester (Visueller Modus)

Der Live-Chart zeigt uns das aktuelle Verhalten, aber was ist, wenn wir sehen wollen, wie sich der Indikator über einen längeren historischen Zeitraum verhält – sagen wir, mehrere Monate an Daten? Hier kommt der Strategietester ins Spiel, auch wenn wir keinen Expert Advisor testen. Wir können den Indikator im visuellen Modus ausführen, um seine Signale unter verschiedenen Marktbedingungen zu beobachten.

So richten Sie es ein:

  • Öffnen Sie den Strategietester (Ansicht → Strategietester oder Strg+R).
  • Im Tester-Fenster:
    • Expert Advisor: Leer lassen (wir führen keinen EA aus).
    • Symbol: USDJPY (oder ein beliebiges Paar Ihrer Wahl).
    • Zeitrahmen: M15.
    • Modell: Wählen Sie „Jeder Tick“ oder „1 Minute OHLC“ (beide funktionieren für die visuelle Beobachtung).
    • Datumsbereich: Wählen Sie einen Zeitraum, der sowohl Trend- als auch Seitwärtsphasen umfasst – zum Beispiel die letzten 6-12 Monate.
    • Visueller Modus: Aktivieren Sie dieses Kontrollkästchen. Dies ist wichtig – so können wir beobachten, wie der Indikator während des Tests in Echtzeit gezeichnet wird.
  • Klicken Sie auf „Start“. Der Tester beginnt zu laufen und ein Chartfenster öffnet sich, in dem der Indikator Tick für Tick oder Bar für Bar angewendet wird.

Beobachten Sie während des Tests:

  • In starken Trendphasen erscheinen sowohl die Baseline-Pfeile (blau) als auch die gefilterten Pfeile (rot) in dieselbe Richtung. Die gefilterten Pfeile erscheinen möglicherweise etwas später (eine gewisse Verzögerung ist der Preis für die stärkere Glättung), aber sie werden im Allgemeinen mit der Trendrichtung übereinstimmen.
  • Achten Sie in Seitwärts- oder volatilen Phasen auf den Unterschied. Die blauen Pfeile erscheinen immer wieder – hoch, runter, hoch, runter –, da der schnelle EMA jeder Schwankung folgt. Die roten Pfeile hingegen werden deutlich spärlicher sein. Einige Seitwärtsphasen erzeugen möglicherweise überhaupt keine roten Pfeile. Hier zeigt sich die Wirkung der Filterung.
  • Beachten Sie, wie sich die SSA-Linie (magenta) verhält. Während Seitwärtsphasen wird sie oft fast horizontal und bleibt dabei nahezu ohne Crossover-Signale. Sie „sitzt“ das Rauschen effektiv „aus“.
  • Die Spline-Ableitung (braun) kann in Seitwärtsmärkten weiterhin Aktivität zeigen. Da sie skaliert und zum Kurs addiert wird, sind ihre Oszillationen als Schwankungen um das Kursniveau sichtbar. Sie können mit dem Parameter SplineDerivScale experimentieren, um ihn stärker oder schwächer hervorzuheben.

Abb. 2. Strategietester im visuellen Modus

Schritt 4: Mit Parametern spielen

Eine der besten Möglichkeiten zu lernen ist, die Eingaben anzupassen und sofort die Auswirkungen zu sehen. Entfernen Sie den Indikator aus Ihrem Chart (Rechtsklick → Indikatoren → auswählen → Löschen), ziehen Sie ihn dann wieder darauf und ändern Sie jeweils nur einen Parameter. Beobachten Sie, was passiert:

  • Erhöhen Sie FilterWindow (z. B. von 14 auf 30): Alle gefilterten Linien (grün, dodger-blau, orange) werden glatter. Sie reagieren langsamer auf Kursänderungen. Crossover-Signale (rote Pfeile) werden seltener erscheinen, aber mit mehr Verzögerung. Dies ist der klassische Kompromiss: Glätte vs. Reaktionsfähigkeit.
  • Verringern Sie FilterWindow (z. B. auf 5): Die gefilterten Linien schmiegen sich nun enger an den ungefilterten Kurs an. Sie werden mehr rote Pfeile sehen – einige erscheinen möglicherweise sogar fast zur gleichen Zeit wie blaue Pfeile. Der Filtereffekt wird reduziert.
  • Passen Sie SSAWindow an (versuchen Sie 20, dann 50): Die magentafarbene SSA-Linie ändert ihre Glätte. Ein kleineres Fenster macht sie reaktionsfähiger (aber immer noch glatter als der ungefilterte Kurs); ein größeres Fenster erzeugt eine sehr langsam verlaufende Linie, die nur die langfristigsten Bewegungen erfasst. Wenn Sie das Fenster zu groß wählen, verschwindet die Linie möglicherweise auf der linken Seite des Charts – SSA benötigt genügend Daten zur Berechnung.
  • Ändern Sie SSARank (versuchen Sie 3, dann 8): Dies steuert, wie viele Komponenten bei der Rekonstruktion beibehalten werden. Niedrigerer Rang = glatter (aggressivere Filterung). Höherer Rang = mehr Details bleiben erhalten (näher am ursprünglichen Kurs). Werte zwischen 4 und 7 funktionieren oft gut für Forex-Daten auf M15.
  • Ändern Sie SplineDerivScale: Machen Sie ihn größer (z. B. 20), und die Schwingungen der braunen Linie werden wilder – sie sind leichter zu erkennen, können aber weit vom Kurs abweichen. Machen Sie ihn kleiner (z. B. 2), und die Linie schmiegt sich eng an den Kurs an, wodurch Nulldurchgänge der Ableitung schwerer zu erkennen sind. Finden Sie einen Wert, der die Schwingungen sichtbar macht, ohne abzulenken.

Durch dieses praktische Experimentieren entwickeln Sie ein Gefühl dafür, wie jede mathematische Technik die Daten formt. Sie lesen nicht mehr nur über ALGLIB – Sie sehen, wie es in Echtzeit auf Ihren eigenen Charts arbeitet.


Schlussfolgerung

Nachdem wir den Indikator nun in Aktion gesehen haben – sowohl auf Live-Charts als auch anhand historischer Daten im Strategietester –, lassen Sie uns darüber reflektieren, was wir gemeinsam erreicht haben.

Wir verfügen nun über einen funktionierenden Indikator, der es uns ermöglicht, Kreuzungen von gefilterten gleitenden Durchschnitte visuell nebeneinander zu vergleichen. Auf unseren Charts können wir deutlich sehen, wie sich die Baseline-EMAs im Vergleich zu ihren gefilterten Gegenstücken verhalten. Die gefilterten Crossovers treten in Seitwärtsmärkten seltener auf – genau das, was wir uns von der mathematischen Vorverarbeitung erhofft hatten.

Wir haben gelernt, dass wir mit Parametern experimentieren können, um herauszufinden, wie sich jeder Filter verhält. Durch die Anpassung von FilterWindow, SSAWindow, SSARank und SplineDerivScale können wir sofort die Auswirkungen auf Glättung, Verzögerung und Signalfrequenz sehen. Diese praktische Erkundung baut Intuition weitaus besser auf als das bloße Lesen der Theorie.

Wir haben konkrete Beispiele dafür gesehen, wie Mathematik im Handel angewendet werden kann. Die SMA-, EMA- und LRMA-Filter haben vertraute Glättungskonzepte demonstriert. Die singuläre Spektralanalyse hat uns gezeigt, wie eine datenadaptive Zerlegung zugrunde liegende Trends extrahieren kann. Die Spline-Ableitung hat verdeutlicht, wie die Änderungsrate direkt im Chart visualisiert werden kann. Nichts davon erforderte, dass wir Mathematiker werden – ALGLIB übernahm die komplexen Berechnungen, während wir uns auf die Interpretation konzentrierten.

Aus einem einfachen gleitenden Durchschnitts-Crossover haben wir eine analytische Plattform mit mehreren Filtern aufgebaut. Die zugrunde liegende Strategie hat sich nicht geändert – es sind immer noch zwei sich kreuzende gleitende Durchschnitte –, aber die Daten, die in sie einfließen, wurden transformiert. Dies ist die Kernidee, die wir gemeinsam erforscht haben: Vorverarbeitung ist wichtig. Dieselbe Handelslogik, angewandt auf unterschiedlich gefilterte Daten, erzeugt unterschiedliche Signale, und jetzt haben wir ein Werkzeug, um diese Unterschiede aus erster Hand zu untersuchen.

Die modulare Struktur unseres Codes bedeutet, dass wir:

  • Den EMA-gefilterten Crossover durch Crossovers aus einer der anderen gefilterten Reihen (SMA-gefiltert, LRMA-gefiltert, SSA-Trend usw.) ersetzen und diese vergleichen könnten.
  • Die gefilterten Signale extrahieren könnten, um Alarme oder Benachrichtigungen zu generieren, wenn Crossovers auftreten.
  • Die hier demonstrierten Vorverarbeitungstechniken als Grundlage für einen Expert Advisor nutzen könnten – indem wir unsere gefilterte Crossover-Logik nehmen und sie für Backtesting und Forward-Testing automatisieren.
  • Mit völlig anderen ALGLIB-Funktionen experimentieren könnten – Optimierungsroutinen, Clustering-Algorithmen oder fortgeschrittenen statistischen Tests – und diese auf unsere Handelsideen anwenden könnten.

Durch diesen Artikel haben wir entdeckt, dass ALGLIB MQL5 von einer auf integrierte Indikatoren beschränkten Plattform in eine echte numerische Forschungsumgebung verwandelt. Egal, ob wir Trader sind, die sauberere Signale suchen, Entwickler, die Analyse-Tools bauen, oder einfach neugierig auf angewandte Mathematik sind, ALGLIB öffnet Türen, die uns zuvor verschlossen waren.

Laden Sie den Indikator aus dem Anhang unten herunter. Wenden Sie ihn auf Ihre bevorzugten Paare und Zeitrahmen an. Variieren Sie seine Parameter. Zerstören, reparieren, verbessern Sie ihn. Lassen Sie sich von der visuellen Rückmeldung bei Ihrem Verständnis leiten. Und wenn Sie bereit sind, machen Sie den nächsten Schritt – bauen Sie diesen Roboter, führen Sie diese Optimierung durch, erkunden Sie diesen neuen Filter.

Ich würde mich freuen, Ihre Beobachtungen, Fragen und Experimente in der Diskussion zu hören. Der Code steht Ihnen zur Verfügung, um ihn zu verwenden, zu ändern und daraus zu lernen. Ihre Beiträge helfen dabei, diese Ideen zu verfeinern und unsere Gemeinschaft zu stärken.

Viel Spaß beim Programmieren allerseits.


Anhänge

Quelldateiname Typ Version  Beschreibung
ALGLIB_FilterDemo Indikator  1.00 Demonstrationsindikator zur Veranschaulichung fortgeschrittener Trendfiltertechniken unter Verwendung der Standard-ALGLIB-Bibliothek in MetaTrader 5. Er vergleicht traditionelle EMA-Crossovers mit Linear Regression Moving Average (LRMA)-Crossovers und enthält einen kubischen Spline mit ableitungsbasierter Steigungsvisualisierung für eine verbesserte Trenderkennung und reduzierte Fehlsignale in Seitwärtsmärkten.

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

Beigefügte Dateien |
Integration von MQL5 mit Datenverarbeitungspaketen (Teil 8): Einsatz von Graph Neural Networks zur Erkennung von Liquiditätszonen Integration von MQL5 mit Datenverarbeitungspaketen (Teil 8): Einsatz von Graph Neural Networks zur Erkennung von Liquiditätszonen
Dieser Artikel zeigt, wie man die Marktstruktur in MQL5 als Graph darstellt, indem Swing-Highs/-Lows in Knoten mit Merkmalen umgewandelt und durch Kanten miteinander verbunden werden. Es wird ein Graph Neural Network trainiert, um potenzielle Liquiditätszonen zu bewerten, das Modell nach ONNX exportiert und für die Echtzeit-Inferenz in einem Expert Advisor verwendet. Die Leser lernen, wie man die Daten-Pipeline aufbaut, das Modell integriert, Zonen im Chart visualisiert und die Signale für eine regelbasierte Handelsausführung nutzt.
Larry Williams’ Marktgeheimnisse (Teil 14): Erkennung versteckter Hidden-Smash-Day-Umkehrmuster mit einem benutzerdefinierten Indikator Larry Williams’ Marktgeheimnisse (Teil 14): Erkennung versteckter Hidden-Smash-Day-Umkehrmuster mit einem benutzerdefinierten Indikator
Dieser Artikel entwickelt einen praktischen MQL5-Indikator, der Hidden-Smash-Day-Bars anhand strenger numerischer Kriterien und einer optionalen Bestätigung in der folgenden Sitzung identifiziert. Wir behandeln Erkennungsroutinen, das Einrichten der Puffer und die Plot-Einstellungen, um Pfeile an gültigen Bars zu platzieren. Der Ansatz liefert stabile, nicht nachträglich neu gezeichnete Signale für historische Tests und Echtzeitüberwachung.
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.
Vereinheitlichte Validierungspipeline gegen Backtest-Overfitting Vereinheitlichte Validierungspipeline gegen Backtest-Overfitting
Dieser Artikel erklärt, warum Standard-Walk-Forward und k-fache Cross-Validation Ergebnisse bei Finanzdaten systematisch zu positiv erscheinen lassen, und zeigt dann, wie dies behoben werden kann. V-in-V erzwingt strikte Datenpartitionen und verankertes Walk-Forward über Zeitfenster hinweg, CPCV bereinigt Datenlecks mittels Purging und Embargo und aggregiert die Performance auf Pfadebene, und CSCV misst die Wahrscheinlichkeit von Backtest-Overfitting. Anwender erhalten einen kohärenten Rahmen zur Bewertung der Robustheit über verschiedene Marktregime hinweg und der Verlässlichkeit der Strategieauswahl.