English Русский Deutsch
preview
MQL5における二変量コピュラ(第3回):混合コピュラモデルの実装とチューニング

MQL5における二変量コピュラ(第3回):混合コピュラモデルの実装とチューニング

MetaTrader 5 |
33 3
Francis Dube
Francis Dube

はじめに

これまでの2つの記事では、コピュラ関数について代表的な2種類のクラスである楕円コピュラとアルキメデスコピュラを扱いました。その分析を通じて、異なるコピュラがそれぞれ異なる種類のデータ依存構造を捉えることが確認されました。しかし、金融データは本質的に複雑であり、単一のコピュラファミリーだけでは、データセット内に存在するすべての依存構造を十分に表現できない場合があります。この問題を解決する方法の1つが混合コピュラです。混合コピュラは、複数のコピュラファミリーの長所を組み合わせることで、より広範囲の依存関係をモデル化できます。本記事では、前回までに紹介したコピュラファミリーを利用した混合コピュラモデルの実装について説明します。


混合コピュラとは何か

簡単に言えば、混合コピュラとは複数のコピュラファミリーから構成される多変量関数です。数学的には、混合コピュラ関数は複数の異なるコピュラを線形結合したものであり、データ間の複雑な依存構造を表現するために使用されます。

混合コピュラの数学的な定義は以下のとおりです。

混合コピュラ式

この式では、w_i​ は各コピュラへ割り当てられる重みを表します。すべての重みの合計は1になる必要があります。変数sは、混合モデルに含まれる単一コピュラの数を示します。混合コピュラのパラメータには、それぞれの構成要素となるコピュラの個別パラメータ(θi)が含まれます。この構造により、混合コピュラは単一のコピュラでは表現できない幅広い依存構造を柔軟にモデル化できます。目的は、十分な候補コピュラを組み合わせ、データセット内に存在する依存構造をできるだけ網羅的に表現できるモデルを構築することです。

最適なコピュラ数や、対象データセットに適したファミリーを決定する方法については本記事の範囲外ですが、ここでは3種類の異なるファミリーから構成される混合コピュラの実装を紹介します。この手法は、Fernando Sabino da Silva、Flavio Ziegelmann、João Caldeiraによる論文「Mixed Copula Pairs Trading Strategy on the S&P 500」で提案された方法論に基づいています。著者らは、Clayton-Frank-Gumbel混合モデルおよびClayton-Student-t-Gumbel混合モデルを利用したペアトレード戦略を提案しています。これらの組み合わせは、非対称なテール依存性や、データ内のレジーム切替的な挙動を捉えることを目的としています。これらの混合コピュラの有効性は、以下の表に示すように、各成分が持つ独自の強みに由来します。 

コピュラ  特徴  関連性 
Clayton 下側テール依存 共同で発生する極端な下落を捉える
Gumbel 上側テール依存 共同で発生する極端な上昇を捉える
Frank 対称性、テール依存なし 極端なイベントを仮定せず、分布の中央部における通常の依存構造を捉える
Student-t  対称性、テール依存あり 上下方向の極端な変動やファットテールを捉える(極端な出来事(上昇または下降)が発生した場合、銘柄は一緒に動く可能性が高いことを前提とする) 

混合比率は、データ内の依存構造を最も適切に説明するコピュラへ大きな重みを与えます。たとえば、Frankコピュラは、極端なテール挙動を伴わない低〜中程度の相関を持つデータで効果を発揮します。一方、Student-tコピュラは、非対称ではないものの極端な変動を伴う状況を捉えるために設計されています。Clayton-Frank-Gumbel混合モデルは完全なアルキメデス型構成であり、下側テール、上側テール、そして中央部分の独立的な挙動を区別することに優れています。この組み合わせは、計算効率と解釈性という2つの利点を持ちます。対照的に、Clayton-Student-t-Gumbel混合モデルはハイブリッド型です。Student-tコピュラを追加することで、Frankコピュラにはない、上下両方向のテール依存性を同時に捉える柔軟性を得られます。これは、ボラティリティクラスタリングが顕著な低時間足データにおいて特に重要です。

前述の論文では、この手法の概念は説明されていますが、具体的な実装の記述は十分ではありません。そこで本記事では、補足として、Zongwu CaiおよびXian WangによるJournal of the American Statistical Association(ASA)掲載論文「Selection of Mixed Copula Models via Penalized Likelihood」を参照します。


混合コピュラのパラメータ推定

ASAの論文では、ペナルティ付き尤度法と縮小演算子を組み合わせた、混合コピュラモデルの選択および推定フレームワークが紹介されています。著者らは、複数のコピュラファミリーを同時に組み合わせ、調整することで、金融データに存在する複雑な依存構造を捉える方法を提案しています。

この手法では、尤度最大化処理にSCAD (Smoothly Clipped Absolute Deviation)ペナルティを適用することで、不要または重要度の低いコピュラ要素を除外します。つまり、モデル選択とパラメータ推定を同時に実行できます。重みに対してペナルティを適用することで、関連性の低いコピュラ成分の係数を0へ縮小します。処理は、まず候補となるコピュラを選択し、その後クロスバリデーションによって最適なSCAD調整パラメータを決定する流れになります。

SCAD

SCADは、変数選択とパラメータ推定を同時に実行するために導入された正則化手法です。これは、Lasso(L1正則化)やRidge(L2正則化)が持つ問題を克服するために設計されました。特に、Lassoが大きな係数を過剰に縮小してしまうことによるバイアス問題を解決することを目的としています。理想的なペナルティ関数には、一般的に「オラクル特性」と呼ばれる3つの特性が求められます。 

  • スパース性:小さく重要でない係数を0へ設定できる能力
  • 不偏性:大きく重要な係数を過度に縮小しない性質
  • 連続性:データの小さな変化に対して不安定な変動を起こさない性質

SCADは、この3つすべてを満たす数少ない手法の1つとして広く利用されています。SCADペナルティは単純な1つの式ではなく、導関数によって定義されます。適用されるパラメータ(ここでは重み)の大きさによって動作が変化します。この手法は次の3つのステップで機能します。

  1. 小さい係数では、Lasso正則化と同様に係数を0へ近づけます。


    SCAD小係数

  2. 中程度の係数では、Lasso効果が二次的な変化によって徐々に弱まります。


    SCAD中係数

  3. 大きな係数に対しては、ペナルティは一定値となります。大きな係数では、SCADは一定値へ変化し、それ以上の抑制を行いません。これにより、Lassoで発生する推定バイアスを回避できます。

    SCAD大係数

上記の式では、λはスパース性の閾値を決定する調整パラメータ、aはペナルティが飽和する速度を制御するパラメータ、θはペナルティ対象となるパラメータを表します。SCADペナルティの主な欠点は、目的関数が非凸になる点です。RidgeやLassoのような単純な鉢型の形状とは異なり、SCADでは複数の局所最小値が存在する可能性があります。そのため、高度な最適化アルゴリズムが必要になります。

最適な調整パラメータを求めるために、クロスバリデーションを使用します。データを学習用とテスト用に分割し、候補となるλおよびaの組み合わせについてグリッドサーチを実行します。各組み合わせについて、学習データで混合コピュラモデルを適合させ、テストデータ上でペナルティ付き尤度を評価します。目的は、構成コピュラのパラメータによる尤度最大化と、コピュラ重みに適用されるSCADペナルティの差を最大化することです。

最適なSCADパラメータが決定された後、最終モデルのパラメータは全データを使用して推定されます。複数のコピュラを同時に推定する処理は計算量が大きいため、ここではEMアルゴリズムを使用します。

  1. 処理は、初期値を求めるための2段階の初期推定から始まります。通常、重みは均等に分配され、各コピュラパラメータは制約条件を満たす有効な初期値に設定されます。
  2. 次に、EMアルゴリズムのExpectationステップを実行します。この段階では、各データポイントがどのコピュラ成分に属するかの確率を計算し、重みを更新します。
  3. 最後に、Maximizationステップで、前段階で計算された重みを利用しながら、各コピュラパラメータを尤度最大化方向へ更新します。

これらの処理を収束するまで繰り返すことで、観測された依存構造を反映した混合コピュラモデルが完成します。次のセクションでは、これらの手順を実装するコードについて説明します。 


MQL5による混合コピュラモデルの実装

ここで説明する実装は、もともとPythonで作成されたHudson and ThamesのリポジトリをベースにMQL5向けへ適応したものです。ネイティブMQL5による混合コピュラの中核ロジックは、mixed.mqhヘッダーファイルに含まれています。このファイルでは、抽象クラスであるCMixedCopulaが、すべての混合コピュラ実装の基盤として機能します。このクラスでは、混合モデルを管理するために複数のprotectedプロパティを定義しています。

クラス内では、個々の構成コピュラファミリーを表すm_copulas配列を定義しています。各コピュラ成分へ割り当てられる混合比率は、ベクトルm_weightsに保存されます。また、それぞれのコピュラ成分が持つ固有のパラメータは、1つのベクトルm_cop_parametersにまとめて格納されます。抽象基底クラスを利用することで、アーキテクチャは高いモジュール性を維持できます。これにより、統一されたインターフェースを保ちながら、異なるコピュラの組み合わせを柔軟に構築することが可能になります。

