English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Fisher Dönüşümü ve Ters Fisher Dönüşümünü MetaTrader 5'te Piyasa Analizine Uygulama

Fisher Dönüşümü ve Ters Fisher Dönüşümünü MetaTrader 5'te Piyasa Analizine Uygulama

MetaTrader 5Ticaret | 22 Aralık 2021, 14:00
220 0
investeo
investeo

Giriş

Aşağıdaki makalede, finansal piyasalara uygulanan Fisher Dönüşümü ve Ters Fisher Dönüşümü sunulmaktadır.

Fisher Dönüşümü teorisi, "Stocks and Commodities" dergisinin Ekim 2010 sayısında sunulan Düzgünleştirilmiş RSI Ters Fisher Dönüşümü göstergesinin MQL5 sürümünün uygulanmasıyla uygulamaya konulmuştur. Gösterge karlılığı, Fisher göstergesine dayalı sinyalleri kullanan Expert Advisor tarafından geriye dönük test edilir.

Makale J.F.Ehlers'in kitaplarına ve internette bulunan makalelere dayanmaktadır. Tüm referanslar makalenin sonunda belirtilmiştir.


1. Gauss PDF'i ve Piyasa Döngüleri

Yaygın bir varsayım, fiyatların normal olasılık yoğunluk fonksiyonuna sahip olmasıdır.

Bu, ortalamadan fiyat sapmalarının iyi bilinen bir Gauss çanı olarak tanımlanabileceği anlamına gelir:

Şekil 1. Gauss dağılımı 

Şekil 1. Gauss çanı

Normal olasılık yoğunluk fonksiyonundan söz etmiştim. Bunu tam olarak anlamak için, birkaç fikir ve matematik formülü sunalım; umarım bunlar, okuyucuların çoğu için anlaşılır olacaktır.

Merriam-Webster sözlüğü olasılık takibi şu şekilde tanımlanır

  1. Belirli bir olayı üreten eşit derecede olası sonuçların kapsamlı bir kümesindeki sonuçların sayısının, olası sonuçların toplam sayısına oranı veya
  2. Belirli bir olayın meydana gelme olasılığı.

Bir rastgele değişken, değeri bir tür rastgele süreç üzerindeki bir ölçümden kaynaklanan bir değişkendir. Bizim durumumuzda, rastgele değişken bir varlığın fiyatıdır. 

Son olarak, PDF, Olasılık Yoğunluk Fonksiyonu'nun kısaltmasıdır - Bir X rastgele değişkeninin (yine - bizim durumumuzda fiyat) belirli bir olası değerler aralığında bir değer alma olasılığını tanımlayan bir fonksiyon. Bir Gauss dağılımından veya Normal dağılımdan kaynaklanan bir rastgele değişken değeri, genellikle tek bir ortalama değer etrafında kümelenme eğiliminde olan gerçek dünyadaki rastgele değişkenleri tanımlamak için kullanılan bir olasılık dağılımıdır.

Matematiksel olarak konuşursak, X rastgele değişkeninin [a,b] aralığında yer alan bir değeri alması olasılığı integral olarak tanımlanır:

Şekil 2. Olasılık Yoğunluk integrali

Bu, a'dan b'ye f(x) eğrisinin altındaki alanı temsil eder. Olasılık 0'dan %100'e veya 0'dan 1,00'a kadar sayılır; bu nedenle f(x) eğrisi altındaki toplam alanın 1'e (olasılıkların toplamı) eşit olması gerektiği konusunda bir sınır vardır:

Şekil 3. Eğri altındaki toplam alan

Şimdi Şekil 1'in alt kısmına geri dönelim:

Şekil 4. Gauss şekli alt kısmı 

Şekil 2. Gauss çanı standart sapmaları

Burada ortalama +/- 1-3 standart sapmalarının (sigma) altındaki değerlerin yüzdesini görebilirsiniz. Gauss PDF'i ile, olayların %68,27'si ortalamadan artı/eksi bir standart sapma içinde, %95,45'i artı/eksi iki standart sapma içinde ve %99,73'ü ortalamadan artı/eksi üç standart sapma içinde yer almaktadır.

Sizce gerçek piyasa verilerinde durum bu şekilde mi? Pek sayılmaz. Piyasa fiyatlarına baktığımızda, grafiğin bir kare dalga gibi göründüğünü - büyük talimatların gruplandırıldığı direnç veya destek düzeylerini aştıktan sonra fiyatların yükselme veya bir sonraki destek/direnç düzeyine düşme eğiliminde olduğunu varsayabiliriz. Bu nedenle piyasa, büyük bir yakınlıkla kare dalga veya sinüs dalgası olarak modellenebilir.

Lütfen aşağıdaki sinüs çizimine dikkat edin:

sinüs

Şekil 3. Sinüs çizimi

