English Русский 中文 Español Deutsch Português
preview
知っておくべきMQL5ウィザードのテクニック(第04回):線形判別分析

知っておくべきMQL5ウィザードのテクニック(第04回):線形判別分析

MetaTrader 5トレーディングシステム | 16 1月 2023, 13:16
284 0
Stephen Njuki
Stephen Njuki

線形判別分析(LDA)は、分類問題の非常に一般的な次元削減手法です。 前の記事のkohonenマップのように、観測を 分類したい高次元データ (つまり、多数の属性または variables変数 を含む) がある場合、LDA はデータを変換してクラスを可能な限り区別するのに役立ちます。より厳密には、LDAは、クラス分離の尺度を最適化する低次元部分空間へのデータの線形射影を見つけます。この部分空間の次元がクラスの数を超えることはありません。 この記事では、LDAをシグナル、トレーリング指標、資金管理ツールとして使用する方法について説明します。ただし、まず大胆な定義を見てから、その適用に進みましょう。 

LDAは、PCA、QDA、ANOVAの手法と非常によく似ています。これらすべてが通常省略されているという事実は、あまり役に立ちません。この記事では、これらのさまざまな手法を紹介したり説明したりせず、相違点を強調するだけにします。

1)主成分分析(PCA)

LDAはPCAに非常に似ています。実際、PCAを実行した後にLDA正則化を実行する(曲線あてはめを避けるため)ことに意味があるかどうかを尋ねる人もいます。これは、別の日に記事にする必要がある長いトピックです。

ただし、この記事では、2次元削減方法の決定的な違いは、PCAが、データが分散しているほど、分離可能性が高いという前提で、データセット全体の分散が最大になる軸を見つけようとする一方、LDAは分類に基づいてデータを実際に区別する軸を見つけようとすることです。

lda

したがって、上の図から、PCAがLD2を与えるのに対し、LDAがLD1を与えることは容易にわかります。これにより、PCAとLDAの主な違い(したがってLDAの優先度)が痛々しいほど明白になります。特徴の分散(分布)が高いからといって、それがクラスの予測に役立つとは限りません。

2)二次判別分析(QDA)

QDAは、LDAを分類器として一般化したものです。LDAは、クラスの条件付き分布が同じ共分散行列を持つガウス分布であると想定します。

QDAは、この等分散性の仮定を作成せず、すべてのクラスの共分散を推定しようとします。これはより堅牢なアルゴリズムのように見えるかもしれませんが(仮定が少ない場合)、推定するパラメータの数がはるかに多いことも意味します。パラメータの数がクラスの数に応じて二次的に増加することは十分に確立されています!したがって、共分散の推定値が信頼できることを保証できない限り、QDAを使用したくない場合があります。

結局のところ、LDAとQDAの関係について、次元削減にはどちらが適しているか、分類にはどちらが適しているかなど、混乱が生じる可能性があります。この CrossValidated投稿とリンクはすべて役立つ可能性があります。

3)分散分析(ANOVA):

LDAと分散分析の目的は似ています。どちらも、観測された変数をいくつかの独立/従属変数に分解しようとします。ただし、ウィキペディアによるとANOVAで使用される手段は、LDAが使用するものをミラーリングしたものです。

「LDAは、分散分析(ANOVA)および回帰分析と密接に関連しており、1つの従属変数を他の特徴または測定値の線形結合として表現しようとします。しかし、ANOVAはカテゴリカル独立変数と連続従属変数を使用します。一方、判別分析には連続独立変数とカテゴリカル従属変数(つまり、クラスラベル)」があります。

 

通常、LDAは次のように定義されます。

ここでは、

  • nはクラスの数
  • μはすべての観測値の平均
  • N i i番目のクラスの観測数
  • μii番目のクラスの平均
  • Σii番目のクラスの散布行列


次に、SWクラス内散布行列として定義します。これは次の式で与えられます。

SW = ∑ i = 1 n Σ i


SBクラス間散布行列として定義します。これは、次の式で与えられます。

SB=∑i=1nNi(μi−μ)(μi−μ)T


その固有値と固有ベクトルを取得するためにはSW−1SBを対角化します。

k最大固有値、およびそれらに関連付けられた固有ベクトルを選択します。これらのベクトルがまたがる部分空間に観測結果を投影します。