//+------------------------------------------------------------------+
//|base class for mixed copula                                       |
//+------------------------------------------------------------------+
class CMixedCopula:public CObject
  {
protected:
   uint              m_num_cops;
   CBivariateCopula* m_copulas[];
   vector            m_weights;
   vector            m_cop_params;
   ENUM_COPULA_MIX   m_mixture;
public:
                     CMixedCopula(void):m_weights(vector::Zeros(0)),
                     m_cop_params(vector::Zeros(0)),
                     m_num_cops(0),
                     m_mixture(WRONG_VALUE)
     {
     }
                    ~CMixedCopula(void)
     {
      for(uint i = 0; i<m_copulas.Size(); ++i)
         if(CheckPointer(m_copulas[i]) == POINTER_DYNAMIC)
            delete m_copulas[i];
     }

CMixedCopulaクラスは、統計分析、サンプリング、およびモデル管理のためのメソッドも提供します。混合コピュラモデルの統計的特性を評価することに関して、このクラスはコピュラの同時密度を評価するCopula_PDF()メソッドを定義します。

double            Copula_PDF(double u, double v, double _eps = 1.e-5)
     {
      u = fmin(fmax(_eps,u),1. - _eps);
      v = fmin(fmax(_eps,v),1. - _eps);
      vector pdf_ = vector::Zeros(m_weights.Size());
      for(uint i = 0; i<m_copulas.Size(); ++i)
         pdf_[i] = m_copulas[i]?m_weights[i]*m_copulas[i].Copula_PDF(u,v,false):0.0;
      return pdf_.Sum();
     }

vector            Copula_PDF(vector& u, vector& v, double _eps = 1.e-5)
     {
      vector pdf_ = vector::Zeros(u.Size());
      for(uint i = 0; i<m_copulas.Size(); ++i)
        {
         if(!m_copulas[i])
            continue;
         m_copulas[i].Set_eps(_eps);
         pdf_ += m_weights[i]*m_copulas[i].Copula_PDF(u,v);
        }
      return pdf_;
     }

Copula_CDF()メソッドはコピュラの同時累積分布を計算し、Conditional_Probability()メソッドは条件付き累積分布確率を決定します。

double            Copula_CDF(double u, double v, double _eps = 1.e-5)
     {
      u = fmin(fmax(_eps,u),1. - _eps);
      v = fmin(fmax(_eps,v),1. - _eps);
      vector cdf_ = vector::Zeros(m_weights.Size());
      for(uint i = 0; i<m_copulas.Size(); ++i)
         cdf_[i] = m_copulas[i]?m_weights[i]*m_copulas[i].Copula_CDF(u,v,false):0.0;
      return cdf_.Sum();
     }

vector            Copula_CDF(vector& u, vector& v, double _eps = 1.e-5)
     {
      vector cdf_ = vector::Zeros(u.Size());
      for(uint i = 0; i<m_copulas.Size(); ++i)
        {
         if(!m_copulas[i])
            continue;
         m_copulas[i].Set_eps(_eps);
         cdf_+=m_weights[i]*m_copulas[i].Copula_CDF(u,v);
        }
      return cdf_;
     }
double            Conditional_Probability(double u, double v, double _eps = 1.e-5)
     {
      u = fmin(fmax(_eps,u),1. - _eps);
      v = fmin(fmax(_eps,v),1. - _eps);
      vector result_ = vector::Zeros(m_weights.Size());
      for(uint i = 0; i<m_copulas.Size(); ++i)
         result_[i] = m_copulas[i]?m_weights[i]*m_copulas[i].Conditional_Probability(u,v,false):0.0;
      return result_.Sum();
     }

vector            Conditional_Probability(vector& u, vector& v, double _eps = 1.e-5)
     {
      vector result_ = vector::Zeros(u.Size());
      for(uint i = 0; i<m_copulas.Size(); ++i)
        {
         if(!m_copulas[i])
            continue;
         m_copulas[i].Set_eps(_eps);
         result_+=m_weights[i]*m_copulas[i].Conditional_Probability(u,v);
        }
      return result_;
     }

Sample()メソッドは、適合させた混合コピュラモデルから合成データポイントを生成するために使用されます。

matrix            Sample(ulong num)
     {
      vector r = np::arange(m_weights.Size());
      vector cop_identities = np::choice(r,m_weights,num);
      matrix sample_pairs = matrix::Zeros(num,2);
      matrix temp;
      for(ulong i = 0; i<cop_identities.Size(); ++i)
        {
         temp = m_copulas[uint(cop_identities[i])].Sample(1);
         sample_pairs.Row(temp.Row(0),i);
        }
      return sample_pairs;
     }

Save()メソッドとLoad()メソッドはモデル状態の保存と再読み込みを容易にし、再学習することなく、学習済みモデルの状態を保存および取得できるようにします。

virtual bool      Save(const int file_handle)
     {
      if(file_handle!=INVALID_HANDLE)
        {
         if(FileWriteLong(file_handle,-1)==sizeof(long))
           {
            if(FileWriteInteger(file_handle,int(m_copulas.Size()),INT_VALUE)!=INT_VALUE)
               return(false);
            if(FileWriteInteger(file_handle,int(m_mixture),INT_VALUE)!=INT_VALUE)
               return(false);
            if(FileWriteLong(file_handle,long(m_weights.Size()))!=sizeof(long))
               return(false);
            if(m_weights.Size())
              {
               for(ulong i = 0; i<m_weights.Size(); ++i)
                  if(FileWriteDouble(file_handle,m_weights[i])!=sizeof(double))
                     return(false);
              }
           }
        }
      else
         return false;

      for(ulong i = 0; i<m_copulas.Size(); ++i)
        {
         if(CheckPointer(m_copulas[i])!=POINTER_INVALID)
           {
            if(!m_copulas[i].Save(file_handle))
               return false;
           }
        }
      return true;
     }
   virtual bool      Load(const int file_handle)
     {
      if(file_handle!=INVALID_HANDLE)
        {
         long ff = FileReadLong(file_handle);
         if(ff == -1)
           {
            int size = FileReadInteger(file_handle,INT_VALUE);
            ENUM_COPULA_MIX mixture = ENUM_COPULA_MIX(FileReadInteger(file_handle,INT_VALUE));
            if(ArraySize(m_copulas)!=size || mixture!=m_mixture)
              {
               Print(__FUNCTION__, " You are attempting to load a model incompatible with this class ");
               return false;
              }
            ulong size_weights = (ulong)FileReadLong(file_handle);
            if(size_weights)
              {
               m_weights = vector::Zeros(size_weights);
               switch(m_mixture)
                 {
                  case CFG_MIX:
                     m_cop_params = vector::Zeros(size_weights);
                     break;
                  case CTG_MIX:
                     m_cop_params = vector::Zeros(size_weights+1);
                     break;
                 }
               for(ulong i = 0; i<size_weights; ++i)
                  m_weights[i] = FileReadDouble(file_handle);
              }
           }
         else
            return false;
        }
      else
         return false;
      //---
      for(ulong i = 0,k = 0; i<m_copulas.Size(); ++i)
        {
         m_copulas[i] = bivariate_copula(file_handle);
         if(m_copulas[i]==NULL)
           {
            Print(__FUNCTION__, " failed to load a bivariate copula from file ", GetLastError());
            return false;
           }
         if(m_weights.Size())
           {
            switch(ENUM_COPULA_TYPE(m_copulas[i].Type()))
              {
               case CLAYTON_COPULA:
               case GUMBEL_COPULA:
               case JOE_COPULA:
               case N13_COPULA:
               case N14_COPULA:
               case FRANK_COPULA:
                  m_cop_params[k++] = m_copulas[i].Get_theta();
                  break;
               case STUDENT_COPULA:
                  m_cop_params[k++] = m_copulas[i].Get_nu();
                  m_cop_params[k++] = m_copulas[i].Get_rho();
                  break;
              }
           }
        }
      return true;
     }

最後に、このクラスはオーバーライドされることを前提とした2つの仮想メソッドを定義しています。Fit()メソッドは、擬似観測値のサンプルが与えられた場合に、SCADペナルティを組み込んだPenalized_Log_Likelihood()メソッドで指定された尤度関数を最小化することにより、コピュラのパラメータを推定するロジックを実装する必要があります。

virtual double    Fit(matrix& qdata, ulong maxiter = 25, double gamma_scad = 0.0, double a_scad = 0.0,double weight_margin=1.e-2)
     {
      return EMPTY_VALUE;
     }

virtual double    Penalized_Log_Likelihood(matrix &data,double g_scad, double a_scad)
     {
      return EMPTY_VALUE;
     }

mixed.mqhには、ENUM_COPULA_MIX列挙型も定義されており、これは実装されている混合コピュラタイプのリストを提供し、簡単に選択できるようにするものです。

//+------------------------------------------------------------------+
//| mixed copula type                                                |
//+------------------------------------------------------------------+
enum ENUM_COPULA_MIX
  {
   CFG_MIX=0,//Clayton-Frank-Gumbel
   CFJ_MIX,//Clayton-Frank-Joe
   CTG_MIX,//Clayton-Student-Gumbel
   JFG_MIX//Joe-Frank-Gumbel
  };

CFGMixCopクラスは、Clayton-Frank-Gumbel混合コピュラを表します。ユーザーがデータからモデルパラメータを推定するのではなく、明示的に定義することを好む場合のために、パラメトリックコンストラクタを備えています。

public:
                     CFGMixCop(void)
     {
      m_mixture = CFG_MIX;
      m_num_cops = 3;
      ArrayResize(m_copulas,int(m_num_cops));
      for(uint i = 0; i<m_num_cops; ++i)
         m_copulas[i] = NULL;
     }

                     CFGMixCop(vector &params, vector& weights)
     {
      m_mixture = CFG_MIX;
      m_num_cops = 3;
      ArrayResize(m_copulas,int(m_num_cops));
      if(params.Size()<3 || weights.Size()<3)
         Print(__FUNCTION__, " invalid parameters ");
      else
        {
         m_weights = weights;
         m_cop_params = params;
         for(ulong i = 0; i<3; ++i)
           {
            if(!i)
               m_copulas[i] = new CClayton();
            else
               if(i==1)
                  m_copulas[i] = new CFrank();
               else
                  m_copulas[i] = new CGumbel();
            m_copulas[i].Set_theta(m_cop_params[i]);
           }
        }
     }

パラメトリックコンストラクタを使用する場合、パラメータはベクトルコンテナで指定する必要があります。コピュラパラメータとそれに対応する重みは、いずれも特定の順序に従う必要があります。

  1. Claytonパラメータ
  2. Frankパラメーター
  3. Gumbelパラメータ

同様に、ゲッターメソッドを呼び出すと、値がこの一貫した順序で返されるため、モデル全体で予測可能なデータ処理が保証されます。Fit()メソッドは、データからモデルを推定します。 

virtual double            Fit(matrix& qdata, ulong maxiter = 50, double gamma_scad = 0.0,double a_scad = 0.0, double weight_margin = 1.e-2) override
     {
      if(CheckPointer(m_copulas[0])==POINTER_INVALID)
         m_copulas[0] = new CClayton();
      if(CheckPointer(m_copulas[1])==POINTER_INVALID)
         m_copulas[1] = new CFrank();
      if(CheckPointer(m_copulas[2])==POINTER_INVALID)
         m_copulas[2] = new CGumbel();

      matrix wc = _fit_quantile_em(qdata,maxiter,gamma_scad,a_scad);
      if(!wc.Rows())
         return EMPTY_VALUE;
      wc.Row(adjust_weights(wc.Row(0),weight_margin),0);
      m_weights = wc.Row(0);
      m_cop_params = wc.Row(1);

      m_copulas[0].Set_theta(m_cop_params[0]);
      m_copulas[1].Set_theta(m_cop_params[1]);
      m_copulas[2].Set_theta(m_cop_params[2]);

      vector u1 = qdata.Col(0);
      vector u2 = qdata.Col(1);

      return _ml_qfunction(u1,u2,wc.Row(1),wc.Row(0),gamma_scad,a_scad,false);
     }  
  • データ入力変数は、擬似観測値([0,1]の区間に変換された生の値)の行列(最低2列)です。
  • maxiter関数の入力は、EMアルゴリズムの最大反復回数を定義する整数です。
  • 入力値gamma_scadとa_scadは、SCADハイパーパラメータを表すdouble型の値です。
  • weight_margin入力は閾値であり、この制限を下回る重みはスパース性を確保するためにゼロに切り捨てられます。

Fit()関数は、正常に実行された場合はペナルティなしの対数尤度を返し、そうでない場合はEMPTY_VALUEを返します。推定の中核となるロジックは、反復処理を統括する保護されたメソッド_fit_quantile_em()内にカプセル化されています。

matrix            _fit_quantile_em(matrix &qd, ulong max_iter,double gamma_scad, double a_scad)
     {
      vector init_weights = {0.33, 0.33, 1. - 0.33 - 0.33};
      vector init_cop_params = {3,4,5};
      vector weights = _expectation_step(qd,gamma_scad,a_scad,init_cop_params,init_weights);
      if(!weights.Size())
         return matrix::Zeros(0,0);
      vector cop_params = _maximization_step(qd,gamma_scad,a_scad,init_cop_params,weights);
      if(!cop_params.Size())
         return matrix::Zeros(0,0);
      vector oldparams,newparams;
      oldparams = newparams = vector::Zeros(6);

      np::vectorCopy(oldparams,init_weights,0,3);
      np::vectorCopy(oldparams,init_cop_params,3);

      np::vectorCopy(newparams,weights,0,3);
      np::vectorCopy(newparams,cop_params,3);

      double ll_diff = MathAbs(oldparams-newparams).Sum();
      ulong i = 1;
      while(i<max_iter && ll_diff>(5.*1.e-2))
        {
         np::vectorCopy(oldparams,weights,0,3);
         np::vectorCopy(oldparams,cop_params,3);

         weights = _expectation_step(qd,gamma_scad,a_scad,cop_params,weights);
         if(!weights.Size())
           {
            Print(__FUNCTION__, " invalid weights ", i);
            return matrix::Zeros(0,0);
           }

         cop_params = _maximization_step(qd,gamma_scad,a_scad,cop_params,weights);
         if(!cop_params.Size())
           {
            Print(__FUNCTION__, " failed convergence at iteration ", i);
            return matrix::Zeros(0,0);
           }

         np::vectorCopy(newparams,weights,0,3);
         np::vectorCopy(newparams,cop_params,3);

         ll_diff = MathAbs(oldparams-newparams).Sum();
         i+=1;
        }

      matrix out = matrix::Zeros(3,3);
      out.Row(weights,0);
      out.Row(cop_params,1);
      return out;
     }
protectedメソッド_expectation_step()は、EMアルゴリズムの期待値計算段階を実装します。このメソッドは、指定されたSCADパラメータの値に応じて、2つの異なるモードで動作します。両方のSCADパラメータが有効な場合(スパース性パラメータが0.0より大きく、バイアス制御パラメータが2.0より大きい場合)、ペナルティ付き尤度法が有効になります。これにより、モデルは重要度の低い重みを0へ縮小することで、自動的に変数選択を実行できます。一方、いずれか一方のSCADパラメータが無効な場合、SCADペナルティは無効化され、処理は標準的な最尤推定(MLE)へ切り替わります。
vector            _expectation_step(matrix &qd,double gamma_scad, double a_scad,vector& cop_params,vector &weights)
     {
      //---
      ulong num = qd.Rows();
      vector u1 = qd.Col(0);
      vector u2 = qd.Col(1);
      //---
      double dif = 1;
      double tol_weight = 1.e-2;
      long iteration = 0;
      //---
      for(ulong i = 0; i<3; ++i)
         m_copulas[i].Set_theta(cop_params[i]);
      //---
      vector nweights;
      //---
      if(gamma_scad>0.0 && a_scad>2.0)
        {
         while(dif>tol_weight && iteration<10)
           {
            nweights = vector::Zeros(3);
            nweights.Fill(double("nan"));
            iteration+=1;
            for(ulong i = 0; i<3; ++i)
              {
               vector sum_ml_1st = vector::Zeros(u1.Size());
               double sum,sum_ml,numerator,denominator;
               sum = sum_ml = numerator = denominator = 1.e-12;
               for(ulong t = 0; t<num; ++t)
                 {
                  sum = 1.e-12;
                  for(ulong j = 0; j<3; ++j)
                     sum+=weights[j]*m_copulas[j].Copula_PDF(u1[t],u2[t],true,true);
                  sum_ml_1st[t] = weights[i]*m_copulas[i].Copula_PDF(u1[t],u2[t],true,true)/sum;
                 }
               sum_ml = sum_ml_1st.Sum();
               numerator = weights[i]*scad_derivative(weights[i],gamma_scad,a_scad)-sum_ml/double(num);
               for(ulong j = 0; j<3; ++j)
                  denominator+=weights[j]*scad_derivative(weights[j],gamma_scad,a_scad);
               denominator-=1.;
               nweights[i] = fabs(numerator/denominator);
              }
            dif = MathAbs(weights-nweights).Sum();
            weights = nweights;
           }
        }
      else
        {
         matrix wd = matrix::Zeros(weights.Size(),num);
         vector td, temp;
         while(dif>tol_weight && iteration<10)
           {
            nweights = vector::Zeros(weights.Size());
            iteration+=1;

            for(ulong i = 0; i<wd.Rows(); ++i)
               if(!wd.Row(weights[i]*m_copulas[i].Copula_PDF(u1,u2,true,true),i))
                 {
                  Print(__FUNCTION__, " row insertion error ", GetLastError());
                  return vector::Zeros(0);
                 }
            td = wd.Sum(0);
            td.Clip(1.e-12,DBL_MAX);
            for(ulong i = 0; i<weights.Size(); ++i)
              {
               temp = (wd.Row(i)/td);
               nweights[i] = fabs(temp.Sum()/double(num));
              }
            dif = MathAbs(weights-nweights).Sum();
            weights = nweights;
           }
        }
      //---
      return weights;
     }

最大化ステップは、_maximization_step()メソッドとして定義されます。

vector            _maximization_step(matrix&qd, double gamma_scad, double a_scad, vector& cop_params, vector& weights)
     {
      vector u1 = qd.Col(0);
      vector u2 = qd.Col(1);

      double eps = 1.e-3;

      double _x_[3];
      for(uint i = 0; i<_x_.Size(); _x_[i] = cop_params[i], ++i);

      double bndl[3] = {-1.,-50.,1.};
      double bndu[3] = {100.,50.,100.};

      CObject             obj;
      CNDimensional_Func1 ffunc;
      CNDimensional_Rep   frep;

      ffunc.set_params(this,u1,u2,weights,gamma_scad,a_scad,bool(gamma_scad>0.0&&a_scad>2.0),-1);

      CMinBLEICStateShell state;

      CMinBLEICReportShell rep;

      double epsg=eps;

      double epsf=0;

      double epsx=0;

      double epso=eps;

      double epsi=eps;

      double diffstep=1.0e-6;

      CAlglib::MinBLEICCreateF(_x_,diffstep,state);

      CAlglib::MinBLEICSetBC(state,bndl,bndu);

      CAlglib::MinBLEICSetInnerCond(state,epsg,epsf,epsx);

      CAlglib::MinBLEICSetOuterCond(state,epso,epsi);

      CAlglib::MinBLEICOptimize(state,ffunc,frep,false,obj);

      CAlglib::MinBLEICResults(state,_x_,rep);

      vector out = vector::Zeros(0);

      int termination_reason = rep.GetTerminationType();

      if(termination_reason<0)
        {
         Print(__FUNCTION__, " termination reason ", termination_reason);
         return out;
        }

      out.Assign(_x_);

      return out;
     }

このステップでは、ALGLIBの境界線形等式不等式制約(BLEIC, Boundary, Linear Equality-Inequality Constraints)最小化アルゴリズムを活用します。この最小化アルゴリズムは、ペナルティ付き対数尤度を定義する_ml_qfunc()メソッドを対象としています。これは、public objective()メソッドを通じて公開されており、ALGLIBオプティマイザインスタンスが実行中にこの関数にアクセスできるようになります。

double                   objective(vector& x,vector& u1, vector& u2,vector& weights, double gamma_scad, double a_scad, bool if_penalty = true, double multiplier= 1.)
     {
      return  _ml_qfunction(u1,u2,x,weights,gamma_scad,a_scad,if_penalty,multiplier);
     }

Fit()メソッドは、最適化処理(最小化処理)を開始する役割を担います。最小化対象となる目的関数の種類は、このメソッドへ渡されるSCADパラメータによって決定されます。いずれかのパラメータが無効な場合(gamma_scad <= 0.0またはa_scad <= 2.0の場合)、目的関数はペナルティ項を含まない標準的なMLEへ切り替わります。一方、両方のパラメータが有効な場合、目的関数にはペナルティ付きMLEが使用されます。

CTGMixCopクラスは、Clayton-Student-t-Gumbel混合コピュラを実装するクラスであり、設計構造はCFGMixCopクラスとほぼ同一です。主な違いは、構成要素となるコピュラの1つをFrankコピュラからStudent-tコピュラへ置き換えている点です。

public:
                     CTGMixCop(void)
     {
      m_mixture = CTG_MIX;
      m_num_cops = 3;
      ArrayResize(m_copulas,int(m_num_cops));
      for(uint i = 0; i<m_num_cops; ++i)
         m_copulas[i] = NULL;
     }
                     CTGMixCop(vector& params, vector& weights)
     {
      m_mixture = CTG_MIX;
      m_num_cops = 3;
      ArrayResize(m_copulas,int(m_num_cops));
      if(params.Size()<4 || weights.Size()<3)
         Print(__FUNCTION__, " invalid parameters ");
      else
        {
         m_weights = weights;
         m_cop_params = params;
         for(ulong i = 0; i<3; ++i)
           {
            if(i == 0 || i == 2)
              {
               if(!i)
                 {
                  m_copulas[i] = new CClayton();
                  m_copulas[i].Set_theta(m_cop_params[0]);
                 }
               else
                 {
                  m_copulas[i] = new CGumbel();
                  m_copulas[i].Set_theta(m_cop_params[3]);
                 }
              }
            else
              {
               m_copulas[i] = new CStudent();
               matrix corr = {{1.,m_cop_params[1]},{m_cop_params[1],1.}};
               m_copulas[i].Set_covariance(corr);
               m_copulas[i].Set_nu(m_cop_params[2]);
              }
           }
        }
     }

mixed.mqhヘッダーファイルには、SCADハイパーパラメータを調整するための専用ルーチンも定義されています。tune_scad_parameters()関数は、グリッドサーチを実行して正則化パラメータを最適化します。

//+------------------------------------------------------------------+
//|Implements the 5-fold cross-validation tuning process of the SCAD |
//|parameters                                                        |
//+------------------------------------------------------------------+
bool tune_scad_parameters(matrix &data, double gama_start, double gama_stop, ulong gamma_count, double a_start, double a_stop,ulong a_count, ENUM_COPULA_MIX mix, bool shuffle, int seed, bool show_details, double& out_gamma, double& out_a)
  {
   np::Folds folds[];
   if(!np::kfold(data.Rows(),folds,5,shuffle,seed))
      return false;

   CMixedCopula* mixedcop = NULL;

   switch(mix)
     {
      case CFG_MIX:
         mixedcop = new CFGMixCop();
         break;
      case CTG_MIX:
         mixedcop = new CTGMixCop();
         break;
      case CFJ_MIX:
         mixedcop = new CFJMixCop();
         break;
      case JFG_MIX:
         mixedcop = new JFGMixCop();
         break;
     }

   if(CheckPointer(mixedcop) == POINTER_INVALID)
     {
      Print(__FUNCTION__, " failed to initialize ", EnumToString(mix), " copula ");
      return false;
     }

   matrix traindata,testdata;
   double ll, best_score;
   vector scores = vector::Zeros(folds.Size());
   vector gamma_grid = np::linspace(gama_start,gama_stop,gamma_count);
   vector a_grid = np::linspace(a_start,a_stop,a_count);
   best_score = -DBL_MAX;
   bool use_mle = false;
   double mle = 0;
   double p_mle = 0;
   for(ulong i = 0; i<gamma_grid.Size(); ++i)
     {
      for(ulong j = 0; j<a_grid.Size(); ++j)
        {
         for(uint k = 0; k<folds.Size() && !IsStopped(); ++k)
           {
            traindata = np::selectMatrixRows(data,folds[k].train_indices);
            testdata = np::selectMatrixRows(data,folds[k].test_indices);
            ll = mixedcop.Fit(traindata,25,gamma_grid[i],a_grid[j]);

            if(ll == EMPTY_VALUE)
              {
               Print(__FUNCTION__, " error fitting data ", "| sparcity ", gamma_grid[i], " bias ", a_grid[j]);
               continue;
              }

            scores[k] = mixedcop.Penalized_Log_Likelihood(testdata,gamma_grid[i],a_grid[j]);

           }
         ll = scores.Sum();
         if(show_details)
            Print(__FUNCTION__, "| sparcity: ", gamma_grid[i], "| bias: ", a_grid[j], "| likelihood  ", ll, " \nweights ", mixedcop.Weights(), "| params ", mixedcop.Params());
         if(ll>best_score)
           {
            best_score = ll;
            out_a = a_grid[j];
            out_gamma = gamma_grid[i];
           }
        }
     }

   delete mixedcop;
   return true;
  }

この関数は、以下の入力を受け取ります。

  • データ入力は、疑似観測値で構成された行列です。各列は、それぞれ1つの系列を表します。
  • 次に、この関数では6つの入力変数を指定します。最初の3つはgamma接頭辞を持ち、残りの3つはa接頭辞を持ちます。これらは、最適なSCADハイパーパラメータの組み合わせを探索するグリッドサーチの範囲と粒度を定義します。count接尾辞を持つ引数は、startおよびstop接尾辞を持つ引数によって定義された範囲内で評価する候補値の数を指定します。
  • 次に、この関数では6つの入力変数を指定します。最初の3つはgamma接頭辞を持ち、残りの3つはa接頭辞を持ちます。これらは、最適なSCADハイパーパラメータの組み合わせを探索するグリッドサーチの範囲と粒度を定義します。count接尾辞を持つ引数は、startおよびstop接尾辞を持つ引数によって定義された範囲内で評価する候補値の数を指定します。
  • mix入力は列挙型であり、探索対象となる混合コピュラモデルの種類を指定します。
  • shuffle入力はブール型の引数で、データを分割する前にランダム化するかどうかを指定します。また、seed入力は疑似乱数生成器のシード値であり、同じ条件で再現可能な結果を得るために使用されます。
  • show_detailsブールフラグは、各反復処理の実行詳細をターミナルの操作ログへ出力するかどうかを制御します。
  • 参照渡しの入力であるout_aとout_gammaは、処理によって発見された最適なSCADパラメータを格納する出力パラメータです。

SCADペナルティ関数およびその導関数は、utils.mqhで定義されています。これらの関数は縮小メカニズムを実装しており、モデルが重要なコピュラ重みと、影響の小さいコピュラ重みを区別できるようにします。

//+------------------------------------------------------------------+
//|SCAD (smoothly clipped absolute deviation) penalty function.      |
//+------------------------------------------------------------------+
double scad_penalty(double x, double gamma, double a)
  {
   bool is_linear = (fabs(x)<=gamma);
   bool is_quadratic = (gamma<fabs(x)) & (fabs(x)<=a*gamma);
   bool is_constant = ((a*gamma)<fabs(x));

   double linear_part = gamma * fabs(x) * double(is_linear);
   double quadratic_part = (2.*a*gamma*fabs(x) - pow(x,2.)- pow(gamma,2.))/(2.*(a-1.))*double(is_quadratic);
   double constant_part = (pow(gamma,2.)*(a+1.))/2.*(double(is_constant));

//Print(__FUNCTION__, " linear part ", linear_part,"\n quadratic part ", quadratic_part, "\n constant part ", constant_part);

   return linear_part+quadratic_part+constant_part;
  }
//+------------------------------------------------------------------+
//|The derivative of SCAD penalty function w.r.t x.                  |
//+------------------------------------------------------------------+
double scad_derivative(double x, double gamma, double a)
  {
   double p1 = gamma*double(x<=gamma);
   double p2 = gamma *(a*gamma-x)*double((a*gamma-x)>0.)/((a - 1.)*gamma)*double(x>gamma);
   return p1+p2;
  }

次のセクションでは、SCADペナルティに適したハイパーパラメータを選択するプロセスについて詳しく説明します。実務で利用する際には、単純にクロスバリデーションを実行するだけではなく、いくつかの重要な点を理解しておく必要があります。


SCADハイパーパラメータの調整

SCADペナルティでは、調整パラメータであるλ(スパース性)とa(バイアス低減)が、それぞれスパース化の閾値とバイアス低減速度を制御します。最適な値は最終的にはデータによって決まりますが、学術研究や実務で一般的に使用される範囲が存在します。バイアス低減パラメータは、ペナルティが飽和するまでの速度を制御します。このパラメータを調整する場合、2より大きい値のみを検討する必要があります。これは、関数がハード閾値処理とは異なる閾値処理特性を維持するためには、パラメータが厳密に2より大きくなければならないためです。

一方、スパース性パラメータは、学習データのスケールやサンプル数に大きく依存します。このパラメータは、係数を0へ縮小する基準となるカットオフ値を定義します。調整時に検討される値の範囲は、一般的に0から1の間です。下限値は、モデルがペナルティなしのMLEに近づける程度に十分小さく設定する必要があります。たとえば、0.001などの値が使用されます。一方、上限値は、すべての係数(つまり混合モデル内の各構成コピュラへ割り当てられる重み)を0にできる可能性がある程度、大きく設定する必要があります。一般的に、サンプル数が多いほど、必要となるスパース性パラメータは小さくなります。

スパース性パラメータが高い場合、モデルはよりスパースになり、多くの混合重みが0になります。バイアス低減パラメータが高い場合、ペナルティ効果がより長く維持されるため、ペナルティ付き推定から不偏推定への移行がより緩やかになります。バイアス低減パラメータが2に近いほど、ペナルティ効果はより速く減衰します。

これらの概念を検証するために、Scad_CV.mq5スクリプトでは、tune_scad_parameters()関数の実際の動作を示しています。

//+------------------------------------------------------------------+
//|                                                      Scad_CV.mq5 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property script_show_inputs
#include<Copulas\Bivariate\mixed.mqh>
#include<ECDF\linear_cdf.mqh>

input string   FirstSymbol="XAUUSD";
input string   SecondSymbol="XAUEUR";
input datetime TrainingDataStart=D'2025.01.01';
input ENUM_TIMEFRAMES TimeFrame = PERIOD_D1;
input ENUM_COPULA_MIX CopulaType = CTG_MIX;
input ulong    HistorySize=1200;
input bool     Show_details = true;
input bool     Shuffle_Data = false;
input int      Random_Seed = 0;
input double   g_from = 0.001;
input double   g_to = 1.0;
input ulong    g_count = 5;
input double   a_from = 2.0;
input double   a_to = 10.0;
input ulong    a_count_ = 5; 
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
  //---
   vector p_1,p_2,p_3,p_n;
   matrix pdata,pobs;
   if(!p_1.CopyRates(FirstSymbol,TimeFrame,COPY_RATES_CLOSE,TrainingDataStart,HistorySize) ||
      !p_2.CopyRates(SecondSymbol,TimeFrame,COPY_RATES_CLOSE,TrainingDataStart,HistorySize) ||
      p_1.Size()!=p_2.Size() ||
      !pdata.Resize(p_1.Size(),2) ||
      !pdata.Col(p_1,0) ||
      !pdata.Col(p_2,1))
     {
      Print(" failed to collect and initialize rates matrix ", GetLastError());
      return;
     }
//---
   CLinearCDF qt();
   if(!qt.fit(pdata))
      return;
//---
   pobs = qt.to_quantile(pdata);
   
    double gamma_scad,a_scad;
   if(!tune_scad_parameters(pobs,g_from,g_to,g_count,a_from,a_to,a_count_,CopulaType,Shuffle_Data,Random_Seed,Show_details,gamma_scad,a_scad))
    {
     Print(" failed ");
     return;
    }
   
   Print(EnumToString(CopulaType)," sparcity -> ", gamma_scad, " || bias -> ", a_scad);
  }
