English Русский 中文 Español Deutsch Português
preview
MQL5の圏論(第17回):関手とモノイド

MQL5の圏論(第17回):関手とモノイド

MetaTrader 5トレーディングシステム | 10 11月 2023, 09:51
340 0
Stephen Njuki
Stephen Njuki

はじめに

圏論の考察を続けて、関手圏関数についてもう1回考察します。これまで、Expert trailingクラスとExpert Signalクラスのカスタムインスタンスの実装における圏理論の応用を見てきました。そのため、この記事では Expert Moneyクラスの使用における応用を検討します。これらのクラスはすべてMeta Editor IDEに付属しており、最小限のコーディングでエキスパートアドバイザー(EA)を組み立てる際にMQL5ウィザードと共に使用されます。

ポジションサイジングは、取引システムの設計に関わる話題の1つです。EAの予備テストの結果はすべて、ポジションサイジングに非常に影響を受けやすいので、それを完全に省く(固定証拠金または固定ロットサイズを使用)か、どうしても必要な場合は、エグジット方法とバランスの取れた適切なエントリシグナルがすでにあるときに、一番最後に追加することをお勧めします。それはともかく、EAのマネークラスのカスタムインスタンスで、予測されるストップロスに基づいて理想的なポジションサイズを設定することを試みます。

関手は、間の架け橋であり、各圏の対象間の違いだけでなく、その形態素の違いも捉えます。グラフや線形順序の形をした圏を見るとき、この捕捉された情報がボラティリティの変化や市場動向の予測にどのように利用できるかを見ることができました。リコールグラフと線形順序はそれ自体圏ではありませんが、主要な圏公理が存在するため、そのように見なされました。

関手は、第14回第15回で、単純な一次方程式を使って実装されました。そこでは、写像は、終域範疇のオブジェクトと射を決定するために、傾きの係数と切片のyを必要とするだけでした。第16回から、関手を多層パーセプトロンと呼ばれる単純なニューラルネットワークとして見るようになりました。このネットワークは、ウォーレン・マカロックウォルター・ピッツの研究に端を発し、-1から+1までの任意の連続関数を近似し、多層であればXOR関数を複製することが以前から知られています。

この記事では、関手に関する考察のまとめとして、モノイドと証券価格の前順序と組み合わせることで、ある証券(BTCUS:ビットコイン)を取引する際のポジションサイズを設定するシステムを構築できることを検証します。前回モノイドについて見たときは、トレーダーへのモノイドの主な応用は、取引ステップを分類し、それぞれのモノイドの操作によって意思決定ができるようにすることでした。モノイドとは、集合、二項演算、および単位元であることを思い出してください。そのため、トレーダーがポジションを建てる意思決定をする際に直面する想定ステップごとにモノイドを作成しました。


取引における関手とモノイドについて

これまでの基本的な事柄を簡単にまとめると、オブジェクト(以前の記事ではドメインと呼ばれた)は圏のセル(構成要素)です。圏内では、オブジェクトは射と呼ばれるマッピングを互いに持ち、オブジェクトをつなぐ射があるのと同じように、関手も圏をつなぎます。

つまり、関手が提供する圏間の結びつきは、終域の圏が私たちの予測対象である時系列であったため、予測を行う上で有用でした。前回の記事では、S&P500を買うか売るかの判断材料としました。

ただし、前回の記事では関手がグラフと線形順序を結んでいた野に比べ、今回はモノイドをドメイン圏とします。前述したように、モノイドを取引を行う際の各ステップにおける意思決定ポイントとして使用しました。戦略の違いから、他のトレーダーが使っているものとは異なる手順は、時間枠の選択、ルックバック期間の選択、使用する適用価格の選択、そして、前述の選択した時間枠、ルックバック、適用価格を組み込んで読み取り値を生成する指標の選択です。最終的な選択は、取引行動でした。つまり、指標値が与えられた時に、そのトレンドに従うか、あるいはその値に逆らうポジションを取るかです。そのため、モノイドはこれらの決定ごとにコード化され、各モノイドの二項演算は、集合のすべての値を反復した後、各集合から適切な値を選択する役割を担っていました。


多層パーセプトロン(MLP)としての関手

