bvarSvForecast#

Purpose#

Generate density forecasts from a fitted SV-BVAR model with time-varying volatility propagation.

Format#

dfc = bvarSvForecast(result, h)#
dfc = bvarSvForecast(result, h, ctl)
dfc = bvarSvForecast(result, h, ctl, xreg=X_future)
Parameters:
  • result (struct) – an instance of a bvarSvResult structure returned by bvarSvFit().

  • h (scalar) – forecast horizon (number of steps ahead).

  • ctl (struct) –

    Optional input, an instance of an svForecastControl structure. An instance is initialized by calling svForecastControlCreate() and the following members can be set:

    ctl.h

    Scalar, forecast horizon. Default = 12.

    ctl.mode

    String, forecast mode.

    "mean_path"

    Deterministic h-path using posterior mean innovations. Fast but underestimates forecast variance (Jensen’s inequality). (Default)

    "simulate"

    Draw innovation paths from the SV-implied time-varying covariance. Gives proper predictive density.

    ctl.n_paths

    Scalar, number of simulation paths per posterior draw ("simulate" mode only). Default = 100.

    ctl.quantile_levels

    Vector, quantile levels to report. Default = 0.05|0.16|0.50|0.84|0.95.

    ctl.h_init

    String, log-volatility initialization for forecasting.

    "stochastic"

    Draw h_T from the reservoir. Captures h_T uncertainty. (Default)

    "posterior_mean"

    Use posterior mean h_T. Faster, underestimates tails.

    ctl.store_draws

    Scalar, 1 to store raw forecast draws in dfc.draws, 0 to discard. Default = 0.

    ctl.seed

    Scalar, RNG seed for simulation mode. Default = 42.

  • xreg (hxK matrix) – Optional keyword, future values of exogenous regressors. Required if the model was fit with xreg.

  • quiet (scalar) – Optional keyword, set to 1 to suppress printed output. Default = 0.

Returns:

dfc (struct) –

An instance of a densityForecastResult structure containing:

dfc.fc_mean

hxm matrix, mean forecast across posterior draws.

dfc.fc_median

hxm matrix, median forecast across posterior draws.

dfc.quantile_bands

Array of hxm matrices, one per quantile level. Access the i-th quantile band as dfc.quantile_bands[i].

dfc.quantile_levels

n_quantiles x 1 vector, quantile levels corresponding to each band (e.g., 0.05, 0.16, 0.50, 0.84, 0.95).

dfc.log_vol_mean

hxm matrix, mean forecast log-volatility per equation.

dfc.log_vol_median

hxm matrix, median forecast log-volatility per equation.

dfc.h

Scalar, forecast horizon.

dfc.m

Scalar, number of variables.

dfc.n_draws

Scalar, effective number of posterior draws used.

dfc.mode

String, forecast mode used: "mean_path" or "simulate".

dfc.var_names

Mx1 string array, variable names.

dfc.draws

(n_draws)x(h*m) matrix, raw forecast draws. Empty matrix unless ctl.store_draws = 1. Row layout: each row is one draw, columns ordered as h1_v1, h1_v2, …, h1_vm, h2_v1, …

Examples#

Quick Mean-Path Forecast#

new;
library timeseries;

data = loadd(getGAUSSHome("pkgs/timeseries/examples/macro.dat"));

result = bvarSvFit(data, quiet=1);

struct densityForecastResult dfc;
dfc = bvarSvForecast(result, 12);

print "Mean forecast:";
print dfc.fc_mean;

print "Median forecast:";
print dfc.fc_median;

Full Density Forecast (Simulate Mode)#

new;
library timeseries;

data = loadd(getGAUSSHome("pkgs/timeseries/examples/macro.dat"));
result = bvarSvFit(data, quiet=1);

// Simulate mode for proper predictive density
fctl = svForecastControlCreate();
fctl.mode = "simulate";
fctl.n_paths = 500;

dfc = bvarSvForecast(result, 24, fctl);

Custom Quantiles for VaR#

new;
library timeseries;

data = loadd(getGAUSSHome("pkgs/timeseries/examples/macro.dat"));
result = bvarSvFit(data, quiet=1);

fctl = svForecastControlCreate();
fctl.mode = "simulate";
fctl.n_paths = 1000;
fctl.quantile_levels = 0.01|0.05|0.10|0.50|0.90|0.95|0.99;

dfc = bvarSvForecast(result, 12, fctl);

// 1% VaR forecast (first quantile band)
var_01 = dfc.quantile_bands[1];
print "1% quantile forecast (VaR):";
print var_01;

// 5% VaR forecast (second quantile band)
var_05 = dfc.quantile_bands[2];

Forecast Log-Volatility Path#

new;
library timeseries;

data = loadd(getGAUSSHome("pkgs/timeseries/examples/macro.dat"));

ctl = bvarSvControlCreate();
ctl.p = 4;
ctl.n_draws = 10000;
ctl.n_burn = 5000;
result = bvarSvFit(data, ctl, quiet=1);

dfc = bvarSvForecast(result, 24);

// Future volatility path
print "Forecast log-volatility (mean):";
print dfc.log_vol_mean;

// Convert to standard deviations
print "Forecast std dev:";
print exp(dfc.log_vol_mean / 2);