//+------------------------------------------------------------------+

Scad_CV.ex5スクリプトのデフォルト設定では、ユーザーが調整可能な入力として、スパース性パラメータとバイアスパラメータの試行値を比較的狭い範囲のグリッドで指定しています。この設定により、1000件強の観測データ数に対しても、スクリプトを効率的に実行できます。ここで注意すべき点は、試行グリッドにバイアスパラメータ値2.0が含まれていることです。この値はバイアスパラメータとして無効であるため、SCADペナルティは完全に無効化されます。これにより、ペナルティを適用しない尤度最大化が、より良い結果をもたらすかどうかを比較できます。Clayton-Frank-Gumbel混合モデルを選択してスクリプトを実行すると、以下の結果が出力されます。

PE      0       07:19:59.780    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.001| bias: 2.0| likelihood  584.3449797418596 
NH      0       07:19:59.780    Scad_CV (XAUUSD,D1)     weights [0,0.2503264642029614,0.7496735357960386]| params [0.07777184570809823,4.98716120261952,2.938523462235503]
JG      0       07:20:04.549    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.001| bias: 4.0| likelihood  584.3388831186738 
GI      0       07:20:04.549    Scad_CV (XAUUSD,D1)     weights [0,0.2503330189828707,0.7496669810161294]| params [0.07783293123073377,4.987168638354295,2.938531600897639]
NJ      0       07:20:09.278    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.001| bias: 6.0| likelihood  584.5057912775926 
LF      0       07:20:09.278    Scad_CV (XAUUSD,D1)     weights [0,0.2475903622229043,0.7524096377760957]| params [0.08186119438950079,4.982135308682525,2.934272675707406]
OL      0       07:20:13.997    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.001| bias: 8.0| likelihood  584.5035349829863 
ED      0       07:20:13.997    Scad_CV (XAUUSD,D1)     weights [0,0.2475907179493826,0.7524092820496174]| params [0.08234560301866138,4.982135272704732,2.934273169230999]
JL      0       07:20:18.700    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.001| bias: 10.0| likelihood  584.5011307062207 
ER      0       07:20:18.700    Scad_CV (XAUUSD,D1)     weights [0,0.2475914144776672,0.7524085855213327]| params [0.08233571375095404,4.98213630991471,2.934274176680373]
FQ      0       07:20:23.187    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.25075| bias: 2.0| likelihood  584.3449797418596 
PL      0       07:20:23.187    Scad_CV (XAUUSD,D1)     weights [0,0.2503264642029614,0.7496735357960386]| params [0.07777184570809823,4.98716120261952,2.938523462235503]
ES      0       07:20:27.501    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.25075| bias: 4.0| likelihood  283.7391184805832 
RM      0       07:20:27.501    Scad_CV (XAUUSD,D1)     weights [0,0.9999999999989904,0]| params [0.1511818127315188,7.344139133115162,20.25573962738841]
ID      0       07:20:31.999    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.25075| bias: 6.0| likelihood  5659.479627674678 
JO      0       07:20:31.999    Scad_CV (XAUUSD,D1)     weights [0,0.5844120297582153,0.4155879702407769]| params [0.1376209847408496,5.640552910020598,3.811839085505817]
JF      0       07:20:38.263    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.25075| bias: 8.0| likelihood  334.8224130043968 
KJ      0       07:20:38.263    Scad_CV (XAUUSD,D1)     weights [0,0.02895916433928,0.97104083565972]| params [0.1037932306526668,4.669895137807593,2.641209026360089]
OK      0       07:20:42.346    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.25075| bias: 10.0| likelihood  6420.623549439398 
ND      0       07:20:42.346    Scad_CV (XAUUSD,D1)     weights [0,0.04002009450317316,0.9599799054958269]| params [0.1193049328638911,4.63258676700795,2.654870180909923]
DH      0       07:20:46.831    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.5005| bias: 2.0| likelihood  584.3449797418596 
KF      0       07:20:46.831    Scad_CV (XAUUSD,D1)     weights [0,0.2503264642029614,0.7496735357960386]| params [0.07777184570809823,4.98716120261952,2.938523462235503]
FN      0       07:20:49.490    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.5005| bias: 4.0| likelihood  34.55576102335817 
KR      0       07:20:49.490    Scad_CV (XAUUSD,D1)     weights [0,0,0.9999999999989903]| params [0.1197956723049384,4.584548412565545,2.619284560176268]
NN      0       07:20:52.885    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.5005| bias: 6.0| likelihood  15.363216317653269 
HR      0       07:20:52.885    Scad_CV (XAUUSD,D1)     weights [0,0.01784571505390212,0.9821542849450979]| params [0.1043980264613316,4.628446940510745,2.628580283819081]
QS      0       07:20:56.830    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.5005| bias: 8.0| likelihood  6102.473148256049 
RP      0       07:20:56.830    Scad_CV (XAUUSD,D1)     weights [0,0.02673340177232474,0.9732665982266753]| params [0.1037622447823746,4.698345592025231,2.638332966096248]
IS      0       07:21:00.708    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.5005| bias: 10.0| likelihood  3.301592693093255 
RM      0       07:21:00.708    Scad_CV (XAUUSD,D1)     weights [0,0.0300952343044497,0.9699047656945503]| params [0.1029115313643473,4.61667495323261,2.643127744938425]
KE      0       07:21:05.196    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.75025| bias: 2.0| likelihood  584.3449797418596 
QH      0       07:21:05.196    Scad_CV (XAUUSD,D1)     weights [0,0.2503264642029614,0.7496735357960386]| params [0.07777184570809823,4.98716120261952,2.938523462235503]
JI      0       07:21:08.606    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.75025| bias: 4.0| likelihood  -297.39396856892415 
GH      0       07:21:08.606    Scad_CV (XAUUSD,D1)     weights [0,0.01107956745287137,0.9889204325461286]| params [2.9984906563128,4.76765198814707,2.620207254516393]
KH      0       07:21:12.649    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.75025| bias: 6.0| likelihood  -303.8281831341336 
CE      0       07:21:12.649    Scad_CV (XAUUSD,D1)     weights [0,0.01742743973978789,0.9825725602592119]| params [2.9984906563128,4.637005162809593,2.628040342667032]
FO      0       07:21:18.050    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.75025| bias: 8.0| likelihood  5512.03076596105 
DG      0       07:21:18.050    Scad_CV (XAUUSD,D1)     weights [0,0.02364115960349121,0.9763588403955088]| params [2.9984906563128,4.667363798628771,2.635026851516195]
PM      0       07:21:23.276    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.75025| bias: 10.0| likelihood  5953.875750743017 
OR      0       07:21:23.276    Scad_CV (XAUUSD,D1)     weights [0,0.03021524144755516,0.9697847585514447]| params [2.9984906563128,4.626181869637053,2.643168795782705]
KQ      0       07:21:27.767    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 1.0| bias: 2.0| likelihood  584.3449797418596 
ML      0       07:21:27.767    Scad_CV (XAUUSD,D1)     weights [0,0.2503264642029614,0.7496735357960386]| params [0.07777184570809823,4.98716120261952,2.938523462235503]
FQ      0       07:21:31.781    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 1.0| bias: 4.0| likelihood  -727.4266957539727 
GN      0       07:21:31.781    Scad_CV (XAUUSD,D1)     weights [0.4409776856415021,0,0.5590223143574978]| params [0.2842084359703793,8.160381312758863,3.894704689012704]
JG      0       07:21:35.806    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 1.0| bias: 6.0| likelihood  -727.4266957539727 
IH      0       07:21:35.806    Scad_CV (XAUUSD,D1)     weights [0.4409776856415021,0,0.5590223143574978]| params [0.2842084359703793,8.160381312758863,3.894704689012704]
JE      0       07:21:39.839    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 1.0| bias: 8.0| likelihood  -727.4266957539727 
GJ      0       07:21:39.839    Scad_CV (XAUUSD,D1)     weights [0.4409776856415021,0,0.5590223143574978]| params [0.2842084359703793,8.160381312758863,3.894704689012704]
MH      0       07:21:43.911    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 1.0| bias: 10.0| likelihood  -727.4266957539727 
QD      0       07:21:43.911    Scad_CV (XAUUSD,D1)     weights [0.4409776856415021,0,0.5590223143574978]| params [0.2842084359703793,8.160381312758863,3.894704689012704]
DK      0       07:21:43.911    Scad_CV (XAUUSD,D1)     CFG_MIX sparcity -> 0.25075 || bias -> 10.0

