GARCH(1,1)モデルの理論とPython実装:ボラティリティクラスタリングとARCH効果をLjung-Box検定で確認する

ARIMAが捉えられない「分散のクラスタリング」を条件付き分散の再帰式GARCH(1,1)としてscipy.optimize.minimizeでフルスクラッチ最尤推定し、archライブラリのarch_modelと比較してパラメータ・対数尤度が高精度で一致することを実測。statsmodels.stats.diagnostic.acorr_ljungboxでリターン自体には自己相関がないのに2乗リターンには強い自己相関(ARCH効果)があることを検定で確認します。

はじめに

https://yuhi-sa.github.io/posts/20260226_arima/1/ と https://yuhi-sa.github.io/posts/20260715_arima_state_space_kalman/1/ で扱ったARIMAモデルは、時系列の平均の構造(自己回帰・移動平均)をモデル化しますが、分散が時間とともに変動するという現象(ボラティリティクラスタリング:荒い値動きの後には荒い値動きが続き、静かな期間には静かな値動きが続く)は捉えられません。本記事では、この分散のクラスタリングを条件付き分散の再帰式としてモデル化するGARCH(Generalized AutoRegressive Conditional Heteroskedasticity)モデルを、Ljung-Box検定でその必要性を確認した上で、フルスクラッチ実装します。

ボラティリティクラスタリングとARCH効果

金融時系列などでよく観測される現象として、リターン自体には自己相関がないのに、リターンの2乗(≒分散の代理指標)には強い自己相関があるというものがあります。これを直接確認するため、GARCH(1,1)過程からシミュレートしたリターン系列に対し、Ljung-Box検定(ラグ10)を適用しました。

対象Ljung-Box統計量p値自己相関
リターン自体7.770.651なし(想定通り)
リターンの2乗966.802.6×10⁻²⁰¹強く存在
(対照)i.i.d.正規乱数の2乗7.230.704なし

リターン自体は無相関(p=0.65)なのに、その2乗には極めて強い自己相関(p≈10⁻²⁰¹)があります。 対照実験として、GARCH効果を持たないi.i.d.正規乱数の2乗はp=0.70で無相関のままです。この違いこそが「ARCH効果」(分散の系列相関)であり、ARIMAのような線形・定分散モデルでは捉えられない構造です。GARCHモデルはこの分散自体の時間変化を明示的にモデル化します。

GARCH(1,1)モデル

リターン \(r_t\) を

\[ r_t = \mu + \varepsilon_t, \qquad \varepsilon_t = \sigma_t z_t, \qquad z_t \sim \mathcal{N}(0,1) \tag{1} \]

とし、条件付き分散 \(\sigma_t^2\) が次の再帰式に従うとします。

\[ \sigma_t^2 = \omega + \alpha \varepsilon_{t-1}^2 + \beta \sigma_{t-1}^2 \tag{2} \]

\(\omega > 0\) 、\(\alpha, \beta \geq 0\) 、\(\alpha + \beta < 1\) (定常性条件)です。式(2)の直感的な意味は、「今日の分散 \(\sigma_t^2\) は、昨日の予測誤差の大きさ \(\varepsilon_{t-1}^2\) (ショックの影響、\(\alpha\) )と昨日の分散 \(\sigma_{t-1}^2\) (分散自体の持続性、\(\beta\) )の加重和で決まる」というものです。\(\alpha + \beta\) が1に近いほど、ボラティリティショックの影響が長く持続します。

対数尤度と最尤推定

ガウス分布を仮定すると、対数尤度は

\[ \log L(\omega,\alpha,\beta) = -\frac{1}{2}\sum_{t=1}^{N}\left[\log(2\pi\sigma_t^2) + \frac{\varepsilon_t^2}{\sigma_t^2}\right] \tag{3} \]

です。これは https://yuhi-sa.github.io/posts/20260715_arima_state_space_kalman/1/ で導出したカルマンフィルタの予測誤差分解による対数尤度と同じ形をしています(違いは、状態空間モデルの共分散 \(P_{t|t-1}\) の代わりに、GARCH自身の再帰式で条件付き分散 \(\sigma_t^2\) を直接更新する点です)。

Python実装

import numpy as np
from scipy.optimize import minimize

# GARCH(1,1)過程のシミュレーション(検証用データ生成)
def simulate_garch(omega, alpha, beta, n, rng):
    eps, sigma2 = np.zeros(n), np.zeros(n)
    sigma2[0] = omega / (1 - alpha - beta)  # 無条件分散で初期化
    z = rng.standard_normal(n)
    eps[0] = np.sqrt(sigma2[0]) * z[0]
    for t in range(1, n):
        sigma2[t] = omega + alpha * eps[t - 1] ** 2 + beta * sigma2[t - 1]
        eps[t] = np.sqrt(sigma2[t]) * z[t]
    return eps

