English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Application de la transformation de Fisher et de la transformation inverse de Fisher à l'analyse des marchés dans MetaTrader 5

Application de la transformation de Fisher et de la transformation inverse de Fisher à l'analyse des marchés dans MetaTrader 5

MetaTrader 5Trading | 12 janvier 2022, 17:03
269 0
investeo
investeo

Introduction

L'article suivant présente la transformation de Fisher et la transformation inverse de Fisher appliquées aux marchés financiers.

La théorie de la transformation de Fisher est mise en pratique en mettant en œuvre la version MQL5 de l'indicateur Smoothed RSI Inverse Fisher Transform présenté dans le numéro d'octobre 2010 du magazine « Actions et produits de base ». La rentabilité de l'indicateur est backtestée par Expert Advisor qui utilise des signaux basés sur l'indicateur Fisher.

L'article est basé sur des livres et des articles de JFEhlers trouvés sur Internet. Toutes les références sont mentionnées en fin d'article.


1. PDF gaussien vs cycles de marché

Une hypothèse courante est que les prix ont une fonction de densité de probabilité normale.

Cela signifie que les écarts de prix par rapport à la moyenne peuvent être décrits comme une cloche gaussienne bien connue :

Figure 1. Distribution gaussienne 

Figure 1. Cloche gaussienne 

J'ai mentionné la fonction de densité de probabilité normale. Pour bien comprendre cela, introduisons plusieurs idées et formules mathématiques, j'espère qu'elles seront toutes compréhensibles pour la majorité des lecteurs.

Chercher Merriam-Webster, dictionnaire probabilité est définie comme

  1. Le rapport du nombre de résultats dans un ensemble exhaustif de résultats également probables qui produisent un événement donné au nombre total de résultats possibles ou
  2. La chance qu'un événement donné se produise.

Une variable aléatoire est une variable dont la valeur résulte d'une mesure sur un certain type de processus aléatoire. Dans notre cas, la variable aléatoire est le prix d'un actif. 

Enfin, PDF est l'acronyme de Probability Density Function (fonction de densité de probabilité) - une fonction qui décrit la probabilité qu'une variable aléatoire X (encore une fois - dans notre cas le prix) prenne une valeur dans un certain intervalle de valeurs possibles. Une valeur de variable aléatoire qui résulte d'une distribution gaussienne ou d'une distribution normale est une distribution de probabilité qui est souvent utilisée pour décrire des variables aléatoires du monde réel qui ont tendance à se regrouper autour d'une seule valeur moyenne.

Mathématiquement parlant, la probabilité que la variable aléatoire X prenne la valeur qui se situe dans l'intervalle [a,b] est définie comme intégrale :

Figure 2. Intégrale de densité de probabilité

Cela représente l'aire sous la courbe f(x) de a à b. La probabilité est comptée de 0 à 100 % ou de 0 à 1,00, il y a donc une limite selon laquelle l'aire totale sous la courbe f(x) doit être égale à 1 (somme des probabilités) :

Figure 3. Aire totale sous la courbe

Revenons maintenant à la partie inférieure de la figure 1 :

Figure 4. Partie inférieure de la figure gaussienne 

Figure 2. Ecarts types en cloche gaussienne  

Vous pouvez voir ici quel pourcentage de valeurs se situe sous la moyenne +/- 1-3 écarts types (sigmas). Avec la PDF gaussien, 68,27 % des occurrences se situent à plus/moins un écart-type par rapport à la moyenne, 95,45 % se situent à plus/moins deux écarts-types et 99,73 % se situent à plus/moins trois écarts-types par rapport à la moyenne.

Pensez-vous que c'est le cas avec les données de marché réelles ? Pas tout à fait. Lorsque nous examinons les prix du marché, nous pouvons supposer que le graphique ressemble à une vague carrée - après avoir franchi les niveaux de résistance ou de support où les commandes importantes sont groupées, les prix ont tendance à augmenter ou à baisser jusqu'au prochain niveau de support/résistance. C'est pourquoi le marché peut être modélisé avec une grande approximation comme une vague carrée ou sinusoïdale.

Veuillez observer le diagramme sinusoïdal ci-dessous :

sinus

Figure 3. Diagramme sinusoïdal 

Vous devriez remarquer qu'en réalité, la plupart des transactions sont placées de la même manière près des niveaux de support et de résistance, ce qui semble assez naturel. Maintenant, je vais tracer le graphique de la densité d'une onde sinusoïdale. Vous pourriez imaginer que nous tournions la figure 3 de 90 degrés vers la droite et que tous les cercles qui font tomber le tracé tombent au sol : 

Densité 

Figure 4. Diagramme de densité de courbe sinusoïdale  

Vous pouvez remarquer que la densité est plus élevée sur les positions les plus à gauche et les plus à droite. Cela semble être en accord avec l'affirmation précédente selon laquelle la plupart des transactions sont effectuées très près des niveaux de résistance et de support. Vérifions le pourcentage d'occurrences en dessinant un histogramme :

Histogramme

Figure 5. Histogramme de densité de courbe sinusoïdale