具体的には、これが意味することは、行列Aを形成するということです。その列は上記で選択したk固有ベクトルです。 alglibライブラリのCLDAクラスはまさにこれをおこない、固有値に基づいて降順でベクトルを並べ替えます。つまり、予測を行うために最適な予測ベクトルを選択するだけで済みます。

以前の記事と同様に、EAのLDAを実装する際にMQLコードライブラリを使用します。具体的には、「dataanalysis.mqh」ファイルの「CLDA」クラスに依存します。

2022年の外国為替ペアUSDJPYのLDAを毎日の時間枠で調査します。エキスパートアドバイザー(EA)の入力データの選択は、主にユーザー次第です。このLDAの場合、入力データには変数とクラスコンポーネントがあります。テストを実行する前に、このデータを準備する必要があります。終値を扱うため、デフォルトで(生の状態で)「継続」されます。データの変数およびクラスコンポーネントに正規化と離散化を適用します。正規化は、すべてのデータが設定された最小値と最大値の間にあることを意味し、離散化はデータがブール値(trueまたはfalse)に変換されることを意味します。 以下は、シグナル用の5セットのデータの準備です。

  1. クラスカテゴリに一致する終値の変化を追跡する離散化された変数データ
  2. -1.0から+1.0の範囲への生の終値の変化の正規化された変数データ
  3. 生の終値の変化における連続変数データ 
  4. 終値

正規化は、終値の変化を最後の2つの足の範囲の割合として(-1.0から+1.0まで)10進数で提供しますが、離散化は、価格が上昇した(インデックスが2)か、中立的な範囲にとどまった(インデックスが1)、拒否された(インデックスが0)かを示します。示します。パフォーマンスを調べるために、すべてのデータ型をテストします。この準備は、以下に示すDataメソッドによっておこなわれます。4つのデータ型はすべて正則化され、m_signal_regulizer入力でデータのニュートラルゾーンを定義し、ホワイトノイズを減らします。

//+------------------------------------------------------------------+
//| Data Set method                                                  |
//| INPUT PARAMETERS                                                 |
//|     Index   -   int, read index within price buffer.             |
//|                                                                  |
//|     Variables                                                    |
//|             -   whether data component is variables or .         |
//|                  classifier.                                     |
//| OUTPUT                                                           |
//|     double  -   Data depending on data set type                  |
//|                                                                  |
//| DATA SET TYPES                                                   |
//| 1. Discretized variables. - 0                                    |
//|                                                                  |
//| 2. Normalized variables. - 1                                     |
//|                                                                  |
//| 3. Continuized variables. - 2                                    |
//|                                                                  |
//| 4. Raw data variables. - 3                                       |
//|                                                                  |
//+------------------------------------------------------------------+
double CSignalDA::Data(int Index,bool Variables=true)
   {
      m_close.Refresh(-1);
         
      m_low.Refresh(-1);
      m_high.Refresh(-1);
            
      if(Variables)
      {
         if(m_signal_type==0)
         {
            return(fabs(Close(StartIndex()+Index)-Close(StartIndex()+Index+1))<m_signal_regulizer*Range(Index)?1.0:((Close(StartIndex()+Index)>Close(StartIndex()+Index+1))?2.0:0.0));
         }
         else if(m_signal_type==1)
         {
            if(fabs(Close(StartIndex()+Index)-Close(StartIndex()+Index+1))<m_signal_regulizer*Range(Index))
            {
               return(0.0);
            }
            return((Close(StartIndex()+Index)-Close(StartIndex()+Index+1))/fmax(m_symbol.Point(),fmax(High(StartIndex()+Index),High(StartIndex()+Index+1))-fmin(Low(StartIndex()+Index),Low(StartIndex()+Index+1))));
         }
         else if(m_signal_type==2)
         {
            if(fabs(Close(StartIndex()+Index)-Close(StartIndex()+Index+1))<m_signal_regulizer*Range(Index))
            {
               return(0.0);
            }
            return(Close(StartIndex()+Index)-Close(StartIndex()+Index+1));
         }
         else if(m_signal_type==3)
         {
            if(fabs(Close(StartIndex()+Index)-Close(StartIndex()+Index+1))<m_signal_regulizer*Range(Index))
            {
               return(Close(StartIndex()+Index+1));
            }
            return(Close(StartIndex()+Index));
         }
      }
      
      return(fabs(Close(StartIndex()+Index)-Close(StartIndex()+Index+1))<m_signal_regulizer*Range(Index)?1.0:((Close(StartIndex()+Index)>Close(StartIndex()+Index+1))?2.0:0.0));
   }