結果から、Clayton-Frank-Gumbel混合モデルにおける最適なSCADパラメータは、スパース性パラメータが0.25075、バイアスパラメータが10であることが分かります。次に示すClayton-Student-t-Gumbel混合モデルの結果は、特に興味深い内容となっています。

JF      0       07:23:09.254    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.001| bias: 2.0| likelihood  599.6351926572415 
HK      0       07:23:09.254    Scad_CV (XAUUSD,D1)     weights [0,0.03267640297340715,0.9673235970255923]| params [0.026704520400007,0.5822697866462155,7,2.635263431033769]
NH      0       07:23:31.432    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.001| bias: 4.0| likelihood  599.6274718728072 
FI      0       07:23:31.433    Scad_CV (XAUUSD,D1)     weights [0,0.03267798343975953,0.96732201655924]| params [0.02669592147577486,0.5822648258079013,7,2.6352494228926]
FK      0       07:23:53.828    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.001| bias: 6.0| likelihood  599.6244749857701 
GD      0       07:23:53.828    Scad_CV (XAUUSD,D1)     weights [0,0.03267834828227598,0.9673216517167235]| params [0.02669671670147136,0.5822637634505266,7,2.635245690184943]
CN      0       07:24:16.075    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.001| bias: 8.0| likelihood  599.6215815910193 
ES      0       07:24:16.075    Scad_CV (XAUUSD,D1)     weights [0,0.03267864853568959,0.9673213514633099]| params [0.02669727070086427,0.5822626295795441,7,2.635242405736884]
ER      0       07:24:38.223    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.001| bias: 10.0| likelihood  599.61866242213 
MQ      0       07:24:38.223    Scad_CV (XAUUSD,D1)     weights [0,0.03267912346489563,0.9673208765341038]| params [0.02669711773038876,0.5822617798491028,7,2.635240094669517]
ES      0       07:24:59.495    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.25075| bias: 2.0| likelihood  599.6351926572415 
KM      0       07:24:59.495    Scad_CV (XAUUSD,D1)     weights [0,0.03267640297340715,0.9673235970255923]| params [0.026704520400007,0.5822697866462155,7,2.635263431033769]
EE      0       07:25:12.505    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.25075| bias: 4.0| likelihood  468.644205273507 
GK      0       07:25:12.505    Scad_CV (XAUUSD,D1)     weights [0,0.01620981928802398,0.983790180710976]| params [2.862242105331717,0.9975906244136006,7,2.566020598217]
PH      0       07:26:18.429    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.25075| bias: 6.0| likelihood  359.9685977593964 
JD      0       07:26:18.429    Scad_CV (XAUUSD,D1)     weights [0,0,0.999999999999]| params [0.02596060043458071,0.5877560061777306,7,2.60814677938215]
GJ      0       07:26:35.438    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.25075| bias: 8.0| likelihood  341.04401153470667 
EE      0       07:26:35.438    Scad_CV (XAUUSD,D1)     weights [0,0.0101303301858873,0.9898696698131126]| params [0.03276229272869093,0.5873194208156135,7,2.6159294869276]
PL      0       07:26:50.782    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.25075| bias: 10.0| likelihood  331.81315199928497 
OE      0       07:26:50.782    Scad_CV (XAUUSD,D1)     weights [0,0.01344107163199763,0.9865589283670023]| params [0.01828802392046799,0.5853696555031691,7,2.618615230362836]
DL      0       07:27:12.118    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.5005| bias: 2.0| likelihood  599.6351926572415 
OP      0       07:27:12.118    Scad_CV (XAUUSD,D1)     weights [0,0.03267640297340715,0.9673235970255923]| params [0.026704520400007,0.5822697866462155,7,2.635263431033769]
NR      0       07:28:58.374    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.5005| bias: 4.0| likelihood  39.715438762939925 
NM      0       07:28:58.374    Scad_CV (XAUUSD,D1)     weights [0,0,0.999999999999]| params [2.885268158668136,0.5815643981885116,7,2.60814677938215]
MR      0       07:29:14.021    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.5005| bias: 6.0| likelihood  15.766736485645538 
PM      0       07:29:14.021    Scad_CV (XAUUSD,D1)     weights [0,0,0.999999999999]| params [2.886114952573396,0.5885681475003665,7,2.60814677938215]
FR      0       07:31:20.013    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.5005| bias: 8.0| likelihood  12.582743928163211 
KN      0       07:31:20.013    Scad_CV (XAUUSD,D1)     weights [0,0,0.999999999999]| params [2.886068065102342,0.588279448169273,7,2.60814677938215]
GR      0       07:33:38.602    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.5005| bias: 10.0| likelihood  9.373323825700936 
HM      0       07:33:38.602    Scad_CV (XAUUSD,D1)     weights [0,0,0.999999999999]| params [2.885905528406098,0.5876282323959312,7,2.60814677938215]
LR      0       07:33:59.933    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.75025| bias: 2.0| likelihood  599.6351926572415 
NO      0       07:33:59.933    Scad_CV (XAUUSD,D1)     weights [0,0.03267640297340715,0.9673235970255923]| params [0.026704520400007,0.5822697866462155,7,2.635263431033769]
PF      0       07:34:12.979    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.75025| bias: 4.0| likelihood  -342.3070420888405 
GK      0       07:34:12.979    Scad_CV (XAUUSD,D1)     weights [0,0,0.999999999999]| params [2.999235107389794,0.5744384247930826,7,2.608146780258969]
MG      0       07:34:25.802    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.75025| bias: 6.0| likelihood  -313.5880991228416 
NK      0       07:34:25.802    Scad_CV (XAUUSD,D1)     weights [0,0,0.999999999999]| params [2.999235107389794,0.5712426547670767,7,2.608146780258969]
JG      0       07:34:38.627    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.75025| bias: 8.0| likelihood  -315.3277234364691 
GK      0       07:34:38.627    Scad_CV (XAUUSD,D1)     weights [0,0,0.999999999999]| params [2.999235107389794,0.5700039115725434,7,2.608146780258969]
PG      0       07:34:51.411    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 0.75025| bias: 10.0| likelihood  -316.34493893784384 
OJ      0       07:34:51.411    Scad_CV (XAUUSD,D1)     weights [0,0,0.999999999999]| params [2.999235107389794,0.5700489107543522,7,2.608146780258969]
RF      0       07:35:12.660    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 1.0| bias: 2.0| likelihood  599.6351926572415 
DJ      0       07:35:12.660    Scad_CV (XAUUSD,D1)     weights [0,0.03267640297340715,0.9673235970255923]| params [0.026704520400007,0.5822697866462155,7,2.635263431033769]
CH      0       07:35:14.020    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 1.0| bias: 4.0| likelihood  689.1665208571073 
DH      0       07:35:14.020    Scad_CV (XAUUSD,D1)     weights [0,0,0]| params [3,0.5,4,2.608146566441139]
DR      0       07:35:15.389    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 1.0| bias: 6.0| likelihood  689.1665208571073 
EN      0       07:35:15.389    Scad_CV (XAUUSD,D1)     weights [0,0,0]| params [3,0.5,4,2.608146566441139]
KL      0       07:35:16.734    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 1.0| bias: 8.0| likelihood  689.1665208571073 
PD      0       07:35:16.734    Scad_CV (XAUUSD,D1)     weights [0,0,0]| params [3,0.5,4,2.608146566441139]
CE      0       07:35:18.094    Scad_CV (XAUUSD,D1)     tune_scad_parameters| sparcity: 1.0| bias: 10.0| likelihood  689.1665208571073 
MJ      0       07:35:18.094    Scad_CV (XAUUSD,D1)     weights [0,0,0]| params [3,0.5,4,2.608146566441139]
DS      0       07:35:18.094    Scad_CV (XAUUSD,D1)     CTG_MIX sparcity -> 1.0 || bias -> 4.0