Est-ce que ça ressemble à une cloche gaussienne ? Pas exactement. Les trois premières et dernières mesures semblent avoir le plus d'occurrences.

J.F. Dans son livre « Analyse cybernétique des actions et des contrats à terme » Ehlers décrit une expérience où il a analysé des T-Bonds américains sur une période de 15 ans. Il a appliqué un canal normalisé de 10 barres de long et mesuré l'emplacement du prix dans les 100 cases et a compté le nombre de fois où le prix était dans chaque case. Les résultats de cette distribution de probabilité rappellent étroitement ceux d'une onde sinusoïdale.  


2. La transformation de Fisher et son application aux séries chronologiques

Puisque nous savons maintenant que la PDF d'un cycle de marché ne rappelle pas une Gaussienne mais plutôt une PDF d'une onde sinusoïdale et que la plupart des indicateurs supposent que la PDF du cycle de marché est Gaussienne, nous avons besoin d'un moyen de « corriger » cela. La solution consiste à utiliser la transformation de Fisher. La transformation de Fisher change la PDF de n'importe quelle forme d'onde en une forme approximativement gaussienne.

L'équation de la transformation de Fisher est :

Figure 6. Équation de la transformation de Fisher

 Figure 5. Transformation de Fisher

Figure 6. Transformation de Fisher  

J'ai mentionné que la sortie de la transformée de Fisher est approximativement une PDF gaussienne. Pour expliquer cela, il convient d'examiner la figure 6.

Lorsque les données d'entrée sont proches de sa moyenne, le gain est approximativement égal à l'unité (voir le graphique pour |X<0,5|). D'autre part, lorsque l'entrée normalisée s'approche de l'une ou l'autre limite, la sortie est fortement amplifiée (voir le graphique pour 0,5<|x|<1). Dans la pratique, on peut penser à une queue « presque gaussienne », croissante, lorsque les écarts sont les plus importants - c'est exactement ce qui se passe avec la PDF transformée. 

Comment appliquer la transformation de Fisher au trading ? Dans un premier temps, en raison de la contrainte |x|<1, les prix doivent être normalisés dans cet intervalle. Lorsque les prix normalisés sont soumis à la transformation de Fisher, les mouvements de prix extrêmes deviennent relativement rares. Cela signifie que la transformation de Fisher capte ces mouvements de prix extrêmes et nous permet de faire du trading en fonction de ces extrêmes.


3. La transformation de Fisher dans MQL5

Le code source de l'indicateur de la transformation de Fisher est décrit dans le livre de Ehlers « Cybernetic Analysis for Stocks and Futures ».

Il a déjà été mis en œuvre dans MQL4 et je l'ai converti en MQL5. L'indicateur utilise les prix médians (H+L)/2, j'ai utilisé la fonction iMA() pour extraire les prix médians de l'historique.

Dans un premier temps, les prix sont normalisés dans un intervalle de 10 barres et les prix normalisés sont soumis à la transformation de Fisher.

//+------------------------------------------------------------------+
//|                                              FisherTransform.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                           http://www.investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http://www.investeo.pl"
#property version   "1.00"
#property indicator_separate_window

#property description "MQL5 version of Fisher Transform indicator"

#property indicator_buffers 4
#property indicator_level1 0
#property indicator_levelcolor Silver
#property indicator_plots 2
#property indicator_type1         DRAW_LINE
#property indicator_color1        Red
#property indicator_width1 1
#property indicator_type2         DRAW_LINE
#property indicator_color2        Blue
#property indicator_width2 1

double Value1[];
double Fisher[];
double Trigger[];

input int Len=10;

double medianbuff[];
int hMedian;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,Fisher,INDICATOR_DATA);
   SetIndexBuffer(1,Trigger,INDICATOR_DATA);
   SetIndexBuffer(2,Value1,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,medianbuff,INDICATOR_CALCULATIONS);
   ArraySetAsSeries(Fisher,true);
   ArraySetAsSeries(Trigger,true);
   ArraySetAsSeries(Value1,true);
   ArraySetAsSeries(medianbuff,true);
   
   hMedian = iMA(_Symbol,PERIOD_CURRENT,1,0,MODE_SMA,PRICE_MEDIAN);
   if(hMedian==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iMA indicator for the symbol %s/%s, error code %d",
                 _Symbol,
                 EnumToString(PERIOD_CURRENT),
                 GetLastError());
      //--- the indicator is stopped early, if the returned value is negative
      return(-1);
     }
//---
   return(0);
  }
  
