Title: Regime-Switching Dynamic Correlation Models
Version: 1.1-2
Description: Estimation, forecasting, simulation, and portfolio construction for regime-switching models with exogenous variables as in Pelletier (2006) <doi:10.1016/j.jeconom.2005.01.013>.
License: GPL-3
Encoding: UTF-8
RoxygenNote: 7.3.2
URL: https://github.com/ArdiaD/RSDC
BugReports: https://github.com/ArdiaD/RSDC/issues
Imports: Rdpack (≥ 2.0), DEoptim, mvtnorm, stats, utils
Suggests: knitr, rmarkdown, testthat (≥ 3.0.0), quadprog, Rsolnp
Config/testthat/edition: 3
RdMacros: Rdpack
Depends: R (≥ 3.5)
LazyData: true
NeedsCompilation: no
Packaged: 2025-08-28 18:40:15 UTC; ardiad
Author: David Ardia ORCID iD [aut, cre], Benjamin Seguin [aut]
Maintainer: David Ardia <david.ardia.ch@gmail.com>
Repository: CRAN
Date/Publication: 2025-09-03 08:00:24 UTC

RSDC: Regime-Switching Correlation Models for Portfolio Analysis

Description

The RSDC package provides a comprehensive framework for modeling, estimating, and forecasting correlation structures in multivariate time series under regime-switching dynamics. It supports both fixed transition probabilities and time-varying transition probabilities (TVTP) driven by exogenous variables.

The methodology is particularly suited to empirical asset pricing and portfolio management applications, enabling users to incorporate macroeconomic, financial, or climate-related predictors into the regime dynamics. The package integrates the full workflow — from model estimation to covariance matrix reconstruction and portfolio optimization — in a single, reproducible pipeline.

Main Features

Authors

David Ardia and Benjamin Seguin

References

Engle RF (2002). “Dynamic conditional correlation: A simple class of multivariate generalized autoregressive conditional heteroskedasticity models.” Journal of Business & Economic Statistics, 20(3), 339–350. doi:10.1198/073500102288618487.

Hamilton JD (1989). “A New Approach to the Economic Analysis of Nonstationary Time Series and the Business Cycle.” Econometrica, 57(2), 357–384. doi:10.2307/1912559.

Pelletier D (2006). “Regime switching for dynamic correlations.” Journal of Econometrics, 131(1-2), 445–473. doi:10.1016/j.jeconom.2005.01.004.


Green vs Brown portfolio dataset

Description

Daily returns for a green and a brown portfolios constructed following the equal-weighted 10-90 percentile approach.

Usage

data(greenbrown)

Format

A data frame with 2266 rows and three columns:

DATE

Dates ranging from 2014-01-02 to 2024-12-30.

return_green

Numeric returns for the green portfolio.

return_brown

Numeric returns for the brown portfolio.

Source

Originally data in inst/extdata/green-brown-ptf.xlsx.

Examples

data("greenbrown")
str(greenbrown)
head(greenbrown)


Estimate Regime-Switching or Constant Correlation Model (Wrapper)

Description

Unified front-end that dispatches to one of three estimators:

Usage

rsdc_estimate(
  method = c("tvtp", "noX", "const"),
  residuals,
  N = 2,
  X = NULL,
  out_of_sample = FALSE,
  control = list()
)

Arguments

method

Character. One of "tvtp", "noX", "const".

residuals

Numeric matrix T \times K. Typically standardized residuals/returns.

N

Integer. Number of regimes. Ignored when method = "const".

X

Numeric matrix T \times p of exogenous covariates (required for "tvtp").

out_of_sample

Logical. If TRUE, a fixed 70/30 split is applied prior to estimation.

control

Optional list. Currently forwards do_trace = FALSE and seed = 123 to the backends.

Details

Value

transition_matrix

Estimated transition matrix (1 \times 1 for "const").

correlations

Regime lower-triangular correlations.

covariances

Array of full correlation matrices.

log_likelihood

Maximized log-likelihood.

beta

TVTP coefficients (only for "tvtp").

References