取引における多層パーセプトロンの役割は誇張できません。ニューラルネットワークに関する膨大な量の関連記事はすべて、なぜニューラルネットワークがこれまでも、そしてこれからもますます必要不可欠になっていくのかを明確に証明するものです。しかし、ほとんどのトレーダーにとって、その用途は証券の次の価格動向を予測することです。これに問題はないのですが、見落とされがちなのは、ネットワークの入力データの選択(そしておそらく正則化)だと私は思います。時系列を予測したいのですが、どのようなデータストリームに基づいて予測するか、そして何故するのかということです。些細なことに聞こえるかもしれませんが、他の要因も含め、膨大な量のデータで訓練された多くのネットワークが、テスト実行のときと同じように機能しない理由かもしれません。

第9回の非常に基本的な取引システムや、それに続く他のいくつかの取引システムで、各ステップでの意思決定にモノイドを使ってきたように、この記事でも同じことを行いますが、唯一の例外は、4つのステップを残して最後のステップを省略することです。省略された5番目のステップのモノイドは、トレンドに従うか、トレンドに逆らった取引をするかを設定するもので、ここでは関係ありません。多層パーセプトロン(MLP)は、残りの4つのモノイド出力値をそれぞれ入力として使用します。MLPが学習する目標出力は、ポジションの理想的なストップロスポイントとなります。このストップロスギャップの大きさは、ポジションの取引ロットに反比例するため、ポジションサイズの重要な指標となります。

よって、予想されるストップロスギャップに基づいてポジションサイズを決定します。

         //output from MLP forecast
         double _stoploss_gap=_y_output[0];
         
         //printf(__FUNCSIG__+" ct call: "+DoubleToString(_stoploss_gap));
      
         sl=m_symbol.Ask()+fabs(_stoploss_gap);
         
         //--- select lot size
         double _ct_1_lot_loss=(_stoploss_gap/m_symbol.TickSize())*m_symbol.TickValue();
         double lot=((m_percent/100.0)*m_account.FreeMargin())/_ct_1_lot_loss;
         
         //--- calculate margin requirements for 1 lot
         if(m_account.FreeMarginCheck(m_symbol.Name(),ORDER_TYPE_SELL,lot,m_symbol.Bid())<0.0)
         {
            printf(__FUNCSIG__" insufficient margin for sl lot! ");
            lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,m_symbol.Bid(),m_percent);
         }
         
         //--- return trading volume
         return(Optimize(lot));

まず、1ロットのポジションが予想ストップロスギャップを超えて赤で開いたときに発生するロットの損失またはドローダウンのドル値を計算します。これは、ギャップをティックサイズで割って、ティック値をかけたものです。通常、新規ポジションに割り当てられる証拠金の配分率を「m_percent」とし、開くポジションの最大許容ドローダウン率を「m_percent」とすると、ロットはその割合を100で割ったものに余剰証拠金を掛け、ロットの損失で割ったものになります。言い換えれば、最大ドローダウン額の中で、どれだけの単一ロットの損失を維持できるかということです。


ポジションサイジングのためのモノイド演算

これまでの記事のように各モノイドの決定を行うコーディングは、「Operate」関数という1つの関数で処理され、入力されたモノイドの操作方法に応じて、モノイド集合の値から選択を行っていました。私たちのケースで使用した演算方法は非常に初歩的なもので、6つあり、そのうち4つだけを使用しました。これは、加算と乗算ではモノイド集合に常に0と1が存在する必要があるためですが、このケースでは不可能でした。この列挙と関数をハイライトしたコードは以下の通りです。

//+------------------------------------------------------------------+
//| Enumeration for Monoid Operations                                |
//+------------------------------------------------------------------+
enum EOperations
  {
      OP_FURTHEST=5,
      OP_CLOSEST=4,
      OP_MOST=3,
      OP_LEAST=2,
      OP_MULTIPLY=1,
      OP_ADD=0
  };


//+------------------------------------------------------------------+
//|   Operate function for executing monoid binary operations        |
//+------------------------------------------------------------------+
void CMoneyCT::Operate(CMonoid<double> &M,EOperations &O,int IdenityIndex,int &OutputIndex)
   {
      OutputIndex=-1;
      //
      double _values[];
      ArrayResize(_values,M.Cardinality());ArrayInitialize(_values,0.0);
      //
      for(int i=0;i<M.Cardinality();i++)
      {
         m_element.Let();
         if(M.Get(i,m_element))
         {
            if(!m_element.Get(0,_values[i]))
            {
               printf(__FUNCSIG__+" Failed to get double for 1 at: "+IntegerToString(i+1));
            }
         }
         else{ printf(__FUNCSIG__+" Failed to get element for 1 at: "+IntegerToString(i+1)); }
      }
      
      //
      
      if(O==OP_LEAST)
      {
         ...
      }
      else if(O==OP_MOST)
      {
         ...
      }
      else if(O==OP_CLOSEST)
      {
         ...
      }
      else if(O==OP_FURTHEST)
      {
         ...
      }
   }