//+------------------------------------------------------------------+
//| 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[])
  {
//---
   int  nLimit=MathMin(rates_total-Len-1,rates_total-prev_calculated);
   int copied = CopyBuffer(hMedian,0,0,nLimit,medianbuff);
   if (copied!=nLimit) return (-1);
   nLimit--;
   for(int i=nLimit; i>=0; i--) 
     {
      double price=medianbuff[i];
      double MaxH = price;
      double MinL = price;
      for(int j=0; j<Len; j++) 
        {
         double nprice=medianbuff[i+j];
         if (nprice > MaxH) MaxH = nprice;
         if (nprice < MinL) MinL = nprice;
        }
      Value1[i]=0.5*2.0 *((price-MinL)/(MaxH-MinL)-0.5)+0.5*Value1[i+1];
      if(Value1[i]>0.9999) Value1[i]=0.9999;
      if(Value1[i]<-0.9999) Value1[i]=-0.9999;
      Fisher[i]=0.25*MathLog((1+Value1[i])/(1-Value1[i]))+0.5*Fisher[i+1];
      Trigger[i]=Fisher[i+1];
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Veuillez noter que des signaux aigus sont générés.

La ligne de signal est simplement le prix transformé de Fisher retardé d'une barre :

Indicateur de transformation de Fisher 

Figure 7. Indicateur de transformation de Fisher  

 

4. Transformation de Fisher inverse et son application aux indicateurs de cycle

L'équation de la transformation de Fisher inverse est obtenue en résolvant l'équation de la transformation de Fisher pour x en fonction de y :

Figure 8. Équation de la transformation de Fisher inverse,

Figure 6. Transformation de Fisher inverse 

Figure 8. Transformation de Fisher inverse 

La réponse de transfert de cette fonction est inverse de celle de la transformation de Fisher.

Pour |x|>2 l'entrée est compressée pour ne pas dépasser l'unité (pour les nombres négatifs -1 et pour les positifs +1) et pour |x|<1 c'est une relation presque linéaire qui signifie que la sortie a plus moins les mêmes caractéristiques que l'entrée.

Le résultat est que lorsque la transformation de Fisher inverse est appliquée à des données d'entrée correctement préparées, la sortie a de grandes chances d'être -1 ou +1. Cela rend la transformation de Fisher inverse parfaite pour l'appliquer aux indicateurs d'oscillateur. La transformation de Fisher inverse peut les améliorer en donnant des signaux d'achat ou de vente précis. 

 

5. Exemple de transformation de Fisher inverse dans MQL5

Afin de vérifier la transformation de Fisher inverse, j'ai mis en œuvre la version MQL5 de l'indicateur Vervoort Smoothed RSI transformation de Fisher inverse de Sylvain présenté dans le numéro d'octobre 2010 du magazine «Stocks and Commodities » et j'ai construit un module de signal de trading et Expert Advisor basé sur cet indicateur.

L'indicateur de transformation de Fisher inverse a déjà été mis en œuvre pour de nombreuses plateformes de trading, les codes sources sont disponibles sur les sites web traders.com site web et MQL5.com Code Base.

Comme il n'y avait pas de fonction irSIOnArray dans MQL5, je l'ai ajoutée au code indicateur. La seule différence avec l'indicateur original est la période RSIP fixée à 21 et la période EMAP fixée à 34, car il se comporte mieux pour mes paramètres (EURUSD 1H). Vous pouvez le changer par défaut pour RSIPeriod 4 et EMAPeriod 4.

//+------------------------------------------------------------------+
//|                            SmoothedRSIInverseFisherTransform.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                           http://www.investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http://www.investeo.pl"
#property version   "1.00"
#property indicator_separate_window
#include <MovingAverages.mqh>
#property description "MQL5 version of Silvain Vervoort's Inverse RSI"
#property indicator_minimum -10
#property indicator_maximum 110
#property indicator_buffers 16
#property indicator_level1 12
#property indicator_level2 88
#property indicator_levelcolor Silver
#property indicator_plots 1
#property indicator_type1         DRAW_LINE
#property indicator_color1        LightSeaGreen
#property indicator_width1 2

int                  ma_period=10;             // period of ma
int                  ma_shift=0;               // shift
ENUM_MA_METHOD       ma_method=MODE_LWMA;        // type of smoothing
ENUM_APPLIED_PRICE   applied_price=PRICE_CLOSE// type of price

double wma0[];
double wma1[];
double wma2[];
double wma3[];
double wma4[];
double wma5[];
double wma6[];
double wma7[];
double wma8[];
double wma9[];
double ema0[];
double ema1[];
double rainbow[];
double rsi[];
double bufneg[];
double bufpos[];
double srsi[];
double fish[];

int hwma0;

int wma1weightsum;
int wma2weightsum;
int wma3weightsum;
int wma4weightsum;
int wma5weightsum;
int wma6weightsum;
int wma7weightsum;
int wma8weightsum;
int wma9weightsum;

extern int     RSIPeriod=21;
extern int     EMAPeriod=34;

  
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0,fish,INDICATOR_DATA);
   SetIndexBuffer(1,wma0,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,wma1,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,wma2,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,wma3,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,wma4,INDICATOR_CALCULATIONS);
   SetIndexBuffer(6,wma5,INDICATOR_CALCULATIONS);
   SetIndexBuffer(7,wma6,INDICATOR_CALCULATIONS);
   SetIndexBuffer(8,wma7,INDICATOR_CALCULATIONS);
   SetIndexBuffer(9,wma8,INDICATOR_CALCULATIONS);
   SetIndexBuffer(10,wma9,INDICATOR_CALCULATIONS);
   SetIndexBuffer(11,rsi,INDICATOR_CALCULATIONS);
   SetIndexBuffer(12,ema0,INDICATOR_CALCULATIONS);
   SetIndexBuffer(13,srsi,INDICATOR_CALCULATIONS);
   SetIndexBuffer(14,ema1,INDICATOR_CALCULATIONS);
   SetIndexBuffer(15,rainbow,INDICATOR_CALCULATIONS);

   ArraySetAsSeries(fish,true);
   ArraySetAsSeries(wma0,true);
   ArraySetAsSeries(wma1,true);
   ArraySetAsSeries(wma2,true);
   ArraySetAsSeries(wma3,true);
   ArraySetAsSeries(wma4,true);
   ArraySetAsSeries(wma5,true);
   ArraySetAsSeries(wma6,true);
   ArraySetAsSeries(wma7,true);
   ArraySetAsSeries(wma8,true);
   ArraySetAsSeries(wma9,true);
   ArraySetAsSeries(ema0,true);
   ArraySetAsSeries(ema1,true);
   ArraySetAsSeries(rsi,true);
   ArraySetAsSeries(srsi,true);
   ArraySetAsSeries(rainbow,true);

   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,0);
