
Fisher Dönüşümü ve Ters Fisher Dönüşümünü MetaTrader 5'te Piyasa Analizine Uygulama
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 ç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
- 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
- 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:
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:
Şimdi Şekil 1'in alt kısmına geri dönelim:
Ş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:
Ş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:
Ş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:
Ş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ü
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:
Ş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ü
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); } //+------------------------------------------------------------------+
Ş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:
,
,
ve artık tanh(x) şu şekilde elde edilebilir:
,
ve...
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.
Şekil 10. Ters Fisher Dönüşümü EA
Ş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
- Fisher Dönüşümü
- Fisher Dönüşümünü Kullanma
- Ters Fisher Dönüşümü
- Smoothed RSI Ters Fisher Dönüşümü
MetaQuotes Ltd tarafından İngilizceden çevrilmiştir.
Orijinal makale: https://www.mql5.com/en/articles/303





- Ücretsiz alım-satım uygulamaları
- İşlem kopyalama için 8.000'den fazla sinyal
- Finansal piyasaları keşfetmek için ekonomik haberler
Gizlilik ve Veri Koruma Politikasını ve MQL5.com Kullanım Şartlarını kabul edersiniz