*! version 1.0.1 21aug2026

Title

gvar bforecast -- predictive density over the retained draws

Syntax

gvar bforecast , variables(spec) [options]

options

variables(spec) the elements to forecast, as unit:variable. Required.

step(#) horizons. Default 8.

bands(numlist) coverage percentages. Default 68 90.

graph fan chart, one panel per variable.

fan shade every band rather than the outermost only.

name(name) graph name.

saving(name) save the table as a dataset.

nosummary suppress the report.

gvar bayes and gvar solve must have run
first.

Description

gvar bforecast forecasts by stacking and solving every retained draw
separately, so the resulting interval carries parameter uncertainty as well as
shock uncertainty.

That is the whole reason it exists. gvar forecast's bands
come from

Omega(h) = sum_ Phi_j Sigma_eta Phi_j'

with the estimated system treated as known, so they contain no parameter
uncertainty at all. Integrating over the draws adds it, and on the shipped
26-unit demo that roughly doubles the interval:

h gvar forecast gvar bforecast ratio

1 0.012061 0.026890 2.229

4 0.021225 0.040762 1.920

8 0.030911 0.057073 1.846

90% half-widths for usa:y. Reproduce them with

. gvar bayes, prior(mn) prmean(0) noeigentrim draws(200) burnin(200) seed(20260811)
. gvar solve
. gvar forecast, step(8) variables(usa:y)
. gvar bforecast, variables(usa:y) step(8) bands(90)

The settings are given because the figures are quoted to six places and an MCMC
number without its seed and chain length is not reproducible. Reading
gvar forecast's bands as predictive intervals on this model understates
uncertainty by about half.

The ratio cannot fall below one. The predictive variance decomposes as
E_theta[Omega(h)] + Var_theta(mu_h): gvar forecast supplies the first
term at theta-hat and gvar bforecast carries both. The second cannot
be negative, so a predictive interval narrower than the analytic one means shock
or parameter uncertainty is being dropped somewhere -- it is a bug, never a
finding about the data. _test54.do asserts it at every horizon.

Options

variables(spec) names what to forecast, as unit:variable with
* wildcards, exactly as in gvar hd and
gvar fevd. It is required: the system is solved jointly either
way, but a predictive density over all the endogenous variables is a table
nobody reads.

bands(numlist) sets the coverage percentages. The widest band supplies the
lower and upper columns of the printed table; every band is in
r(table) and in the fan chart.

graph draws one panel per variable, palest shade outermost.

Remarks

These are not sample paths. Each horizon is drawn from its own marginal
predictive, using the cumulative forecast-error covariance at that horizon. So a
row of the output is exactly right for the interval at its own horizon, and
must not be read as a trajectory: within one draw the horizons do not share
shock realisations. BGVAR does the same, and the distinction matters if you
intend to compute anything from the joint behaviour of a path.

Cross-country shock correlation is zero. The per-draw Sigma_zeta is
block diagonal in the country covariances, because the sampler in
gvar bayes treats the units independently and never estimates
a cross-unit covariance. BGVAR's predictive does the same -- its Sig_t is
Ginv S_large Ginv' with S_large the stacked per-country matrix. The
consequence is that joint uncertainty across countries is understated, and it is
inherited from the sampler rather than chosen here. gvar irf
still reads Sigma_zeta from the residuals, which does carry the
cross-country correlation.

Two defects in BGVAR's predictive are corrected, not reproduced. Both were
settled by reading predict.R and utils.R:

the trend freezes. .get_companion carries the deterministic block
forward with diag(nd), so a trend stays at its last in-sample value and the
drift contribution is a1*T at every horizon instead of a1*(T+h). A
trended forecast is flat in its trend component.

the state starts a period early. It is initialised at Xn[bigT,],
which .mlag fills with y_...y_, so the first companion
multiply returns the fitted value at T and horizon h is really
T+h-1.

This command reuses the same routine gvar forecast uses,
which starts from the observed terminal values and advances the trend. So both
are fixed by construction and the two commands cannot drift apart.

Neither is offered as a reproduction option. bgvarsv and bgvarhs in
gvar bayes exist because reproducing those defects lets you
match published BGVAR output on quantities that are otherwise defensible. A
forecast whose first horizon is an in-sample fit is not defensible, and nobody
wants to match it.

Check the chains first. The interval is only as good as the draws behind
it; run gvar bconv before reading anything from this.

Cost. Every draw is stacked and solved, so the work is roughly
draws times one gvar solve. A few hundred draws is quick; several
thousand is not.

Examples

Sample, check, solve, forecast. Note prmean(0): the default random-walk
prior mean gives an unstable GVAR on this data, and a forecast from an explosive
system diverges rather than being merely wide -- see
gvar bayes.

. gvar bayes, prior(mn) prmean(0) noeigentrim draws(2000) burnin(2000) seed(20260811)

. gvar bconv

. gvar solve

. gvar bforecast, variables(usa:y) step(8)

A fan chart for three series, with a third band:

. gvar bforecast, variables(usa:y uk:y euro:y) step(12) bands(50 68 90) graph

Every output gap in the model, saved rather than printed:

. gvar bforecast, variables(*:y) step(8) saving(bfc) nosummary

Side by side with the interval that ignores parameter uncertainty:

. gvar forecast, step(8) variables(usa:y) bands(90)

. gvar bforecast, variables(usa:y) step(8) bands(90)

Stored results

gvar bforecast stores the following in r():

r(table) one row per (variable, horizon): horizon, variable index, predictive mean, then one column per quantile in ascending order

r(draws) draws integrated over

r(step) horizons

r(bands) the coverage percentages

r(quantiles) the quantiles, matching the table columns

r(varlist) variables() as typed

Source

BGVAR R/predict.R; R/utils.R .get_companion and .mlag.
The mean path is the Toolbox's forecast_GVAR.m, shared with
gvar forecast.

Author

Dr Merwan Roudane

merwanroudane920@gmail.com

https://github.com/merwanroudane