このケースでは、最適なSCADパラメータとして1.0と4.0が示されています。スパース性パラメータが1.0という値は非常に高く、その結果、すべての重みが0へ縮小されています。これは混合モデルとしては意味を成さない結果です。このような結果は、多くの場合、選択した混合モデルが対象データに適していない、またはペナルティが過度に強く設定されていることを示しています。

このような場合、まずSCADペナルティを適用しないMLEアプローチでモデルを適合させることが推奨されます。MLEによって妥当な重みが得られる場合、問題の原因はスパース性パラメータが大きすぎることであると判断できます。この場合、MLEを使用するか、クロスバリデーションで試行するスパース性パラメータの上限値を下げる必要があります。

したがって、すべての重みが0になった試行結果は無視します。その結果、ペナルティなしのMLEアプローチが最も高い尤度を達成していることが確認できます。この段階で、Clayton-Frank-Gumbel混合モデルの最適なSCADパラメータ(0.25075, 10)と、Clayton-Student-t-Gumbel混合モデルの最適なSCADパラメータ(0.001, 2.0)を特定できました。これらの情報を利用することで、全学習データセットを用いて混合コピュラモデルを構築し、比較することが可能になります。


モデルの選択と比較

MixedCopulaSelection.mq5スクリプトの目的は、指定されたデータサンプルに最も適合する混合コピュラモデルを特定することです。