Mullen K, Ardia D, Gil D, Windover D, Ulrich J (2011). “DEoptim: An R Package for Global Optimization by Differential Evolution.” Journal of Statistical Software, 40(6), 1–26. doi:10.18637/jss.v040.i06.

Hamilton JD (1989). “A New Approach to the Economic Analysis of Nonstationary Time Series and the Business Cycle.” Econometrica, 57(2), 357–384. doi:10.2307/1912559.

Pelletier D (2006). “Regime switching for dynamic correlations.” Journal of Econometrics, 131(1-2), 445–473. doi:10.1016/j.jeconom.2005.01.004.

See Also

rsdc_hamilton and rsdc_likelihood.

Examples


y <- scale(matrix(rnorm(100 * 3), 100, 3))
rsdc_estimate("const", residuals = y)
rsdc_estimate("noX", residuals = y, N = 2)
X <- cbind(1, scale(seq_len(nrow(y))))
rsdc_estimate("tvtp", residuals = y, N = 2, X = X)



Forecast Covariance/Correlation Paths from an RSDC Model

Description

Generates per-period correlation and covariance matrices from a fitted model: "const" (constant correlation), "noX" (fixed transition matrix), or "tvtp" (time-varying transition probabilities).

Usage

rsdc_forecast(
  method = c("tvtp", "noX", "const"),
  N,
  residuals,
  X = NULL,
  final_params,
  sigma_matrix,
  value_cols,
  out_of_sample = FALSE,
  control = list()
)

Arguments

method

Character. One of "tvtp", "noX", "const".

N

Integer. Number of regimes (ignored for "const").

residuals

Numeric matrix T \times K used to compute correlations or run the filter.

X

Optional numeric matrix T \times p (required for "tvtp").

final_params

List with fitted parameters (e.g., from rsdc_estimate): must include correlations, and either transition_matrix ("noX") or beta ("tvtp"); include log_likelihood for BIC computation.

sigma_matrix

Numeric matrix T \times K of forecasted standard deviations.

value_cols

Character/integer vector of columns in sigma_matrix that define asset order.

out_of_sample

Logical. If TRUE, use a fixed 70/30 split; otherwise use the whole sample.

control

Optional list; supports threshold (in (0,1), default 0.7).

Details

Value

smoothed_probs

N \times T^\ast smoothed probabilities ("noX"/"tvtp" only).

sigma_matrix

T^\ast \times K slice aligned to the forecast horizon.

cov_matrices

List of K \times K covariance matrices \Sigma_t = D_t R_t D_t.

predicted_correlations

T^\ast \times \binom{K}{2} pairwise correlations in combn(K, 2) order.

BIC

Bayesian Information Criterion \mathrm{BIC} = \log(n)\,k - 2\,\ell.

y

T^\ast \times K residual matrix aligned to the forecast horizon.

See Also

rsdc_hamilton, rsdc_estimate, rsdc_minvar, rsdc_maxdiv

Examples

set.seed(123)
T <- 60; K <- 3; N <- 2
y <- scale(matrix(rnorm(T*K), T, K))
vols <- matrix(0.2 + 0.05*abs(sin(seq_len(T)/7)), T, K)
rho <- rbind(c(0.10, 0.05, 0.00), c(0.60, 0.40, 0.30))
Pfix <- matrix(c(0.9, 0.1, 0.2, 0.8), 2, 2, byrow = TRUE)
rsdc_forecast("noX", N, y, NULL,
              list(correlations = rho, transition_matrix = Pfix, log_likelihood = -200),
              vols, 1:K)

Hamilton Filter (Fixed P or TVTP)

Description

Runs the Hamilton (1989) filter for a multivariate regime-switching correlation model. Supports either a fixed (time-invariant) transition matrix P or time-varying transition probabilities (TVTP) built from exogenous covariates X via a logistic link. Returns filtered/smoothed regime probabilities and the log-likelihood.

Usage

rsdc_hamilton(y, X = NULL, beta = NULL, rho_matrix, K, N, P = NULL)

Arguments

y

