English Русский 中文 Español 日本語 Português
preview
MQL5 Wizard-Techniken, die Sie kennen sollten (Teil 06): Fourier-Transformation

MQL5 Wizard-Techniken, die Sie kennen sollten (Teil 06): Fourier-Transformation

MetaTrader 5Tester | 10 Juli 2023, 09:59
229 0
Stephen Njuki
Stephen Njuki

Einführung

Fourier-Transformation ist eine Methode zur Zerlegung einer Welle von Datenpunkten in mögliche Bestandteile, die von Joseph Fourier entwickelt wurde. Die Integration über alle möglichen Frequenzen in der Fourier-Transformation ergibt ein Spektrum von Komponenten, da die ursprüngliche Funktion in ihre Bestandteile zerlegt wird, die jeweils einer anderen Frequenzkomponente entsprechen.

Die Fourier-Transformation reicht per Definition von minus unendlich bis plus unendlich:


wobei F(w) die Fourier-Transformierte der Funktion f(t), i die imaginäre Einheit, w die Winkelfrequenz und e die Exponentialfunktion ist.

In der Praxis wird jedoch bei der Verwendung der Transformation die Anzahl der Epizyklen auf eine kleine, überschaubare Anzahl festgelegt. Je mehr Epizyklen (Komponentenfrequenzen) man verwendet, desto genauer kann man die ursprüngliche Kurve beschreiben, aber an einem bestimmten Punkt wird es ineffizient, da mehr Epizyklen keinen sinnvollen Unterschied in der Kurve, die in Teilen beschrieben wird, ergeben.

Dies führt dazu, dass sich die Nutzer der Transformation für eine diskrete, endliche Anzahl n von Epizyklen entscheiden. Dadurch wird unsere obige Formel leicht abgeändert.

Wenn wir alle möglichen Frequenzen addieren, summieren wir den Beitrag jeder einzelnen zur ursprünglichen Funktion. Jede Frequenzkomponente wird durch eine komplexe Zahl dargestellt, die sowohl Betrags- als auch Phaseninformationen enthält. Der Betrag gibt die Amplitude der Welle an, während die Phase die zeitliche Verschiebung der Welle darstellt. Unsere obige modifizierte Gleichung summiert sich also über n Komponenten, und jede dieser n Komponenten hat eine Welle mit verschiedenen Werten zum Zeitpunkt t.

Bei der Lösung der einzelnen Komponenten kommt es darauf an, den f(t) jeder Komponente zu finden, der sowohl einen Real- als auch einen Imaginärteil darstellt. Das Fourier-System schreibt jede Funktion f(t) für das Intervall 0 bis 2 pi mit komplexen Zahlen als diese „unendliche Summe“ um.  „Unendlich“ steht in Anführungszeichen, weil es sich zu Null addiert.


Mit unserer obigen Gleichung, in der Lösung für sagen wir den Koeffizienten:  C 2 ,

Wir würden beide Seiten der Gleichung multiplizieren mit: e-2it

Durch Integration vereinfacht sich unsere Gleichung zu:



Die 2 (und nicht die 2 in 2 pi!) kann also durch n ersetzt werden, um jeden anderen Koeffizienten in der obigen f(t)-Gleichung zu erhalten. All diese Berechnungen werden von der Klasse „CFastFourierTransform“ durchgeführt, die in der Datei aufgeführt ist: Math\Alglib\fasttransforms.mqh', sodass wir nur noch diese Bibliothek verwenden müssen.


Anwendungen

