English Русский 中文 Español Deutsch Português
preview
MQL5の圏論(第16回):多層パーセプトロンと関手

MQL5の圏論(第16回):多層パーセプトロンと関手

MetaTrader 5テスター | 6 10月 2023, 14:47
402 0
Stephen Njuki
Stephen Njuki

はじめに

当連載ではこれまで、トレーダーがより堅牢なトレードシステムを開発するために、圏論の基礎となる概念をどのように表現し、MQL5コードで使用できるかを示してきました。圏論のテーマには多くの側面があるが、間違いなく、関手自然変換の2つが重要でしょう。(前の2つの記事と同じように)関手に再びこだわることで、このテーマの主要なアイデアのひとつを強調することになります。

前回と同様に関手にこだわるとしても、トレーリングストップの調整だけに焦点を当てた前回とは異なり、この記事の焦点は、エントリーシグナルとエグジットシグナルの生成における応用を探ることにあります。繰り返しになりますが、添付されたコードの中に聖杯があるわけではなく、これは読者が市場をどのように見るかによって改善し、修正すべきアイデアなのです。


復習:MQL5における関手とグラフ

関手とは、2つの圏のオブジェクト間の関係だけでなく、それらの圏の射間の関係も捉える圏間の写像です。このことは、この2つの写像のどちらか一方としてコードに実装していることを意味します。予測を行う際に、事実上、オブジェクト間の写像は射間の写像を確認し、その逆もまた同様だからです。

矢印と頂点で相互接続されたシステムを表現していると見ることができるグラフは連載第11回で紹介されました。前回の記事では、MetaQuotesがMetaTrader 5ターミナルで提供する経済指標カレンダーデータを用いて、時系列の一部を形成する4つの異なるデータポイントをリンクする単純な仮説を用いて説明しました。記事にあったこのグラフは、事実上、それ自体がひとつの圏です。

前回の記事で取り上げた関手は、単純な一次方程式によって2つの圏を写像しました。共有されたコードには、これを2次方程式にスケールアップするオプションがありましたが、この記事のためのテストでは実装されませんでした。関手の写像は本質的に、始域におけるオブジェクトの値を取り、それに係数を掛け、定数を加えて、終域におけるオブジェクトの値を得ます。係数と定数は事実上、単純な一次方程式の傾きとy切片であるため、線形でした。


経済指標カレンダーデータからの圏論関手

カレンダーデータの複雑な相互関連性を考えると、グラフの使用によって、圏として経済カレンダーデータを再フォーマットを実現したことは適切でした。MetaTrader 5 ターミナルの[カレンダー]タブからわかるように、さまざまな種類の経済データが多数あります。この問題は以前の記事でも強調しましたが、通貨固有のデータであるため、通貨ペアの取引を決定する際にこのデータを組み合わせる必要がありますが、これは難しいことです。前回の記事と今回の記事で意図した証券については、データを対にする必要はありませんが、それでも、このデータの一部が他の経済データに依存しているという考え方は、特に私たちの証券であるS&P500の広範な重要性を考えると、考慮すべきことです。そこで、前回の記事では、CPIはPMIに左右され、PMIは直近の10年物利回りに左右され、その利回りは小売売上高に左右されるという単純な仮説を立てました。従って、これらの経済データの時系列を1つだけ持つのではなく、S&P500のボラティリティの基礎となる複数のポイントを持つことになります。

ただし今回は、前回の記事のようにS&P500のボラティリティだけでなく、そのトレンドにも注目します。その短期的な(毎月の)トレンドを予測し、エキスパートアドバイザー(EA)でポジションを建てるためにそれらの予測を使用したいと考えています。つまり、本連載でこれまで扱っていた「Expert Trailing」クラスではなく、「Expert Signal」クラスを扱うことになります。つまり、経済カレンダーのデータのグラフに関手ベースの変換を実行すると、S&P500の予想される変化が得られます。この実装は、多層パーセプトロンの助けを借りて実現されます。

前回の記事では、4つの経済データをリンクさせた単純な仮説を図式化しましたが、単純化しすぎており、時系列グラフとして示しませんでした。下図はそれを実現しようとするものです。

d_1