各指標値が4つの変数を提供することを意味する4の次元を使用しています。したがって、ここでは簡潔にするために、訓練の各データセットの最後の4つの指標値を見ていきます。ここでの分類も、各データセットのクラスコンポーネントで2つのクラス(最小)のみを使用する基本的なものになります。また、訓練サンプルのデータポイントの数を設定する必要があります。この値は、入力パラメータm_signal_pointsによって格納されます。

LDAの出力は通常、係数の行列です。これらの係数はベクトルで並び替えられ、これらのベクトルのいずれか1つと現在の指標データポイントとの内積によって値が生成され、この新しい/現在のデータポイントを分類するために、訓練データセットの積によって生成された同様の値と比較されます。したがって、簡単にするために、訓練セットにLDA射影が0と1の2つのデータポイントしかなく、新しい値が0.9のドット積を生成する場合、LDA射影が1のデータポイントにより近いので同じカテゴリにあると結論付けます。一方、たとえば0.1の値が得られた場合、この新しいデータポイントは、LDA投影が0であったデータポイントと同じカテゴリに属している必要があると考えられます。 

訓練データセットが2つのデータポイントのみであることはめったにないため、実際には、各クラスの「重心」を、新しいデータポイントの内積とLDAの出力ベクトルの出力との比較として使用します。この「重心」は、各クラスのLDA射影平均になります。

各データポイントを強気か弱気かを分類するには、単純に指標値のの指標値を確認するだけです。正ならばデータポイントが強気、負ならば弱気です。また、横ばいになる可能性もあります。簡単にするために、横ばいまたは価格の変化がない場合と強気の場合を考えます。

ExpertSignalクラスは、通常、正規化された整数値(0~100)に依存して、売買の決定を重み付けします。LDA予測はdouble型にバインドされるため、以下に示すように、-1.0から+1.0の範囲に収まるように正規化します(弱気の場合は負、強気の場合は正)。

         // best eigen vector is the first 
         for(int v=0;v<__S_VARS;v++){ _unknown_centroid+= (_w[0][v]*_z[0][v]); }
         
         //

         
         if(fabs(_centroids[__S_BULLISH]-_unknown_centroid)<fabs(_centroids[__S_BEARISH]-_unknown_centroid) && fabs(_centroids[__S_BULLISH]-_unknown_centroid)<fabs(_centroids[__S_WHIPSAW]-_unknown_centroid))
         {
            _da=(1.0-(fabs(_centroids[__S_BULLISH]-_unknown_centroid)/(fabs(_centroids[__S_BULLISH]-_unknown_centroid)+fabs(_centroids[__S_WHIPSAW]-_unknown_centroid)+fabs(_centroids[__S_BEARISH]-_unknown_centroid))));
         }
         else if(fabs(_centroids[__S_BEARISH]-_unknown_centroid)<fabs(_centroids[__S_BULLISH]-_unknown_centroid) && fabs(_centroids[__S_BEARISH]-_unknown_centroid)<fabs(_centroids[__S_WHIPSAW]-_unknown_centroid))
         {
            _da=-1.0*(1.0-(fabs(_centroids[__S_BEARISH]-_unknown_centroid)/(fabs(_centroids[__S_BULLISH]-_unknown_centroid)+fabs(_centroids[__S_WHIPSAW]-_unknown_centroid)+fabs(_centroids[__S_BEARISH]-_unknown_centroid))));
         }

この値は、シグナルクラスで期待される一般的な整数(0~100)に簡単に正規化されます。

   if(_da>0.0)
     {
      result=int(round(100.0*_da));
     }

 (Checklong関数の場合)、および、

   if(_da<0.0)
     {
      result=int(round(-100.0*_da));
     }

(Checkshort関数の場合)

各入力データ型のテスト実行により、以下のストラテジーテスターレポートが得られます。

データセット1レポート

sr1

cs1

 

データセット2レポート

sr2

cs2

 

データセット3レポート

sr3

cs3

 

データセット4レポート

sr4