Bevor wir uns mit ganz konkreten Beispielen befassen, ist es vielleicht sinnvoll, zunächst einen umfassenderen Blick darauf zu werfen, wie die Händler von dieser Möglichkeit profitieren können, eine Welle von Datenpunkten in ihre Bestandteile zu zerlegen. Es gibt sehr viele Anwendungen. Hier ist eine mögliche kurze Liste:

  1. Analyse der Aktienkursentwicklung: Wenn wir Aktienkursdaten sammeln und sie in einem Zeitreihenformat anordnen, können wir die Fourier-Transformation auf die Reihendaten anwenden, um ihre Frequenzkomponenten zu erhalten. Die Analyse dieser separaten Frequenzkomponenten zur Ermittlung von Mustern und Trends in den Daten kann helfen, besser informierte Handelsentscheidungen zu treffen. So kann ein Händler beispielsweise feststellen, dass eine bestimmte Aktie bei einer bestimmten Frequenz eine wiederkehrende Spitze in ihrem Frequenzspektrum aufweist, was auf ein sich wiederholendes Muster in den Kursbewegungen der Aktie hinweist. Diese Beobachtung kann genutzt werden, um die Aktie zu kaufen, wenn sie zu einem niedrigen Preis steht, und sie zu verkaufen, wenn sie zu einem hohen Preis steht, in der Erwartung, dass der Preis diesem beobachteten Muster folgen wird. Im Laufe der Zeit muss dies jedoch häufig überwacht werden, um sicherzustellen, dass die Muster weiterhin anwendbar sind.
  1. Analyse der langfristigen Zyklen: Wir müssten uns zwischen einem Konjunkturzyklus oder einem Marktzyklus entscheiden. Wenn wir uns für einen Konjunkturzyklus entscheiden, könnten unsere möglichen Datenquellen folgende sein:

  • Bruttoinlandsprodukt (BIP): Einer der wichtigsten Indikatoren für das Wirtschaftswachstum, der den Gesamtwert der in einem Land während eines bestimmten Zeitraums (in der Regel ein Jahr) produzierten Waren und Dienstleistungen misst.
  • Beschäftigungsdaten: Zahlen wie die Arbeitslosenquote oder die Zahl der neu geschaffenen Arbeitsplätze können Aufschluss über die Gesundheit des Arbeitsmarktes geben. Steigende Arbeitslosigkeit oder stagnierendes Beschäftigungswachstum können auf eine schwächelnde Wirtschaft hindeuten.
  • Daten zur Industrieproduktion: Dazu gehören der Industrieller Produktionsindex, der die Produktion des verarbeitenden Gewerbes, des Bergbaus und des Versorgungssektors misst und auf die allgemeine Gesundheit der Wirtschaft hinweist, der Einkaufsmanagerindex, Kapazität (Wirtschaft), Aufträge für langlebige Güter, Beschäftigung im verarbeitenden Gewerbe und viele andere.
  • Daten zum Verbrauchervertrauen: Dazu gehören der Verbrauchervertrauensindex, der Verbraucherstimmungsindex der Universität Michigan, der Verbrauchervertrauensindex des Conference Board, die Einzelhandelsumsätze, die Verbraucherkredite, um nur einige zu nennen.
  • Daten zu den Zinssätzen: Die Zinssätze können sich auf die Unternehmensinvestitionen und die Verbraucherausgaben auswirken, die beide die Wirtschaftsleistung beeinflussen können. Steigende Zinssätze dämpfen tendenziell Investitionen und Ausgaben, während sinkende Zinssätze Investitionen und Ausgaben fördern können, was sich letztendlich auf den Kurs von börsennotierten Unternehmensaktien auswirkt.
  • Inflationsdaten: Sie misst die Steigerungsrate der Preise für Waren und Dienstleistungen und kann somit Aufschluss über den Zustand einer Wirtschaft geben. Eine hohe Inflation kann auf eine überhitzte Wirtschaft hinweisen, während eine niedrige Inflation ein Zeichen für eine schwache Wirtschaft sein kann. Dies ist ein weiterer Datensatz, der die Entscheidungen der Händler beim Kauf verschiedener Aktien beeinflussen kann und daher eine wichtige Datenquelle darstellt.
  • Wohnungsdaten: Dies könnte Hausverkäufe und Baubeginne umfassen und Aufschluss über die Gesundheit des Wohnungsmarktes geben, der eine wichtige Komponente der Wirtschaft ist und für eine bestimmte Aktie, die ein Händler in seinem Portfolio hat, relevant sein könnte.

