dcvar: Dynamic Copula VAR Models for Time-Varying Dependence

dcvar logo

R-CMD-check Lifecycle: experimental License: GPL v3+

dcvar fits Bayesian copula vector autoregressions of order one for bivariate time series. The modelling idea is to keep two questions separate: how each series is distributed on its own, and how the two series move together. A copula carries the dependence, so each margin may follow its own distribution while a single association parameter describes how the series are coupled at a given time.

The conditional mean follows a first-order vector autoregression, so each series depends on the recent past of both. The innovations are joined by a Gaussian copula, with a Clayton copula also available for the constant baseline. The association can be held constant, allowed to drift smoothly as a random walk, allowed to switch between latent regimes, or expressed as a function of covariates. In the dynamic model the autoregressive coefficients and the innovation scales may vary over time as well; in the HMM model, the regime can also govern the intercepts, autoregressive coefficients, innovation scales, and marginal families. Everything is estimated in a fully Bayesian way through Stan, which returns posterior distributions for all quantities.

Two further families, a multilevel version for panel data and a structural-equation version for latent processes, are provided as experimental extensions.

Installation

dcvar uses rstan as its default backend.

Install dcvar from CRAN:

install.packages("dcvar")

For the development version:

install.packages("remotes")
remotes::install_github("benlug/dcvar")

Optionally, you can use cmdstanr as an alternative backend:

install.packages(
  "cmdstanr",
  repos = c("https://stan-dev.r-universe.dev", getOption("repos"))
)
cmdstanr::install_cmdstan()

For skew-normal margins, install sn:

install.packages("sn")

Example

The example below simulates a bivariate series whose association declines over time, fits the dynamic copula model, and compares it with the regime-switching and constant-association alternatives by cross-validation.

library(dcvar)

# simulate data with decreasing coupling
sim <- simulate_dcvar(
  n_time = 150,
  rho_trajectory = rho_decreasing(150, rho_start = 0.7, rho_end = 0.3)
)

# fit the DC-VAR model
fit <- dcvar(sim$Y_df, vars = c("y1", "y2"))

# inspect results
summary(fit)
plot_rho(fit, true_rho = sim$true_params$rho)

# compare models via leave-one-out cross-validation
fit_hmm <- dcvar_hmm(sim$Y_df, vars = c("y1", "y2"), K = 2)
fit_con <- dcvar_constant(sim$Y_df, vars = c("y1", "y2"))
dcvar_compare(dcvar = fit, hmm = fit_hmm, constant = fit_con)

Models

The core models differ in how dependence, marginal distributions, and the vector-autoregressive mean are allowed to change over time.

Model Function Association over time Status
DC-VAR dcvar() Drifts smoothly as a random walk on the Fisher z scale; the autoregressive coefficients and innovation scales may also drift Core
HMM Copula dcvar_hmm() Switches between K latent regimes Core
Constant Copula dcvar_constant() Held constant (Gaussian or Clayton) Core
Covariate DC-VAR dcvar_covariate() A function of observed covariates on the Fisher z scale Core
Multilevel dcvar_multilevel() Series-specific autoregressive coefficients across many units Experimental
SEM dcvar_sem() Latent processes measured by observed indicators Experimental

Because the copula keeps the margins separate from the dependence, every model accepts per-variable margins. Pass a length-two vector such as margins = c("normal", "exponential") to let each series follow a different marginal family. The single-level models dcvar(), dcvar_hmm(), and dcvar_constant() with a Gaussian copula support all four families (normal, exponential, skew-normal, and gamma), used on their own or in combination. dcvar_multilevel() and dcvar_sem() support all four families as a single family or in combination. dcvar_constant(copula = "clayton") provides a Clayton-copula baseline with normal or mixed margins.

In dcvar(), the association always evolves over time. Setting tv_phi = TRUE additionally lets the autoregressive coefficients drift as random walks, and tv_sigma = TRUE lets the innovation scales drift. tv_phi also accepts "ar" or "cross" to let only the autoregressive or only the cross-lagged coefficients vary. With both options off, the model reduces to the constant-coefficient dynamic copula.

In dcvar_hmm(), switch = "rho" gives the classic regime-switching copula model, where only the copula correlation changes by latent state. Passing components such as switch = c("rho", "mu", "phi", "sigma") fits a fuller Markov-switching VAR(1). The HMM can also use state-specific marginal families by passing a length-K list to margins; hmm_state_params() extracts the effective state-specific intercepts, VAR matrices, scale parameters, and families.

Estimation and checks

Fitted and one-step-ahead predicted values are available for every fitted model. For multilevel fits these are specific to each unit; for structural-equation fits they cover both the latent states (type = "link") and the observed indicators (type = "response").

Leave-one-out cross-validation through loo() is available for the single-level fits, the covariate fits, the multilevel fits, and the naive structural-equation score fits, and dcvar_compare() places several fits on a common predictive scale. Comparisons that mix model families whose pointwise predictive densities are not on the same footing are flagged with a warning.

Residual checks based on the probability integral transform, pit_values() and pit_test(), are provided for the single-level models. They use posterior means and are best read as heuristic checks rather than exact calibration tests. Posterior predictive checks through plot_ppc() are available for normal and exponential margins; gamma and skew-normal fits do not yet store replicated residuals on the observed margin scale.

The package also includes a constant Clayton-copula baseline, a multilevel model with exponential margins, and naive structural-equation score models that were used in the accompanying simulation studies.

Documentation

Citation

If you use dcvar in your work, cite it with:

citation("dcvar")

Getting Help