Numeric matrix T \times K of observations (e.g., standardized residuals/returns). Columns are treated as mean-zero with unit variance; only the correlation structure is modeled.

X

Optional numeric matrix T \times p of covariates for TVTP. Required if beta is supplied.

beta

Optional numeric matrix N \times p. TVTP coefficients; row i governs persistence of regime i via plogis(X[t, ] %*% beta[i, ]).

rho_matrix

Numeric matrix N \times C of regime correlation parameters, where C = K(K-1)/2. Each row is the lower-triangular part (by lower.tri) of a regime's correlation matrix.

K

Integer. Number of observed series (columns of y).

N

Integer. Number of regimes.

P

Optional N \times N fixed transition matrix. Used only when X or beta is NULL.

Details

Value

A list with:

filtered_probs

N \times T matrix of filtered probabilities \Pr(S_t = j \mid \Omega_t).

smoothed_probs

N \times T matrix of smoothed probabilities \Pr(S_t = j \mid \Omega_T).

log_likelihood

Scalar log-likelihood of the model given y.

Note

TVTP uses a logistic link on the diagonal; off-diagonals are equal by construction.

References

Hamilton JD (1989). “A New Approach to the Economic Analysis of Nonstationary Time Series and the Business Cycle.” Econometrica, 57(2), 357–384. doi:10.2307/1912559.

See Also

rsdc_likelihood and rsdc_estimate.

Examples

set.seed(1)
T <- 50; K <- 3; N <- 2
y <- scale(matrix(rnorm(T * K), T, K), center = TRUE, scale = TRUE)

# Example rho: two regimes with different average correlations
rho <- rbind(c(0.10, 0.05, 0.00),
             c(0.60, 0.40, 0.30))  # lower-tri order for K=3

# Fixed-P filtering
Pfix <- matrix(c(0.9, 0.1,
                 0.2, 0.8), nrow = 2, byrow = TRUE)
out_fix <- rsdc_hamilton(y = y, X = NULL, beta = NULL,
                         rho_matrix = rho, K = K, N = N, P = Pfix)
str(out_fix$filtered_probs)

# TVTP filtering (include an intercept yourself)
X <- cbind(1, scale(seq_len(T)))
beta <- rbind(c(1.2, 0.0),
              c(0.8, -0.1))
out_tvtp <- rsdc_hamilton(y = y, X = X, beta = beta,
                          rho_matrix = rho, K = K, N = N)
out_tvtp$log_likelihood


Negative Log-Likelihood for Regime-Switching Correlation Models

Description

Computes the negative log-likelihood for a multivariate correlation-only regime-switching model, with either a fixed (time-invariant) transition matrix or time-varying transition probabilities (TVTP) driven by exogenous covariates. Likelihood evaluation uses the Hamilton (1989) filter.

Usage

rsdc_likelihood(params, y, exog = NULL, K, N)

Arguments

params

Numeric vector of model parameters packed as:

  • No exogenous covariates (exog = NULL): first N(N-1) transition parameters (for the fixed transition matrix), followed by N \times K(K-1)/2 correlation parameters, stacked row-wise by regime in lower.tri order.

  • With exogenous covariates (exog provided): first N \times p TVTP coefficients (beta, row i corresponds to regime i), followed by N \times K(K-1)/2 correlation parameters, stacked row-wise by regime in lower.tri order.

y

Numeric matrix T \times K of observations (e.g., standardized residuals). Columns are treated as mean-zero, unit-variance; only correlation is modeled.

exog

Optional numeric matrix T \times p of exogenous covariates. If supplied, a TVTP specification is used.

K

Integer. Number of observed series (columns of y).

N

Integer. Number of regimes.

Details

Value

Numeric scalar: the negative log-likelihood to be minimized by an optimizer.

Note

The function is written for use inside optimizers; it performs inexpensive validation and returns large penalties for invalid parameterizations instead of stopping with errors.

See Also

rsdc_hamilton (filter), optim, and DEoptim

Examples

# Small toy example (N = 2, K = 3), fixed P (no exog)
set.seed(1)
T <- 40; K <- 3; N <- 2
y <- scale(matrix(rnorm(T * K), T, K), center = TRUE, scale = TRUE)