Umgekehrt könnten einige Quellen für Marktzyklusdaten sein:

  • Kurs/Gewinn-Verhältnis (KGV): Diese gängige Kennzahl vergleicht den Aktienkurs eines Unternehmens mit seinem Gewinn pro Aktie (earnings per share, EPS) und kann verwendet werden, um festzustellen, ob der Markt eine Aktie überbewertet (bei einem hohen Wert) oder ob der Markt die Aktie unterbewertet, wenn der Wert typischerweise unter 15 oder sogar 10 liegt, je nach Region des Marktes.
  • Dividendenrenditen: Sie messen die Höhe der Dividende, die für jede Aktie pro Aktienkurs ausgeschüttet wird. Niedrige Dividendenrenditen können auf eine überbewertete Aktie hindeuten, während hohe Dividendenrenditen auf eine Unterbewertung hindeuten können.
  • Technische Indikatoren: Eine Liste, die gleitende Durchschnitte, Momentum-Indikatoren und Indikatoren für die relative Stärke enthält, kann helfen, die aktuelle Kursentwicklung einer Aktie zusammenzufassen. Wenn ein Aktienkurs beispielsweise über seinem gleitenden 200-Tage-Durchschnitt gehandelt wird, kann dies auf einen Aufwärtstrend hindeuten, während ein Handel unter dem gleitenden 200-Tage-Durchschnitt einen Abwärtstrend signalisieren kann; in diesem Fall könnten unsere Daten die Spanne zwischen dem Kurs und seinem gleitenden 200-Tage-Durchschnitt sein.
  • Market Breite: Hier wird die Anzahl der Aktien gemessen, die in einem bestimmten Markt steigen, im Vergleich zu den Aktien, die fallen. Wenn eine große Anzahl von Aktien steigt, kann dies auf einen gesunden Markt hindeuten, während eine sinkende Breite auf Schwäche hindeuten kann. Solche Daten könnten von Dritten bezogen werden, die sie in der Regel mit anderen Datenströmen gegen eine einmalige Gebühr oder in einigen Fällen gegen ein Abonnement bündeln.
  • Volatilität: Dieser wird anhand von Indikatoren wie dem VIX gemessen und hilft bei der Bewertung des Marktrisikos und der Anlegerstimmung. Er korreliert häufig positiv mit dem Marktrisiko und der negativen Stimmung.

Sobald wir unsere relevanten Finanzdaten aus den oben genannten möglichen Quellen gesammelt haben, würden wir sie in eine Zeitreihe einordnen und dann die Fourier-Transformation anwenden, um sie in ihre Frequenzkomponenten zu zerlegen. Die Analyse dieser Bestandteile, d. h. die Suche nach sich wiederholenden Zyklen in den Daten, könnte unsere Handelsentscheidungen verbessern. Ein Händler kann dies beispielsweise nutzen, um einen wiederkehrenden Zyklus in den Zinsdaten zu erkennen, der in der Regel mehrere Jahre andauert und eine verzögerte positive Korrelation mit der von ihm gehandelten Aktie oder dem ETF aufweist. Mit diesem Wissen kann er in langfristige Positionen investieren, wenn der Markt einen Tiefpunkt erreicht hat, und Drawdown-Positionen über längere Zeiträume halten und sie erst dann aufgeben, wenn die Korrelation der Zinsdaten negativ wird oder einen Abschwung vorhersagt.

  1. Signalverarbeitung: Bei der Betrachtung von Signalen könnten wir Preiswellenmuster in Betracht ziehen, die vor größeren Ausbrüchen nach oben oder nach unten liegen. Eine spezifischere Datenquelle könnte hier zum Beispiel nur das Gartley Muster im Kursverlauf einer bestimmten Aktie betrachten und die anderen Daten auslassen. Diese Wellenpreisdaten würden als Zeitreihe aufgezeichnet werden (auch wenn erhebliche Lücken bestehen würden, da das Muster selten ist). Eine Fourier-Transformation würde auf jede Welle in dieser Reihe angewandt werden. Wir könnten dann einen Frequenzschwellenwert für die Fourier-Komponenten festlegen (auf der Grundlage unserer Beobachtungen mit Korrelation zu den möglichen Ausbrüchen) und diejenigen auslassen, die den Schwellenwert nicht erfüllen. Diese gefilterten Wellen würden wir dann nutzen, um unsere Prognosen für die Zukunft zu erstellen. Dieser Preispuffer kann für eine Aktie, ein Devisenpaar oder sogar einen Rohstoff gelten. Das Prinzip wäre das gleiche.
  1. Risikomanagement: Wenn wir uns auf das Kreditrisiko beschränken, da sich andere Risikoarten, wie das Marktrisiko, mit den oben bereits behandelten Risiken überschneiden könnten, könnten dies unsere Datenquellen sein: 

  • Ausfallraten: Vierteljährliche oder jährliche Ausfallquoten für einen bestimmten Bankenmarkt, z. B. die USA, können zur Analyse des Kreditrisikos für die USA und damit der Performance des S&P 500 verwendet werden.
  • Kreditspreads: Tägliche oder wöchentliche Daten zu den Kreditspreads zwischen Unternehmensanleihen und Staatsanleihen können bei der Bewertung des Kreditrisikos helfen, das mit Änderungen der Marktwahrnehmung der Kreditwürdigkeit verbunden ist.
  • Zahlungsrückstände bei Krediten: Das ist aber nicht dasselbe wie die Ausfallraten, die monatlich oder vierteljährlich für eine bestimmte Bank oder einen Kreditgeber ermittelt werden können und dazu dienen, das mit dem Kreditportfolio dieser Bank verbundene Kreditrisiko zu untersuchen, wenn ein Händler den Kauf dieser bestimmten Bankaktie in Betracht zieht.
  • Bonitätsbewertungen: Diese Daten sind zwar nicht so fortlaufend wie die meisten Daten, können aber dennoch über einen angemessenen historischen Zeitraum vierteljährlich oder jährlich für ein bestimmtes Unternehmen erfasst und zur Bewertung der Bonität der Commercial Papers oder sogar der langfristigen Anleihen eines Unternehmens verwendet werden.
  • Credit Default Swaps (CDS): Die in der Regel auf eine Versicherung des Kreditgebers für seine Kredite hinauslaufen, können täglich oder wöchentlich auf die Preise ihrer Verträge bezogen und zur Analyse des Kreditrisikos verwendet werden, das mit Änderungen der Marktwahrnehmung der Kreditwürdigkeit verbunden ist.