私たちが今関心があるのはポジションサイジングであって市場トレンド予測のボラティリティではないので、最終的な「アクション」モノイドとその決定は関手で置き換えることができます。そこで、最初の4つのモノイドを実行し、ポジションサイジングの指針となる指標の読み方を決定するのに役立てます。ここでは、RSIとボリンジャーバンドの指標を使用し、RSIのような0から100の間の値を得るために、先ほどと同様に正規化します。つまり、この指標の読みは、先の3つのモノイドの結果であるにもかかわらず、多層パーセプトロンの入力を形成する4つの値のセットを作成するために、それらと対にされるのです。したがって、時間枠と適用価格の入力は、前回の記事で行ったように、MLPで処理可能な数値形式に正規化する必要があります。

繰り返しになりますが、モノイドとは、単純に集合、二項演算、および単位元であり、二項演算によって定義された集合から要素を選択することができます。時間枠、ルックバック期間、適用価格を選択することで、正規化された値(0-100)がMLPの4番目の入力となる指標の入力が得られます。

時間枠、ルックバック期間、適用価格、使用するインディケータを選択するステップの詳細は、以前の記事で取り上げましたが、それぞれの関数からの出力がどのように得られるかを以下に示します。

         ENUM_TIMEFRAMES _timeframe_0=SetTimeframe(m_timeframe,0);
         int _lookback_0=SetLookback(m_lookback,_timeframe_0,0);
         ENUM_APPLIED_PRICE _appliedprice_0=SetAppliedprice(m_appliedprice,_timeframe_0,_lookback_0,0);
         double _indicator_0=SetIndicator(_timeframe_0,_lookback_0,_appliedprice_0,0);


関手とモノイドの統合による包括的なポジションサイジング

MLPを適切に活用するためには、MLPを適切に訓練する必要があります。前回の記事では、訓練は初期化時に行われ、選択されたネットワーク設定で利用可能であれば、最も収益性の高いネットワークの重みが読み込まれ、重みを調整する訓練プロセスの開始点として使用されました。この記事では、初期化前や初期化時に事前訓練は行いません。その代わり、新しいバーが出るたびに、ネットワークは訓練されます。一度に一本のバーです。これは、それが正しい方法であることを示唆するものではなく、むしろ、MLPまたはネットワークを訓練する場合にある多くのオプションを単に示しているだけです。しかし、この意味するところは、初期の重みが常にランダムであるため、同じEA設定でもテスト実行によって結果が大きく異なるということです。これを回避するために、有益なテスト実行ではその重みをファイルに書き出します。これらの重みは、同様のネットワーク設定(隠れ層の項目数)で次の実行を開始するときに読み込まれ、テスト実行の初期重みとして機能します。ネットワーク読み書きの関数は専有されたままであるため、読者が独自に実装することを意図して、ここではそのライブラリへの参照のみが示されています。

つまり、モノイドとMLPの相乗効果こそが、ここで本当に提示されているものです。なぜなら、どちらか一方だけでもストップ距離の予測は可能だと言えるからです。これには、理想的には検証用のコントロールが必要になります。つまり、モノイドだけを実装したEAとMLPだけを実装したEAを別々に用意し、3つすべての結果を比較する必要があります。残念ながらこの記事では実現不可能ですが、両方のアイデアを示すソースコードが添付されているので、読者は、この相乗効果の考えを探求し、検証 (または反論)することができます。

この2つを統合したコードを以下に示します。

      m_open.Refresh(-1);
      m_high.Refresh(-1);
      m_close.Refresh(-1);
      
      CMLPTrain _train;
      
      int _info=0;
      CMLPReport _report;
      CMatrixDouble _xy;_xy.Resize(1,__INPUTS+__OUTPUTS);
      
      _xy[0].Set(0,RegularizeTimeframe(_timeframe_1));
      _xy[0].Set(1,_lookback_1);
      _xy[0].Set(2,RegularizeAppliedprice(_appliedprice_1));
      _xy[0].Set(3,_indicator_1);
      //
      int _x=StartIndex()+1;
      
      double _sl_1=m_high.GetData(_x)-m_low.GetData(_x);
      
      if(m_open.GetData(_x)>m_close.GetData(_x))
      {
         _sl_1=m_high.GetData(_x)-m_open.GetData(_x);
      }
      
      double _stops=(2.0*(m_symbol.Ask()-m_symbol.Bid()))+((m_symbol.StopsLevel()+m_symbol.FreezeLevel())*m_symbol.Point());
      
      _xy[0].Set(__INPUTS,fmax(_stops,_sl_1));
      
      _train.MLPTrainLM(m_mlp,_xy,1,m_decay,m_restarts,_info,_report);