図からわかるように、時系列オブジェクトを追加することで複雑さが増し、これがグラフであることの根拠となっています。たとえば、CPIは小売売上高の結果であり、PMIはPMIの影響を受けると主張する人もいるなど、この根拠となる仮説には議論の余地があります。PMIは10年間の入札実績から測定されるマネーサプライによって設定される、などです。S&P500の予想デルタに影響を与える上で、おそらくより重要な、異なる、あるいはより多くの経済データポイントによる他の多くの組み合わせもあります。良い知らせは、これらすべての可能な順列と仮説にもかかわらず、ターミナル内のストラテジーテスターがこれらの議論をすべて終わらせることができるということです。これは、アイデアを効率的にテストすることができる形式で明確にレイアウトするのによい理由です。

これを支援するために、MQL5ウィザードでは、シグナルファイルをコーディングするだけで、数回のクリックでEAを簡単に組み立てることができます。


S&P500指数値の圏論関手

シグナルファイル内で、S&P500指数の値をグラフとして表すことは、圏に相当します。これは、前回の記事で共有したように、グラフの各頂点(データポイント)がオブジェクトに相当し、頂点間の矢印を射として捉えることができるためです。オブジェクトには1つの要素を含めることができますが、この場合、データポイントには、カテゴリに含めるとみなされていない追加データとして、関心のある値以外の値も含まれます。経済データが発表された日、発表に至るまでのそのデータのコンセンサス予測などの、MetaTrader ターミナルの[カレンダー]タブにリストされるデータです。このリンクは、カレンダーイベントタイプのページにつながり、列挙された各属性はオブジェクトに適用されます。これらのデータはすべて、経済カレンダーの圏でオブジェクト、あるいは集合と呼ばれるものを形成します。

過去の経済カレンダーのデータを分析し、前処理するために関手を利用することは、残念ながら、サードパーティを介したストラテジーテスターでのみ可能であり、MetaQuotesのサーバーから直接行うことはできません。前の記事で行ったように、スクリプトでデータをcsvにエクスポートし、そのcsvをストラテジーテスターで読み込むことで、このボトルネックに対処しました。ここでの違いは、後続のクラスではなく、EAトシグナルクラスのインスタンスに対して行っていることです。2つの関手を扱っているので、使用されたスクリプトでは、関手がオブジェクトにまたがっていることを意味する接頭辞「true」と、射にまたがっていることを意味する接頭辞「false」が付いた2つのファイルを書きました。書いたファイルは記事の最後に添付されています。

上の図は、変換したS&P500種株価指数をグラフ化したものです。


関手ベースのニューラルネットワークアーキテクチャ

この記事での多層パーセプトロン(ニューラルネット)としての関手は、カテゴリ間、さらにはカテゴリ内のオブジェクトを写像するときに使用していた以前の線形または二次関係から一歩進んだものです(2つの要素間の射関係は同じように定義できるため)。先に強調したように、関手の使用は、2つの圏のオブジェクト間の写像だけでなく、それぞれの射間の写像も意味します。それらは互いに確認できます。つまり、終域の対象が分かれば、射は暗示されるし、その逆もまた然りです。圏間で2つのパーセプトロンを扱うことになります。

また、この記事は、パーセプトロンについての入門を提供するものではありません。このWebサイトに掲載されている記事だけでなく、一般的なオンライン記事もすでにたくさんあるので、ここで紹介されていることを明確にするのに役立つのであれば、好奇心旺盛な読者の方はご自分で背景をお調べてください。ここで実装されているネットワークアーキテクチャは、MetaTraderのIDEでIncludeMathフォルダの下でアクセスできるAlglibのおかげです。これが、ライブラリを使ったパーセプトロンの初期化です。

//+------------------------------------------------------------------+
//|   Function to train Perceptron.                                  |
//+------------------------------------------------------------------+
bool CSignalCT::Train(CMultilayerPerceptron &MLP)
   {
      CMLPBase _base;
      CMLPTrain _train;
      
      if(!ReadPerceptron(m_training_profit))
      {
         _base.MLPCreate1(__INPUTS,m_hidden,__OUTPUTS,MLP);
         m_training_profit=0.0;
      }
      else
      {
         printf(__FUNCSIG__+" read perceptron, with profit: "+DoubleToString(m_training_profit));
      }
      
      ...
      
      return(false);
   }