Die Daten aus einer dieser Quellen werden zu einer Zeitreihe zusammengesetzt, und dann wird die Fourier-Transformation auf die Zeitreihendaten angewendet, um die Frequenzkomponenten zu erhalten. Eine Analyse, welche Komponente am besten mit eventuellen finanziellen Schocks oder spezifischeren Aktienkursschwankungen korreliert, könnte bei der Entwicklung wirksamer Risikomanagementstrategien helfen.

  1. Optionspreise: Historische Daten über den Basiswert, den Ausübungspreis, die Zeit bis zum Verfall, die Volatilität, die Zinssätze und die Dividenden für Optionen können aus einer Reihe von Quellen, z. B. dem Bloomberg-Terminal, bezogen werden. Beachten Sie, dass jeder dieser Datensätze eine „Frequenzkomponente“ für den Preis der Option darstellt. Bei diesen zahlreichen Datensätzen gibt es viele Möglichkeiten, eine Analyse durchzuführen. Bedenken Sie, dass es per se keinen Konsens darüber gibt, wie hoch der Preis einer Option zu einem bestimmten Zeitpunkt ist. Diese sind jedoch nicht immer zuverlässig. Ein Ansatz könnte darin bestehen, einfach den Basiswertkurs zu einem bestimmten Zeitpunkt vor dem Verfall zu zerlegen und zu prüfen, welche Frequenzkomponente am besten mit der Differenz zwischen dem Basiswert und dem Ausübungspreis bei Verfall korreliert. Diese Analyse könnte für europäische Optionen nützlich sein, aber die amerikanischen Optionen, die vor dem Verfall ausgeübt werden können, stellen komplexere Herausforderungen dar. 
  1. Stimmungsanalyse: Wir haben einen langen Weg zurückgelegt, was das Beschaffen von Daten im Internet angeht, und heute ist Social Media Management Software eine große Sache. Namen wie Zoho Social, Hootsuite, Khoros Marketing, um nur einige wenige zu nennen, fassen schnell Fuß als führende Unternehmen. Vorbei sind die Zeiten, in denen man „Gefällt mir“ und „Gefällt mir nicht“ zählte und dann Feierabend machte. Heute ermöglicht die Textanalyse (in Verbindung mit KI) den Unternehmen eine bessere Quantifizierung des Kundenengagements und der Zufriedenheit mit ihren Produkten/Dienstleistungen. Es können also viele Daten gesammelt werden. Als Händler, der sich für zwei konkurrierende Unternehmen interessiert, möchten Sie vielleicht wissen, ob es eine Korrelation zwischen der Dauer des Engagements bei der Überprüfung eines Produkts und dem letztendlichen Verkauf des Produkts nach drei oder sechs Monaten gibt. Durch die Umwandlung der Engagementdaten in eine Zeitreihe und ihre Zerlegung in ihre Bestandteile lässt sich feststellen, welcher Bestandteil am besten mit unserem Ziel (in diesem Fall den künftigen Verkäufen) korreliert, und dieses System leitet uns dann bei der Entscheidung über den Kauf von Aktien und deren Menge.
  1. Maschinelles Lernen: Die Fourier-Transformation für diese Anwendung (und viele andere) könnte dazu beitragen, die Eingabedaten zu vektorisieren, indem sie in einzelne Frequenzen zerlegt werden. Hätten wir nur verschiedene geschlossene Preiswellen als Eingabedaten, könnte jede dieser Wellen in n Wellen zerlegt werden, wobei jede neue Welle nun Teil eines Vektors von Wellen der alten ungeteilten Welle ist. Dadurch erhalten wir mehr identifizierende Informationen für jeden neuen Datenpunkt, den wir auswerten müssen, und es ermöglicht einen genaueren Vergleich mit bereits trainierten Daten bei der Auswertung einer unbekannten Welle als nur der ursprünglichen Einzelwelle. Das Training dieser vektorisierten Daten und der Vergleich mit den Testdaten, z. B. unter Verwendung des euklidischen Abstands, könnte also dazu beitragen, die Prognosen für das Modell zu verbessern.


