MQL5でボラティリティモデルを構築する(第I回):初期実装
はじめに
本記事では、ボラティリティのモデリングおよび予測をおこなうためのMQL5ライブラリを紹介します。主な目的は、さまざまな種類のボラティリティ過程を柔軟に定義できるツールを提供することです。これらのツールには、構築されたモデルの品質を定量化するための解析的ユーティリティも付属しています。MQL5におけるARCH (Autoregressive Conditional Heteroskedasticity)およびGARCH (Generalized ARCH)ファミリーに属する各種ボラティリティ過程の構築方法を示します。
コードの概要
ここで提示するライブラリは、金融計量経済学に特化したPythonのarchパッケージに着想を得ています。archは、ARCHおよびGARCHモデルに重点を置いたツールキットです。同パッケージの主な機能は各種ボラティリティモデルを実装することですが、それに加えて、一定平均モデル、ゼロ平均モデル、自己回帰(AR)モデルなどの平均方程式のモデリングに関しても多様な選択肢を提供しています。さらに、標準化残差の分布として、正規分布、t分布、非対称t分布(Skewed Student's t-distribution)などを指定することも可能です。ここでの目的は、これらの機能をMQL5上でネイティブに再現することです。

このネイティブ実装のアーキテクチャはモジュール型であり、平均過程をボラティリティ過程および誤差分布から分離しています。したがって、モデルはこれら3つの異なるコンポーネントの組み合わせとして構成されます。平均過程は中核となるコンポーネントであり、他の要素はそこに付随する形で接続されます。特筆すべき点として、すべてのパラメータの同時推定はこの中心コンポーネントを通じてのみ管理されます。各要素は基底クラスとして実装されており、具体的なバリエーションはサブクラスとして表現されています。
ライブラリ内のすべてのクラスは標準化された構造に従います。各クラスはデフォルトコンストラクタに加えてパラメトリックコンストラクタを備えています。さらに、すべてのクラスにはinitialize()メソッドが実装されており、デフォルトコンストラクタを用いてインスタンスを生成した場合には、このメソッドの明示的な呼び出しが必須となります。便宜上、パラメトリックコンストラクタを使用する場合には、initialize()メソッドは暗黙的に呼び出されます。 以降のセクションでは、平均過程、ボラティリティ過程、および誤差分布の実装について説明します。
モデルの設定
条件付き平均をモデル化するコードはmean.mqhに配置されています。このファイル内では、HARXクラスがすべての平均モデル実装の基底型として定義されています。前述の通り、平均モデルはフルボラティリティモデルにおける主要インターフェースでもあります。このクラスは、データへのモデル適合および予測生成に必要な機能を提供します。
//+------------------------------------------------------------------+ //| Heterogeneous Autoregression (HAR) | //+------------------------------------------------------------------+ class HARX: public CArchModel { protected: bool _initialize(ArchParameters &vol_dist_params); public: HARX(void):m_extra_simulation_params(0) HARX(ArchParameters& model_specification) ~HARX(void) bool initialize(ArchParameters& vol_dist_params) matrix get_x(void) { return m_model_spec.x; } matrix get_regressors(void) { return m_regressors; } vector get_y(void) { return m_model_spec.y; } virtual vector resids(vector ¶ms, vector &y, matrix ®ressors); virtual ulong num_params(void); bool set_volatility_process(CVolatilityProcess* &vp); bool set_distribution(CDistribution* &dist); virtual matrix simulate(vector ¶ms, ulong nobs, ulong burn, vector &initial_vals,matrix &x, vector &initial_vals_vol); ArchForecast forecast(ulong horizon = 1, long start = -1, ENUM_FORECAST_METHOD method=FORECAST_ANALYTIC, ulong simulations=1000, uint seed=0); ArchForecast forecast(matrix& x[],ulong horizon = 1, long start = -1, ENUM_FORECAST_METHOD method=FORECAST_ANALYTIC, ulong simulations=1000, uint seed=0); virtual ArchForecast forecast(vector& params, matrix& x[],ulong horizon = 1, long start = -1, ENUM_FORECAST_METHOD method=FORECAST_ANALYTIC, ulong simulations=1000, uint seed=0); ArchModelFixedResult fix(vector& params,long first_obs = 0, long last_obs = -1); ArchModelResult fit(double scaling = 1.0, uint maxits = 0, ENUM_COVAR_TYPE cov_type = COVAR_ROBUST, long first = 0, long last = -1, double tol = 1e-9, bool guardsmoothness=false, double gradient_test_step = 0.0); ArchModelResult fit(vector& startingvalues,vector& backcast, double scaling = 1.0, uint maxits = 0, ENUM_COVAR_TYPE cov_type = COVAR_ROBUST, long first = 0, long last = -1, double tol = 1e-9, bool guardsmoothness=false, double gradient_test_step = 0.0); };
平均モデルのバリエーションはHARXクラスのサブクラスとして実装されています。すべての平均モデルのパラメトリックコンストラクタおよびinitialize()メソッドは、共通の入力としてArchParametersというカスタム構造体を使用します。
struct ArchParameters { // --- Data & Core Configuration vector observations; matrix exog_data; vector mean_lags; ENUM_MEAN_MODEL mean_model_type; ENUM_VOLATILITY_MODEL vol_model_type; ENUM_DISTRIBUTION_MODEL dist_type; ulong holdout_size; bool is_rescale_enabled; double scaling_factor; // --- Mean Model Parameters bool include_constant; bool use_har_rotation; // --- Volatility Process Parameters (GARCH/ARCH) int vol_rng_seed; ulong garch_p; ulong garch_o; ulong garch_q; double vol_power; long sample_start_idx; long sample_end_idx; ulong min_bootstrap_sims; // --- Distribution Parameters vector dist_init_params; int dist_rng_seed; };
この構造体は、フルボラティリティモデルを構成するために必要なすべての変数をカプセル化しています。その内容は以下のとおりです。
| 変数 | データ型 | 詳細 |
|---|---|---|
| observations | vector | モデル化対象となる時系列ベクトル。 |
| exog_data | matrix | モデルに含める任意の外生変数のためのオプション行列。各列は1つの変数を表し、行数は構造体のyプロパティで定義される従属変数の長さと一致しなければなりません。 |
| mean_lags | vector | ARまたはHAR過程のいずれかに対する任意のラグ。ARモデルでは、ラグは、現在の値に対する過去の値への単純な参照で、連続でも非連続でも構いません。HAR過程では、ラグは、平均が計算される期間長またはルックバック期間を表します。 |
| mean_model_type | ENUM_MEAN_MODEL列挙型 | 従属変数の期待値をモデル化するための平均過程を明示的に指定する列挙型。現在、6つの平均モデルが実装されています。すなわち、一定平均モデル、ゼロ平均モデル、および外生変数の有無それぞれに対するAR過程とHAR過程です。 |
| vol_model_type | ENUM_VOLATILITY_MODEL列挙型 | MODEL列挙型従属変数yの条件付き分散をモデル化するためのボラティリティ過程を定義します。一定分散から各種ARCHおよびGARCHファミリーまで7種類の選択肢があり、デフォルトは一定分散過程です。 |
| dist_type | ENUM_DISTRIBUTION_MODEL列挙型 | フルモデルにおける誤差分布を規定する列挙型。現在、正規分布、t分布、非対称t分布、一般化誤差分布(GED)の4種類から選択可能で、デフォルトは正規分布です。 |
| holdout_size | unsigned long | モデル適合時にデータから除外される観測数。 |
| is_rescale_enabled | bool | データのスケールをチェックするかどうかを示すブールフラグ。trueの場合、モデルはデータのスケールを評価し、リスケーリングが必要であればMetaTrader 5ターミナルに警告を出力し、推奨スケーリング係数を提示します。 |
| include_constant | bool | 平均モデルに定数項を含めるかどうかを指定するブールフラグ。 |
| use_har_rotation | bool | HAR平均モデルでラグが指定されている場合にのみ関連します。trueの場合、平均は非重複期間に対して計算されます。たとえばラグ{1,5,22}が指定されていると仮定します。このプロパティがfalseの場合、モデルは従属変数の直近1、5、22個の値に対する単純な平均を使用します。一方でtrueの場合、平均は互いに重ならない区間を用いて計算されます。具体的には、第1ラグ(1)、2から5の期間、そして6から22の期間に対してそれぞれ平均が計算されます。 |
| vol_rng_seed | int | ボラティリティ過程で使用される乱数生成器のオプションシード値。 |
| garch_p | unsigned long | ARCH/GARCH過程におけるpパラメータ。 |
| garch_o | unsigned long | GARCH系過程におけるoパラメータ。 |
| garch_q | unsigned long | GARCH系過程におけるqパラメータ。 |
| vol_power | double | GARCH系ボラティリティ過程における冪乗パラメータ。 |
| min_bootstrap_sims | unsigned long | ブートストラップ法による予測時に使用される最小ブートストラップ回数。 |
| dist_init_params | vector | 誤差分布の初期パラメータ。 |
| dist_rng_seed | int | 指定された分布で使用される乱数生成器のオプションシード。 |
ArchParameters変数は、平均モデルのパラメトリックコンストラクタ、またはそのinitialize()メソッドのいずれかに渡す前に、必ず宣言および設定されていなければなりません。
initialize()メソッドは、すべてのパラメータを検証し、それらが選択された平均過程、ボラティリティ過程、および誤差分布と正しく対応していることを確認する役割を担います。この段階で検出された軽微な不整合は、ユーザーに明示的に通知することなく自動修正されます。
bool _initialize(ArchParameters &vol_dist_params) { if(m_model_spec.mean_model_type!=WRONG_VALUE && vol_dist_params.mean_model_type!=WRONG_VALUE && vol_dist_params.mean_model_type!=m_model_spec.mean_model_type) { m_initialized = false; Print(__FUNCTION__" Incorrect initialization of mean model. \nMake sure input parameters correspond with the correct class "); return false; } if(m_model_spec.mean_model_type!=WRONG_VALUE && vol_dist_params.mean_model_type==WRONG_VALUE) vol_dist_params.mean_model_type = m_model_spec.mean_model_type; m_model_spec = vol_dist_params; switch(m_model_spec.mean_model_type) { case MEAN_CONSTANT: m_model_spec.mean_lags = vector::Zeros(0); m_name = "Constant Mean"; m_model_spec.include_constant = true; m_model_spec.use_har_rotation = false; break; case MEAN_AR: m_model_spec.use_har_rotation = false; m_model_spec.exog_data = matrix::Zeros(0,0); m_name = "AR"; break; case MEAN_ARX: m_model_spec.use_har_rotation = false; m_name ="AR-X"; break; case MEAN_HAR: m_model_spec.exog_data = matrix::Zeros(0,0); m_name = "HAR"; break; case MEAN_HARX: m_name = "HAR-X"; break; case MEAN_ZERO: m_model_spec.exog_data=matrix::Zeros(0,0); m_model_spec.mean_lags = vector::Zeros(0); m_model_spec.include_constant = false; m_model_spec.use_har_rotation = false; m_name = "Zero Mean"; break; default: m_name = "HAR-X"; break; } m_fit_indices = vector::Zeros(2); m_fit_indices[1] = (m_model_spec.observations.Size())?double(m_model_spec.observations.Size()):-1.; if(m_model_spec.mean_lags.Size()) { switch(m_model_spec.mean_model_type) { case MEAN_AR: case MEAN_ARX: m_lags = matrix::Zeros(2,m_model_spec.mean_lags.Size()); m_lags.Row(m_model_spec.mean_lags,0); m_lags.Row(m_model_spec.mean_lags,1); break; case MEAN_HAR: case MEAN_HARX: m_lags = matrix::Zeros(1,m_model_spec.mean_lags.Size()); m_lags.Row(m_model_spec.mean_lags,0); break; } } else m_lags = matrix::Zeros(0,0); m_constant = m_model_spec.include_constant; m_rescale = m_model_spec.is_rescale_enabled; m_rotated = m_model_spec.use_har_rotation; m_holdback = m_model_spec.holdout_size; m_initialized = _init_model(); if(!m_initialized) return false; m_num_params = num_params(); if(CheckPointer(m_vp)==POINTER_DYNAMIC) delete m_vp; m_vp = NULL; switch(vol_dist_params.vol_model_type) { case VOL_CONST: m_vp = new CConstantVariance(m_model_spec.vol_rng_seed,m_model_spec.min_bootstrap_sims); break; case VOL_ARCH: m_vp = new CArchProcess(m_model_spec.garch_p,m_model_spec.vol_rng_seed,m_model_spec.min_bootstrap_sims); break; case VOL_GARCH: m_vp = new CGarchProcess(m_model_spec.garch_p,m_model_spec.garch_q,m_model_spec.vol_rng_seed,m_model_spec.min_bootstrap_sims); break; default: m_vp = new CConstantVariance(m_model_spec.vol_rng_seed,m_model_spec.min_bootstrap_sims); break; } if(CheckPointer(m_distribution)==POINTER_DYNAMIC) delete m_distribution; m_distribution = NULL; switch(vol_dist_params.dist_type) { case DIST_NORMAL: m_distribution = new CNormal(); break; default: m_distribution = new CNormal(); break; } m_initialized = ( m_distribution!=NULL && m_vp!=NULL && m_vp.is_initialized() && m_distribution.initialize(m_model_spec.dist_init_params, m_model_spec.dist_rng_seed) ); return m_initialized; }
このメソッドが失敗するのは、サンプルデータに問題がある場合、または指定されたパラメータが与えられたサンプル系列と矛盾する場合に限られます。そのような場合には、メソッドはfalseを返します。モデル仕様が有効である場合には、メソッドはフルモデルを構成する残りのコンポーネントの初期化処理へと進みます。この二次的な初期化フェーズでエラーが発生した場合、メソッドはそれを検出し、falseを返します。メソッドが正常に完了した場合、適合処理を開始することが可能になります。
モデルパラメータの同時推定は、fit()メソッドのいずれかを呼び出すことで実行されます。
データにモデルを適合させる
適合手続きは、Alglibの非線形制約付き最適化 (Nonlinearly constrained optimization with preconditioned augmented Lagrangian algorithm)を用いて処理されます。これはCMinNLCクラスとして実装されています。最小化される関数は、HARXクラスのメンバとして定義されている対数尤度関数です。
vector objective(vector& parameters, vector& sigma2, vector &backcast, matrix& varbounds, bool individual=false) { return _loglikelihood(parameters,sigma2,backcast,varbounds,individual); }
fit()メソッドの入力値は、以下の表に一覧表示され、説明されています。
| パラメータ名 | データ型 | 詳細 |
|---|---|---|
| startingvalues | vector | 最適化過程で使用されるモデルパラメータの初期値ベクトル。ユーザーは任意の値を指定できます。空ベクトルを指定した場合は、適切な初期値が自動的に計算されます。 |
| backcast | vector | 条件付きボラティリティ過程のパラメータ推定に使用されるベクトル。条件付き分散の式は再帰的であるため、事前サンプルデータが存在しない場合には初期観測値を計算するための値が必要になります。このパラメータも空ベクトルを受け付け、その場合は内部で適切なバックキャスト値が決定されます。 |
| scaling | double | サンプル系列を変換するためのスケーリング係数。データがどのように変換されたかを最適化器が把握している方が、最適化性能が向上します。デフォルト値は1です。 |
| cov_type | ENUM_COV_TYPE列挙型 | パラメータ共分散行列の推定方法を指定する列挙型。 |
| maxits | unsigned long | 最適化器に許可される最大反復回数。 |
| first、last | int | パラメータ推定に使用するサンプル系列内の開始および終了インデックス。 |
| tol | double | 最適化過程が収束したと判断するための許容誤差(閾値)。 |
| guardsmoothness | bool | 非滑らか性モニタリングの有効/無効を切り替える最適化器の設定。有効にすると、完全に微分可能ではない関数も考慮して最適化がおこなわれます。詳細はALGLIBドキュメントを参照してください。 |
| gradient_test_step | double | 非ゼロに設定された場合、最適化器に対して解析的勾配またはヤコビアン関数の検証をおこなうよう指示します。これにより数学的整合性は保証されますが、計算速度には大きな影響を与えます。特定のユースケースに適切な設定値についてはALGLIBドキュメントを参照してください。 |
fit()メソッドはArchModelResult構造体を返します。この構造体には、最適化結果(推定係数、統計的有意性、およびモデル診断など)が含まれます。
struct ArchModelFixedResult { double loglikelihood; vector params; vector conditional_volatility; ulong nobs; vector resid; }; //+------------------------------------------------------------------+ //| arch model result | //+------------------------------------------------------------------+ struct ArchModelResult: public ArchModelFixedResult { long fit_indices[2]; matrix param_cov; double r2; ENUM_COVAR_TYPE cov_type;
以下は、ArchModelResult構造体に含まれるプロパティとメソッドです。
| 項目 | データ型 | 詳細 |
|---|---|---|
| params | vector | 最適化過程の結果であり、ボラティリティモデルのパラメータを表します。値は特定の順序で整理されています。 まず平均モデルのパラメータ(定数項、AR/HAR係数、外生変数など)、 次にボラティリティパラメータ(GARCHにおけるomega、alpha、betaなど)、 最後に分布パラメータ(自由度や歪度など)です。 |
| conditional_volatility | vector | インサンプルの条件付きボラティリティを保持するベクトルであり、推定期間におけるモデルのボラティリティ予測を表します。 |
| nobs | int | モデルパラメータの適合に実際に使用されたサンプル系列の観測数を示します。 |
| resids | vector | フルモデルの残差を格納するベクトルであり、観測値と平均方程式による予測値との差を表します。モデル適合の品質評価に利用できます。 |
| loglikelihood | double | 収束時点における対数尤度関数の値です。最適化過程において目的関数が達成した最小値を表します。 |
| fit_indices | vector | モデル推定に使用されたサンプル系列のインデックス範囲(開始と終了)を明示的に示す2要素のベクトルです。 |
| param_cov | matrix | モデルパラメータの推定共分散行列。推定された全パラメータ数に対応する次元の正方行列です。 |
| r2 | double | 従属変数の分散のうち、平均モデルによって説明される割合を示す指標。 |
| cov_type | 列挙型 | パラメータ共分散行列の計算に使用された推定手法。 |
ArchModelResult構造体のメソッドは、単なる点推定を超えて、モデルの妥当性を評価するためのより詳細な統計情報を提供します。以下に、統計的メソッドとそれらによって得られる指標を示します。
| tvalues(void) | 各パラメータのt統計量を返します。これは推定係数をその標準誤差で割った値として計算されます。 |
vector tvalues(void) { return params/std_err(); }
| pvalues(void) | t統計量に対応するp値を返します。これは観測されたパラメータ値が偶然に生じた確率を評価するもので、通常0.05未満であれば統計的に有意とみなされます。 |
vector pvalues(void) { vector pvals = tvalues(); for(ulong i = 0; i<pvals.Size(); ++i) pvals[i] = CAlglib::NormalCDF(-1.0*MathAbs(pvals[i]))*2.0; return pvals; }
| rsquaredadj(void) | 平均モデルの調整済み決定係数(Adjusted R-squared)を返します。標準的な決定係数(R²)とは異なり、不要な変数の追加に対してペナルティを課し、モデルの複雑さに対してどれだけ分散が説明されているかを示します。 |
double rsquared_adj(void) { return 1.0 - ((1.0-r2)*double(nobs-1)/double(nobs-num_params())); }
| stderror(void) | パラメータの標準誤差を返します。これは推定値の精度を表し、値が小さいほど信頼性が高いことを意味します。 |
vector std_err(void) { return sqrt(param_cov.Diag()); }
最適化過程が収束しなかった場合、ArchModelResultの各プロパティは通常デフォルト値を保持し、paramsベクトルは空になります。そのため、分析や予測をおこなう前にparamsベクトルを確認することが推奨されます。
予測
モデルの適合が正常に完了した後、予測はオーバーロードされたforecastメソッドによって処理されます。この柔軟性により、異なるデータ入力に基づいた予測生成が可能になります。以下に、将来のボラティリティと平均の推定値を生成するために、forecastメソッドの各オーバーロードで共通して使用されるパラメータを示します。
| パラメータ名 | データ型 | 詳細 |
|---|---|---|
| horizon | unsigned long | 予測ホライズン(将来何ステップ先まで予測するか)を定義する整数。条件付き平均および条件付きボラティリティの両方を何ステップ先まで予測するかを決定します。デフォルト値は1です。 |
| start | int | 予測の起点となるデータ系列内の位置。どの観測値の直後から将来予測を開始するかを決定します。デフォルトではデータの最終インデックスです。 |
| method | ENUM_FORECAST_METHOD列挙型 | 将来のボラティリティを推定するための手法。平均モデルは通常標準的に処理されますが、ボラティリティ過程はモデルの複雑さに応じて複数の方法で推定できます。選択肢はAnalytic、Simulation、Bootstrapで、デフォルトはAnalyticです。 Analyticメソッドは、閉形式の数式を用いて期待分散を計算します。ただし、冪乗パラメータに関して重要な制約があります。モデルが分散を残差の二乗として仮定している場合、このメソッドは任意のホライズンに対して適用可能です。一方で、冪乗が2以外の場合、1ステップを超えるホライズンでは使用できません。これは、非線形変換の期待値が単純な再帰解を持たないためです。 Simulation(モンテカルロ)メソッドは、仮定された分布に基づいて多数の将来パスをシミュレーションし、それらの平均を取ることで予測をおこないます。一方、Bootstrapは特定の分布を仮定せず、過去の残差から直接リサンプリングすることで将来パスを生成します。 |
| simulations | int | 生成するパス(サンプル)の数。methodがSimulationまたはBootstrapの場合にのみ使用されます。 |
| seed | int | 疑似乱数生成器(RNG)を初期化するためのオプション整数。SimulationまたはBootstrapにおける乱数パスの再現性を確保します。 |
| params | vector | オプションの係数ベクトル。指定した場合、内部のfit()結果ではなく、この値を用いて予測が計算されます。 |
| x | 行列配列 | 平均モデルに外生変数が含まれる場合に必要となる入力。外生変数はボラティリティ過程とは独立しているため、その将来値はモデル内部で予測できず、事前に指定する必要があります。モデルがk個の外生変数で適合されている場合、この入力は予測計算に必須となります。 このxに渡す各行列の次元には注意が必要です。必要な形状は、ホライズン、外生変数の数、およびsスタートとサンプルサイズの関係によって決まります。 配列のサイズ(行列の数)は外生変数の数と一致しなければなりません。各行列について、行数は「サンプル総数 − 予測開始インデックス」以上である必要があります。さらに、列数はhorizonと一致している必要があります。 |
forecast()メソッドを呼び出すと、ArchForecast構造体が返されます。このコンテナは、平均およびボラティリティの予測パスを格納します。この構造体は、3つの主要な行列で構成されています。
//+------------------------------------------------------------------+ //| arch forecast result | //+------------------------------------------------------------------+ struct ArchForecast { matrix mean; matrix variance; matrix residual_variance;
mean行列は、条件付き平均(期待価格または期待リターン)の予測値を格納します。variance行列は、条件付き分散の予測値を格納します。最後に、residual_variance行列は、残差の条件付き分散の予測値を表します。
モデル検証
モデルを適合させた後、残差にARCH効果(不均一分散)が残っているかどうかを確認するための標準的な診断手法はラグランジュ乗数(LM)検定(EngleのARCH検定とも呼ばれる)です。モデルが適切であれば、残差はホワイトノイズであるべきであり、すなわち残差の二乗に有意な自己相関は検出されないはずです。archlmtest()関数は、残差の二乗をそのラグに対して回帰することでこれを評価します。
//+------------------------------------------------------------------+ //| The Lagrange multiplier test | //+------------------------------------------------------------------+ WaldTestStatistic archlmtest(vector& residuals,vector& conditional_volatility,ulong lags,bool standardized = false) { WaldTestStatistic out; vector resids = residuals; if(standardized) resids = resids/conditional_volatility; if(resids.HasNan()) { vector nresids = vector::Zeros(resids.Size() - resids.HasNan()); for(ulong i = 0, k = 0; i<resids.Size(); ++i) if(MathClassify(resids[i]) == FP_NAN) continue; else nresids[k++] = resids[i]; resids = nresids; } int nobs = (int)resids.Size(); vector resid2 = MathPow(resids,2.0); if(!lags) lags = ulong(ceil(12.0*pow(nobs/100.0,1.0/4.0))); lags = MathMax(MathMin(resids.Size()/2 - 1,lags),1); if(resid2.Size()<3) { Print(__FUNCTION__, " Test requires at least 3 non-nan observations "); return out; } matrix matres = matrix::Zeros(resid2.Size(),1); matres.Col(resid2,0); matrix lag[]; if(!lagmat(matres,lag,lags,TRIM_BOTH,ORIGINAL_SEP)) { Print(__FUNCTION__, " lagmat failed "); return out; } matrix lagout; if(!addtrend(lag[0],lagout,TREND_CONST_ONLY,true,HAS_CONST_SKIP)) { Print(__FUNCTION__, " addtrend failed "); return out; } lag[0] = lagout; OLS ols; if(!ols.Fit(lag[1].Col(0),lag[0])) { Print(__FUNCTION__, " OLS fitting failed "); return out; } out.stat = nobs*ols.Rsqe(); if(standardized) { out.null = "Standardized residuals are homoskedastic"; out.alternative = "Standardized residuals are conditionally heteroskedastic"; } else { out.null = "Residuals are homoskedastic"; out.alternative = "Residuals are conditionally heteroskedastic"; } out.df = lags; return out; }
以下の入力が必要です。
| パラメータ名 | データ型 | 詳細 |
|---|---|---|
| residuals | vector | ArchModelResultから取得される残差ベクトル。適合済みモデルの生の誤差を表します。 |
| conditional_volatility | vector | 適合済みモデルにおけるインサンプルの条件付きボラティリティ。 |
| lags | unsigned long | 検定回帰に含めるラグ数。 |
| standardized | bool | 残差をconditional_volatilityで標準化するかどうかを指定するブールフラグ。 |
archlmtest()関数を呼び出すと、WaldTestStatistic構造体が返されます。
//+------------------------------------------------------------------+ //|Test statistic holder for Wald-type tests | //+------------------------------------------------------------------+ struct WaldTestStatistic { ulong df; double stat; string null; string alternative; WaldTestStatistic(void) { stat = EMPTY_VALUE; df = 0; null = alternative = NULL; } WaldTestStatistic(double _stat, ulong _df, string _null, string _alt) { stat = _stat; df = _df; null = _null; alternative = _alt; } WaldTestStatistic(WaldTestStatistic &other) { stat = other.stat; df = other.df; null = other.null; alternative = other.alternative; } void operator=(WaldTestStatistic &other) { stat = other.stat; df = other.df; null = other.null; alternative = other.alternative; } double pvalue(void) { int ecode = 0; double val = 1.- MathCumulativeDistributionChiSquare(stat,double(df),ecode); if(ecode) Print(__FUNCTION__," Chisquare cdf error ", ecode); return val; } vector critical_values(void) { vector out = {0.9,0.95,0.99}; int ecode = 0; for(ulong i = 0; i<out.Size(); ++i) out[i] = MathQuantileChiSquare(out[i],double(df),ecode); if(ecode) Print(__FUNCTION__," Chisquare cdf error ", ecode); return out; } };
この構造体には、モデルがデータ中のボラティリティクラスタを適切に除去できているかを判断するために必要な統計結果が格納されています。
| 項目 | データ型 | 詳細 |
|---|---|---|
| df | unsigned long | 検定の自由度。関数呼び出し時に指定されたラグ数に対応します。 |
| stat | double | 計算された検定統計量。帰無仮説の下でカイ二乗分布に従います。 |
| pvalue(void) | double | ARCH効果が残っていないと仮定した場合に、観測された検定統計量以上に極端な値が得られる確率を返します。 |
| crtical(void) | vector | 90%、95%、99%の3つの信頼水準に対応する臨界値のベクトルを返します。 |
モデルの妥当性を評価する際には、主にp値を確認します。p値が0.05より大きい場合は合格と判断され、帰無仮説を棄却できないことを意味します。これは残差が等分散(一定分散)であることを示しており、ARCH/GARCHモデルが適切に機能していることを示唆します。一方で、p値が0.05以下の場合は帰無仮説を棄却します。これは残差にARCH効果が依然として残っていることを示し、モデルが不十分である可能性を示唆します。この場合、ラグ次数を増やす、あるいは別のモデル仕様を試す必要があります。statは残差二乗の相関が強くなるほど大きくなります。非常に大きなstatは非常に小さなp値をもたらし、モデルが重要なボラティリティパターンを捉え損ねていることを示します。
外生変数を組み込んだ例
このセクションでは、外生変数を含むモデルの指定方法を示します。ARXおよびHARXにおける「X」は、回帰方程式内のこれら外部の独立変数を指します。この枠組みにおいては、モデル化される時系列が従属変数となり、外生の説明変数は各列が1つの変数を表す行列として与えられます。
外生変数の柔軟性を示すために、ARXモデルとHeterogeneous Autoregressive (HAR)モデルの興味深い関係を考察します。過去データの平均値を外生入力としてARXモデルに与えることで、HARモデルの挙動を再現することができます。この比較は、外生変数の実用的な利用方法と、HARモデルの内部構造の両方を明らかにします。HARモデルは、もともと金融市場における実現ボラティリティをモデル化するために設計されたものですが、他の変数にも適用可能です。「Heterogeneous」と呼ばれるのは、異なる市場参加者が異なる時間スケールでボラティリティに反応するという仮定に基づき、過去の影響を短期、中期、長期といった複数の時間軸に分解して扱うためです。

最も一般的なHARモデルは、短期、中期、長期の3つの期間における実現ボラティリティを使用します。それぞれの期間は、平均実現ボラティリティを計算するために用いられる時間点の数を定義します。HARモデルは、これらの重なり合う平均項を通じて、ボラティリティの長期記憶性を捉えます。
ARXモデルは、標準的な自己回帰(AR)過程と外生変数(X)を組み合わせたものです。現在の値が、自身の過去値および外部変数の現在または過去の値に依存することを仮定します。ARX(p, q)モデルの一般式は以下の通りです。

スクリプトHAR_as_ARX_Demo.ex5は、ARXモデルを用いてHARモデルを模倣する方法を示します。このスクリプトは以下の手順を実装しています。
- 平均化項の数を選択可能な標準的HARモデルを構築する
- 同じ平均化項を外生入力行列として使用するARXモデルを指定する
- 両モデルのパラメータを比較し、それらの等価性を示す
//+------------------------------------------------------------------+ //| HAR_as_ARX_Demo.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<Arch\Univariate\mean.mqh> //--- input parameters input string Symbol_="AUDUSD"; input ENUM_TIMEFRAMES TimeFrame=PERIOD_D1; input datetime StartDate=D'2025.01.01'; input ulong HistoryLen = 504; input double ScaleFactor=100.; input bool MeanConstant = true; input string MeanLags ="1,5,22"; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //---download data vector prices; if(!prices.CopyRates(Symbol_,TimeFrame,COPY_RATES_CLOSE,StartDate,HistoryLen)) { Print(" failed to get close prices for ", Symbol_,". Error ", GetLastError()); return; } //--- prices = log(prices); //--- vector returns = np::diff(prices); //--- string lag_info[]; //--- vector lags=vector::Zeros(0); //--- int nlags = StringSplit(MeanLags,StringGetCharacter(",",0),lag_info); //--- double atod; if(nlags>0) { for(uint i = 0; i<uint(nlags); ++i) { if(StringLen(lag_info[i])>0) { atod = StringToDouble(lag_info[i]); if(atod>0 && ulong(atod)<returns.Size()-1) if(lags.Resize(lags.Size()+1,3)) lags[lags.Size()-1] = atod; } } } //--- if(lags.Size()) np::sort(lags); //---build the HAR model ArchParameters har_spec; har_spec.observations=returns*ScaleFactor; har_spec.include_constant = MeanConstant; har_spec.mean_lags = lags; har_spec.vol_model_type = VOL_CONST; //--- HAR harmodel; //--- if(!harmodel.initialize(har_spec)) return; //--- ArchModelResult har = harmodel.fit(ScaleFactor); //--- if(!har.params.Size()) { Print("Convergence failed ", GetLastError()); return; } //--- Print(" Har model parameters\n", har.params); //---Now we build an equivalent ARX model matrix exogvars = matrix::Zeros(returns.Size(),lags.Size()); //---calculate averages double sum; ulong lag,count; for(ulong i = 0; i<exogvars.Cols(); ++i) { lag = (ulong)lags[i]; count = lag; for(ulong k = lag; k<exogvars.Rows(); ++k) { sum = 0.0; for(ulong j = 0; j<count; ++j) sum+=returns[k-j-1]; exogvars[k,i] = sum/double(count); } } //--- ArchParameters arx_spec; arx_spec.observations = ScaleFactor*np::sliceVector(returns,long(lags[lags.Size()-1])); arx_spec.exog_data = ScaleFactor*np::sliceMatrixRows(exogvars,long(lags[lags.Size()-1])); arx_spec.include_constant = MeanConstant; arx_spec.vol_model_type=VOL_CONST; //--- ARX arxmodel; if(!arxmodel.initialize(arx_spec)) return; //--- ArchModelResult arx = arxmodel.fit(ScaleFactor); if(!arx.params.Size()) { Print(" convergence failed ", GetLastError()); return; } //--- Print("ARX model parameters\n", arx.params); } //+------------------------------------------------------------------+
スクリプトはデフォルトのパラメータで実行されました。

以下の出力は、適合されたモデルパラメータを示しています。
NR 0 22:12:43.671 HAR_as_ARX_Demo (XAUUSD,D1) Har model parameters CE 0 22:12:43.672 HAR_as_ARX_Demo (XAUUSD,D1) [-0.02336784243846212,-0.04576660950059414,0.02963893847811298,-0.1589020837643845,0.3352700836173772] RE 0 22:12:43.691 HAR_as_ARX_Demo (XAUUSD,D1) ARX model parameters HN 0 22:12:43.691 HAR_as_ARX_Demo (XAUUSD,D1) [-0.02336784243846212,-0.04576660950059416,0.02963893847811294,-0.1589020837643847,0.3352700836173772]
このデモンストレーションにより、スクリプトの出力が示すように、両手法で同一のモデルパラメータが得られることが確認されました。
結論
本記事では、MQL5におけるネイティブなボラティリティモデリングの基盤を構築しました。ArchParametersおよびArchModelResult構造体によってインターフェースを標準化することで、モデルの仕様定義、最適化、および検証を可能にするワークフローを実現しました。このフレームワークにより、モデルの初期化、データへの適合、そして残差に不均一分散が残っていないことを確認するためのARCH-LM検定などの厳密な診断チェックを一貫して実行できます。
現時点のライブラリは、いくつかの基本的なボラティリティ過程を実装していますが、誤差分布については標準正規分布を仮定する点に制限があります。次回の記事では、より高度なボラティリティ過程の実装とともに、より幅広い誤差分布への対応を追加する予定です。本記事に関連するすべてのコードは以下に示します。
| ファイル | 詳細 |
|---|---|
| MQL5/include/Arch | ボラティリティモデリングライブラリのすべてのヘッダファイルを含むフォルダ |
| MQL5/include/Regression | ボラティリティモデリングコードで使用される回帰関連ユーティリティを含むフォルダ |
| MQL5/include/np.mqh | ベクトルおよび行列操作のための各種ユーティリティを含むヘッダファイル |
| MQL5/scripts/HAR_as_ARX_Demo.mq5 | HARモデルを外生変数付きARモデルとして表現する方法を示すスクリプト |
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/20589
警告: これらの資料についてのすべての権利はMetaQuotes Ltd.が保有しています。これらの資料の全部または一部の複製や再プリントは禁じられています。
この記事はサイトのユーザーによって執筆されたものであり、著者の個人的な見解を反映しています。MetaQuotes Ltdは、提示された情報の正確性や、記載されているソリューション、戦略、または推奨事項の使用によって生じたいかなる結果についても責任を負いません。
Python-MetaTrader 5ストラテジーテスター(第2回):シミュレーターにおけるバー、ティック、組み込み関数のオーバーロード処理
MQL5でのAI搭載取引システムの構築(第8回):アニメーション、タイミング指標、応答管理ツールによるUIの改善
ラリー・ウィリアムズの『市場の秘密』(第4回):MQL5における短期的スイングハイとスイングローの自動化
ラリー・ウィリアムズの『市場の秘密』(第3回):MQL5で非ランダムな市場の動きを証明する
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索
非常に興味深いアイデアだ!
複数の時間枠のボラティリティを組み合わせる。
とても興味深いアイデアだ!
複数の時間枠のボラティリティを組み合わせる。