このライブラリで使用されているパーセプトロンは非常に基本的なもので、入力層、隠れ層、出力層の3つの層から構成されています。経済データ圏には一度に4つのデータポイントがある(仮説に基づく)ので、隠れ層の入力数は4になります。隠れ層のポイント数は数少ない最適化可能なパラメータのひとつですが、デフォルトは7です。そして最後に、出力層に1つの出力があります。S&P500指数の予測変化です。パーセプトロンのフィードフォワード機能を理解する上で、重み、バイアス、活性化関数の知識が鍵となります。これらについては、必要に応じてお調べください。


関手ベースのニューラルネットワークの訓練

過去の経済指標カレンダーデータに対する学習プロセスは、レーベンバーグ・マルカート法アルゴリズムを使用して行われます。このコーディングは、フィードフォワードやバックプロパゲーションと同様、AlgLib関数によって処理されます。ライブラリから以下のような訓練を実施します。

      int _info=0;
      CMatrixDouble _xy;
      CMLPReport _report;
      TrainingLoad(m_training_stop,_xy,m_training_points,m_testing_points);
      //
      if(m_training_points>0)
      {
         _train.MLPTrainLM(MLP,_xy,m_training_points,m_decay,m_restarts,_info,_report);
         
         if(_info>0){ return(true); }
      } 


ここで重要なのは、共通ディレクトリにあるcsvファイルからの入力データをXY行列に入力することです。行列は、新しいバーが生成されるたびに(またはタイマーで)、各データ行に定義された4つのデータポイントを履歴データとして取得し、それを使用してネットワークを訓練し、重みとバイアスを生成します。XY入力行列の母集団は、以下のように'TrainingLoad'関数によって処理されます。

//+------------------------------------------------------------------+
//|   Function Get Training Points and Initialize Training Matrix.   |
//+------------------------------------------------------------------+
void CSignalCT::TrainingLoad(datetime Date,CMatrixDouble &XY,int &TrainingPoints,int &TestingPoints)
   {
      TrainingPoints=0;
      TestingPoints=0;
      
      ResetLastError();
      string _file="_s_"+m_currency+"_"+m_symbol.Name()+"_"+EnumToString(m_period)+"_"+string(m_objects)+".csv";
      int _handle=FileOpen(_file,FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,"\n",CP_ACP);
      
      if(_handle!=INVALID_HANDLE)
      {
         string _line="";
         int _line_length=0;
         
         while(!FileIsLineEnding(_handle))
         {
            //--- find out how many characters are used for writing the line
            _line_length=FileReadInteger(_handle,INT_VALUE);
            //--- read the line
            _line=FileReadString(_handle,_line_length);
            
            string _values[];
            ushort _separator=StringGetCharacter(",",0);
            if(StringSplit(_line,_separator,_values)==6)
            {
               datetime _date=StringToTime(_values[0]);
               
               _d_economic.Let(); _d_economic.Cardinality(4);
               
               //printf(__FUNCSIG__+" initializing for: "+TimeToString(Date)+" at: "+TimeToString(_date));
               
               if(_date<Date)
               {
                  TrainingPoints++;
                  //
                  XY.Resize(TrainingPoints,__INPUTS+__OUTPUTS);
                  
                  for(int i=0;i<__INPUTS;i++)
                  {
                     XY[TrainingPoints-1].Set(i,StringToDouble(_values[i+1]));
                  }
                  //
                  XY[TrainingPoints-1].Set(__INPUTS,StringToDouble(_values[__INPUTS+1]));
               }
               else
               {
                  TestingPoints++;
               }
            }
         }
         
         FileClose(_handle);
      }
      else
      {
         printf(__FUNCSIG__+" failed to load file. Err: "+IntegerToString(GetLastError()));
      }
   }


注目に値するのは、訓練後のニューラルネットワークが機能し、人気がある理由は、重みとバイアスを開発して再利用できる能力にあるということです。この記事では、これらの重みとバイアスのストレージはカスタム関数によって処理されています。現時点で共有することには抵抗があるため、ex5ライブラリとしての参照はリストに表示されていますが、そのコードは提示していません。

