Diversification fails when it matters most. In a crisis, correlations jump and assets that usually offset each other start moving together.
The mathematics is in chapter three of Financial Risk Forecasting. We start with an EWMA covariance recursion, then estimate constant conditional correlation and dynamic conditional correlation, which shows what changes when correlation is held fixed and when it is allowed to move. Chapter 18 covers the GARCH estimation these models use, and R handles the multivariate fits with tsmarch (manual, vignette, GitHub).
22.1 Data and libraries
tsmarch handles the multivariate models in R. The two stock series are loaded for all three languages.
data =ProcessRawData()Return = data$Returndates = Return$date
data = ProcessRawData()Return = data['Return']
data =ProcessRawData();# Select the two assetsReturn = data["Return"][:, [:JPM, :INTC]];
22.2 EWMA
Exponentially Weighted Moving Average (EWMA) is one of the simplest approaches to multivariate volatility modelling. Unlike sample covariance which treats all observations equally, EWMA gives more weight to recent observations, making it responsive to changing market conditions.
EWMA introduces the covariance-matrix recursion that DCC builds on. It estimates the covariance matrix at time \(t\) using:
where \(\EWMAdecay\) is the decay parameter (typically 0.94) and \(\CompoundReturns_t\) is the vector of returns. The recursion assumes returns have zero mean (the RiskMetrics convention, J.P. Morgan (1994)), so the outer product of returns approximates the second moment directly, without subtracting a sample mean.
The EWMA update uses matrix multiplication to compute the covariance matrix. The main operation is the outer product of returns vectors.
For a vector of returns \(\CompoundReturns_{t-1} = [\CompoundReturns_{t-1,1}, \CompoundReturns_{t-1,2}]'\), the outer product \(\CompoundReturns_{t-1} \times \CompoundReturns_{t-1}'\) creates a matrix:
Under the zero-mean assumption this outer product is the new one-period input to the recursion. Its diagonal entries are squared returns and its off-diagonal entries are cross-products. EWMA then weights it against the previous covariance estimate.
We start with the special case of two assets to illustrate the mechanics, using JPM and Intel (INTC). The slides compare JPM and XOM instead. We use JPM and INTC throughout this notebook for consistency with the data loaded above.
Only the R tab below also plots the resulting correlation series. The Python and Julia tabs compute the same rhoEWMA series without plotting it.
Everything from here on is R only. We standardise multivariate estimation on tsmarch, because Python’s arch has no multivariate models at all and Julia’s ARCHModels.jl, which does offer DCC, would put a third parameterisation in play for no gain. If you work in Python or Julia, the route to these models is R through rpy2 or RCall.
The attraction is simple. Estimate each volatility on its own, then model how the assets move together. The CCC and DCC models separate volatility modelling into two stages:
Univariate stage: Each asset follows its own GARCH process for volatility;
Correlation stage: the co-movement between assets is estimated from the standardised residuals, held constant in CCC and time-varying in DCC.
Splitting the problem this way is what makes it tractable. A joint estimation would search over the volatility and correlation parameters of every asset at once, while the two-stage version estimates each asset separately and then fits only the correlation parameters.
22.3.1 Constant Conditional Correlation (CCC)
The Constant Conditional Correlation (CCC) model assumes that whilst individual asset volatilities change over time, the correlations between assets remain constant.
In CCC models:
Each asset follows its own univariate GARCH process for volatility;
Correlations are estimated once and held constant over time;
The covariance matrix at time \(t\) is \(\CovMatrix_t = \DiagVolD_t \CorrMatrix \DiagVolD_t\).
Here \(\DiagVolD_t\) is a diagonal matrix of conditional standard deviations and \(\CorrMatrix\) is the constant correlation matrix.
CCC is the benchmark for whether dynamic correlations improve on constant ones. If correlations are genuinely constant, CCC should perform as well as more complex models.
22.3.2 Dynamic Conditional Correlation (DCC)
DCC relaxes the most restrictive part of CCC — constant correlation. Each asset still follows its own GARCH process, but the correlations can move through time.
22.4 CCC estimation
The CCC model is straightforward to implement. Estimate univariate GARCH models for each asset, extract the standardised residuals and compute their sample correlation matrix. This constant correlation matrix combines with the time-varying GARCH volatilities to give the model’s conditional covariance matrix.
y_xts =xts(Return[, c("JPM", "INTC")], order.by = dates)# Estimate univariate GARCH(1,1) models for each assetccc_garch =lapply(1:ncol(y_xts), function(i) { spec =garch_modelspec(y_xts[, i], model ="garch", order =c(1, 1), constant =TRUE)estimate(spec)})# Extract standardised residualsresid_ccc =sapply(ccc_garch, function(m) as.numeric(residuals(m, standardize =TRUE)))# Constant correlation matrix from standardised residualsR_ccc =cor(resid_ccc)R_ccc
The DCC model extends CCC by allowing the correlation matrix to evolve over time. The estimation proceeds in two stages.
Estimate univariate GARCH models for each asset to obtain the standardised residuals \(\StdNormal_{t,i} = \CompoundReturns_{t,i} / \Vol_{t,i}\).
Estimate \(\DCCzeta\) and \(\DCCxi\) by maximising the correlation component of the Gaussian log-likelihood over the standardised residuals.
The second stage models an auxiliary matrix \(\DCCauxQ_t\), initialised at the constant correlation matrix from CCC, \(\DCCauxQ_1 = \CorrMatrix\), and updated for \(t > 1\) by
where \(\DCCzeta\) is the weight on the most recent shock and \(\DCCxi\) is the weight on the previous value of \(\DCCauxQ_t\). For \(\DCCauxQ_t\) to stay positive semidefinite, \(\DCCzeta, \DCCxi \geq 0\) and \(\DCCzeta + \DCCxi < 1\).
\(\DCCauxQ_t\) is positive semidefinite but its diagonal is not one, so it is not itself a valid correlation matrix. Rescaling with the diagonal matrix \(\DCCrescaleZ_t\), whose entries are \(1/\sqrt{\DCCelement_{t,ii}}\) for the diagonal elements \(\DCCelement_{t,ii}\) of \(\DCCauxQ_t\), gives the correlation matrix
tsmarch estimates \(\DCCzeta\) and \(\DCCxi\) under the internal names alpha_1 and beta_1, shown by summary(dcc_res) below.
The package tsmarch estimates multivariate volatility models using the same approach as tsgarch for univariate models. Unlike the older rmgarch package which uses S4 methods, tsmarch uses S3 methods for a cleaner interface.
In tsmarch, fit the univariate GARCH models with keep_tmb = TRUE. The second stage needs the retained TMB object:
# Estimate univariate GARCH models for each assetgarch_models =lapply(1:ncol(y_xts), function(i) { spec =garch_modelspec(y_xts[, i], model ="garch", order =c(1, 1), constant =TRUE)estimate(spec, keep_tmb =TRUE)})names(garch_models) =colnames(y_xts)
Combine the univariate models into a multi-estimate object:
multi_garch =to_multi_estimate(garch_models)
Create the DCC specification. The dynamics parameter selects dynamic correlation over the constant-correlation default, the dcc_order parameter specifies the order of the DCC process (analogous to GARCH orders) and distribution specifies the multivariate distribution:
Attaching package: ‘data.table’
The following objects are masked from ‘package:xts’:
first, last
The following objects are masked from ‘package:reshape2’:
dcast, melt
The following objects are masked from ‘package:zoo’:
yearmon, yearqtr
The following objects are masked from ‘package:lubridate’:
hour, isoweek, mday, minute, month, quarter, second, wday, week,
yday, year
The fitted \(\DCCzeta\) (alpha_1) is 0.033 and \(\DCCxi\) (beta_1) is 0.809, well inside the \(\DCCzeta + \DCCxi < 1\) stability constraint, so correlations revert only slowly towards their long-run average.
Extract the conditional covariances using tscov(). The result is a 3-dimensional array where the first two dimensions are the covariance matrix and the third is time:
# Get the conditional covariance matricesH =tscov(dcc_res)dim(H)
par(mar =c(2, 4, 2, 0))matplot(cbind(rhoEWMA, rhoDCC),type ='l',bty ='l',lty =1,col =c("green", "blue"),main ="EWMA and DCC correlations for JPM and INTC",ylab ="Correlations",las =1)legend("bottomright",legend =c("EWMA", "DCC"),lty =1,col =c("green", "blue"),bty ='n')
The two series track each other but not closely. EWMA and DCC both raise correlation in turbulent periods and lower it in calm ones, which is the behaviour neither a sample correlation nor CCC can produce. Where they part company is speed and level. EWMA has one fixed decay applied to everything, while DCC estimates how fast correlation reverts and to what long-run value, so it pulls back towards that level after a shock instead of drifting wherever the recent data leave it.
Which to use is not settled by this plot. DCC is the richer model and costs an estimation step that can fail on a large cross-section, and the restrictions set out above apply to every pair at once. EWMA has no parameters to estimate and no way to be wrong about mean reversion, because it makes no claim about it. Chapter 24 puts both into a portfolio VaR calculation, where the difference between them becomes a number rather than a picture.
22.7 Exercise
Extend the CCC and DCC models above to three or more assets and compare the resulting portfolio VaR estimates. Consider how the choice of correlation model affects diversification benefits.