フィッシャートランスフォームの適用とMetaTrader5の市場分析に対するフィッシャートランスフォーム
はじめに
以下の記事は、フィッシャートランスフォームと、金融市場に適用されるフィッシャートランスフォームを紹介します。
フィッシャートランスフォーム理論は、雑誌"Stocks and Commodities"(株と商品)の2010年10月号にて記載されていたSmoothed RSI Inverse Fisher TrasnformインジケーターのMQL5版を稼働させることで、実行されます。そのインジケーターの確率は、Fisherインジケーターに基づくシグナルを使用するエキスパートアドバイザーによってバックテストされています。
この記事は、J.F.Ehlersの著書とネット上に見られる記事に基づいています。すべての参照元は、記事の最後に記載されています。
1. ガウジアンPDF vs 市場サイクル
共通の想定は、価格は標準の確率密度関数を備えているということです。
これは、価格の逸脱は、よく知られるガウジアンベルトとして紹介されることを意味します。
図1. ガウジアンベルト
標準の確率密度関数について紹介しました。完璧に理解するために、いくつかのアイディアと数学の公式を紹介します。多くの読者にとって理解いただけることを願っています。
Merriam-Webster辞書を調べると確率 は以下のように定義されています。
- 同等に等しい結果における、特定の結果の数の比率であり、特定のイベントにつながるであろう合計の数に対する
- 特定のイベントを生み出す結果です。
ランダム変数は、いくつかのランダムなプロセスにおける基準から生じる結果の変数です。この場合、ランダム変数は資産の価格です。
最後に、PDFは、確率密度関数の頭字語であり、その関数はランダム変数X(この場合、価格)が可能な値の範囲の中での数値を取得します。標準分布か正規分布から生じるランダム変数は、現実世界の一つの値になりがちのランダム変数を示すために使用される確率分布です。
数学的に言うと、[a,b]間にある値をランダム変数が取得する可能性は、必須であると定義されています。
これは、aからbまでのカーブf(x)の下にあるエリアを示し、確率は、0から100で数えるか、0から1.00で数えられます。したがって、f(x)カーブの下の合計のエリアは1でなければならないという制限があります(確率の合計):
図1の下部を見てみましょう:
図2. ガウジアンベル標準逸脱
どのパーセントの値が標準偏差+/-1-3の下にあるか見えます。ガウジアンPDF67.2%の発生は、標準偏差1プラス/マイナスの範囲にあり、94.5%は、標準偏差2プラス/マイナスにあり、99.73%は標準偏差プラス/マイナス3の範囲にあります。
これは実際の市場データにもあてはまると思いますか?実際はそうではありません。市場価格を見ると、むしろチャートは、短形波のようになります。大きい注文はグループ化される抵抗・サポート線を突破した後、価格は次のサポート/抵抗線より上昇するか、減少します。なので、市場は、短形波や正弦波としてモデル化されます。
以下の正弦をみてください。
図3. 正弦図
実際は、大半のトレードは、単純にサポート、抵抗線の近くに配置され、自然に見えるということに注意しなければなりません。それでは、正弦波の密度図を描きます。図3を90度右に回転させ、図を下に落ちるように回転させたようだと想像できるでしょう。
図4. 正弦曲線密度図
密度は、一番左か右の位置にて最も高くなります。これは、多くのトレードが抵抗・サポート線近くにて作成されるという以前述べた内容に一致しています。発生率がどのようなものとしてヒストグラムによって描かれているのかチェックしてみましょう;
図5. 正弦曲線密度ヒストグラム
ガウジアンベルトのように見えるでしょうか?そうでもありません。最初と最後3つのバーは、多くの発生を持っているようdす。
J.F. 著書"Сybernetic analysis for stocks and futures"(株と将来における人工頭脳学の分析)の中でEhlersは、彼が15年間の間アメリカのT-Bondsを分析した実験について紹介しています。T-Bonds over a span of 15 years. 彼は、標準化されたチャネル10のバーを適用し、100ビンの間での価格の位置を計り、価格がそれぞれのビンにあった回数を数えました。この確率分布の毛かは正弦波のものに近くなります。
2. フィッシャートランスフォームとその時系列への適用。
市場サイクルのPDFは、ガウジアンではなく、むしろ正弦波のPDFになり、多くのインジケーターが市場サイクルPDFはガウジアンであると知っているため、それを正す必要があります。その解決策は、フィッシャートランスフォームを使用することです。フィッシャートランスフォームは、いかなる波形のPDFをガウス性に変換します。
フィッシャートランスフォームにおいての公式は:
,
図6. フィッシャートランスフォーム
フィッシャートランスフォームの結果は、おおよそガウジアンPDFになると述べました。これを説明するために、図6を見ることが有効です。
入力データがその平均値に近い場合、その利益は、単一になります(|X<0.5|のチャートをみてください)一方、標準の入力値が制限に近づいている際は、そのアウトプットは大いに拡大されます( 0.5<|x|<1のチャートをご覧ください). 実際、偏差が多く出現すれば、成長する「ガウジアン」の尻尾であると考えるでしょうーこれは、正しくは変形されたPDFに出現するものです。
フィッシャートランスフォームをどのようにトレーディングに適用するのでしょうか?まず最初は、|x|<1 定数のせいで、価格はこの範囲に標準化されなければなりません。標準化された価格がフィッシャートランスフォームに適用された際、その価格移動は、相対的にまれになります。これは、フィッシャートランスフォームがこれらの価格移動を取得し、それらの極値に沿ってトレードすることを可能にしています。
3. MQL5でのフィッシャートランスフォーム
フィッシャートランスフォームインジケーターのソースコードは、Ehlerの著書 "Cybernetic Analysis for Stocks and Futures"(株と先物における人工頭脳的な分析).
MQL4にてすでに実行されており、それをMQL5に転換しました。そのインジケーターは平均価格 (H+L)/2を使用し、 iMA()関数が履歴から平均価格を抽出するために使用されます。
最初は、価格が10バーの範囲にて正規化され、正規化された価格がフィッシャートランスフォームに適用されます。
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
シャープシグナルが生成されていることに注意してください。
シャープラインは、一つバーによって遅延されたフィッシャートランスフォーム価格です。
図7. フィッシャートランスフォームインジケーター
4. 反対のフィッシャートランスフォームと、サイクルインジケーターへの適用
反対のフィッシャートランスフォーム等式は、yの期間でのxにおけるフィッシャートランスフォーム等式を解くことで取得されます。
,
図8. 反対のフィッシャートランスフォーム
この関数の遷移レスポンスは、フィッシャートランスフォームのものの反対の形になります。
|x|>2においての入力値は、超過しない単一の値に一致します(負の数においては-1、正の数においては+1)、そして、 |x|<1においては、アウトプットが多かれ少なかれインプットと同じ特徴を入力持つことを意味する直線相関となります。
その結果は、フィッシャートランスフォームの対が適切に準備された入力データに適用された際に、そのアウトプットは、-1か+1になる可能性を持ちます。これにより、フィッシャートランスフォームの対をオシレーターインジケーターに適用する上で完璧となります。フィッシャートランスフォームの対は、鋭い売り・買いシグナルにより改善されます。
5. MQL5でのフィッシャートランスフォームの例
フィッシャートランスフォームを確認するために、 "Stocks and Commodities"(株と商品)という雑誌の2010年10月号にて記載されている、Sylvain's Vervoort Smoothed RSI Inverse Fisher Transformインジケーターを実行し、そのインジケーターに基づくエキスパートアドバイザーとトレーディングシグナルモジュールを作成します。
フィッシャートランスフォームインジケーターは、すでに多くのトレーディングプラットフォームにて実装されており、そのソースコードはtraders.comや、 MQL5.com Code Baseにてみることができます。.
iRSIOnArray関数がMQL5にはないので、そのインジケーターコードに追加しています。元のインジケーターとの唯一の違いは、21にセットされたRSIPeriodと、34にセットされたEMAPeriodです。私の設定の方がよりよく作動するため、変更しました(EURUSD 1H)RSIPeriod 4、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); } //+------------------------------------------------------------------+
図9. 対のフィッシャーインジケーター
変形等式のみを紹介したため、フィッシャートランスフォームやその対のものに困惑するかもしれません。
この記事を書くための資料を集めている際に、どのようにFisherが両方の変形を取得したのか気になりましたが、インターネットでは見つかりませんでした。
しかし、両方のフィッシャートランスフォーム、対のフィッシャートランスフォームを見て、それらが三角法や総局関数を思い出させました。(類似点がわかりますか?)これらの関数は、Eulerの公式に由来し、「e」というEulerの用語で表現されているため、本に戻り、チェックしました。
,
,
tanh(x)は、以下によって取得されます:
,
そして...
ええ、これは、上記で紹介した方程式と同じものです、フィッシャートランスフォームが解明されました!フィッシャートランスフォームは、単にarchtanh(x)であり、対のフィッシャートランスフォームはその逆、tanh(x)だったのです!
6. トレーディングシグナルモジュール
対のフィッシャートランスフォームを確認するために、そのインジケーターに基づくトレーディングシグナルモジュールを作成します。
カスタムインジケーターに基づくトレーディングモジュールを見ることは役に立つかもしれません。 CExpertSignal クラスの4つの再定義済みの仮装メソッドとフィッシャーインジケーターを維持するためにCiCustomクラスを使用しました: CheckOpenLong()とCheckOpenShort()は、オープンポジションがなければ、シグナルを生成する役割を担います。そして、CheckReverseLong()と CheckReverseShort()はオープンポジションをリバースするための役割を担います。
//+------------------------------------------------------------------+ //| 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. エキスパートアドバイザー
フィッシャートランスフォームを確認するため、以前紹介されたトレーディングモジュールを使用する標準EAを作成しました。
"MQL5 Wizard: How to Create a Module of Trailing of Open Positions"(MQL5ウィザード:オープンポジションのトレーリングモジュールの作成方法の記事から取得したストップロスモジュールを追加しました。
//+------------------------------------------------------------------+ //| 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は、すべての資産やすべてのタイムフレームにおいて有益ではないことを認めなければなりませんが、EURUSD 1Hタイムフレームにては良い結果を出すよう微調整しました。
読者の皆様には、シグナルモジュールやインジケータの設定を調整し、この記事のEAよりも有益なものにしていただきたいです。
図10. フィッシャートランスフォームEA
図11. フィッシャートランスフォームEAバランスグラフ
結論
この記事がフィッシャートランスフォームやその対へのよりイントロダクションを提供し、カスタムインジケーターに基づくシグナルトレーディングモジュールの作成方法を紹介できたことを期待しています。
Sylvain's Vervoort Smoothed RSI Inverse Fisher Transformインジケーターを使用しましたが、実際は対のフィッシャートランスフォームを簡単にすべてのオシレーターに適用し、EAを作成することができます。
読者の皆様には、紹介したものに基づいて有益なEAを作成できるよう設定を調整していただきたいと思います。以下にさらなる参照のために外部のリンクを記載しています。
参照
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/303
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索