//+------------------------------------------------------------------+
//|                                         MixedCopulaSelection.mq5 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property script_show_inputs
#include<Copulas\Bivariate\mixed.mqh>
#include<ECDF\linear_cdf.mqh>
#include<Files\FileBin.mqh>
//--- input parameters
input string   FirstSymbol="XAUUSD";
input string   SecondSymbol="XAUEUR";
input datetime TrainingDataStart=D'2025.01.01';
input ENUM_TIMEFRAMES TimeFrame = PERIOD_D1;
input ulong    HistorySize=1200;
input double   CTG_Scad_Gamma = 0.0;
input double   CTG_Scad_A = 2.0;
input double   CFG_Scad_Gamma = 0.25075;
input double   CFG_Scad_A = 10.0;
input uint     Max_Iterations = 25;
input bool     SaveModel = true;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   vector p_1,p_2,p_3,p_n;
   matrix pdata,pobs;
   if(!p_1.CopyRates(FirstSymbol,TimeFrame,COPY_RATES_CLOSE,TrainingDataStart,HistorySize) ||
      !p_2.CopyRates(SecondSymbol,TimeFrame,COPY_RATES_CLOSE,TrainingDataStart,HistorySize) ||
      p_1.Size()!=p_2.Size() ||
      !pdata.Resize(p_1.Size(),2) ||
      !pdata.Col(p_1,0) ||
      !pdata.Col(p_2,1))
     {
      Print(" failed to collect and initialize rates matrix ", GetLastError());
      return;
     }