通常、ネットワークを訓練する際にはデータの前処理が行われ、データを同等の値に正規化し、訓練セットとテストセットに分割します。ただし、ここでの目的では、EA初期化時に読み込まれた履歴データのセットを訓練し、その後、入力された日付によって訓練データからの分割が定義されたcsvデータの別の部分を使用してテストします。最適化可能なパラメータは隠れ層の重みの数(5から12まで)だけなので、訓練したネットワークの重みを共通ディレクトリのファイルに書き込み、各最適化パスの最後に、そのパスで得られた最適化基準が、以前のパスですでに書き込まれたファイルの最適化基準を上回った場合にのみ、書き込みます。これが達成され、ファイルが書き込まれると、次のパスでネットワークを初期化する際に、初期重みはそのファイルから書き込まれたものになります。

バックプロパゲーションはすべてAlgLibのCMLPTrainクラスにあるMLPTrainLM関数によって処理されます。


関手とニューラルネットワークを用いた取引シグナル生成

指数の変化の線形順序であるS&P 500圏は、経済指標カレンダー データ圏からの「2 つの」関手への終域を形成します。復習すると、オブジェクトと射がリンクしているので、「2つ」あるのです。つまり、csvファイルから読み出された入力日付によって定義されるテスト期間におけるシグナルは、各訓練の終了時に得られた重みによって生成されることになります。この記事に添付されているコードの訓練は、EAを初期化するたびに行われます。添付されているシグナルファイルは、以前の記事で添付されたトレーリングファイルと同様に、MetaEditor IDEを介してMQL5ウィザードで一度組み立てれば使用できます。新しいバーが出るたびにcsvファイルに新しいデータ行が追加されるため、タイマーを使って追加訓練することも可能ですが、このアプローチについては記事中で検討していません。

GetOutput関数は、過去の記事と同じように、取引の決定を処理するための値を取得する役割を果たします。以下のリストからわかるように、現在の値で圏を更新することに加えて、共通ディレクトリ内のcsvファイルからの現在のカレンダー読み取り値に基づいてネットワーク入力が準備され、配列の転送元である_x_inputs配列に埋められます。 配列はここからCMLPBaseクラスの一部である関数MLPProcessを使用してネットワークに供給されます。コードは以下の通りです。

//+------------------------------------------------------------------+
//|   Get Output value, forecast for next change in price bar range. |
//+------------------------------------------------------------------+
double CSignalCT::GetOutput(datetime Date)
   {
      if(Date>=D'2023.07.01')
      {
         printf(__FUNCSIG__+" log profit: "+DoubleToString(m_training_profit)+", account profit: "+DoubleToString(m_account.Profit())+", equity: "+DoubleToString(m_account.Equity())+", deposit: "+DoubleToString(m_training_deposit));
         
         if(m_training_profit<m_account.Equity()-m_training_deposit)
         {
            printf(__FUNCSIG__+" perceptron write... ");
            m_training_profit=m_account.Equity()-m_training_deposit;
            
            WritePerceptron(m_training_profit,_MLP);
         }
      }
      
      ...
      
      _value="";_e.Let();_e.Cardinality(1);
      _d_economic.Get(3,_e);_e.Get(0,_value);
      _x_inputs[3]=StringToDouble(_value);//printf(__FUNCSIG__+" val 4: "+_value);
      
      //forward feed?...
      CMLPBase _base;
      _base.MLPProcess(_MLP,_x_inputs,_y_inputs);
      
      _output=_y_inputs[0];
      
      //printf(__FUNCSIG__+" output is: "+DoubleToString(_output));
               
      return(_output);
   }


また、これらの手法を使う取引システムには、リスク管理やポジションサイジングを組み込む可能性もあり、シグナルの大きさに応じてサイジングを行うこともできます。この場合、シグナル値を正規化する必要があり、ポジションサイジングを変更する場合は、常に細心の注意を払う必要があります。ExpertSignalクラスのカスタムインスタンスを使ってエントリーポイントとエグジットポイントを定義しているのと同じように、ExpertMoneyクラスのカスタムインスタンスを作成することで、これらの変更を実現できます。


バックテストとパフォーマンス評価

