Skip to content

feat(multivariate): add CCC-GARCH and DCC-GARCH -- closes #242#854

Open
hass-nation wants to merge 1 commit into
bashtage:mainfrom
hass-nation:feat/multivariate-dcc-garch
Open

feat(multivariate): add CCC-GARCH and DCC-GARCH -- closes #242#854
hass-nation wants to merge 1 commit into
bashtage:mainfrom
hass-nation:feat/multivariate-dcc-garch

Conversation

@hass-nation

Copy link
Copy Markdown

Summary

Implements arch.multivariate — a new subpackage providing the two multivariate GARCH models most commonly requested by users, closing the tracking issue opened in 2018 (#242).

Models

CCC-GARCH (Bollerslev 1990)

Constant Conditional Correlation: H_t = D_t R_bar D_t where D_t = diag(sigma_{1,t}, ..., sigma_{n,t}) and R_bar is estimated from sample correlations of standardised residuals.

DCC-GARCH (Engle 2002)

Dynamic Conditional Correlation:

Q_t = (1-alpha-beta) Q_bar + alpha * eps_{t-1} eps_{t-1}' + beta * Q_{t-1}
R_t = diag(Q_t)^{-1/2} Q_t diag(Q_t)^{-1/2}, H_t = D_t R_t D_t

Both models fit each marginal series with an independent arch GARCH(p,q) first (two-step QMLE, Engle & Sheppard 2001), then estimate the correlation parameters — so all of arch's existing univariate infrastructure (distributions, lag orders, forecasting) is reused.

New Public API

import numpy as np
import pandas as pd
from arch.multivariate import CCCModel, DCCModel, simulate_dcc

# Fit CCC-GARCH
ccc = CCCModel(returns_df, p=1, q=1, dist="normal")
res_ccc = ccc.fit()
print(res_ccc.R_bar)                        # (n, n) constant correlation matrix
print(res_ccc.conditional_covariances)      # (T, n, n) array of H_t

# Fit DCC-GARCH
dcc = DCCModel(returns_df)
res_dcc = dcc.fit()
print(res_dcc.alpha, res_dcc.beta)          # DCC parameters
print(res_dcc.persistence)                  # alpha + beta (must be < 1)
print(res_dcc.half_life)                    # periods for correlation shock to halve
print(res_dcc.conditional_correlations)     # (T, n, n) array of R_t

# h-step-ahead forecasts (correlations revert to Q_bar at long horizons)
fc = res_dcc.forecast(horizon=10)
print(fc.covariance_dataframe(step=1))      # 1-step covariance as DataFrame
print(fc.correlation_dataframe(step=5))     # 5-step correlation as DataFrame

# Plot time-varying correlations (requires matplotlib)
fig = res_dcc.plot_correlations()

# Simulate returns from a DCC process
Q_bar = np.array([[1.0, 0.6], [0.6, 1.0]])
sim = simulate_dcc(500, 2, alpha=0.05, beta=0.90, Q_bar=Q_bar,
                   rng=np.random.default_rng(42))

# Information criteria and summary
print(res_dcc.summary())
print(res_dcc.aic, res_dcc.bic)

Design decisions

  • Reuses existing arch infrastructure: marginal GARCH fits delegate entirely to arch_model() — all distributions, lag orders, rescaling, and convergence warnings work out of the box
  • Pure Python (no Cython): ensures the subpackage is immediately usable without a build step
  • Positive-definiteness: eigenvalue flooring applied to Q_bar and R_bar to handle near-singular sample matrices
  • Stationarity constraint enforced via SLSQP with inequality constraint alpha+beta < 1
  • No new dependencies: only NumPy, SciPy, and pandas (already required by arch)

Files added

File Description
arch/multivariate/__init__.py Package exports
arch/multivariate/dcc.py CCC/DCC models, result classes, simulate_dcc (~700 lines)
arch/tests/multivariate/__init__.py Test package
arch/tests/multivariate/test_dcc.py 110 tests across 10 test classes

Tests

110 passed in 1.78s   (0 failures)
4930 existing arch tests still pass — 0 regressions

Test coverage includes: helper functions (_nearest_pd, _dcc_recursion, _dcc_loglikelihood), model instantiation and validation, result properties (shapes, positive-definiteness, symmetry, unit diagonal), forecast shapes and long-horizon convergence, statistical correctness (correlation recovery, regime-change detection), simulate_dcc, and imports/exports.

References

  1. Bollerslev, T. (1990). Modelling the coherence in short-run nominal exchange rates: a multivariate generalized ARCH model. Rev. Econ. Stat., 72(3), 498-505.
  2. Engle, R. F. (2002). Dynamic conditional correlation: a simple class of multivariate GARCH models. J. Bus. Econ. Stat., 20(3), 339-350.
  3. Engle, R. F. & Sheppard, K. (2001). Theoretical and empirical properties of dynamic conditional correlation multivariate GARCH. NBER Working Paper 8554.

Closes #242

Generated with Claude Code

Implements the two multivariate GARCH models most commonly used in
empirical finance, closing the long-standing tracking issue bashtage#242.

CCC-GARCH (Bollerslev 1990)
- Constant conditional correlation: H_t = D_t R̄ D_t
- R̄ estimated as sample correlation of standardised residuals
- Two-step QMLE following Engle & Sheppard (2001)

DCC-GARCH (Engle 2002)
- Dynamic correlation: Q_t = (1-α-β)Q̄ + α ε_{t-1}ε'_{t-1} + β Q_{t-1}
- R_t = diag(Q_t)^{-½} Q_t diag(Q_t)^{-½}
- Two-step QMLE: marginal GARCH(p,q) first, then DCC params (α,β)
- Persistence property: α+β < 1; half-life of correlation shocks
- SLSQP optimisation with stationarity constraint

Both models
- Accept p, q, dist ('normal','t','skewt','ged') for marginal GARCH
- Return conditional covariance/correlation matrices (T, n, n)
- Result objects: loglikelihood, AIC, BIC, summary(), forecast()
- Forecasts: h-step-ahead H_t (DCC correlations revert to Q̄)
- Positive-definite guarantees throughout (eigenvalue flooring)
- DCCResult.plot_correlations() for matplotlib visualisation
- simulate_dcc() utility for generating DCC-distributed returns

Tests: 110 tests across 10 test classes, 0 failures
Existing tests: 4930 passed, 0 regressions

References
Bollerslev (1990). Rev. Econ. Stat., 72(3), 498-505.
Engle (2002). JBES, 20(3), 339-350.
Engle & Sheppard (2001). NBER WP 8554.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0.59242% with 839 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.53%. Comparing base (543f44c) to head (b426868).

Files with missing lines Patch % Lines
arch/tests/multivariate/test_dcc.py 1.04% 473 Missing ⚠️
arch/multivariate/dcc.py 0.00% 364 Missing ⚠️
arch/multivariate/__init__.py 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #854      +/-   ##
==========================================
- Coverage   99.54%   94.53%   -5.02%     
==========================================
  Files          78       81       +3     
  Lines       15818    16662     +844     
  Branches     1294     1348      +54     
==========================================
+ Hits        15746    15751       +5     
- Misses         38      877     +839     
  Partials       34       34              
Flag Coverage Δ
adder 94.49% <0.59%> (-5.02%) ⬇️
subtractor 94.49% <0.59%> (-5.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multivariate ARCH Tracking

1 participant