DCC-GARCH in R (rmgarch)¶
Multivariate volatility, part 2c: the package cross-check¶
This validates the from-scratch and Bayesian DCC fits with rmgarch (Ghalanos) — the industry-standard R implementation of Engle's DCC, which wraps rugarch for the univariate stage and estimates the correlation dynamics in one dccfit call. (rmgarch runs fine through the Jupyter IR kernel used to execute this notebook; the segfaults seen earlier were an artifact of launching R through a bare non-interactive Rscript, not the package.)
Data: DJIA & NASDAQ daily returns, equity_returns.csv (1993–2024) — the same series as dcc_python.ipynb.
In [1]:
.libPaths('C:/Users/user/R/win-library/4.6')
suppressMessages(library(rmgarch))
d <- read.csv('equity_returns.csv'); dates <- as.Date(d$date); R <- as.matrix(d[, c('dji', 'nasdaq')])
# stage-1 spec: GARCH(1,1)-normal, zero mean, for each series; DCC(1,1) on top
uspec <- multispec(replicate(2, ugarchspec(mean.model = list(armaOrder = c(0, 0), include.mean = FALSE),
variance.model = list(model = 'sGARCH', garchOrder = c(1, 1)),
distribution.model = 'norm')))
spec <- dccspec(uspec, dccOrder = c(1, 1), distribution = 'mvnorm')
fit <- dccfit(spec, data = R)
cf <- coef(fit); a <- cf['[Joint]dcca1']; b <- cf['[Joint]dccb1']
for (s in c('dji', 'nasdaq'))
cat(sprintf(' %-7s alpha %.4f beta %.4f persist %.3f\n', s,
cf[paste0('[', s, '].alpha1')], cf[paste0('[', s, '].beta1')],
cf[paste0('[', s, '].alpha1')] + cf[paste0('[', s, '].beta1')]))
cat(sprintf('\nDCC dynamics (rmgarch::dccfit): a %.4f b %.4f a+b %.4f\n', a, b, a + b))
cat('cross-check -> from-scratch Python a .0532 b .9391 a+b .9923; Bayesian a .042 b .953 (agree)\n')
Warning message: "package 'rmgarch' was built under R version 4.6.1"
dji alpha 0.1103 beta 0.8729 persist 0.983 nasdaq alpha 0.0978 beta 0.8911 persist 0.989 DCC dynamics (rmgarch::dccfit): a 0.0525 b 0.9400 a+b 0.9926 cross-check -> from-scratch Python a .0532 b .9391 a+b .9923; Bayesian a .042 b .953 (agree)
In [2]:
options(repr.plot.width = 12, repr.plot.height = 4.4)
rho <- rcor(fit)[1, 2, ] # DCC conditional correlation, DJIA-NASDAQ
rho_ma <- filter(rho, rep(1/21, 21)); const <- cor(R)[1, 2]
plot(dates, rho, type = 'l', col = rgb(.7,.1,.1,.30), lwd = .4, ylim = c(0.2, 1),
xlab = '', ylab = 'conditional correlation',
main = 'DCC-GARCH in R (rmgarch::dccfit): DJIA-NASDAQ correlation')
lines(dates, rho_ma, col = 'darkred', lwd = 1.4)
abline(h = const, col = 'navy', lty = 2, lwd = 1.2)
for (dt in c('2000-03-10', '2008-09-15', '2020-03-16')) abline(v = as.Date(dt), col = 'grey55', lty = 3)
legend('bottom', c('DCC rho (daily)', 'DCC rho (21-day avg)', sprintf('constant corr %.2f', const)),
col = c(rgb(.7,.1,.1,.5), 'darkred', 'navy'), lwd = c(1, 1.5, 1.2), lty = c(1, 1, 2),
bty = 'n', cex = .8, ncol = 3)
Results¶
rmgarchreproduces the from-scratch DCC. The industry-standarddccfitreturns correlation dynamics $a\approx0.05,\ b\approx0.94,\ a+b\approx0.99$ — matching the hand-written two-step engine and the NumPyro posterior — and the conditional-correlation path shows the same story: low in the late-1990s tech divergence, high in every crisis (dashed: dot-com, GFC, COVID).- Three independent engines now agree on DCC: from-scratch Python (two-step QMLE), NumPyro (full Bayesian), and R (
rmgarch::dccfit). rmgarchadds: analytic standard errors, DCC/aDCC/FDCC variants, copula-GARCH, and multi-step covariance forecasting viadccforecast— the production toolkit around the same estimator.
References¶
- Engle, R. F. (2002). Dynamic conditional correlation. JBES 20, 339–350.
- Ghalanos, A.
rmgarch: Multivariate GARCH models in R.