//---
   CLinearCDF qt();
   if(!qt.fit(pdata))
      return;
//---
   pobs = qt.to_quantile(pdata);
//---
   if(SaveModel)
     {
      CFileBin file;
      string filename = FirstSymbol+"_"+SecondSymbol+".ecdf";
      file.Open(filename,FILE_WRITE|FILE_COMMON);
      if(!qt.save(file.Handle()))
         Print(" Failed to save ", filename);
      else
         Print("Ecdf model save to ", filename);
      file.Close();
     }

//---
   vector lowest = vector::Zeros(4);
   lowest.Fill(DBL_MAX);
//---
   Print("[[ Clayton - Student - Gumbel ]]");
//---
   CTGMixCop ctg;
   double fit;
//---
   fit = ctg.Fit(pobs,Max_Iterations,CTG_Scad_Gamma,CTG_Scad_A);
//---
   Print(" CTG loglikelihood ", fit);
   Print(" CTG weights ", ctg.Weights());
   Print(" CTG Params ", ctg.Params());
//---
   lowest[2] = aic(fit,int(pobs.Rows()));
   Print(" CTG sic ", sic(fit,int(pobs.Rows())));
   Print(" CTG aic ", lowest[2]);
   Print(" CTG hqic ", hqic(fit,int(pobs.Rows())));
//---
   Print("[[ Clayton - Frank - Gumbel ]]");
//---
   CFGMixCop cfg;
//---
   fit = cfg.Fit(pobs,Max_Iterations,CFG_Scad_Gamma,CFG_Scad_A);
//---
   Print(" CFG loglikelihood ", fit);
   Print(" CFG weights ", cfg.Weights());
   Print(" CFG Params ", cfg.Params());
//---
   lowest[0] = aic(fit,int(pobs.Rows()));
   Print(" CFG sic ", sic(fit,int(pobs.Rows())));
   Print(" CFG aic ", lowest[0]);
   Print(" CFG hqic ", hqic(fit,int(pobs.Rows())));
//---
   if(SaveModel)
     {
      CFileBin file;
      string filename,extension;
      ulong shift = lowest.ArgMin();
      CMixedCopula* mcop  = NULL;
      ENUM_COPULA_MIX mixtype = (ENUM_COPULA_MIX)shift;

      switch(mixtype)
        {
         case CFG_MIX:
            mcop = GetPointer(cfg);
            extension = ".cfgcopula";
            break;
         case CTG_MIX:
            mcop = GetPointer(ctg);
            extension = ".ctgcopula";
            break;
        }

      filename = FirstSymbol+"_"+SecondSymbol+extension;
      file.Open(filename,FILE_WRITE|FILE_COMMON);
      if(!mcop.Save(file.Handle()))
         Print("Failed to save ", filename);
      else
         Print("MixedCopula saved to ", filename, " in common folder.");
      file.Close();
      mcop = NULL;
     }
//---
  }
//+------------------------------------------------------------------+

この処理では、Clayton-Frank-Gumbel混合コピュラモデルとClayton-Student-t-Gumbel混合コピュラモデルを、同じ学習データセットに対して適合させ、比較を行います。使用する推定方法は、設定されたSCADパラメータに応じて、ペナルティ付き尤度法またはペナルティなしのMLEアプローチのいずれかが選択されます。スクリプトは、それぞれのモデルの情報量基準を比較することで、どの混合モデルが最も高い統計的適合度を持つかを判定します。その後、より優れたモデルはシリアライズされ、ファイルへ保存されます。正常に実行されると、ターミナルにはログ尤度の値と、保存されたモデルのファイル名を確認できる出力ログが表示されます。以下は、クロスバリデーション手順によって取得したSCADパラメータを使用してスクリプトを実行した場合の出力例です。

JQ      0       11:26:22.119    MixedCopulaSelection (XAUUSD,D1)        Ecdf model save to XAUUSD_XAUEUR.ecdf
CO      0       11:26:22.119    MixedCopulaSelection (XAUUSD,D1)        [[ Clayton - Student - Gumbel ]]
IJ      0       11:26:30.566    MixedCopulaSelection (XAUUSD,D1)         CTG loglikelihood 821.3707128783087
NR      0       11:26:30.566    MixedCopulaSelection (XAUUSD,D1)         CTG weights [0,0.03552603447650678,0.9644739655224931]
NL      0       11:26:30.566    MixedCopulaSelection (XAUUSD,D1)         CTG Params [-0.006169340694795771,0.4543309925241095,7,3.054494819573707]
ER      0       11:26:30.566    MixedCopulaSelection (XAUUSD,D1)         CTG sic -1635.6513489208414
QI      0       11:26:30.566    MixedCopulaSelection (XAUUSD,D1)         CTG aic -1640.7414257566174
HJ      0       11:26:30.566    MixedCopulaSelection (XAUUSD,D1)         CTG hqic -1638.824033401239
QL      0       11:26:30.566    MixedCopulaSelection (XAUUSD,D1)        [[ Clayton - Frank - Gumbel ]]
QJ      0       11:26:32.184    MixedCopulaSelection (XAUUSD,D1)         CFG loglikelihood 821.5620161629782
JD      0       11:26:32.184    MixedCopulaSelection (XAUUSD,D1)         CFG weights [0,0.03875313891414744,0.9612468610848526]
HO      0       11:26:32.184    MixedCopulaSelection (XAUUSD,D1)         CFG Params [0.002088006991783055,4.242903358363938,3.061932796342449]
MR      0       11:26:32.184    MixedCopulaSelection (XAUUSD,D1)         CFG sic -1636.0339554901805
RI      0       11:26:32.184    MixedCopulaSelection (XAUUSD,D1)         CFG aic -1641.1240323259565
RK      0       11:26:32.184    MixedCopulaSelection (XAUUSD,D1)         CFG hqic -1639.206639970578
PL      0       11:26:32.185    MixedCopulaSelection (XAUUSD,D1)        MixedCopula saved to XAUUSD_XAUEUR.cfgcopula in common folder.

最も適合度の高い混合コピュラモデルとして、Clayton-Frank-Gumbel混合モデルが選択されました。しかし、これらの結果を単一コピュラモデルの適合結果と比較すると、最良の混合コピュラモデルであっても、最良の単一コピュラモデルと比べて適合度が劣ることが分かります。 

