トレーディングシステム作成のための判別分析の利用
はじめに
テクニカル分析の主要タスクのひとつはマーケットが将来変動する方向を判断することです。統計的な視点から、将来のマーケット状況が2つに分類される可能性の基となるインディケータ選択とその値決定についてずはりお話します。 マーケットの2分類とは、1)上昇気運、2)下降気運です。
判別分析はどのようなインディケータとどの値がこれらに分類の差別化を可能にする方法の一つを提供してくれます。言い方を変えれば、判別分析によりインディケータから受け取ったデータを基にマーケットの方向を予想するモデル構築が可能になる、ということです。
ただし、そのような分析はかなり8複雑で、インプット時に膨大なデータを要求します。よってマーケット状況分析をマニュアルで利用するのはきわめて大きな時間のロスです。さいわい、MQL5言語と統計的ソフトウェアがあり、それによりデータ選択、準備、判別分析適用を自動化することができます。
本稿ではマーケットデータ収集のための EA 開発例を提供します。本稿はStatistica ソフトウェアにおいてFOREXマーケットに対する予測モデル構築のための判別分析を使うための指導書の役割を果たします。
1. 判別分析とは?
判別分析(以降 "DA")とはのパターン認識手法の一つです。ニューラルネットワークは DAの特殊なケースと考えられています。DA はパターン認識に基づき成功したディフェンスシステムの多くで利用されています。
それはどの変数が着信するデータフローをグループ分け(判別)するのかを可能にし、またそのような判別のメカニズムを知ることを可能にします。
FOREX マーケットでDAを活用するシンプルな例を見ます。We have data values from 相対強度指数 (RSI)、 MACD、相対活力指数 (RVI) からデータを取得し価格方向を予想する必要があります。DAの結果、以下を取得します。
a. RVI 指数は予測に貢献しない。よって分析から除外します。
b. DA は判別式を2つ作成。
- G1 = a1*RSI+b1*MACD+с1 価格上昇のケースの式です。
- G2 = a2*RSI+b2*MACD+с2 価格下降のケースの式です。
それぞれのバーの初めで G1 と G2 を計算し G1 > G2ならば価格は上昇、G1 < G2ならば価格は下降と予想します。
DA はニューラルネットワークのとっかかりには有用だと証明されるかもしれません。DAを使用するとき、ニューラルネットワーク処理計算に似た式を取得するからです。このことはそのストラクチャをよりよく理解し、あらかじめご自身の戦略でニューラルネットワークを利用する価値があるか判断するのに役立ちまず。
2. 判別分析の段階
この分析は何段階かに分けることができます。
- データ準備段階
- 準備されたデータからもっともすぐれた変数を選択します。
- 検証データを用いた結果モデルの分析と検証
- 判別式を基にしたモデルの構築
判別分析は統計的データ分析用に作成された近代的ソフトウェアパッケージのほとんどすべてに入っています。もっともよく利用されるのがStatistica(StatSoft社製)および SPSS(IBM 社製)です。われわれは後に Statistica ソフトウェアを使用して判別分析を適用することを考察します。スクリーンショットは Statistica version 8.0より取得しました。これらはソフトウェアの古いバージョンでは同様に見えます。Statistica はニューラルネットワークを含めトレーダーにとって有用なその他多くのツールを提供していることを知っておくとよいでしょう。
2.1. データ準備
データ収集は手元にある一定のタスクに依存します。ここでタスクを次のように定義します。:インディケータを用いてインディケータの基地の値に続くバーについての価格チャートの方向を予想すること。An EA はファイルにインディケータ値および価格データを保存するためにデータ収集をする目的で開発されるものです。
これは以下のストラクチャを持つ CSV ファイルである必要があります。変数はすべての行が特定のインディケータに対応する行で整理されます。列には連続測定値(ケース)が入ります。すなわち特定バーに対するインディケータ値です。言い換えれば、ヨコの表ヘッダにはインディケータが、タテには連続バーがきます。
表はそれを基にグループ化が行われる変数(グループ化変数)を持ちます。われわれの場合、そのような変数はそのインディケータ値が取得されるバーが続くバー上での価格変更に基づきます。グループ化変数には同じラインで表示されるデータのグループバン後が含まれます。たとえば、価格が上昇する場合の1番や価格が下降する場合の2番です。
われわれは次のインディケータ値が必要です。
- アクセラレータオシレーター
- ベアパワー
- ブルパワー;
- オーサムオシレータ
- 商品チャネル指数
- DeMarker
- 変動適応移動平均
- MACD;
- 相対強度指数
- 相対活力指数
- ストカスティック;
- Williams Percent Range
OnInit() 関数はインディケータ(インディケータハンドルを取得します。)と行データヘッダを保存する MasterData.csv ファイルを作成します。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- initialization of the indicators h_AC=iAC(Symbol(),Period()); h_BearsPower=iBearsPower(Symbol(),Period(),BearsPower_PeriodBears); h_BullsPower=iBullsPower(Symbol(),Period(),BullsPower_PeriodBulls); h_AO=iAO(Symbol(),Period()); h_CCI=iCCI(Symbol(),Period(),CCI_PeriodCCI,CCI_Applied); h_DeMarker=iDeMarker(Symbol(),Period(),DeM_PeriodDeM); h_FrAMA=iFrAMA(Symbol(),Period(),FraMA_PeriodMA,FraMA_Shift,FraMA_Applied); h_MACD=iMACD(Symbol(),Period(),MACD_PeriodFast,MACD_PeriodSlow,MACD_PeriodSignal,MACD_Applied); h_RSI=iRSI(Symbol(),Period(),RSI_PeriodRSI,RSI_Applied); h_RVI=iRVI(Symbol(),Period(),RVI_PeriodRVI); h_Stoch=iStochastic(Symbol(),Period(),Stoch_PeriodK,Stoch_PeriodD,Stoch_PeriodSlow,MODE_SMA,Stoch_Applied); h_WPR=iWPR(Symbol(),Period(),WPR_PeriodWPR); if(h_AC==INVALID_HANDLE || h_BearsPower==INVALID_HANDLE || h_BullsPower==INVALID_HANDLE || h_AO==INVALID_HANDLE || h_CCI==INVALID_HANDLE || h_DeMarker==INVALID_HANDLE || h_FrAMA==INVALID_HANDLE || h_MACD==INVALID_HANDLE || h_RSI==INVALID_HANDLE || h_RVI==INVALID_HANDLE || h_Stoch==INVALID_HANDLE || h_WPR==INVALID_HANDLE) { Print("Error creating indicators"); return(1); } ArraySetAsSeries(buf_AC,true); ArraySetAsSeries(buf_BearsPower,true); ArraySetAsSeries(buf_BullsPower,true); ArraySetAsSeries(buf_AO,true); ArraySetAsSeries(buf_CCI,true); ArraySetAsSeries(buf_DeMarker,true); ArraySetAsSeries(buf_FrAMA,true); ArraySetAsSeries(buf_MACD_m,true); ArraySetAsSeries(buf_MACD_s,true); ArraySetAsSeries(buf_RSI,true); ArraySetAsSeries(buf_RVI_m,true); ArraySetAsSeries(buf_RVI_s,true); ArraySetAsSeries(buf_Stoch_m,true); ArraySetAsSeries(buf_Stoch_s,true); ArraySetAsSeries(buf_WPR,true); FileHandle=FileOpen("MasterData2.csv",FILE_ANSI|FILE_WRITE|FILE_CSV|FILE_SHARE_READ,';'); if(FileHandle!=INVALID_HANDLE) { Print("FileOpen OK"); //--- saving names of the variables in the first line of the file for convenience of working with it FileWrite(FileHandle,"Time","Hour","Price","AC","dAC","Bears","dBears","Bulls","dBulls", "AO","dAO","CCI","dCCI","DeMarker","dDeMarker","FrAMA","dFrAMA","MACDm","dMACDm", "MACDs","dMACDs","MACDms","dMACDms","RSI","dRSI","RVIm","dRVIm","RVIs","dRVIs", "RVIms","dRVIms","Stoch_m","dStoch_m","Stoch_s","dStoch_s","Stoch_ms","dStoch_ms", "WPR","dWPR"); } else { Print("FileOpen action failed. Error",GetLastError()); ExpertRemove(); } //--- return(0); }
OnTick() イベントハンドラは新規バーを特定しファイルにデータを保存します。
価格変動は最終完了バーにより判断され、インディケータ値は最終完了バーの前のバーから取得されます。絶対インディケータ値とは別に変動方向を見るために絶対値と前回値の差を保存する必要があります。例で提供されているそのような変数の名前には接頭辞 "d" がついています。
シグナルラインインディケータについてはその変動状態と共にメインとシグナルラインの間の差を保存する必要があります。また、新規バーの時刻と適切な時間値を保存します。これは時刻でデータをフィルターにかけやすくします。
よって価格変動を推定するための推測モデルを構築するために37個のインディケータを考えます。
//+------------------------------------------------------------------+ //| Expert tick function | //| Monitoring the market situation and saving values | //| of the indicators into the file at the beginning of every new bar| //+------------------------------------------------------------------+ void OnTick() { //--- declaring a static variable of datetime type static datetime Prev_time; //--- it will be used to store prices, volumes and spread of each bar MqlRates mrate[]; MqlTick tickdata; ArraySetAsSeries(mrate,true); //--- obtaining the recent quotes if(!SymbolInfoTick(_Symbol,tickdata)) { Alert("Quote update error - error: ",GetLastError(),"!!"); return; } ///--- copying data of the last 4 bars if(CopyRates(_Symbol,_Period,0,4,mrate)<0) { Alert("Historical quote copy error - error: ",GetLastError(),"!!"); return; } //--- if both time values are equal, there is no new bar if(Prev_time==mrate[0].time) return; //--- saving the time in the static variable Prev_time=mrate[0].time; //--- filling the arrays with values of the indicators bool copy_result=true; copy_result=copy_result && FillArrayFromBuffer1(buf_AC,h_AC,4); copy_result=copy_result && FillArrayFromBuffer1(buf_BearsPower,h_BearsPower,4); copy_result=copy_result && FillArrayFromBuffer1(buf_BullsPower,h_BullsPower,4); copy_result=copy_result && FillArrayFromBuffer1(buf_AO,h_AO,4); copy_result=copy_result && FillArrayFromBuffer1(buf_CCI,h_CCI,4); copy_result=copy_result && FillArrayFromBuffer1(buf_DeMarker,h_DeMarker,4); copy_result=copy_result && FillArrayFromBuffer1(buf_FrAMA,h_FrAMA,4); copy_result=copy_result && FillArraysFromBuffers2(buf_MACD_m,buf_MACD_s,h_MACD,4); copy_result=copy_result && FillArrayFromBuffer1(buf_RSI,h_RSI,4); copy_result=copy_result && FillArraysFromBuffers2(buf_RVI_m,buf_RVI_s,h_RVI,4); copy_result=copy_result && FillArraysFromBuffers2(buf_Stoch_m,buf_Stoch_s,h_Stoch,4); copy_result=copy_result && FillArrayFromBuffer1(buf_WPR,h_WPR,4); //--- checking the accuracy of copying the data if(!copy_result==true) { Print("Data copy error"); return; } //--- saving to the file the price movement within the last two bars //--- and the preceding values of the indicators if(FileHandle!=INVALID_HANDLE) { MqlDateTime tm; TimeCurrent(tm); uint Result=0; Result=FileWrite(FileHandle,TimeToString(TimeCurrent()),tm.hour, // time of the bar (mrate[1].close-mrate[2].close)/_Point, // difference between the closing prices of the last two bars buf_AC[2],buf_AC[2]-buf_AC[3], // value of the indicator on the preceding bar and its dynamics buf_BearsPower[2],buf_BearsPower[2]-buf_BearsPower[3], buf_BullsPower[2],buf_BullsPower[2]-buf_BullsPower[3], buf_AO[2],buf_AO[2]-buf_AO[3], buf_CCI[2],buf_CCI[2]-buf_CCI[3], buf_DeMarker[2],buf_DeMarker[2]-buf_DeMarker[3], buf_FrAMA[2],buf_FrAMA[2]-buf_FrAMA[3], buf_MACD_m[2],buf_MACD_m[2]-buf_MACD_m[3], buf_MACD_s[2],buf_MACD_s[2]-buf_MACD_s[3], buf_MACD_m[2]-buf_MACD_s[2],buf_MACD_m[2]-buf_MACD_s[2]-buf_MACD_m[3]+buf_MACD_s[3], buf_RSI[2],buf_RSI[2]-buf_RSI[3], buf_RVI_m[2],buf_RVI_m[2]-buf_RVI_m[3], buf_RVI_s[2],buf_RVI_s[2]-buf_RVI_s[3], buf_RVI_m[2]-buf_RVI_s[2],buf_RVI_m[2]-buf_RVI_s[2]-buf_RVI_m[3]+buf_RVI_s[3], buf_Stoch_m[2],buf_Stoch_m[2]-buf_Stoch_m[3], buf_Stoch_s[2],buf_Stoch_s[2]-buf_Stoch_s[3], buf_Stoch_m[2]-buf_Stoch_s[2],buf_Stoch_m[2]-buf_Stoch_s[2]-buf_Stoch_m[3]+buf_Stoch_s[3], buf_WPR[2],buf_WPR[2]-buf_WPR[3]); if(Result==0) { Print("FileWrite action error ",GetLastError()); ExpertRemove(); } } }
EA起動後、MasterData.CSV ファイルが terminal_data_directory/MQL5/Filesに作成されます。テスターで EA を起動するときは、 terminal_data_directory/tester/Agent-127.0.0.1-3000/MQL5/Filesにセットします。取得されたファイルはすでに Statisticaで使用可能です。
その類のファイルサンプルはMasterData.CSVにあります。シンボル EURUSD、時間枠 H1、期間 2011.8.1 ~2011.10.1のデータが収集されました。
Statisticaでファイルを開くには以下に従います。
- Statisticaでメニューに進み、ファイル > 開く、ファイルタイプData files を選択し、ファイルを開きます。
- Delimited は Text File Import Type ウィンドウに残し OKをクリックします。
- 開いたウィンドの下線が引かれた項目を有効にします。
- 小数点記号文字フィールドがすでにあってもなかってもそこに小数点をつけることを忘れないでください。
図1 Statisticaへのファイルインポート
OK をクリックすると、われわれのデータを持つテーブルの完成です。
図2 Statistica内データベース
ここでPrice変数を基にグループ化変数を作成します。
価格の動きに応じて4つのグループを選び出します。
- 200 ポイント以上の下降
- 200 ポイント以下の下降
- 200 ポイント以下の上昇
- 200 ポイント以上の上昇
新規変数を追加するため AC 列ヘッダで右クリックし、「変数追加」オプションを選択します。
図3 新規変数の追加
開いたウィンドウの新規変数に「グループ」と名前をつけ、Price 変数をグループ数に変換する式を追加します。
以下がそのフォーミュラです。
=iif(v3<=-200;1;0)+iif(v3<0 and v3>-200;2;0)+iif(v3>0 and v3<200;3;0)+iif(v3>=200;4;0)
図4 変数記述
判別分析のファイルができました。その類のファイルサンプルはMasterData.STAにあります。
2.2. 最良変数の選択
判別分析を実行します(Statistics->Multivariate Exploratory Techniques->Discriminant Analysis)。
図5 判別分析の実行
開いたウィンドウで「変数」をクリックします。
最初のフィールドでグループ化変数を選択し、二番目のフィールドでグループ化を行う基になるすべての変数を選択します。
ここの場合は、最初のフィールドで Group 変数が指定され、二番目のフィールドでインディケータから取得されるすべての変数および追加の変数 Hour (データ受信時刻)を指定します。
図6 変数選択
「ケース選択」ボタンをクリックします(図8)。判別分析に用いられるケース(データ行)の選択ウィンドウが開きます。以下のスクリーンショット(図7)に示される項目を有効にします。
分析には最初の700 ケースだけが使用されます。残りはのちほど予後モデルの結果検証に使用されます。変数 V0を用いてケース数が設定されます。この方法でケースを指定することで DA のトレーニングサンプルを設定します。.
OKをクリックします。
図7 トレーニングサンプルの定義
われわれの予後モデルを構築するグループを選択します。
ここで注意点が一点あります。DA の欠点の一つはデータ異常値に対する感受性です。稀であるが影響力のあるイベント - ここでの場合価格の急騰、はモデルを歪める可能性があります。たとえば、予想外のニュースが起こった後、マーケットがそれに反応して数時間継続する相当な変動をするなど。テクニカルインディケータ値はこの場合予測に関してはあまり重要ではありませんが、それでも際立った価格変動があったのでDAにおいてはひじょうに有意であるとみなされます。よって DA実行前に異常値に関してデータチェックをすることです。
われわれの例から異常値を除外するためにグループ2と3のみ分析します。グループ1と4にはかなりの価格変動があったので、インディケータ値にも異常値がある可能性があります。
では、グループ化変数の「コード」をクリックします(図8)。そして分析のためのグループ番号を指定します。
図8 分析対象グループの指定
「詳細」オプションを有効にします。それにより後の段階で必要となる逐次分析ができます。
OKをクリックしDAを実行します。
以下のようなメッセージがポップアップします。これは選択された変数の一つが過剰で実質的に他の変数の条件となっていることを意味します。たとえば、それが他の2つの変数の合計である、など。
これはインディケータから取得されるデータフローに対してよく起こります。そのような変数は分析の質に影響を与えます。よってそのような変数は除去します。このためには DA に対する変数選択ウィンドウまで戻り、過剰変数を一つずつ追加しDA を何度も実行します。
図9 低tolerance 値メッセージ
DA メソッドの選択ウィンドウが開きます(図10)。ドロップダウンリストでSelect Forward Stepwise を選択します。インディケータ値には少し予知される重要性があるので、逐次分析の使用が推奨されます。そしてグループ判別モデルが自動で段階的に構築されます。
特に、各段階ですべての変数は再検討されグループ間判別に最も貢献する関数を決定する判定が行われます。その変数はモデルにインクルードされ、再び処理が始まります。データサンプル間で一番よく判別する変数はすべて段階的に指定の方法で選択されます。
図10 メソッド選択
OK をクリックすると、DA が問題なく完了した旨を告げるウィンドウが開きます。
図11 DA 実行結果のウィンドウ
Summary:モデル内変数をクリックし逐次分析に従ったモデルにインクルードされる変数リストを見ます。これらがわれわれのグループ間で最もよく判別をする変数です。95% (p<0.05) 以上の判別精度を出す変数は赤で表示されていることに留意します。その他別の変数に従う判別精度はもっと低いものです。モデルは最低 95%の精度を出す変数のみインクルードする必要があります。
ただし、統計の『黄金律』によると 95% の精度を出す変数だけが使用されるべきです。よって赤で表示されている変数以外は分析から除外します。それらはdBulls、Bulls、FrAMA、 Hourです。これらを除外するためには段階分析が選択されるウィンドウまで戻り、「変数」をクリックして開くウィンドウでそれらを指定します。
分析を繰り返します。Summary:モデル内変数、をクリックすることで、 まだ3つの変数が非有意として表示されているのが判ります。それらは DeMarker、 Stoch_s、 AOです。それらも分析から除外します。
結果、グループ間で正確な判別(p<0.01)を行う変数をインクルードしたモデルができました。
図12 モデルにインクルードされる変数
そうすると、我々の例では37個の変数中7個だけが残りました。それらが予測に最も有意な変数です。
この方法でのちにカスタムトレーディングシステムを開発するための絵s九にカル分析を基にして主要なインディケータを選択することができます。そこにはニューラルネットワークで使用されるものも含まれます。
2.3. テストデータを使用した結果モデルの分析および検証
DAの完成にあたり、予後モデルとトレーニングデータに適用した結果を取得しました。
モデルとグループ判別結果を確認するため、Classification タブを開きます。
図13 Classification タブ
トレーニングデータにモデルを適用した結果を持つテーブルを見るためにClassification matrixをクリックします。
行は観測される分類を示します。列には計算されたモデルに従い予測される分類がきます。正確な予測を持つセルはグリーンでマークされ、不正確な予測のセルは赤でマークされています。
最初の列には予測精度が %で表示されています。
図14 トレーニングデータ分類
トレーニングデータを用いた予測精度(トータル)は 60%と出ました。
テストデータを使ってモデルを検証します。このために、 v0>700 を指定します。それに従いモデル構築に使用されなかったデータ範囲でモデルがチェックされfます。.
そして以下を取得します。
図15 テストデータ分類
テストサンプルを使用した予測の全体的精度はおおよそ同じレベルで 55%に達します。FOREX マーケットに対してこれはかなり高いレベルです。
2.4. トレーディングシステムの開発
DA の予後モデルは一次方程式に基づいています。それに従いインディケータ値がグループやその他に分類されます。
これら関数の記述を確認するには DA 結果ウィンドウのClassificationタブ(図13)に行って (Figure 13) Classification 関数をクリックします。すると判別式の係数を持つ表のあるウィンドウが表示されます。
図16 判別式
表データを基に以下、2つの式を作成します。
Group2 = 157.17*AC - 465.64*Bears + 82.24*dBears - 0.006*dCCI + 761.06*dFrAMA + 2418.79*dMACDm + 0.01*dStoch_ms - 1.035
Group3 = 527.11*AC - 641.97*Bears + 271.21*dBears - 0.002*dCCI + 1483.47*dFrAMA - 726.16*dMACDm - 0.034*dStoch_ms - 1.353
このモデルを使用するには、式にインディケータ値を挿入し「グループ」値を計算します。
予測には「グループ」値がより高いグループが重要です。 われわれの例では、グループ2の値がグループ3の値より大きければ、今後1時間以内に価格チャートはおそらく下向きに変化すると予想されます。グループ3の値がグループ2の値より大きくなると予測は全く逆になります。
われわれの例におけるインディケータ値と分析期間はかなりランダムに選択されていることに注意が必要です。ただこのデータ数量でも DAの潜在能力と力強さを示すには十分です。
おわりに
FOREX マーケットに対して適用するのに判別分析は有用なツールです。それは異なる予測に対して観測されるインディケータ値を分類できる変数セットの最適性を調査およびチェックするのに使用することができます。また予後モデル構築にも使用可能です。
判別分析の結果として構築されるモデルは簡単に多くの開発経験を要求しない EAに簡単に統語うすることができます。判別分析それ自体は比較的使用が簡単です。前述の段階的指導内容はみなさんご自身のデータ分析に使うのに十分な内容でしょう。
判別分析についてより知りたい場合は電子テキストの相当する項目を参照ください。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/335
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索