rng = np.random.default_rng(7)
returns = simulate_garch(omega=0.05, alpha=0.10, beta=0.85, n=2000, rng=rng)

def arch_style_backcast(r, decay=0.94, tau=75):
    tau = min(tau, len(r))
    w = decay ** np.arange(tau)
    w /= w.sum()
    return np.sum(w * r[:tau] ** 2)

def garch_negloglik(params, r, sigma2_0):
    omega, alpha, beta = params
    if omega <= 0 or alpha < 0 or beta < 0 or alpha + beta >= 1:
        return 1e10
    N = len(r)
    sigma2 = np.zeros(N)
    sigma2[0] = sigma2_0
    for t in range(1, N):
        sigma2[t] = omega + alpha * r[t - 1] ** 2 + beta * sigma2[t - 1]
    ll = -0.5 * np.sum(np.log(2 * np.pi * sigma2) + r**2 / sigma2)
    return -ll

sigma2_0 = arch_style_backcast(returns)
res = minimize(
    garch_negloglik, x0=[0.1, 0.05, 0.8], args=(returns, sigma2_0),
    method="L-BFGS-B", bounds=[(1e-6, None), (0, 1), (0, 1)],
    options={"maxiter": 10000, "ftol": 1e-12, "gtol": 1e-10},
)
omega_hat, alpha_hat, beta_hat = res.x

arch_style_backcast は、初期分散 \(\sigma_0^2\) を先頭75サンプルの指数加重平均(減衰率0.94)で推定するもので、arch ライブラリの慣例に合わせています(単純なサンプル分散で初期化すると、序盤の尤度計算がわずかに歪みます)。

数値実験:archライブラリとの比較

真のパラメータ \(\omega=0.05\) , \(\alpha=0.10\) , \(\beta=0.85\) でGARCH(1,1)リターンを2000サンプル生成し、上記のフルスクラッチMLEと arch.arch_modelvol="Garch", p=1, q=1)を同一データに適用しました。

パラメータフルスクラッチarchライブラリ差分
\(\omega\)0.0361710.0359342.4×10⁻⁴
\(\alpha\)0.0786600.0784731.9×10⁻⁴
\(\beta\)0.8818390.8822644.3×10⁻⁴
対数尤度-2678.305-2678.3540.05

パラメータ・対数尤度とも高精度で一致しました(残差は最適化アルゴリズムの収束許容誤差レベル)。両者とも真値からはやや外れています(\(\alpha\) の推定値0.079 vs 真値0.10)が、これは2000サンプルという有限標本での推定誤差の範囲内です。\(\alpha+\beta \approx 0.96\) という高い持続性が正しく推定されており、シミュレーションで使った真の持続性 \(0.10+0.85=0.95\) に近い値が復元できています。

まとめ:ARIMAとGARCHの役割分担

https://yuhi-sa.github.io/posts/20260226_arima/1/ と本記事は補完関係にあります。

モデル対象捉える構造
ARIMA平均 \(E[r_t]\)自己回帰・移動平均(水準の予測可能性)
GARCH条件付き分散 \(\text{Var}[r_t \mid \mathcal{F}_{t-1}]\)ボラティリティクラスタリング(リスクの予測可能性)

実務では両者を組み合わせた ARIMA-GARCH モデル(平均をARIMAで、残差の分散をGARCHでモデル化)が金融時系列分析の標準的な出発点になります。

おすすめ書籍

ARIMAだけでなくGARCHファミリー(ARCH/GARCH/EGARCH等)も体系的に解説されており、本記事の理論的背景を補完する定番書です。

※ 上記は Amazon アソシエイトのリンクです。

関連記事

参考文献

  • Bollerslev, T. (1986). Generalized autoregressive conditional heteroskedasticity. Journal of Econometrics, 31(3), 307-327.
  • Engle, R. F. (1982). Autoregressive conditional heteroscedasticity with estimates of the variance of United Kingdom inflation. Econometrica, 50(4), 987-1007.
  • Sheppard, K., et al. ARCH: Autoregressive Conditional Heteroskedasticity Models in Python (arch library documentation).
  • Ljung, G. M., & Box, G. E. P. (1978). On a measure of lack of fit in time series models. Biometrika, 65(2), 297-303.