require(copula)
require(rugarch)
In this vignette, we demonstrate the copula GARCH approach (in general). Note that a special case (with normal or student \(t\) residuals) is also available in the rmgarch
package (thanks to Alexios Ghalanos for pointing this out).
First, we simulate the innovation distribution. Note that, for demonstration purposes, we choose a small sample size. Ideally, the sample size should be larger to capture GARCH effects.
## Simulate innovations
200 # sample size
n <- 2 # dimension
d <- 3 # degrees of freedom for t
nu <- 0.5 # Kendall's tau
tau <- iTau(ellipCopula("t", df = nu), tau) # corresponding parameter
th <- ellipCopula("t", param = th, dim = d, df = nu) # define copula object
cop <-set.seed(271) # reproducibility
rCopula(n, cop) # sample the copula
U <- 3.5 # degrees of freedom for the t margins
nu. <- sqrt((nu.-2)/nu.) * qt(U, df = nu.) # margins must have mean 0 and variance 1 for ugarchpath()! Z <-
Now we simulate two ARMA(1,1)-GARCH(1,1) processes with these copula-dependent innovations. To this end, recall that an ARMA(\(p_1\),\(q_1\))-GARCH(\(p_2\),\(q_2\)) model is given by \[\begin{align} X_t &= \mu_t + \epsilon_t\ \text{for}\ \epsilon_t = \sigma_t Z_t,\\ \mu_t &= \mu + \sum_{k=1}^{p_1} \phi_k (X_{t-k}-\mu) + \sum_{k=1}^{q_1} \theta_k \epsilon_{t-k},\\ \sigma_t^2 &= \alpha_0 + \sum_{k=1}^{p_2} \alpha_k (X_{t-k}-\mu_{t-k})^2 + \sum_{k=1}^{q_2} \beta_k \sigma_{t-k}^2. \end{align}\]
## Fix parameters for the marginal models
list(mu = 1,
fixed.p <-ar1 = 0.5,
ma1 = 0.3,
omega = 2, # alpha_0 (conditional variance intercept)
alpha1 = 0.4,
beta1 = 0.2)
list(armaOrder = c(1,1))
meanModel <- list(model = "sGARCH", garchOrder = c(1,1)) # standard GARCH
varModel <- ugarchspec(varModel, mean.model = meanModel,
uspec <-fixed.pars = fixed.p) # conditional innovation density (or use, e.g., "std")
## Simulate ARMA-GARCH models using the dependent innovations
## Note: ugarchpath(): simulate from a spec; ugarchsim(): simulate from a fitted object
ugarchpath(uspec,
X <-n.sim = n, # simulated path length
m.sim = d, # number of paths to simulate
custom.dist = list(name = "sample", distfit = Z)) # passing (n, d)-matrix of *standardized* innovations
## Extract the resulting series
fitted(X) # X_t = mu_t + eps_t (simulated process)
X. <- sigma(X) # sigma_t (conditional standard deviations)
sig.X <- X@path$residSim # epsilon_t = sigma_t * Z_t (residuals)
eps.X <-
## Basic sanity checks :
stopifnot(all.equal(X., X@path$seriesSim, check.attributes = FALSE),
all.equal(sig.X, X@path$sigmaSim, check.attributes = FALSE),
all.equal(eps.X, sig.X * Z, check.attributes = FALSE))
## Plot (X_t) for each margin
matplot(X., type = "l", xlab = "t", ylab = expression(X[t]~"for each margin"))
We now show how to fit an ARMA(1,1)-GARCH(1,1) process to X
(we remove the argument fixed.pars
from the above specification for estimating these parameters):
ugarchspec(varModel, mean.model = meanModel, distribution.model = "std")
uspec <- apply(X., 2, function(x) ugarchfit(uspec, data = x)) fit <-
Check the (standardized) Z
, i.e., the pseudo-observations of the residuals Z
:
sapply(fit, residuals, standardize = TRUE)
Z. <- pobs(Z.)
U. <-par(pty = "s")
plot(U., xlab = expression(hat(U)[1]), ylab = expression(hat(U)[2]))
Fit a \(t\) copula to the standardized residuals Z
. For the marginals, we also assume \(t\) distributions but with different degrees of freedom; for simplicity, the estimation is omitted here.
fitCopula(ellipCopula("t", dim = 2), data = U., method = "mpl") fitcop <-
## Warning in var.mpl(copula, u): the covariance matrix of the parameter estimates
## is computed as if 'df.fixed = TRUE' with df = 2.31167999431156
rep(nu., d) # marginal degrees of freedom; for simplicity using the known ones here
nu. <- cbind(fitted = c(fitcop@estimate, nu.), true = c(th, nu, nu.)) # fitted vs true
est <-rownames(est) <- c("theta", "nu (copula)", paste0("nu (margin ",1:2,")"))
est
## fitted true
## theta 0.6724203 0.7071068
## nu (copula) 2.3116800 3.0000000
## nu (margin 1) 3.5000000 3.5000000
## nu (margin 2) 3.5000000 3.5000000
Simulate from the fitted copula model.
set.seed(271) # reproducibility
rCopula(n, fitcop@copula)
U.. <- sapply(1:d, function(j) sqrt((nu.[j]-2)/nu.[j]) * qt(U..[,j], df = nu.[j]))
Z.. <-## => Innovations have to be standardized for ugarchsim()
lapply(1:d, function(j)
sim <-ugarchsim(fit[[j]], n.sim = n, m.sim = 1,
custom.dist = list(name = "sample",
distfit = Z..[,j, drop = FALSE])))
and plot the resulting series (\(X_t\)) for each margin
sapply(sim, function(x) fitted(x)) # simulated series X_t (= x@simulation$seriesSim)
X.. <-matplot(X.., type = "l", xlab = "t", ylab = expression(X[t]))