ケーススタディ:実践的応用とバックテスト

複合ポジションサイジング法を分析するために、ビットコイン(BTCUSD)をテスト証券として使用します。最適化テストは、2020年1月1日から2023年8月1日まで、1日単位で実施されます。今回は隠れ層が1層しかないMLPを使用しているため、隠れ層の理想的な重み数を最適化することに加え、ポジションサイズを求める際に使用する4つのモノイドを微調整することも検討します。つまり、理想的な単位元と操作タイプを、ポジションサイズを考える際に使用する4つのモノイドそれぞれに設定することになります。ここでの分析はポジションサイジングに重点を置いているため、使用するEAシグナルはMQL5ライブラリで提供されているものでなければなりません。これにはRS EAシグナルクラスを使用します。トレーリングストップは実装せず、これまでのすべてのテストと同様に、利食い値も損切り値も使用しないので、「take level」と「stop level」のパラメータはゼロになります。ただし、私たちのEAは指値注文を使用する可能性にオープンであるため、パラメータ「price level」も以前と同様に最適化されます。

オブジェクト関手と射の関手でテストを行います。その結果をそれぞれ以下に示します。

r_1


r_2

上記のオブジェクト射による実行で得られたような任意の入力値では、各MLPの初期化時にランダムな重みが割り当てられるため、結果は必ずしも再現可能ではありません。毎回ゼロからスタートするのを避けるために、初期化する際に過去に利益が出たときの重みを読み込むことができるのは助かりますが、その場合でも、訓練は新しいバーごとに行われるため、結局利益が出たMLPの重みを調整することになり、同じ結果は得られません。そのため、読者には、自分の戦略に特化したメソッドをコード化し、最高のテスト実行から重みを注意深く記録して読み取ることが求められます。

コントロールとして、同じRSIシグナル、同じトレーリングストップなし、異なるポジションサイジング方法(固定証拠金を使用)でEAを実行すると、以下の結果が得られます:

r_ctrl

その結果、徹底的なテストを行わなくても、私たちのシステムの方が良い結果を出す傾向がありました(可能性を示すことだけが目的だったため、最適化は短縮されました)。しかし、記事の冒頭で述べたように、通常、ほとんどのトレーダーにとって、システムのポジションサイジングの側面は、テスト実行の結果に大きな影響を与えるため、いじるとすれば最後にすべきものです。システムで確かなエントリシグナルが採用されていれば、厳密に言えば何の意味もありません。


制限と考慮事項

関手に基づいたのポジションサイジングから生じる潜在的な課題と限界は、連続したポイントによってカバーされています。いくつかを強調してみましょう。まず、どのトレーダーにとっても、自分の戦略に合ったモノイドセットを入手し、適切なMLP訓練パターンを確立するには、急な学習曲線が伴うことを理解する必要があります。この2つは、ここで紹介する戦略を実行する上で非常に重要であり、結果にたどり着くまでにそれなりの時間を費やす必要があります。

次に、価格ギャップや、1分足のOHLCデータが実際のティックデータと矛盾している証券は、ライブ口座で取引された場合、(フォワードウォークが与えられた場合)信頼できるモノイド設定やMLPの重みが得られません。理由は明白ですが、ここで紹介したアイデアを実行に移すとなると、これが大きなネックとなります。

第三に、過剰適合と汎化はMLPを特に悩ませるもう1つの問題です。先ほど、入力レイヤーのデータセットの重要性を指摘することでこのことをほのめかしましたが、私の考えでは、これを回避するためには、正則化された意味のあるデータを使うべきです。「意味のある」とは、入力レイヤーのデータセットに、私たちが関心を持つ予測に影響を与えると予想される、信頼できる基本的な側面があるということです。

パラメータチューニングの問題もあります。これは前の点と関連していると言う人もいるかもしれませんが、CPUリソースのコストや目標パラメータに到達するまでの時間を考えれば、過剰適合以上の問題であることは明らかです。