cs4

  

これらのレポートは、トレーダーのツールとしてのLDAの可能性を示しています。 

ExpertTrailingクラスは、ポジションのストップロスを調整または設定します。ここでの重要な出力は、新しいストップロスのdoubleです。ポジションに応じて、高値と安値を主要なデータセットと見なします。これらは高値と安値の両方に対して次のように準備され、ポジションのタイプに応じて選択されます。

  1. 離散化された変数データ追跡(高値または安値)の価格変更は、クラスカテゴリに一致します。
  2. -1.0から+1.0の範囲への生(高値または安値)の変化の正規化された変数データ
  3. 生の(高値または安値)価格変化の連続変数データ 
  4. 生の(高値または安値)価格

LDAからの出力は、シグナルクラスと同様に正規化されたdoubleになります。これはストップロスの定義には役に立たないため、ポジションのタイプに応じて以下に示すように調整され、ストップロス価格が算出されます。

      int _index   =StartIndex();
      double _min_l=Low(_index),_max_l=Low(_index),_min_h=High(_index),_max_h=High(_index);
      
      for(int d=_index;d<m_trailing_points+_index;d++)
      {
         _min_l=fmin(_min_l,Low(d));
         _max_l=fmax(_max_l,Low(d));
         _min_h=fmin(_min_h,High(d));
         _max_h=fmax(_max_h,High(d));
      }
      
      if(Type==POSITION_TYPE_BUY)
      {
         _da*=(_max_l-_min_l);
         _da+=_min_l;
      }
      else if(Type==POSITION_TYPE_SELL)
      {
         _da*=(_max_h-_min_h);
         _da+=_max_h;
      }

また、新しいストップロスレベルを調整および設定する方法もここにあります.ロングポジションの場合:

   m_long_sl=ProcessDA(StartIndex(),POSITION_TYPE_BUY);

   double level =NormalizeDouble(m_symbol.Bid()-m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
   double new_sl=NormalizeDouble(m_long_sl,m_symbol.Digits());
   double pos_sl=position.StopLoss();
   double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
//---
   sl=EMPTY_VALUE;
   tp=EMPTY_VALUE;
   if(new_sl>base && new_sl<level)
      sl=new_sl;

ここでおこなっているのは、ロングポジション('m_long_sl')の次の足までの可能性のある低価格ポイントを決定し、ポジションの始値または現在のストップ ロスのいずれかを上回り、買い呼び値からストップ レベルを引いた値を下回っている場合には、新しいストップ ロスとして設定することです。これを計算する際に使用されるデータタイプは低価格です。

ショートポジションのストップロスの設定は、これのミラーバージョンです。

シグナルに…データ型を使用しながら各入力データ型のテストを実行すると、以下の戦略テスターレポートが得られます。

データセット1レポート

tr1

ct1

 

データセット2レポート

tr2



ct2

 

データセット3レポート

tr3

ct3

 

データセット4レポート

tr4

ct4

 

これらのレポートは、回復係数が6.82であることを考えると、継続的な生の変更の.dataセットが最適であることを示している可能性があります。

ExpertMoneyクラスは、ポジションのロットサイズを設定します。これは過去のパフォーマンスの関数である可能性があるため、OptimizedVolumeクラスに基づいて構築しています。ただし、ボラティリティまたは高値と安値の間の範囲を考慮する場合、LDAは初期サイジングに役立ちます。したがって、主要なデータセットは価格バーの範囲になります。価格バーの範囲が増加しているか減少しているかを確認します。それでは、次のデータの準備をしましょう。

  1. 離散化された変数データ追跡範囲値は、クラスカテゴリに一致するように変更されます。
  2. Normalized variables data of生の範囲値の正規化された変数データは、-1.0 から +1.0 の範囲に変更されます。rangevalue changes to the range -1.0 to +1.0. 
  3. 生の連続変数データ 範囲 価値が変わります。 
  4.  範囲 値。

LDAからの出力は、シグナルおよび末尾のクラスと同様に、正規化されたdoubleになります。繰り返しになりますが、これはすぐには役に立たないため、新しいバー範囲をより適切に予測するために以下に示す調整をおこないます。

      int _index   =StartIndex();
      double _min_l=Low(_index),_max_h=High(_index);
      
      for(int d=_index;d<m_money_points+_index;d++)
      {
         _min_l=fmin(_min_l,Low(d));
         _max_h=fmax(_max_h,High(d));
      }
   
      _da*=(_max_h-_min_l);
      _da+=(_max_h-_min_l);

ボリュームの設定は、EAがロングポジションまたはショートポジションのどちらを開いているかに応じて、2つのミラーリングされた関数によって処理されます。以下はロングポジションのハイライトです。

   double _da=ProcessDA(StartIndex());
   
   if(m_symbol==NULL)
      return(0.0);
   
   sl=m_symbol.Bid()-_da;
   
//--- select lot size
   double _da_1_lot_loss=(_da/m_symbol.TickSize())*m_symbol.TickValue();
   double lot=((m_percent/100.0)*m_account.FreeMargin())/_da_1_lot_loss;
   
//--- calculate margin requirements for 1 lot
   if(m_account.FreeMarginCheck(m_symbol.Name(),ORDER_TYPE_BUY,lot,m_symbol.Ask())<0.0)
     {
      printf(__FUNCSIG__" insufficient margin for sl lot! ");
      lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,m_symbol.Ask(),m_percent);
     }
   