QS      0       18:48:06.788    CopulaSelection (XAUUSD,D1)     CLAYTON_COPULA
RD      0       18:48:06.788    CopulaSelection (XAUUSD,D1)      sic 1009.0424155712477
HL      0       18:48:06.788    CopulaSelection (XAUUSD,D1)      aic 1003.9523387354716
DK      0       18:48:06.788    CopulaSelection (XAUUSD,D1)      hqic 1005.8697310908501
KL      0       18:48:06.795    CopulaSelection (XAUUSD,D1)     FRANK_COPULA
OH      0       18:48:06.795    CopulaSelection (XAUUSD,D1)      sic -1282.6359542297741
RP      0       18:48:06.795    CopulaSelection (XAUUSD,D1)      aic -1287.7260310655502
RD      0       18:48:06.795    CopulaSelection (XAUUSD,D1)      hqic -1285.8086387101716
NS      0       18:48:06.802    CopulaSelection (XAUUSD,D1)     GUMBEL_COPULA
PK      0       18:48:06.802    CopulaSelection (XAUUSD,D1)      sic -1620.5768024034212
FE      0       18:48:06.802    CopulaSelection (XAUUSD,D1)      aic -1625.6668792391972
PS      0       18:48:06.802    CopulaSelection (XAUUSD,D1)      hqic -1623.7494868838187
GK      0       18:48:11.931    CopulaSelection (XAUUSD,D1)     JOE_COPULA
NM      0       18:48:11.931    CopulaSelection (XAUUSD,D1)      sic -1917.6641571237963
DG      0       18:48:11.931    CopulaSelection (XAUUSD,D1)      aic -1922.7542339595723
NQ      0       18:48:11.932    CopulaSelection (XAUUSD,D1)      hqic -1920.8368416041938
LE      0       18:48:12.337    CopulaSelection (XAUUSD,D1)     N13_COPULA
CL      0       18:48:12.337    CopulaSelection (XAUUSD,D1)      sic -560.6680141126138
MJ      0       18:48:12.337    CopulaSelection (XAUUSD,D1)      aic -565.75809094839
EL      0       18:48:12.337    CopulaSelection (XAUUSD,D1)      hqic -563.8406985930114
JG      0       18:48:12.345    CopulaSelection (XAUUSD,D1)     N14_COPULA
MR      0       18:48:12.345    CopulaSelection (XAUUSD,D1)      sic -757.9453503106477
MH      0       18:48:12.345    CopulaSelection (XAUUSD,D1)      aic -763.0354271464238
HN      0       18:48:12.345    CopulaSelection (XAUUSD,D1)      hqic -761.1180347910453
QL      0       18:48:12.353    CopulaSelection (XAUUSD,D1)     GAUSSIAN_COPULA
ID      0       18:48:12.353    CopulaSelection (XAUUSD,D1)      sic -1189.1571905959859
ML      0       18:48:12.353    CopulaSelection (XAUUSD,D1)      aic -1194.2472674317619
IH      0       18:48:12.353    CopulaSelection (XAUUSD,D1)      hqic -1192.3298750763834
OR      0       18:48:12.830    CopulaSelection (XAUUSD,D1)     STUDENT_COPULA
PG      0       18:48:12.830    CopulaSelection (XAUUSD,D1)      sic -1233.3072453920256
OQ      0       18:48:12.830    CopulaSelection (XAUUSD,D1)      aic -1238.3973222278016
OD      0       18:48:12.830    CopulaSelection (XAUUSD,D1)      hqic -1236.479929872423

それでも、単一コピュラモデルの代わりに混合コピュラモデルを使用することは可能です。これは、「Bivariate Copulae」連載第2回の記事で紹介したSimpleCopulaStrategy.ex5エキスパートアドバイザー(EA)へ適用できます。インジケータGoldMixedCopulaSignals.mq5は、混合コピュラモデルを利用するように変更されており、SimpleMixedCopulaStrategy.mq5は、混合コピュラをベースとしたEAとして機能します。 

GoldMixedCopulaSignalsインジケータ


結論

本記事では、MQL5上で混合コピュラモデルを実装する方法を紹介しました。単一コンポーネントのコピュラを超えたアプローチを採用することで、金融時系列データにしばしば存在する複雑な依存関係を、より適切にモデル化できる可能性を持つフレームワークを構築しました。混合コピュラ手法は、より大きな計算コストを必要とし、ハイパーパラメータの慎重な調整も必要になります。しかし、より優れたコピュラモデルを構築できる可能性を考慮すると、その価値は十分にあると言えます。

非凸最適化のためのALGLIB統合と、モジュール化されたCMixedCopulaクラス構造により、より高次元の混合モデルへ発展させるための基盤が提供されます。最終的に、コピュラモデルを戦略開発へ適用する際の成功は、学習データが実際の市場状況をどれだけ適切に代表しているか、そして変化する市場ダイナミクスに対応し続けるために、モデルを定期的に再調整できるかどうかに大きく依存します。本記事で参照したすべてのコードは以下に添付されています。各ファイルの説明は、次の表にまとめています。 

ファイル  説明 
MQL5/include/Copulas/ 本記事で説明したモデルを含め、これまでに実装されたすべてのコピュラモデルのヘッダーファイルを含むフォルダ
MQL5/include/ECDF/ 経験累積分布関数(ECDF, Empirical Cumulative Distribution Function)を実装するヘッダーファイルを含むフォルダ 
MQL5/include/np.mqh ベクトルおよび行列処理用の各種ユーティリティをまとめたヘッダーファイル 
MQL5/scripts/Scad_CV.mq5 SCADハイパーパラメータを調整するためのクロスバリデーション手順を実装したスクリプト
MQL5/scripts/MixedCopulaSelection.mq5 サンプルデータセットへ混合コピュラモデルを適合させ、各モデルを比較して最適なコピュラモデルを選択するスクリプト 
MQL5/indicators/GoldMixedCopulaSignals.mq5 混合コピュラモデルを使用するインジケータ 
MQL5/experts/SimpleMixedCopulaStrategy.mq5 混合コピュラモデルから生成されたシグナルを利用するEA 

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

添付されたファイル |
最後のコメント | ディスカッションに移動 (3)
Jacryptoking
Jacryptoking | 13 2月 2026 において 08:08
マレーシアのSnR…SMCに基づいたものを構築する
cemal
cemal | 15 2月 2026 において 22:16

ファイルを指定されたフォルダに正確に配置しました。さらに、Algibのファイル(https://www.mql5.com/ja/code/1146) もダウンロードして指定されたフォルダに配置しましたが、GoldMixedCopula Signalsインジケーターをコンパイルしようとすると、100件のエラーが発生します。どこが間違っているのでしょうか?

エラー

Maxim Kuznetsov
Maxim Kuznetsov | 19 5月 2026 において 10:15
cemal #:

ファイルを指定されたフォルダに配置し、さらに Algibのhttps://www.mql5.com/ja/code/1146 ファイルをダウンロードして適切なフォルダに配置しましたが、GoldMixedCopula Signalsインジケーターをコンパイルしようとすると、100件のエラーが発生します。どこが間違っているのでしょうか?


スクリーンショットの撮り方が間違っています :-)

エラーの解析や修正の手助けが必要な場合は、スクリーンショットに最初のエラーが表示されている必要があります。他のすべてのエラーは、通常「派生した」ものであり、つまりそのエラーの結果に過ぎません

ラリー・ウィリアムズの『市場の秘密』(第11回):カスタムインジケータによるスマッシュデー反転の検出 ラリー・ウィリアムズの『市場の秘密』(第11回):カスタムインジケータによるスマッシュデー反転の検出
ラリー・ウィリアムズのスマッシュデー反転ルールを、確認済みセットアップを矢印で表示する実用的なMQL5インジケータへ変換します。バッファのバインド、プロットプロパティの設定、履歴データへのマッピング、そしてOnCalculate内でのリアルタイム更新までを、段階的に解説します。調整可能なルックバックパラメータと見やすいチャート描画により、有効な反転をすばやく検出できる一方で、最終的な売買判断は裁量と市場状況に委ねられます。
MQL5取引ツール(第16回):改良版スーパーサンプリング・アンチエイリアシング(SSAA)と高解像度レンダリング MQL5取引ツール(第16回):改良版スーパーサンプリング・アンチエイリアシング(SSAA)と高解像度レンダリング
MQL5キャンバスダッシュボードにスーパーサンプリングによるアンチエイリアシングと高解像度レンダリングを追加し、最終的な表示サイズへダウンサンプリングする手法を実装します。また、角丸矩形の塗りつぶしと枠線、角丸三角形の矢印、さらに統計パネルおよびテキストパネル向けのテーマ対応カスタムスクロールバーを実装します。これらのツールにより、MetaTrader 5上で、より滑らかで視認性の高いUIコンポーネントを構築できるようになります。
プライスアクション分析ツールキットの開発(第61回):3スイング検証による構造的傾斜トレンドラインブレイクアウト プライスアクション分析ツールキットの開発(第61回):3スイング検証による構造的傾斜トレンドラインブレイクアウト
3点のスイングによる検証を基準として、客観的なプライスアクションシグナルを生成する、傾斜トレンドラインブレイクアウトツールを紹介します。このシステムは、スイング検出、トレンドライン構築、そしてクロス判定ロジックを用いたブレイクアウト確認を自動化することで、ノイズを低減し、運用・執行判断を標準化します。戦略ルールを解説し、MQL5による実装を示し、テスト結果を検証します。このツールは自動売買を目的としたものではなく、分析およびシグナル確認を支援するためのものです。
MQL5とデータ処理パッケージの統合(第7回):銘柄間連携のためのマルチエージェント環境の構築 MQL5とデータ処理パッケージの統合(第7回):銘柄間連携のためのマルチエージェント環境の構築
マルチエージェント取引のための完全なPython–MQL5統合について解説します。内容には、MT5データ取得、インジケーター計算、各エージェントによる意思決定、そして単一のアクションを出力する重み付きコンセンサス処理が含まれます。シグナルはJSON形式で保存され、Flaskによって提供され、MQL5のエキスパートアドバイザー(EA)によって取得されて実行されます。実行時には、ポジションサイズを計算し、ATRに基づくSL/TPも設定されます。Flaskのルートは、安全なライフサイクル制御とステータス監視のための機能を提供します。