MLPを使って開発されたシステムの解釈可能性と透明性の低さも、コーダーが注意しなければならないハードルです。もしうまくいくシステムがあって、投資家を惹きつけ始めたいのであれば、多くの場合、投資家はあなたのシステムがMLPのおかげでどのように機能するのか、より詳しく開示することを要求します。これは、あなたのネットワークの層やその複雑さによっては、潜在的なクライアントを説得する上で課題となるでしょう。その他にも、重みの読み込み、市場体制の変更、モデルの更新やメンテナンスなど、MLPには必須のデータ前処理のような側面もあります。これらすべての要因を考慮し、それらが顕在化したときに対処できるよう、不測の事態に適切に備える必要があります。

実際、市場体制の変化に関する最後の指摘は、手動取引のような伝統的な取引手法を支持するものだと言えるかもしれません。今日、さまざまな市場体制を捉えた広範な履歴データセットでシステムが開発され、テストされていることを考えると、陪審はそれについてまだ結論を出していないと思います。


結論と今後の方向性

この研究から得られた重要な要点と発見を要約すると、圏としてのモノイドに対する異なる視点が、MQL5言語でどのように実装できるかを示したということです。この実装が、エントリシグナルとエグジットシグナルをRSI指標に依存する取引システムのポジションサイズを導くのに有用であることを、さらに詳しく実証しました。

関手やモノイドがポジションサイジングツールとして使われることの意義は、エントリシグナルや、これらのシリーズでしばしば行われてきたように、トレーリングストップの配置や調整など、取引システムの他の側面でも同じことができることを示唆しています。

最後に述べたように、トレーダーがここで紹介されたアイデアを完全に活用できるようになるには、まだ克服すべき課題やハードルがあります。取引システムを開発する際には関手に基づいた方法を探索し、実験するよう、読者にお勧めします。


参考文献

関連ソースはウィキペディアにあります(記事中のハイパーリンク)。


付録MQL5コードスニペット

MoneyCT_17_.mqhファイルは'MQL5\include\Expert\Money\' and 'ct_9.mqhフォルダーに配置します。'ct_9.mqhはincludeフォルダーに配置します。

EAの一部として組み立てる必要があるため、ウィザードを使用してEAを組み立てる方法についてこちらのガイドに従うとよいでしょう。記事にあるように、RSIオシレーターをエントリーシグナルとして使い、トレーリングストップは使いませんでした。いつものように、この記事の目的は、聖杯を紹介することではなく、読者自身の戦略にカスタマイズできるアイデアを紹介することです。添付されている*.*mq5ファイルは、ウィザードによってアセンブルされたものです。ご自分でコンパイルまたはアセンブルできます。*_control*ファイルは、固定保証金ポジションサイジングでアセンブルされています。


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

添付されたファイル |
ct_17.mq5 (9.25 KB)
ct_9.mqh (65.06 KB)
MoneyCT_17_.mqh (36.29 KB)
MQL5の圏論(第18回):ナチュラリティスクエア(自然性の四角形) MQL5の圏論(第18回):ナチュラリティスクエア(自然性の四角形)
この記事では、圏論の重要な柱である自然変換を紹介します。一見複雑に見える定義に注目し、次に本連載の「糧」であるボラティリティ予測について例と応用を掘り下げていきます。
さまざまな移動平均タイプをテストして、それらがどの程度洞察力に富むかを確認する さまざまな移動平均タイプをテストして、それらがどの程度洞察力に富むかを確認する
多くのトレーダーにとって移動平均指標が重要であることは周知の事実です。取引に役立つ移動平均タイプは他にもあります。この記事ではこれらのタイプを特定し、それぞれのタイプと最も人気のある単純移動平均タイプを簡単に比較して、どれが最良の結果を示すことができるかを確認します。
リプレイシステムの開発—市場シミュレーション(第7回):最初の改善(II) リプレイシステムの開発—市場シミュレーション(第7回):最初の改善(II)
前回の記事では、可能な限り最高の安定性を確保するために、レプリケーションシステムにいくつかの修正を加え、テストを追加しました。また、このシステムのコンフィギュレーションファイルの作成と使用も開始しました。
初めてのMetaTrader VPS:ステップバイステップ 初めてのMetaTrader VPS:ステップバイステップ
自動売買ロボットやコピー取引を利用していると必ず、遅かれ早かれ、取引プラットフォーム用に信頼できる24時間365日のホスティングサーバーをレンタルする必要性を認識するようになります。様々な理由から、MetaTrader VPSの使用が推奨されます。このサービスの支払いとサブスクリプションはMQL5.communityのアカウントで管理できます。