//--- return trading volume
   return(Optimize(lot));

ここで注目に値するのは、レンジ価格の予測される変化を決定し、この予測を買い呼び値から差し引くということです(ストップレベルも差し引く必要があります)。これにより、「リスク調整済み」ストップロスが得られます。パーセント入力パラメータを最大リスク損失パラメータとして使用すると、予想した買い呼び値を下回ってドローダウンが発生した場合にパーセント入力パラメータ値でドローダウンパーセンテージを制限するロットサイズを計算できます。

シグナルに生の終値データ型を使用し、トレーリングに…を使用しながら、各入力データ型のテストを実行すると、以下のストラテジーテスターレポートが得られます。

データセット1レポート

mr1

cm1

 

データセット2レポート

mr2

cm2


データセット3レポート

mr3

cm3


データセット4レポート

mr4


cm4


離散範囲の値の変化のデータセットは、資金管理に最も有望であるようです。 同様に注目に値するのは、すべて同じシグナルとトレーリング設定を使用していることを考えると、資金管理のデータセットの結果に大きな差異があることです。

この記事では、EAの取引ツールとしての判別分析の使用の可能性を強調しました。網羅的ではありませんでした。より長い期間にわたるより多様なデータセットを使用すれば、さらなる分析をおこなうことができます。 


MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/11687

添付されたファイル |
TrailingDA.mqh (16.66 KB)
SignalDA.mqh (13.48 KB)
MoneyDA.mqh (15.19 KB)
ニューラルネットワークが簡単に(第32部):分散型Q学習 ニューラルネットワークが簡単に(第32部):分散型Q学習
この連載で前回Q学習法を紹介しました。この手法は、各行動の報酬を平均化するものです。2017年には、報酬分布関数を研究する際に、より大きな成果を示す2つの研究が発表されました。そのような技術を使って、私たちの問題を解決する可能性を考えてみましょう。
データサイエンスと機械学習(第09回):K近傍法(KNN) データサイエンスと機械学習(第09回):K近傍法(KNN)
これは、訓練データセットから学習しない遅延アルゴリズムです。代わりにデータセットを保存し、新しいサンプルが与えられるとすぐに動作します。シンプルでありながら、実世界でさまざまなケースに応用されています。
DoEasy - コントロール(第26部):ToolTip WinFormsオブジェクトの最終確認とProgressBarの開発開始 DoEasy - コントロール(第26部):ToolTip WinFormsオブジェクトの最終確認とProgressBarの開発開始
今回は、ツールチップコントロールの開発を完了し、ProgressBar WinFormsオブジェクトの開発を開始します。オブジェクトで作業しながら、コントロールやそのコンポーネントをアニメーション化するための普遍的な機能を開発する予定です。
DoEasy - コントロール(第25部):Tooltip WinFormsオブジェクト DoEasy - コントロール(第25部):Tooltip WinFormsオブジェクト
今回は、Tooltipコントロールの開発と、ライブラリの新しいグラフィカルプリミティブの開発を開始する予定です。当然ながら、すべての要素にツールチップがあるわけではないですが、すべてのグラフィックオブジェクトにはツールチップを設定する機能があります。