# Pack parameters: trans (p11, p22), then rho by regime (lower-tri order)
p11 <- 0.9; p22 <- 0.8
rho1 <- c(0.10, 0.05, 0.00)  # (2,1), (3,1), (3,2)
rho2 <- c(0.60, 0.40, 0.30)
params <- c(p11, p22, rho1, rho2)

nll <- rsdc_likelihood(params, y = y, exog = NULL, K = K, N = N)
nll

# TVTP example: add X and beta (pack beta row-wise, then rho)
X <- cbind(1, scale(seq_len(T)))
beta <- rbind(c(1.2, 0.0),
              c(0.8, -0.1))
params_tvtp <- c(as.vector(t(beta)), rho1, rho2)
nll_tvtp <- rsdc_likelihood(params_tvtp, y = y, exog = X, K = K, N = N)
nll_tvtp


Maximum-Diversification Portfolio (Rolling Weights)

Description

Computes rolling maximum-diversification (MaxDiv) portfolio weights from a sequence of per-period covariance matrices implied by forecasted volatilities and correlations. Falls back to equal weights if the nonlinear solver fails.

Usage

rsdc_maxdiv(sigma_matrix, value_cols, predicted_corr, y, long_only = TRUE)

Arguments

sigma_matrix

Numeric matrix T \times K of forecasted standard deviations.

value_cols

Character/integer vector naming columns in sigma_matrix (asset order).

predicted_corr

Numeric matrix T \times \binom{K}{2} of pairwise correlations in combn(K, 2) column order.

y

Numeric matrix T \times K of asset returns (for realized stats).

long_only

Logical. If TRUE, impose w \ge 0 and \sum_i w_i = 1; otherwise bounds are -1 \le w_i \le 1 with \sum_i w_i = 1.

Details

Value

weights

T \times K matrix of weights.

returns

Vector of realized portfolio returns sum(y[t,] * weights[t,]).

diversification_ratios

Vector of realized diversification ratios.

mean_diversification

Average diversification ratio.

K

Number of assets.

assets

Asset names.

volatility

Standard deviation of realized portfolio returns.

See Also

rsdc_minvar, solnp

Examples

# Toy example with K = 3
if (requireNamespace("Rsolnp", quietly = TRUE)) {
  T <- 50; K <- 3
  set.seed(42)
  vols <- matrix(0.2 + 0.05*abs(sin(seq_len(T)/7)), T, K)
  colnames(vols) <- paste0("A", 1:K)
  # simple, stationary correlations (order: (2,1), (3,1), (3,2))
  pred_corr <- cbind(rep(0.20, T), rep(0.10, T), rep(0.05, T))
  rets <- matrix(rnorm(T*K, sd = 0.01), T, K); colnames(rets) <- colnames(vols)

  mx <- rsdc_maxdiv(sigma_matrix   = vols,
                    value_cols     = colnames(vols),
                    predicted_corr = pred_corr,
                    y              = rets,
                    long_only      = TRUE)
  head(mx$weights)
  mx$mean_diversification
}


Minimum-Variance Portfolio (Rolling Weights)

Description

Computes rolling minimum-variance (MV) portfolio weights from a sequence of per-period covariance matrices implied by forecasted volatilities and pairwise correlations. Supports long-only or unconstrained MV. If the QP solver fails at a time step, the routine falls back to equal weights.

Usage

rsdc_minvar(sigma_matrix, value_cols, predicted_corr, y, long_only = TRUE)

Arguments

sigma_matrix

Numeric matrix T \times K of forecasted volatilities (standard deviations), one column per asset.

value_cols

Character or integer vector giving the columns in sigma_matrix to use as assets (order defines the asset order).

predicted_corr

Numeric matrix T \times P of pairwise correlations, where P = \binom{K}{2} and the columns correspond to combn(K, 2) order.

y

Numeric matrix T \times K of asset returns aligned with sigma_matrix. Used only to compute the realized portfolio volatility.

long_only