Umsetzung

Zur Veranschaulichung der Fourier-Transformations-Implementierung in MQL5 betrachten wir die Zerlegung einer Zeitreihe von Preisbereichen (Hochs minus Tiefs). Anschließend werden wir die Häufigkeit dieser Bestandteile untersuchen und feststellen, ob eine bestimmte dieser Häufigkeiten, wenn sie durch den Index identifiziert wird, eine nützliche Korrelation mit den nächsten Veränderungen in den Preisspannen aufweist. Wir werden diese Informationen nutzen, um unsere Anpassung der Stop-Loss für offene Positionen in einer nutzerdefinierten Implementierung der Klasse „CExpertTrailing“ zu steuern. Wir werden ein einfaches eingebautes Signal verwenden, das in „SignalRSI.mqh“ aufgeführt ist, und das Geldmanagement wird eine feste Marge verwenden.

 

Wenn wir unsere nutzerdefinierte Trailing-Klasse wie folgt auflisten. Beim Abrufen der realen und imaginären Koeffizienten für die „Funktion f(t)“ verwenden wir eine Instanz der Struktur „a1_complex“, um diese Informationen nach der Verarbeitung durch die Funktion „FFTR1D“ zu speichern. Um diese Koeffizienten zu verwenden, müssen wir sie „integrieren“ und dafür habe ich eine Matrix „_output“ improvisiert. Diese Matrix enthält Koeffizienten für jeden Epizyklus an jedem Datenpunkt. Wir verwenden 6 Datenpunkte und 5 Epizyklen. Auch unser Vorhersagedatenpunkt-Index „m_points-1“ wird verwendet, da sich Fourier-Zyklen wiederholen, sodass der nächste Schenkel der älteste im Zyklus wäre. 

//+------------------------------------------------------------------+
//|                                                   TrailingCT.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <Math\Alglib\fasttransforms.mqh>
#include <Expert\ExpertTrailing.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Trailing Stop based on 'Fourier Transform' v3              |
//| Type=Trailing                                                    |
//| Name=CategoryTheory                                              |
//| ShortName=CT                                                     |
//| Class=CTrailingFT                                                |
//| Page=trailing_ct                                                 |
//| Parameter=Step,double,0.5,Trailing Step                          |
//| Parameter=Index,int,0,FT-Index                                   |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CTrailingFT.                                               |
//| Appointment: Class traling stops with 'Fourier Transform' v3     |
//|               relative-sets concepts.                            |
//| Derives from class CExpertTrailing.                              |
//+------------------------------------------------------------------+
#define     __PI 245850922/78256779

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CTrailingFT : public CExpertTrailing
  {
protected:
   CFastFourierTransform   FFT;
   
   //--- adjusted parameters
   
   double            m_step;                    // trailing step

   int               m_index;                    // the epicycle index

public:
   //--- methods of setting adjustable parameters
   
   
   
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual bool      CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp);
   virtual bool      CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp);
   //---
                     CTrailingFT(void);
                    ~CTrailingFT(void);
   //--- methods of setting adjustable parameters
   void              Step(double value)                  { m_step=value;      }
   void              Index(int value)                    { m_index=value;     }

protected:
   
   double            ProcessFT(int Index);

  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CTrailingFT::CTrailingFT(void)
  {
//--- initialization of protected data
   m_used_series=USE_SERIES_TIME+USE_SERIES_SPREAD+USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CTrailingFT::~CTrailingFT(void)
  {
  }
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CTrailingFT::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertTrailing::ValidationSettings())
      return(false);
//--- initial data checks
   if(m_index<0 || m_index>=5)
     {
      printf(__FUNCTION__+": index must be greater than 0 and less than epicycles");
      return(false);
     }

//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CTrailingFT::InitIndicators(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertTrailing::InitIndicators(indicators))
      return(false);