//--- sets drawing line empty value
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
//--- digits
   IndicatorSetInteger(INDICATOR_DIGITS,2);

   hwma0=iMA(_Symbol,PERIOD_CURRENT,2,ma_shift,ma_method,applied_price);
   if(hwma0==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iMA indicator for the symbol %s/%s, error code %d",
                  _Symbol,
                  EnumToString(PERIOD_CURRENT),
                  GetLastError());
      //--- the indicator is stopped early, if the returned value is negative
      return(-1);
     }

   return(0);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//---
   int nLimit;

   if(rates_total!=prev_calculated)
     {
      CopyBuffer(hwma0,0,0,rates_total-prev_calculated+1,wma0);
      LinearWeightedMAOnBuffer(rates_total,prev_calculated,0,2,wma0,wma1,wma1weightsum);
      LinearWeightedMAOnBuffer(rates_total,prev_calculated,0,2,wma1,wma2,wma2weightsum);
      LinearWeightedMAOnBuffer(rates_total,prev_calculated,0,2,wma2,wma3,wma3weightsum);
      LinearWeightedMAOnBuffer(rates_total,prev_calculated,0,2,wma3,wma4,wma4weightsum);
      LinearWeightedMAOnBuffer(rates_total,prev_calculated,0,2,wma4,wma5,wma5weightsum);
      LinearWeightedMAOnBuffer(rates_total,prev_calculated,0,2,wma5,wma6,wma6weightsum);
      LinearWeightedMAOnBuffer(rates_total,prev_calculated,0,2,wma6,wma7,wma7weightsum);
      LinearWeightedMAOnBuffer(rates_total,prev_calculated,0,2,wma7,wma8,wma8weightsum);
      LinearWeightedMAOnBuffer(rates_total,prev_calculated,0,2,wma8,wma9,wma9weightsum);

      if(prev_calculated==0) nLimit=rates_total-1;
      else nLimit=rates_total-prev_calculated+1;
      
      for(int i=nLimit; i>=0; i--)
         rainbow[i]=(5*wma0[i]+4*wma1[i]+3*wma2[i]+2*wma3[i]+wma4[i]+wma5[i]+wma6[i]+wma7[i]+wma8[i]+wma9[i])/20.0;

      iRSIOnArray(rates_total,prev_calculated,11,RSIPeriod,rainbow,rsi,bufpos,bufneg);

      ExponentialMAOnBuffer(rates_total,prev_calculated,12,EMAPeriod,rsi,ema0);
      ExponentialMAOnBuffer(rates_total,prev_calculated,13,EMAPeriod,ema0,ema1);

      for(int i=nLimit; i>=0; i--)
         srsi[i]=ema0[i]+(ema0[i]-ema1[i]);

      for(int i=nLimit; i>=0; i--)
         fish[i]=((MathExp(2*srsi[i])-1)/(MathExp(2*srsi[i])+1)+1)*50;         
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
///                        Calculating RSI
//+------------------------------------------------------------------+
int iRSIOnArray(const int rates_total,const int prev_calculated,const int begin,
                const int period,const double &price[],double &buffer[],double &bpos[],double &bneg[])
  {
   int        i;
//--- check for data
   ArrayResize(bneg,rates_total);
   ArrayResize(bpos,rates_total);

   if(period<=1 || rates_total-begin<period) return(0);
//--- save as_series flags
   bool as_series_price=ArrayGetAsSeries(price);
   bool as_series_buffer=ArrayGetAsSeries(buffer);
   if(as_series_price) ArraySetAsSeries(price,false);
   if(as_series_buffer) ArraySetAsSeries(buffer,false);

   double diff=0.0;
//--- check for rates count
   if(rates_total<=period)
      return(0);
//--- preliminary calculations
   int ppos=prev_calculated-1;
   if(ppos<=begin+period)
     {
      //--- first RSIPeriod values of the indicator are not calculated
      for (i=0; i<begin; i++)
      {
      buffer[i]=0.0;
      bpos[i]=0.0;
      bneg[i]=0.0;
      }
      double SumP=0.0;
      double SumN=0.0;
      for(i=begin;i<=begin+period;i++)
        {
         buffer[i]=0.0;
         bpos[i]=0.0;
         bneg[i]=0.0;
         //PrintFormat("%f %f\n", price[i], price[i-1]);
         diff=price[i]-price[i-1];
         SumP+=(diff>0?diff:0);
         SumN+=(diff<0?-diff:0);
        }
      //--- calculate first visible value
      bpos[begin+period]=SumP/period;
      bneg[begin+period]=SumN/period;
      if (bneg[begin+period]>0.0000001)
      buffer[begin+period]=0.1*((100.0-100.0/(1+bpos[begin+period]/bneg[begin+period]))-50);
      //--- prepare the position value for main calculation
      ppos=begin+period+1;
     }
//--- the main loop of calculations

   for(i=ppos;i<rates_total && !IsStopped();i++)
     {
      diff=price[i]-price[i-1];
      bpos[i]=(bpos[i-1]*(period-1)+((diff>0.0)?(diff):0.0))/period;
      bneg[i]=(bneg[i-1]*(period-1)+((diff<0.0)?(-diff):0.0))/period;
      if (bneg[i]>0.0000001)
      buffer[i]=0.1*((100.0-100.0/(1+bpos[i]/bneg[i]))-50);
      //Print(buffer[i]);
     }
//--- restore as_series flags
   if(as_series_price) ArraySetAsSeries(price,true);
   if(as_series_buffer) ArraySetAsSeries(buffer,true);

   return(rates_total);
  }
//+------------------------------------------------------------------+

 Indicateur de Fisher inverse

Figure 9. Indicateur de transformation de Fisher inverse  

Étant donné que je n'ai présenté que des équations de transformation, vous pourriez être intrigué par les origines de la transformation de Fisher et de la transformation de Fisher inverse.

Lorsque j'ai rassemblé les documents nécessaires à la rédaction de l'article, je me suis intéressé à la manière dont Fisher avait obtenu ces deux transformations, mais je n'ai rien trouvé sur Internet.

Mais j'ai regardé la transformation de Fisher et la transformation de Fisher inverse et les deux graphiques m'ont fait penser à une sorte de fonction trigonométrique ou hyperbolique (voyez-vous des similitudes ?). Étant donné que ces fonctions peuvent être dérivées de la formule d'Euler et exprimées en termes de nombre « e » d'Euler, je suis revenu aux livres de calcul et j'ai vérifié que :

Figure 9. Équation de Sinh,

Figure 11. Équation de Cosh,

et puisque nous savons maintenant que tanh(x) peut être obtenu par :

Figure 12. Équation de Tanh,

et... 

Figure 12. Équation d'Atanh 

Oui, ce sont exactement les mêmes équations que j'ai présentées ci-dessus. La transformation de Fisher démystifiée ! La transformation de Fisher est simplement arctanh(x) et la transformation de Fisher inverse est son inverse, tanh(x) !


6. Module de signaux de trading

Afin de vérifier la transformation inverse de Fisher, j’ai construit un module de signal de trading basé sur l'indicateur de transformation inverse de Fisher.

Vous trouverez peut-être utile de voir le module de trading basé sur un indicateur personnalisé. J'ai utilisé l'instance de classe CiCustom pour contenir l'indicateur de Fisher Inverse et remplacé quatre méthodes virtuelles de la classe CExpertSignal : CheckOpenLong() et CheckOpenShort() sont responsables de la génération de signaux lorsqu'il n'y a pas de position ouverte et CheckReverseLong() et CheckReverseShort() sont responsables de l'inversion de la position ouverte. 

//+------------------------------------------------------------------+
//|                               InverseFisherRSISmoothedSignal.mqh |
//|                                    Copyright © 2011, Investeo.pl |
//|                                               http://Investeo.pl |
//|                                                      Version v01 |
//+------------------------------------------------------------------+
#property tester_indicator "SmoothedRSIInverseFisherTransform.ex5"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| Class CSignalInverseFisherRSISmoothed.                           |
//| Description: Class generating InverseFisherRSISmoothed signals   |
//|              Derived from CExpertSignal.                         |
//+------------------------------------------------------------------+

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signal on the Inverse Fisher RSI Smoothed Indicator        |
//| Type=SignalAdvanced                                              |
//| Name=InverseFisherRSISmoothed                                    |
//| Class=CSignalInverseFisherRSISmoothed                            |
//| Page=                                                            |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| CSignalInverseFisherRSISmoothed class                            |
//| Purpose: A class of a module of trade signals,                   |
//| on InverseFisherRSISmoothed                                      |
//+------------------------------------------------------------------+
class CSignalInverseFisherRSISmoothed : public CExpertSignal
  {
protected:
   CiCustom          m_invfish;
   double            m_stop_loss;
   
public:
                     CSignalInverseFisherRSISmoothed();
   //--- methods initialize protected data
   virtual bool      InitIndicators(CIndicators *indicators);
   virtual bool      ValidationSettings();
   //---
   virtual bool      CheckOpenLong(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      CheckReverseLong(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      CheckOpenShort(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      CheckReverseShort(double &price,double &sl,double &tp,datetime &expiration);
   
protected:
   bool              InitInvFisher(CIndicators *indicators);
   double            InvFish(int ind) { return(m_invfish.GetData(0,ind)); }
  };
//+------------------------------------------------------------------+
//| Constructor CSignalInverseFisherRSISmoothed.                                    |
//| INPUT:  no.                                                      |
//| OUTPUT: no.                                                      |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
void CSignalInverseFisherRSISmoothed::CSignalInverseFisherRSISmoothed()
  {
//--- initialize protected data
  }
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//| INPUT:  no.                                                      |
//| OUTPUT: true-if settings are correct, false otherwise.           |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
bool CSignalInverseFisherRSISmoothed::ValidationSettings()
  {
//--- initial data checks
 if(!CExpertSignal::ValidationSettings()) return(false);
//--- ok
   return(true);
  }
  
//+------------------------------------------------------------------+
//| Create Inverse Fisher custom indicator.                          |
//| INPUT:  indicators -pointer of indicator collection.             |
//| OUTPUT: true-if successful, false otherwise.                     |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
  bool CSignalInverseFisherRSISmoothed::InitInvFisher(CIndicators *indicators)
  {
//--- check pointer
   printf(__FUNCTION__+": initializing Inverse Fisher Indicator");
   if(indicators==NULL) return(false);
//--- add object to collection
   if(!indicators.Add(GetPointer(m_invfish)))
     {
      printf(__FUNCTION__+": error adding object");
      return(false);
     }
     MqlParam invfish_params[];
   ArrayResize(invfish_params,2);
   invfish_params[0].type=TYPE_STRING;
   invfish_params[0].string_value="SmoothedRSIInverseFisherTransform";
   //--- applied price
   invfish_params[1].type=TYPE_INT;
   invfish_params[1].integer_value=PRICE_CLOSE;
//--- initialize object
   if(!m_invfish.Create(m_symbol.Name(),m_period,IND_CUSTOM,2,invfish_params))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
   m_invfish.NumBuffers(18);
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Create indicators.                                               |
//| INPUT:  indicators -pointer of indicator collection.             |
//| OUTPUT: true-if successful, false otherwise.                     |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
bool CSignalInverseFisherRSISmoothed::InitIndicators(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL) return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertSignal::InitIndicators(indicators)) return(false);
//--- create and initialize SAR indicator
   if(!InitInvFisher(indicators)) return(false);
   m_stop_loss = 0.0010;
//--- ok
   printf(__FUNCTION__+": all inidicators properly initialized.");
   return(true);
  }
//+------------------------------------------------------------------+
//| Check conditions for long position open.                         |
//| INPUT:  price      - reference for price,                        |
//|         sl         - reference for stop loss,                    |
//|         tp         - reference for take profit,                  |
//|         expiration - reference for expiration.                   |
//| OUTPUT: true-if condition performed, false otherwise.            |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
bool CSignalInverseFisherRSISmoothed::CheckOpenLong(double &price,double &sl,double &tp,datetime &expiration)
  {
   printf(__FUNCTION__+" checking signal");
   
   int idx=StartIndex();
   
//---
   price=0.0;
   tp   =0.0;
//---
   if(InvFish(idx+2)<12.0 && InvFish(idx+1)>12.0)
   { 
      printf(__FUNCTION__ + " BUY SIGNAL");
      return true;
   } else printf(__FUNCTION__ + " NO SIGNAL");
//---
   return false;
  }
//+------------------------------------------------------------------+
//| Check conditions for long position close.                        |
//| INPUT:  price - refernce for price.                              |
//| OUTPUT: true-if condition performed, false otherwise.            |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
bool CSignalInverseFisherRSISmoothed::CheckReverseLong(double &price,double &sl,double &tp,datetime &expiration)
  {
   long tickCnt[1];
   int ticks=CopyTickVolume(Symbol(), 0, 0, 1, tickCnt);
   if (ticks!=1 || tickCnt[0]!=1) return false;
   
   int idx=StartIndex();
   
   price=0.0;
// sl   =m_symbol.NormalizePrice(m_symbol.Bid()+20*m_stop_level);
//---
   
   if((InvFish(idx+1)>88.0 && InvFish(idx)<88.0)  || 
     (InvFish(idx+2)>88.0 && InvFish(idx+1)<88.0) ||
     (InvFish(idx+2)>12.0 && InvFish(idx+1)<12.0))
  {
   printf(__FUNCTION__ + " REVERSE LONG SIGNAL");
   return true;
   } else printf(__FUNCTION__ + " NO SIGNAL");
   return false;
  }
//+------------------------------------------------------------------+
//| Check conditions for short position open.                        |
//| INPUT:  price      - refernce for price,                         |
//|         sl         - refernce for stop loss,                     |
//|         tp         - refernce for take profit,                   |
//|         expiration - refernce for expiration.                    |
//| OUTPUT: true-if condition performed, false otherwise.            |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
bool CSignalInverseFisherRSISmoothed::CheckOpenShort(double &price,double &sl,double &tp,datetime &expiration)
  {
   printf(__FUNCTION__+" checking signal");
   int idx=StartIndex();
//---
   price=0.0;
   sl   = 0.0;
//---
   if(InvFish(idx+2)>88.0 && InvFish(idx+1)<88.0)
   {printf(__FUNCTION__ + " SELL SIGNAL");
      return true;} else printf(__FUNCTION__ + " NO SIGNAL");
      
//---
   return false;
  }
//+------------------------------------------------------------------+
//| Check conditions for short position close.                       |
//| INPUT:  price - refernce for price.                              |
//| OUTPUT: true-if condition performed, false otherwise.            |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
bool CSignalInverseFisherRSISmoothed::CheckReverseShort(double &price,double &sl,double &tp,datetime &expiration)
  {
   long tickCnt[1];
   int ticks=CopyTickVolume(Symbol(), 0, 0, 1, tickCnt);
   if (ticks!=1 || tickCnt[0]!=1) return false;
   
   int idx=StartIndex();
  
   price=0.0;
//---
   
   if((InvFish(idx+1)<12.0 && InvFish(idx)>12.0) ||
    (InvFish(idx+2)<12.0 && InvFish(idx+1)>12.0) ||
    (InvFish(idx+2)<88.0 && InvFish(idx+1)>88.0)) 
  {
   printf(__FUNCTION__ + " REVERSE SHORT SIGNAL");
   return true;
   } else printf(__FUNCTION__ + " NO SIGNAL");
   return false;
  }

 

7. Expert Advisor

Afin de vérifier la transformation inverse de Fisher, j’ai construit un EA standard qui utilise le module de signal de trading présenté précédemment.

J'ai également ajouté un module trailing stop-loss tiré de l'article « MQL5 Wizard : Comment créer un module de suivi des positions ouvertes ».

//+------------------------------------------------------------------+
//|                                                 InvRSIFishEA.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include                                                          |
//+------------------------------------------------------------------+
#include <Expert\Expert.mqh>
//--- available signals
#include <Expert\Signal\MySignal\InverseFisherRSISmoothedSignal.mqh>
//--- available trailing
#include <Expert\Trailing\SampleTrailing.mqh>
//--- available money management
#include <Expert\Money\MoneyFixedLot.mqh>
//+------------------------------------------------------------------+
//| Inputs                                                           |
//+------------------------------------------------------------------+
//--- inputs for expert
input string Expert_Title         ="InvRSIFishEA";   // Document name
ulong        Expert_MagicNumber   =7016; // 
bool         Expert_EveryTick     =true; // 
//--- inputs for main signal
input int    Signal_ThresholdOpen =10;    // Signal threshold value to open [0...100]
input int    Signal_ThresholdClose=10;    // Signal threshold value to close [0...100]
input double Signal_PriceLevel    =0.0;   // Price level to execute a deal
input double Signal_StopLevel     =0.0;   // Stop Loss level (in points)
input double Signal_TakeLevel     =0.0;   // Take Profit level (in points)
input int    Signal_Expiration    =0;    // Expiration of pending orders (in bars)
input double Signal__Weight       =1.0;   // InverseFisherRSISmoothed Weight [0...1.0]
//--- inputs for money
input double Money_FixLot_Percent =10.0;  // Percent
input double Money_FixLot_Lots    =0.2;   // Fixed volume
//+------------------------------------------------------------------+
//| Global expert object                                             |
//+------------------------------------------------------------------+
CExpert ExtExpert;
//+------------------------------------------------------------------+
//| Initialization function of the expert                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Initializing expert
   if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber))
     {
      //--- failed
      printf(__FUNCTION__+": error initializing expert");
      ExtExpert.Deinit();
      return(-1);
     }
//--- Creating signal
   CSignalInverseFisherRSISmoothed *signal=new CSignalInverseFisherRSISmoothed;
   if(signal==NULL)
     {
      //--- failed
      printf(__FUNCTION__+": error creating signal");
      ExtExpert.Deinit();
      return(-2);
     }
//---
   ExtExpert.InitSignal(signal);
   signal.ThresholdOpen(Signal_ThresholdOpen);
   signal.ThresholdClose(Signal_ThresholdClose);
   signal.PriceLevel(Signal_PriceLevel);
   signal.StopLevel(Signal_StopLevel);
   signal.TakeLevel(Signal_TakeLevel);
   signal.Expiration(Signal_Expiration);

//--- Creation of trailing object
   CSampleTrailing *trailing=new CSampleTrailing;
   trailing.StopLevel(0);
   trailing.Profit(20);
   
   if(trailing==NULL)
     {
      //--- failed
      printf(__FUNCTION__+": error creating trailing");
      ExtExpert.Deinit();
      return(-4);
     }
//--- Add trailing to expert (will be deleted automatically))
   if(!ExtExpert.InitTrailing(trailing))
     {
      //--- failed
      printf(__FUNCTION__+": error initializing trailing");
      ExtExpert.Deinit();
      return(-5);
     }
//--- Set trailing parameters
//--- Creation of money object
   CMoneyFixedLot *money=new CMoneyFixedLot;
   if(money==NULL)
     {
      //--- failed
      printf(__FUNCTION__+": error creating money");
      ExtExpert.Deinit();
      return(-6);
     }
//--- Add money to expert (will be deleted automatically))
   if(!ExtExpert.InitMoney(money))
     {
      //--- failed
      printf(__FUNCTION__+": error initializing money");
      ExtExpert.Deinit();
      return(-7);
     }
//--- Set money parameters
   money.Percent(Money_FixLot_Percent);
   money.Lots(Money_FixLot_Lots);
//--- Check all trading objects parameters
   if(!ExtExpert.ValidationSettings())
     {
      //--- failed
      ExtExpert.Deinit();
      return(-8);
     }
//--- Tuning of all necessary indicators
   if(!ExtExpert.InitIndicators())
     {
      //--- failed
      printf(__FUNCTION__+": error initializing indicators");
      ExtExpert.Deinit();
      return(-9);
     }
//--- ok
   return(0);
  }