ここでのバックテストは、隠れ層の理想的な重みの数の最適化です。重みは5から12まであるので、選択肢は8つしかないが、理想的な重み数を選択する前に、それぞれの重みの数について複数回実行します。したがって、複数の実行を行うために、EAのパフォーマンスには影響を与えずに、最適化する必要があるパラメータを追加します。そのため、最適化プロセスに追加の実行を追加して、各重みオプションの数で複数のテスト実行を実現できるようにします。前述のように、各実行の終了時に、テスト結果が共通フォルダに最後に書き込まれたファイルよりも優れていれば、その重みが前に書き込まれたものに置き換わります。最適化の基準は最大利益です。カレンダーの経済指標データは平均してほぼ同じ頻度で更新されるため、月次の時間枠で実行します。テストはS&P500の2022-07-01から2023-08-01まで、月次の時間枠で行われました。オブジェクトからオブジェクトへの関手の最良の実行結果は以下で報告されています。

r1


同様に、射から射への関手によって、以下の報告が得られました。

r2


ドローダウンとプロフィットファクターに関するレポートの主要指標を分析したところ、射から射への関手がより優れたパフォーマンスを持つことがわかりました。おそらく、さらに発展させるために検討する価値のあるものでしょう。これは、他の証券だけでなく、新しいバーごとに訓練を行うべきか、四半期ごとに行うべきかを検討するようなテスト実行を行う際に、異なる訓練アプローチを使用してさらにテストを行うことで答えが得られる問題です。


結論

要約すると、パーセプトロンを使ったテストから得られた重要な知見は、シグナルファイルに示されたようなシグナルを使った取引システムを開発することができるということです。開発に先立って、ストラテジーテスターが簡単にアクセスできる形式のデータを含む適切な圏の始域が利用可能である必要があります。また、信頼できるテストは複数年にわたる傾向があるため、このデータは広範である必要があります。

多層パーセプトロンを関手として使用することの意義は、単にステップアップというだけでなく、ニューラルネットワークが取りうる多くの種類や形式を考えると、多くの可能性を秘めた恵みです。パーセプトロンをさらに研究するためのハイパーリンクは記事の中で紹介されていますが、これはよく知られ、文書化されているテーマなので、それらは単なる指針として機能します。極限、余極限、普遍性など、すでに説明した多くの概念は、すべてニューラルネットワークの助けを借りて定式化することができます。


参照文献

ウィキペディア


添付ファイルに関する注意事項

SignalCT_16_.mqhをMQL5includeExpertSignalフォルダに配置し、ct_16.mqhをMQL5includeフォルダに配置してください。

さらに、EAの一部としてそれらを組み立てる必要があります。ウィザードを使用してEAを組み立てる方法については、こちらのガイドに従ってください。記事にあるように、資金管理にはトレーリングストップなしと固定証拠金を使いました。どちらもMQL5のライブラリーの一部です。いつものことですが、この記事の目的は、聖杯を紹介することではなく、読者自身の戦略にカスタマイズできるアイデアを紹介することです。

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

添付されたファイル |
ct_16.mqh (73.54 KB)
ct_16.mq5 (7.45 KB)
SignalCT_16_.mqh (18.34 KB)
回帰指標を用いたONNXモデルの評価 回帰指標を用いたONNXモデルの評価
回帰とは、ラベル付けされていない例から実際の値を予測するタスクのことです。いわゆる回帰メトリクスは、回帰モデルの予測精度を評価するために使用されます。
MQL5の圏論(第15回):関手とグラフ MQL5の圏論(第15回):関手とグラフ
この記事はMQL5における圏論の実装に関する連載を続け、関手について見ていきますが、今回はグラフと集合の間の橋渡しとして関手を見ていきます。カレンダーデータを再検討します。ストラテジーテスターでの使用には限界がありますが、相関性の助けを借りて、ボラティリティを予測する際に関手を使用するケースを説明します。
MQL5のインタラクティブGUIで取引チャートを改善する(第3回):シンプルで移動可能な取引GUI MQL5のインタラクティブGUIで取引チャートを改善する(第3回):シンプルで移動可能な取引GUI
本連載第3回では、MQL5の移動可能な取引ダッシュボードへのインタラクティブGUIの統合について紹介します。この記事は、第1回と第2回で設定された基礎の上に構築され、静的な取引ダッシュボードを動的で移動可能なものに変えるよう読者を導きます。
RSIディープスリームーブ取引手法 RSIディープスリームーブ取引手法
MetaTrader 5でRSIディープスリームーブ取引テクニックを紹介します。この記事は、株式、通貨、商品などの証券の強さと勢いを測定するために使用されるテクニカル分析指標であるRSIに基づくいくつかの取引テクニックを紹介する新しい一連の研究に基づいています。