//--- 
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for long position.          |
//+------------------------------------------------------------------+
bool CTrailingFT::CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
      if(position==NULL)
         return(false);
      
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
      
      double _ft=ProcessFT(_x);
      double _type=_ft/100.0;
      
      double _atr=fmax(2.0*m_spread.GetData(_x)*m_symbol.Point(),m_high.GetData(_x)-m_low.GetData(_x))*(_type);
      
      double _sl=m_low.GetData(_x)-(m_step*_atr);
      
      double level =NormalizeDouble(m_symbol.Bid()-m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
      double new_sl=NormalizeDouble(_sl,m_symbol.Digits());
      double pos_sl=position.StopLoss();
      double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
      
      sl=EMPTY_VALUE;
      tp=EMPTY_VALUE;
      if(new_sl>base && new_sl<level)
         sl=new_sl;
//---
   return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for short position.         |
//+------------------------------------------------------------------+
bool CTrailingFT::CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
      if(position==NULL)
         return(false);
   
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
      
      double _ft=ProcessFT(_x);
      double _type=_ft/100.0;
   
      double _atr=fmax(2.0*m_spread.GetData(_x)*m_symbol.Point(),m_high.GetData(_x)-m_low.GetData(_x))*(_type);
      
      double _sl=m_high.GetData(_x)+(m_step*_atr);
      
      double level =NormalizeDouble(m_symbol.Ask()+m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
      double new_sl=NormalizeDouble(_sl,m_symbol.Digits());
      double pos_sl=position.StopLoss();
      double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
      
      sl=EMPTY_VALUE;
      tp=EMPTY_VALUE;
      if(new_sl<base && new_sl>level)
         sl=new_sl;
//---
      return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Fourier Transform                                                |
//| INPUT PARAMETERS                                                 |
//|     Index   -   int, read index within price buffer.             |
//| OUTPUT                                                           |
//|     double  -   forecast change in price                         |
//+------------------------------------------------------------------+
double CTrailingFT::ProcessFT(int Index)
   {
      double _ft=0.0;
      
      int _index=Index;//+StartIndex();
      
      m_close.Refresh(-1);
      
      double _a[];
      matrix _output;
      al_complex _f[];
      
      //6 data points, 5 epicycles
   
      ArrayResize(_a,6);ArrayInitialize(_a,0.0);
      _output.Init(6,5);_output.Fill(0.0);
      
      for(int p=0;p<6;p++)
      {
         _a[p]=m_close.GetData(_index+p)-m_close.GetData(_index+p+1);
      }
      
      FFT.FFTR1D(_a,5,_f);
       
      for(int p=0;p<6;p++)
      {
         for(int s=0;s<5;s++)
         {
            double _divisor=(1.0/5),_angle=(p);_angle/=6;
            _output[p][s]=(_divisor*_a[p]*MathExp(-2.0*__PI*(_f[s].im/_f[s].re)*_angle));
         }
      }
      
      double _close=m_close.GetData(_index)>m_close.GetData(_index+1);
      
      _ft=(_output[5][m_index]/fmax(m_symbol.Point(),fabs(_output[5][m_index])+fabs(_close)))*100.0;
      
      return(_ft);
   }
//+------------------------------------------------------------------+


Bei der Kompilierung mit der integrierten RSI-Signalklasse und dem integrierten Fixed-Margin Money Management erhalten wir diese Ergebnisse für: EURJPY während des Zeitraums: 2022.01.01 bis 2023.01.01 mit dem Zeitrahmen: 4-Stunden. Bei der Durchführung dieses Tests setzen wir weder Gewinnziele noch verwenden wir die Standard-Stop-Loss-Einstellung, daher sind beide Eingaben für diese Werte Null. Wir möchten, dass der Ausstieg ausschließlich durch die Umkehrung des Signals oder das Auslösen des durch unseren Trailing-Stop festgelegten Stop-Loss bestimmt wird.


r_1


Für eine zweite/vergleichende Implementierung werden wir in Erwägung ziehen, die konstituierende Frequenz mit der höchsten Amplitude mit Änderungen der Preisspannen wie oben zu korrelieren.

 

Diese Umsetzung ist im Folgenden aufgeführt:

//+------------------------------------------------------------------+
//|                                                   TrailingCT.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <Math\Alglib\fasttransforms.mqh>
#include <Expert\ExpertTrailing.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Trailing Stop based on 'Fourier Transform' v3              |
//| Type=Trailing                                                    |
//| Name=CategoryTheory                                              |
//| ShortName=CT                                                     |
//| Class=CTrailingFT                                                |
//| Page=trailing_ct                                                 |
//| Parameter=Points,int,6,FT-Points                                 |
//| Parameter=Epicycles,int,5,FT-Epicycles                           | 
//| Parameter=Step,double,0.5,Trailing Step                          |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CTrailingFT.                                               |
//| Appointment: Class traling stops with 'Fourier Transform' v3     |
//|               relative-sets concepts.                            |
//| Derives from class CExpertTrailing.                              |
//+------------------------------------------------------------------+
#define     __PI 245850922/78256779

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CTrailingFT : public CExpertTrailing
  {
protected:
   CFastFourierTransform   FFT;
   
   //--- adjusted parameters
   
   double            m_step;                    // trailing step

public:
   //--- methods of setting adjustable parameters
   
   
   
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual bool      CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp);
   virtual bool      CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp);
   //---
                     CTrailingFT(void);
                    ~CTrailingFT(void);
   //--- methods of setting adjustable parameters
   void              Step(double value)                  { m_step=value;      }

protected:
   
   double            ProcessFT(int Index);

  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CTrailingFT::CTrailingFT(void)
  {
//--- initialization of protected data
   m_used_series=USE_SERIES_TIME+USE_SERIES_SPREAD+USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CTrailingFT::~CTrailingFT(void)
  {
  }
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CTrailingFT::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertTrailing::ValidationSettings())
      return(false);
//--- initial data checks

//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CTrailingFT::InitIndicators(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertTrailing::InitIndicators(indicators))
      return(false);
//--- 
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for long position.          |
//+------------------------------------------------------------------+
bool CTrailingFT::CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
      if(position==NULL)
         return(false);
      
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
      
      double _ft=ProcessFT(_x);
      double _type=_ft/100.0;
      
      double _atr=fmax(2.0*m_spread.GetData(_x)*m_symbol.Point(),m_high.GetData(_x)-m_low.GetData(_x))*(_type);
      
      double _sl=m_low.GetData(_x)-(m_step*_atr);
      
      double level =NormalizeDouble(m_symbol.Bid()-m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
      double new_sl=NormalizeDouble(_sl,m_symbol.Digits());
      double pos_sl=position.StopLoss();
      double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
      
      sl=EMPTY_VALUE;
      tp=EMPTY_VALUE;
      if(new_sl>base && new_sl<level)
         sl=new_sl;
//---
   return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for short position.         |
//+------------------------------------------------------------------+
bool CTrailingFT::CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
      if(position==NULL)
         return(false);
   
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
      
      double _ft=ProcessFT(_x);
      double _type=_ft/100.0;
   
      double _atr=fmax(2.0*m_spread.GetData(_x)*m_symbol.Point(),m_high.GetData(_x)-m_low.GetData(_x))*(_type);
      
      double _sl=m_high.GetData(_x)+(m_step*_atr);
      
      double level =NormalizeDouble(m_symbol.Ask()+m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
      double new_sl=NormalizeDouble(_sl,m_symbol.Digits());
      double pos_sl=position.StopLoss();
      double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
      
      sl=EMPTY_VALUE;
      tp=EMPTY_VALUE;
      if(new_sl<base && new_sl>level)
         sl=new_sl;
//---
      return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Fourier Transform                                                |
//| INPUT PARAMETERS                                                 |
//|     Index   -   int, read index within price buffer.             |
//| OUTPUT                                                           |
//|     double  -   forecast change in price                         |
//+------------------------------------------------------------------+
double CTrailingFT::ProcessFT(int Index)
   {
      double _ft=0.0;
      
      int _index=Index;//+StartIndex();
      
      m_close.Refresh(-1);
      
      double _a[];
      matrix _output;
      al_complex _f[];
      
      //6 data points, 5 epicycles
   
      ArrayResize(_a,6);ArrayInitialize(_a,0.0);
      _output.Init(6,5);_output.Fill(0.0);
      
      for(int p=0;p<6;p++)
      {
         _a[p]=m_close.GetData(_index+p)-m_close.GetData(_index+p+1);
      }
      
      FFT.FFTR1D(_a,5,_f);
       
      for(int p=0;p<6;p++)
      {
         for(int s=0;s<5;s++)
         {
            double _divisor=(1.0/5),_angle=(p);_angle/=6;
            _output[p][s]=(_divisor*_a[p]*MathExp(-2.0*__PI*(_f[s].im/_f[s].re)*_angle));
         }
      }
      
      double _close=m_close.GetData(_index)>m_close.GetData(_index+1);
      
      int _max_index=0;
      double _max=fabs(_output[5][_max_index]);
      for(int s=0;s<5;s++)
      {
         if(_max<fabs(_output[5][s]))
         {
            _max_index=s;
            _max=fabs(_output[5][s]);
         }
      }
      
      _ft=(_output[5][_max_index]/fmax(m_symbol.Point(),fabs(_output[5][_max_index])+fabs(_close)))*100.0;
      
      return(_ft);
   }
//+------------------------------------------------------------------+


Bei der Kompilierung mit denselben Signal- und Geldverwaltungsdateien wie beim obigen Testlauf ergibt sich der folgende Bericht:


r_2


Eine abschließende Implementierung, bei der die minimale und nicht die maximale Amplitudenkomponente verwendet wird und deren Code ebenfalls diesem Artikel beigefügt ist, ergibt den folgenden Bericht:


r_3


Aus unseren drei Beispielberichten geht klar hervor, dass eine geringfügige Änderung unseres Trailing-Stop-Systems mit identischen Einstiegssignalen die Ergebnisse in den Berichten erheblich beeinflusst.


Schlussfolgerung

Zum Schluss haben wir uns angesehen, was die Fourier-Transformation aus der Sicht eines Laien-Händlers ist. Wir haben einige der umfangreichen Anwendungsmöglichkeiten dieser Transformation für Händler aufgezeigt. Anschließend haben wir einige einfache Implementierungen dieser Transformation in MQL5 demonstriert, wobei wir uns auf die Verwendung von Volatilitätsprognosen zur Verwaltung von Stop-Loss-Ausgängen offener Positionen konzentriert haben. Diese Transformation hat viele andere Anwendungen, die ich hier nicht aufgeführt habe, sodass der Leser eingeladen ist, diese zu erforschen. Außerdem ist der hier gezeigte Code kein Gral oder ein „Live-Account-fertiger“ Code für einen Expertenberater, aber auch hier wird der Leser ermutigt, eine unabhängige Prüfung vorzunehmen und herauszufinden, was für ihn/sie funktioniert.

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

Beigefügte Dateien |
TrailingFT_3_.mqh (8.72 KB)
TrailingFT_2_.mqh (8.72 KB)
TrailingFT_1_.mqh (8.84 KB)
Matrizen und Vektoren in MQL5: Die Aktivierungsfunktionen Matrizen und Vektoren in MQL5: Die Aktivierungsfunktionen
Hier wird nur einer der Aspekte des maschinellen Lernens beschrieben — die Aktivierungsfunktionen. In künstlichen neuronalen Netzen berechnet eine Neuronenaktivierungsfunktion einen Ausgangssignalwert auf der Grundlage der Werte eines Eingangssignals oder eines Satzes von Eingangssignalen. Wir werden uns mit den inneren Abläufen des Prozesses befassen.
Erstellen eines EA, der automatisch funktioniert (Teil 15): Automatisierung (VII) Erstellen eines EA, der automatisch funktioniert (Teil 15): Automatisierung (VII)
Zum Abschluss dieser Artikelserie über Automatisierung werden wir das Thema des vorangegangenen Artikels weiter erörtern. Wir werden sehen, wie alles zusammenpassen wird, damit der EA wie ein Uhrwerk läuft.
Integration von ML-Modellen mit dem Strategy Tester (Teil 3): Verwaltung von CSV-Dateien (II) Integration von ML-Modellen mit dem Strategy Tester (Teil 3): Verwaltung von CSV-Dateien (II)
Dieses Material bietet eine vollständige Anleitung zur Erstellung einer Klasse in MQL5 für die effiziente Verwaltung von CSV-Dateien. Wir werden die Implementierung von Methoden zum Öffnen, Schreiben, Lesen und Umwandeln von Daten sehen. Wir werden auch überlegen, wie wir sie zum Speichern und Abrufen von Informationen nutzen können. Darüber hinaus werden wir die Grenzen und die wichtigsten Aspekte bei der Verwendung einer solchen Klasse erörtern. Dieser Artikel kann eine wertvolle Ressource für diejenigen sein, die lernen wollen, wie man CSV-Dateien in MQL5 verarbeitet.
Erstellen eines EA, der automatisch funktioniert (Teil 14): Automatisierung (VI) Erstellen eines EA, der automatisch funktioniert (Teil 14): Automatisierung (VI)
In diesem Artikel werden wir das gesamte Wissen aus dieser Serie in die Praxis umsetzen. Wir werden endlich ein 100%ig automatisiertes und funktionierendes System aufbauen. Aber vorher müssen wir noch ein letztes Detail klären.