//+------------------------------------------------------------------+
//| Deinitialization function of the expert                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ExtExpert.Deinit();
  }
//+------------------------------------------------------------------+
//| "Tick" event handler function                                    |
//+------------------------------------------------------------------+
void OnTick()
  {
   ExtExpert.OnTick();
  }
//+------------------------------------------------------------------+
//| "Trade" event handler function                                   |
//+------------------------------------------------------------------+
void OnTrade()
  {
   ExtExpert.OnTrade();
  }
//+------------------------------------------------------------------+
//| "Timer" event handler function                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   ExtExpert.OnTimer();
  }
//+------------------------------------------------------------------+

Je dois admettre que l'EA n'était pas rentable pour chaque actif et pour chaque période, mais je l'ai modifié pour donner de très bons résultats pour la période EURUSD 1H.

J'encourage les lecteurs à essayer de modifier le module de signal et les paramètres de l'indicateur, vous trouverez peut-être un EA plus rentable que celui présenté dans l'article.

Graphique EA 

Figure 10. EA transformation de Fisher inverse

Résultat EA

Figure 11. Graphique d'équilibre EA de la transformation de Fisher inverse


Conclusion

J'espère que cet article a fourni une bonne introduction à la transformation de Fisher et à la transformation de Fisher inverse et a montré une façon de construire un module de trading de signaux basé sur un indicateur personnalisé.