Gerçekte çoğu alım satım işleminin benzer şekilde oldukça doğal görünen destek ve direnç düzeylerine yakın yerleştirildiğini fark etmelisiniz. Şimdi bir sinüs dalgasının yoğunluk çizimini çizeceğim. Şekil 3'ü 90 derece sağa çevirdiğimizi ve düzlük oluşturan tüm dairelerin yere düşmesine izin verdiğimizi hayal edebilirsiniz: 

Yoğunluk 

Şekil 4. Sinüs eğrisi yoğunluk çizimi

Yoğunluğun en soldaki ve en sağdaki konumlarda en yüksek olduğunu fark edebilirsiniz. Bu, alım satım işlemlerinin çoğunun direnç ve destek düzeylerine çok yakın yapıldığına dair önceki ifadeyle uyumlu görünüyor. Bir histogram çizerek olayların yüzde kaçının olduğunu kontrol edelim:

Histogram

Şekil 5. Sinüs eğrisi yoğunluk histogramı

Bu, Gauss çanına benziyor mu? Pek sayılmaz. En çok olay ilk ve son üç çubukta var gibi görünüyor.

J.F. Ehlers "Сybernetic analysis for stocks and futures" adlı kitabında 15 yıllık bir süre boyunca ABD T-Bonolarını analiz ettiği bir tecrübesini ele aldı. 10 çubuk uzunluğunda normalleştirilmiş bir kanal uyguladı ve 100 kutu içindeki fiyat konumunu ölçtü ve fiyatın her bir kutuda kaç kez olduğunu saydı. Bu olasılık dağılımının sonuçları, sinüs dalgasınınkileri yakından hatırlatır.  


2. Fisher Dönüşümü ve zaman serilerine uygulanması

Artık bir piyasa döngüsünün PDF'inin bir Gauss'u değil, bir sinüs dalgasının PDF'ini hatırlattığını bildiğimiz ve göstergelerin çoğu, piyasa döngüsünün PDF'inin Gauss olduğunu varsaydığı için, bunu "düzeltmek" için bir yola ihtiyacımız var. Çözüm, Fisher Dönüşümü'nü kullanmaktır. Fisher dönüşümü, herhangi bir dalga biçiminin PDF'ini yaklaşık Gauss'a dönüştürür.

Fisher Dönüşümü denklemi:

Şekil 6. Fisher dönüşümü denklemi

 Şekil 5. Fisher Dönüşümü

Şekil 6. Fisher Dönüşümü

Fisher dönüşümünün çıktısının yaklaşık olarak Gauss PDF'i olduğundan söz etmiştim. Bunu açıklamak için Şekil 6'ya bakmaya değer.

Giriş verileri ortalamasına yakın olduğunda, kazanç yaklaşık olarak birdir (bkz. |X<0,5| için grafik). Diğer taraftan, normalleştirilmiş giriş yaklaşımlarından herhangi biri sınıra yaklaştığında çıktı büyük ölçüde yükseltilir (bkz. 0,5<|x|<1 için grafik). Pratikte, en fazla sapma meydana geldiğinde 'neredeyse Gauss' kuyruğunu büyütmeyi düşünebilirsiniz - Dönüştürülen PDF'e tam olarak bu olur. 

Fisher Dönüşümünü alım satıma nasıl uygularız? İlk olarak, |x|<1 kısıtı nedeniyle fiyatların bu aralığa normalize edilmesi gerekir. Normalize edilmiş fiyatlar Fisher Dönüşümüne tabi tutulduğunda aşırı fiyat hareketleri nispeten nadir hale gelir. Bu, Fisher Dönüşümünün bu aşırı fiyat hareketlerini yakaladığı ve bu aşırı uçlara göre alım satım yapmamıza izin verdiği anlamına gelir.


3. MQL5'te Fisher Dönüşümü

Fisher Dönüşümü göstergesi kaynak kodu, Ehlers'in "Cybernetic Analysis for Stocks and Futures" adlı kitabında açıklanmıştır.

Bu, MQL4'te zaten uygulandı; ben onu MQL5'e dönüştürdüm. Gösterge, ortalama fiyatları (H+L)/2 kullanır; ben geçmişten ortalama fiyatları çıkarmak için iMA() işlevini kullandım.

İlk olarak, fiyatlar 10 çubuk aralığında normalize edilir ve normalize edilmiş fiyatlar Fisher Dönüşümüne tabi tutulur.

//+------------------------------------------------------------------+
//|                                              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);
  }
//+------------------------------------------------------------------+

Lütfen keskin sinyallerin üretildiğini unutmayın.

Sinyal çizgisi, bir çubuk gecikmeli Fisher dönüştürülmüş fiyatıdır:

Fisher Dönüşümü Göstergesi 