Logical. If TRUE (default), imposes long-only MV with the full-investment constraint \sum_i w_i = 1 and w_i \ge 0. If FALSE, solves unconstrained MV with only \sum_i w_i = 1.

Details

Value

An object of class "minvar_portfolio":

weights

T \times K matrix of MV weights (one row per time).

cov_matrices

List of length T with the per-period K \times K covariance matrices.

volatility

Realized standard deviation of portfolio returns (see Note on units).

y

The input y matrix (coerced to T \times K).

K

Number of assets.

Note on units

The realized portfolio return at time \(t\) is computed as sum(y[t, ] * weights[t, ]) / 100. This assumes y is expressed in \ remove the / 100 in the implementation or convert inputs accordingly.

See Also

rsdc_maxdiv (maximum diversification), solve.QP

Examples

# Toy example with K = 3
T <- 50; K <- 3
set.seed(42)
vols <- matrix(0.2 + 0.05*abs(sin(seq_len(T)/7)), T, K)
colnames(vols) <- paste0("A", 1:K)
# simple, stationary correlations
pred_corr <- cbind(rep(0.20, T), rep(0.10, T), rep(0.05, T))  # order: (2,1), (3,1), (3,2)
rets <- matrix(rnorm(T*K, sd = 0.01), T, K); colnames(rets) <- colnames(vols)

mv <- rsdc_minvar(sigma_matrix  = vols,
                  value_cols    = colnames(vols),
                  predicted_corr= pred_corr,
                  y             = rets,
                  long_only     = TRUE)
head(mv$weights)
mv$volatility


Simulate Multivariate Regime-Switching Data (TVTP)

Description

Simulates a multivariate time series from a regime-switching model with time-varying transition probabilities (TVTP) driven by covariates X. Transition probabilities are generated via a multinomial logistic (softmax) link; observations are drawn from regime-specific Gaussian distributions.

Usage

rsdc_simulate(n, X, beta, mu, sigma, N, seed = NULL)

Arguments

n

Integer. Number of time steps to simulate.

X

Numeric matrix n \times p of covariates used to form the transition probabilities. Row X[t, ] corresponds to covariates available at time t. Only rows 1:(n-1) are used to transition from t-1 to t.

beta

Numeric array N \times N \times p. Softmax coefficients for the multinomial transition model; beta[i, j, ] parameterizes the transition from state i to state j.

mu

Numeric matrix N \times K. Regime-specific mean vectors.

sigma

Numeric array K \times K \times N. Regime-specific covariance (here, correlation/variance) matrices; each K \times K slice must be symmetric positive definite.

N

Integer. Number of regimes.

seed

Optional integer. If supplied, sets the RNG seed for reproducibility.

Details

Value

A list with:

states

Integer vector of length n; the simulated regime index at each time.

observations

Numeric matrix n \times K; the simulated observations.

transition_matrices

Array N \times N \times n; the transition matrix P_t used at each time step (with P_1 undefined by construction; see Details).

Note

Requires mvtnorm for multivariate normal sampling (called as mvtnorm::rmvnorm).

See Also

rsdc_hamilton (filter/evaluation), rsdc_estimate (estimators), rsdc_forecast (forecasting)

Examples

set.seed(123)
n <- 200; K <- 3; N <- 2; p <- 2
X <- cbind(1, scale(seq_len(n)))

beta <- array(0, dim = c(N, N, p))
beta[1, 1, ] <- c(1.2,  0.0)
beta[2, 2, ] <- c(1.0, -0.1)

mu <- rbind(c(0, 0, 0),
            c(0, 0, 0))
rho <- rbind(c(0.10, 0.05, 0.00),
             c(0.60, 0.40, 0.30))
Sig <- array(0, dim = c(K, K, N))
for (m in 1:N) {
  R <- diag(K); R[lower.tri(R)] <- rho[m, ]; R[upper.tri(R)] <- t(R)[upper.tri(R)]
  Sig[, , m] <- R
}
sim <- rsdc_simulate(n = n, X = X, beta = beta, mu = mu, sigma = Sig, N = N, seed = 99)