J'ai utilisé l'indicateur RSI Vervoort Smoothed transformation de Fisher inverse de Sylvain, mais en fait vous pouvez facilement appliquer la transformation de Fisher inverse à n'importe quel oscillateur et construire un EA sur la base de cet article.

J'encourage également les lecteurs à modifier les paramètres pour créer un EA rentable basé sur celui que j'ai présenté. J’ai fournis des liens externes pour une référence supplémentaire ci-dessous.


Références

  1. La transformation de Fisher
  2. Utilisation de la transformation de Fisher
  3. La transformation de Fisher inverse
  4. transformation de Fisher inverse RSI lissée

Traduit de l’anglais par MetaQuotes Ltd.
Article original : https://www.mql5.com/en/articles/303

Comment développer un Expert Advisor à l'aide des outils UML Comment développer un Expert Advisor à l'aide des outils UML
Cet article traite de la création d'Expert Advisors à l'aide du langage graphique UML, qui est utilisé pour la modélisation visuelle de systèmes logiciels orientés objet. Le principal avantage de cette approche est la visualisation du processus de modélisation. L'article contient un exemple qui montre la modélisation de la structure et des propriétés d'un Expert Advisor à l'aide du logiciel Ideas Modeler.
Paiements et modes de paiement Paiements et modes de paiement
Les services de MQL5.community offrent de grandes possibilités aux traders ainsi qu'aux développeurs d'applications pour le terminal MetaTrader. Dans cet article, nous expliquons comment les paiements pour les services MQL5 sont effectués, comment l'argent gagné peut être retiré et comment la sécurité de l'opération est assurée.
Comment ajouter de nouvelles langues à l'interface utilisateur de la plateforme MetaTrader 5 Comment ajouter de nouvelles langues à l'interface utilisateur de la plateforme MetaTrader 5
L'interface utilisateur de la plateforme MetaTrader 5 est traduite en plusieurs langues. Ne vous inquiétez pas si votre langue maternelle ne fait pas partie des langues prises en charge. Vous pouvez facilement effectuer la traduction en utilisant l'utilitaire spécial MetaTrader 5 MultiLanguage Pack, offert gratuitement par MetaQuotes Software Corp. à tous les participants. Dans cet article, nous allons montrer quelques exemples de la façon d'ajouter une nouvelle langue d'interface utilisateur à la plateforme MetaTrader 5.
Utilisation de WinInet dans MQL5.  Partie 2 :  Requêtes et fichiers POST Utilisation de WinInet dans MQL5. Partie 2 : Requêtes et fichiers POST
Dans cet article, nous continuons à étudier les principes du travail avec Internet en utilisant les requêtes HTTP et l'échange d'informations avec le serveur. Il décrit les nouvelles fonctions de la classe CMqlNet, les méthodes d'envoi d'informations à partir de formulaires et l'envoi de fichiers à l'aide de requêtes POST ainsi que l'autorisation sur les sites web sous votre identifiant à l'aide de cookies.