Şekil 7. Fisher Dönüşümü Göstergesi

 

4. Ters Fisher Dönüşümü ve döngü göstergelerine uygulanması

Ters Fisher Dönüşümü denklemi, x için Fisher Dönüşümü denkleminin y cinsinden çözülmesiyle elde edilir:

Şekil 8. Ters Fisher dönüşümü denklemi,

Şekil 6. Ters Fisher Dönüşümü 

Şekil 8. Ters Fisher Dönüşümü

Bu işlevin aktarım yanıtı Fisher Dönüşümünün tersidir.

|x|>2 için girdi, birliği aşmayacak şekilde sıkıştırılır (negatif sayılar -1 için ve pozitif +1 için) ve |x|<1 için bu, hemen hemen doğrusal bir ilişkidir; yani çıktı girdi ile aynı özelliklere daha az sahiptir.

Sonuç olarak, uygun şekilde hazırlanmış girdi verilerine Ters Fisher Dönüşümü uygulandığında, çıktının -1 veya +1 olma olasılığı büyüktür. Bu, Ters Fisher Dönüşümünü osilatör göstergelerine uygulamak için mükemmel hale getirir. Ters Fisher Dönüşümü, keskin al veya sat sinyalleri vererek onları iyileştirebilir. 

 

5. MQL5'te Ters Fisher Dönüşümü Örneği

Ters Fisher Dönüşümünü doğrulamak için, "Stocks and Commodities" dergisinin Ekim 2010 sayısında sunulan Sylvain Vervoort'un Düzgünleştirilmiş RSI Ters Fisher Dönüşümü göstergesinin MQL5 sürümünü uyguladım ve bu göstergeye dayalı bir alım satım sinyali modülü ve Expert Advisor oluşturdum.

Ters Fisher Dönüşümü göstergesi birçok alım satım platformu için zaten uygulandı, kaynak kodları traders.com web sitesinde MQL5.com Kod Tabanı'nda bulunabilir.

MQL5'te iRSIOnArray işlevi olmadığı için bunu gösterge koduna ekledim. Orijinal göstergeyle tek fark, ayarlarım için daha uygun olduğu için varsayılan RSIPerod'un 21'e ve EMAPeriod'un 34'e ayarlanmasıdır (EURUSD 1H). Bunu varsayılan RSIPeriod 4 ve EMAPeriod 4 olarak değiştirmek isteyebilirsiniz.

//+------------------------------------------------------------------+
//|                            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);
  }
//+------------------------------------------------------------------+

 Ters Fisher Göstergesi

Şekil 9. Ters Fisher Dönüşümü göstergesi

Yalnızca dönüşüm denklemlerini sunduğum için Fisher Dönüşümü ve Ters Fisher Dönüşümü kökenleri konusunda kafanız karışmış olabilir.

Makaleyi yazmak için materyal toplarken, Fisher'ın her iki dönüşümü nasıl elde ettiğiyle ilgilendim ama internette hiçbir şey bulamadım.

Ancak hem Fisher Dönüşümünü hem de Ters Fisher Dönüşümü'nü gözden geçirdim ve her iki grafik de bana bir tür trigonometrik veya hiperbolik fonksiyonu hatırlattı (herhangi bir benzerlik görebiliyor musunuz?). Bu fonksiyonlar Euler formülünden türetilebildiği ve Euler'in 'e' sayısı cinsinden ifade edilebildiği için yüksek matematik kitaplarına geri döndüm ve şunu iki kez kontrol ettim:

Şekil 9. Sinh denklemi,

Şekil 11. Cosh denklemi,

ve artık tanh(x) şu şekilde elde edilebilir:

Şekil 12. Tanh denklemi,

ve... 

Şekil 12. Atanh denklemi 

Evet, bunlar tam olarak yukarıda sunduğum denklemler. Fisher dönüşümü gizemi çözdü! Fisher dönüşümü basitçe arctanh(x)'dir ve Ters Fisher Dönüşümü onun tersidir; yani tanh(x)!


6. Alım satım sinyalleri modülü

Ters Fisher Dönüşümünü doğrulamak için Ters Fisher Dönüşümü göstergesine dayalı bir alım satım sinyali modülü oluşturdum.

Özel bir göstergeye dayalı alım satım modülünü görmeyi faydalı bulabilirsiniz. Ters Fisher göstergesini tutmak için CiCustom sınıfı örneğini kullandım ve CExpertSignal sınıfının dört sanal yöntemini geçersiz kıldım: CheckOpenLong() ve CheckOpenShort(), açık pozisyon olmadığında sinyal üretmekten sorumludur ve CheckReverseLong() ve CheckReverseShort() açık pozisyonun tersine çevrilmesinden sorumludur. 

//+------------------------------------------------------------------+
//|                               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