Store Raw Draws for Custom Analysis#

new;
library timeseries;

data = loadd(getGAUSSHome("pkgs/timeseries/examples/macro.dat"));
result = bvarSvFit(data, quiet=1);

fctl = svForecastControlCreate();
fctl.mode = "simulate";
fctl.store_draws = 1;

dfc = bvarSvForecast(result, 12, fctl);

// Raw draws: each row is one draw, columns are h1_v1, h1_v2, ..., h1_vm, h2_v1, ...
print "Draw matrix:" rows(dfc.draws) "x" cols(dfc.draws);

// Extract GDP (variable 1) draws at horizon 1
m = dfc.m;
gdp_h1_draws = dfc.draws[., 1];    // First column = h1, variable 1

Remarks#

Forecast modes:

"mean_path" (default) uses the posterior mean innovation variance at each forecast horizon. This is fast but underestimates forecast uncertainty due to Jensen’s inequality — the mean of convex functions exceeds the function of the mean. Use this for quick point forecasts.

"simulate" draws n_paths innovation paths per posterior draw from the SV-implied time-varying covariance. The log-volatility \(h_{i,t}\) is propagated forward:

\[h_{i,T+s} = \mu_i + \phi_i (h_{i,T+s-1} - \mu_i) + \sigma_i \eta_{i,T+s}\]

and innovations are drawn from \(N(0, \text{diag}(\exp(h_{T+s})))\). This gives a proper predictive density that captures volatility clustering and parameter uncertainty. Required for density forecast evaluation.

h_T initialization:

"stochastic" draws the initial log-volatility \(h_T\) from the reservoir of posterior draws (when sv_keep = "online" or "full"). This captures uncertainty about the current volatility state.

"posterior_mean" uses the posterior mean \(h_T\). Faster but underestimates tail risk by ignoring \(h_T\) uncertainty.

Memory considerations:

Setting store_draws = 1 stores an (n_draws * n_paths) x (h * m) matrix. For large systems or long horizons, this can be substantial. Default is off.

Model#

The SV-BVAR density forecast accounts for three sources of uncertainty:

  1. Parameter uncertainty: different \((B^{(s)}, A^{(s)})\) draws.

  2. Volatility uncertainty: the future path of log-volatilities \(h_{T+1}, \ldots, h_{T+h}\).

  3. Innovation uncertainty: random \(\varepsilon_{T+s}\) with time-varying variance.

At each forecast horizon \(s = 1, \ldots, h\):

\[\begin{split}h_{i,T+s} &= \mu_i + \phi_i (h_{i,T+s-1} - \mu_i) + \sigma_i \eta_{i,T+s} \\ \varepsilon_{T+s} &\sim N(0, \Sigma_{T+s}) \quad \text{where } \Sigma_{T+s} = A_{T+s}^{-1} D_{T+s} A_{T+s}^{-\prime} \\ y_{T+s} &= B_1 y_{T+s-1} + \cdots + B_p y_{T+s-p} + u + \varepsilon_{T+s}\end{split}\]

The resulting predictive density is non-Gaussian and potentially fat-tailed due to volatility clustering — a key advantage over constant-variance BVAR forecasts. Algorithm ———

Simulate mode:

  1. For each posterior draw \((B^{(s)}, A^{(s)}, \mu^{(s)}, \phi^{(s)}, \sigma^{(s)}, h_T^{(s)})\):

    1. For each of n_paths simulation paths: i. Propagate log-volatilities forward: \(h_{T+1}, \ldots, h_{T+h}\). ii. Draw innovations from the time-varying covariance. iii. Iterate the VAR forward.

  2. Collect all forecast paths and compute quantiles.

Mean-path mode: Uses the posterior mean volatility at each horizon (no simulation of \(\eta\)), giving a single path per posterior draw. Faster but underestimates tail risk.

Complexity: Simulate mode: \(O(n\_draws \cdot n\_paths \cdot h \cdot m^2)\). Troubleshooting —————

Density forecasts are too narrow compared to realized outcomes: Use mode = "simulate" instead of "mean_path". The mean-path mode underestimates uncertainty by ignoring future volatility randomness.

Memory issues with large systems: Use store_draws = 0 (default) and rely on the quantile summaries. For systems with m > 10, use sv_keep = "online" in bvarSvFit().

Forecast volatility path seems unreasonable: If \(h_T\) is at an extreme value (e.g., a crisis period), forecasts may show elevated volatility for many periods. This is the model correctly reflecting persistent volatility. If the persistence \(\phi_i\) is near 1, volatility shocks take many periods to decay. Verification ————

SV-BVAR forecast density calibration verified via PIT (probability integral transform) tests on out-of-sample evaluation windows. Forecast paths validated against R bayesianVARs::predict() for structural consistency.

See the Verification and Cross-Validation page. References ———-

  • Clark, T.E. (2011). “Real-time density forecasts from Bayesian vector autoregressions with stochastic volatility.” Journal of Business & Economic Statistics, 29(3), 327-341.

  • Kastner, G. and S. Fruhwirth-Schnatter (2014). “Ancillarity-sufficiency interweaving strategy (ASIS) for boosting MCMC estimation of stochastic volatility models.” Computational Statistics & Data Analysis, 76, 408-423.

Library#

timeseries

Source#

forecast.src