Ters Fisher Dönüşümünü doğrulamak için daha önce sunulan alım satım sinyali modülünü kullanan standart bir EA oluşturdum.

Ayrıca, "MQL5 Sihirbazı: Açık Pozisyonları Takip Etme Modülü Nasıl Oluşturulur?" makalesinden alınan takip eden zarar durdurucu modülünü de ekledim.

//+------------------------------------------------------------------+
//|                                                 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();
  }
//+------------------------------------------------------------------+

EA'nın her varlık ve her zaman dilimi için karlı olmadığını itiraf etmeliyim, ancak EURUSD 1H zaman dilimi için oldukça iyi sonuçlar vermesi için ince ayar yaptım.

Okuyucuları sinyal modülünü ve gösterge ayarlarını değiştirmeyi denemeye teşvik ediyorum, makalede sunulandan daha karlı EA bulabilirsiniz.

EA grafiği 

Şekil 10. Ters Fisher Dönüşümü EA

EA sonucu

Şekil 11. Ters Fisher Dönüşümü EA denge grafiği


Sonuç

Makalenin Fisher Dönüşümü ve Ters Fisher Dönüşümü için iyi bir giriş sağladığını ve özel bir göstergeye dayalı bir sinyal alım satım modülü oluşturmanın bir yolunu gösterdiğini umuyorum.

Sylvain Vervoort'un Düzgünleştirilmiş RSI Ters Fisher Dönüşümü göstergesini kullandım ama aslında Ters Fisher Dönüşümünü herhangi bir osilatöre kolayca uygulayabilir ve bu makaleye dayanarak EA oluşturabilirsiniz.

Ayrıca okuyucuları, sunduğum şeye dayalı olarak karlı bir EA oluşturmak için ayarlarda küçük değişiklikler yapmaları konusunda destekliyorum. Aşağıda daha fazla referans için harici bağlantılar sundum.


Referanslar

  1. Fisher Dönüşümü
  2. Fisher Dönüşümünü Kullanma
  3. Ters Fisher Dönüşümü
  4. Smoothed RSI Ters Fisher Dönüşümü

MetaQuotes Ltd tarafından İngilizceden çevrilmiştir.
Orijinal makale: https://www.mql5.com/en/articles/303

Ekli dosyalar |
UML Araçlarını Kullanarak Expert Advisor Nasıl Geliştirilir? UML Araçlarını Kullanarak Expert Advisor Nasıl Geliştirilir?
Bu makalede, nesne yönelimli yazılım sistemlerinin görsel modellemesi için kullanılan UML grafik dili kullanılarak Expert Advisor'ların oluşturulması ele alınmaktadır. Bu yaklaşımın temel avantajı, modelleme sürecinin görselleştirilmesidir. Makale, Software Ideas Modeler kullanarak bir Expert Advisor'ın yapısının ve özelliklerinin modellenmesini gösteren bir örnek içermektedir.
Ödemeler ve ödeme yöntemleri Ödemeler ve ödeme yöntemleri
MQL5.community Hizmetleri, hem yatırımcılar hem de MetaTrader terminali uygulama geliştiricileri için mükemmel fırsatlar sunar. Bu makalede, MQL5 hizmetleri için ödemelerin nasıl yapıldığını, kazanılan paranın nasıl çekilebileceğini ve işlemlerin güvenliğinin nasıl sağlandığını ele alacağız.
MetaTrader 5 Platformuna Yeni UI Dilleri Nasıl Eklenir? MetaTrader 5 Platformuna Yeni UI Dilleri Nasıl Eklenir?
MetaTrader 5 platformunun kullanıcı arayüzü birkaç dile çevrilmiştir. Ana diliniz desteklenen diller arasında değilse endişelenmeyin. MetaQuotes Software Corp. tarafından herkese ücretsiz olarak sunulan özel MetaTrader 5 Çoklu Dil Paketi yardımcı programını kullanarak çeviriyi kolayca uygulayabilirsiniz. Bu makalede, MetaTrader 5 platformuna yeni bir kullanıcı arayüzü dillerinin nasıl ekleneceğine ilişkin bazı örnekler göstereceğiz.
MQL5'te WinInet'i Kullanma.  Bölüm 2:  POST İstekleri ve Dosyalar MQL5'te WinInet'i Kullanma. Bölüm 2: POST İstekleri ve Dosyalar
Bu makalede, HTTP isteklerini kullanarak İnternet ile çalışma ve sunucu ile bilgi alışverişi yapma prensiplerini incelemeye devam edeceğiz. Burada CMqlNet sınıfının yeni işlevleri, formlardan bilgi gönderme yöntemleri ve POST isteklerini kullanarak dosya gönderme yöntemleri ve ayrıca Çerezleri kullanarak oturum açtığınız web sitelerindeki yetkilendirme açıklanmaktadır.