svarIrf#

Purpose#

Compute posterior sign-restricted IRF, cumulative IRF, and FEVD bands from BVAR or SV-BVAR draws.

Format#

sir = svarIrf(result, ctl)#
Parameters:
  • result (struct) – an instance of a bvarResult or bvarSvResult structure with posterior draws.

  • ctl (struct) –

    an instance of an svarControl structure with sign restrictions defined. An instance is initialized by calling svarControlCreate() and the following members can be set:

    ctl.sign_restr

    Nx4 matrix, sign restrictions on impulse responses. Each row specifies one restriction with columns:

    1

    Variable index (1 to m) — the responding variable.

    2

    Shock index (1 to m) — the structural shock.

    3

    Horizon (0 = impact, 1 = one step ahead, etc.).

    4

    Sign: 1 for positive response, -1 for negative response.

    ctl.zero_restr

    Nx3 matrix, zero restrictions. Reserved for future ARW2018 implementation. Currently raises an error if populated. Columns: variable, shock, horizon.

    ctl.max_tries

    Scalar, maximum rotation attempts per posterior draw. Default = 10000.

    ctl.min_accept_rate

    Scalar, minimum acceptable fraction of draws yielding a valid rotation. An error is raised if the rate falls below this threshold. Default = 0.01.

    ctl.n_ahead

    Scalar, number of IRF horizons. Default = 20.

    ctl.seed

    Scalar, RNG seed for reproducibility. Default = 42.

    ctl.quiet

    Scalar, set to 1 to suppress printed output. Default = 0.

Returns:

sir (struct) –

An instance of an svarPosteriorResult structure containing:

sir.irf_median

Array of (n_ahead+1) mxm matrices, posterior median impulse responses. sir.irf_median[h+1][i, j] is the median response of variable i to shock j at horizon h.

sir.irf_lower_68

Array of (n_ahead+1) mxm matrices, lower 68% credible band (16th percentile).

sir.irf_upper_68

Array of (n_ahead+1) mxm matrices, upper 68% credible band (84th percentile).

sir.irf_lower_90

Array of (n_ahead+1) mxm matrices, lower 90% credible band (5th percentile).

sir.irf_upper_90

Array of (n_ahead+1) mxm matrices, upper 90% credible band (95th percentile).

sir.cirf_median

Array of (n_ahead+1) mxm matrices, posterior median cumulative IRF.

sir.cirf_lower_68

Array of (n_ahead+1) mxm matrices, lower 68% cumulative IRF band.

sir.cirf_upper_68

Array of (n_ahead+1) mxm matrices, upper 68% cumulative IRF band.

sir.cirf_lower_90

Array of (n_ahead+1) mxm matrices, lower 90% cumulative IRF band.

sir.cirf_upper_90

Array of (n_ahead+1) mxm matrices, upper 90% cumulative IRF band.

sir.fevd_median

Array of (n_ahead+1) mxm matrices, posterior median FEVD. Each row sums to 1.0.

sir.fevd_lower_68

Array of (n_ahead+1) mxm matrices, lower 68% FEVD band.

sir.fevd_upper_68

Array of (n_ahead+1) mxm matrices, upper 68% FEVD band.

sir.fevd_lower_90

Array of (n_ahead+1) mxm matrices, lower 90% FEVD band.

sir.fevd_upper_90

Array of (n_ahead+1) mxm matrices, upper 90% FEVD band.

sir.n_attempted

Scalar, total posterior draws attempted.

sir.n_accepted

Scalar, draws that yielded a valid rotation.

sir.accept_rate

Scalar, acceptance rate (n_accepted / n_attempted).

sir.n_ahead

Scalar, number of horizons.

sir.m

Scalar, number of variables.

sir.var_names

Mx1 string array, variable names.

sir.shock_names

Mx1 string array, shock labels.

Examples#

Monetary Policy SVAR with Posterior Bands#

new;
library timeseries;

y = loadd(getGAUSSHome("pkgs/timeseries/examples/macro.dat"), "gdp + cpi + ffr");

// Estimate BVAR
bctl = bvarControlCreate();
bctl.p = 4;
bctl.n_draws = 5000;
bctl.quiet = 1;
result = bvarFit(y, bctl);

// Sign restrictions for monetary policy shock
ctl = svarControlCreate();
ctl.sign_restr = { 3 3 0  1,       // FFR up
                   1 3 0 -1,       // GDP down
                   2 3 0 -1 };     // CPI down

struct svarPosteriorResult sir;
sir = svarIrf(result, ctl);

print "Acceptance rate:" sir.accept_rate;

Horizon Restrictions#

Require that the demand shock (shock 1) keeps GDP and CPI positive for 4 quarters:

new;
library timeseries;

y = loadd(getGAUSSHome("pkgs/timeseries/examples/macro.dat"), "gdp + cpi + ffr");
result = bvarFit(y, quiet=1);

ctl = svarControlCreate();

// Demand shock: GDP and CPI positive for h=0..3
ctl.sign_restr = { 1 1 0  1,  2 1 0  1,
                   1 1 1  1,  2 1 1  1,
                   1 1 2  1,  2 1 2  1,
                   1 1 3  1,  2 1 3  1 };

sir = svarIrf(result, ctl);

Sign-Restricted IRF from SV-BVAR#

new;
library timeseries;

y = loadd(getGAUSSHome("pkgs/timeseries/examples/macro.dat"), "gdp + cpi + ffr");

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

ctl = svarControlCreate();
ctl.sign_restr = { 3 3 0  1,
                   1 3 0 -1,
                   2 3 0 -1 };

sir = svarIrf(result, ctl);

Accessing Results and Plotting#

new;
library timeseries;

// ... (estimate and identify as above) ...

// Median response of GDP to monetary shock at h=5
print sir.irf_median[6, 1, 3];

// 68% band
print sir.irf_lower_68[6, 1, 3] "to" sir.irf_upper_68[6, 1, 3];

// Cumulative response (for differenced VARs)
print "Cumulative GDP response to monetary shock at h=20:";
print sir.cirf_median[21, 1, 3];

// FEVD: GDP variance from monetary shock at h=20
print "GDP variance share from monetary shock:";
print sir.fevd_median[21, 1, 3];

// Plot using irfPlotData
df = irfPlotData(sir, 3, 1);    // Monetary shock → GDP
plotXY(df[., "horizon"], df[., "median"]~df[., "lower_68"]~df[., "upper_68"]);

Remarks#

Algorithm: For each posterior draw \((B^{(i)}, \Sigma^{(i)})\), the function attempts to find an orthogonal rotation Q satisfying all sign restrictions (RRW2010 accept-reject). Draws that fail after ctl.max_tries attempts are discarded. The function reports:

  • IRF bands: pointwise median, 68%, and 90% credible bands

  • Cumulative IRF bands: running sum of IRF, useful for differenced VARs

  • FEVD bands: variance decomposition with posterior uncertainty

Acceptance rate: The acceptance rate (sir.accept_rate) indicates what fraction of posterior draws yielded a valid rotation. Rates below 10% suggest the restrictions may be too tight, contradictory, or implausible for the data.

SV-BVAR draws: For bvarSvResult, the time-T covariance \(\Sigma_T\) is reconstructed from U and \(h_T\) for each draw, giving identification at the current volatility state rather than a time-averaged covariance.

Restriction matrix format: Each row of ctl.sign_restr is {variable, shock, horizon, sign} where indices are 1-based (GAUSS convention). Multiple restrictions are stacked as rows using commas:

ctl.sign_restr = { 3 3 0  1,
                   1 3 0 -1,
                   2 3 0 -1 };

Model#

For each posterior draw \((B^{(s)}, \Sigma^{(s)})\), the function searches for a sign-satisfying rotation \(Q^{(s)}\) and computes:

  • IRF: \(\Theta_h^{(s)} = J (F^{(s)})^h J' P^{(s)} Q^{(s)}\)

  • Cumulative IRF: \(C_h^{(s)} = \sum_{\ell=0}^{h} \Theta_\ell^{(s)}\)

  • FEVD: Variance share from each shock, with posterior uncertainty

The resulting bands integrate over both parameter uncertainty (different draws) and set identification uncertainty (different valid rotations within each draw). Algorithm ———

  1. For each of n_draws posterior draws \((B^{(s)}, \Sigma^{(s)})\):

    1. Form \(L^{(s)} = \text{chol}(\Sigma^{(s)})'\).

    2. Draw random rotations \(Q\) until one satisfies all sign restrictions (accept-reject).

    3. Compute IRF, cumulative IRF, and FEVD under the accepted rotation.

  2. Compute pointwise quantiles across accepted draws.

Complexity: \(O(n\_accepted \cdot h \cdot m^2 p^2 + n\_total\_tries \cdot m^3)\). Troubleshooting —————

Very low acceptance rate (< 5%): Too many restrictions for this model. Options:

  • Remove restrictions at longer horizons (keep impact only).

  • Remove restrictions on variables weakly related to the shock.

  • Use a wider credible level to see if the posterior spans both signs.

Bands are very wide: Sign restrictions are set-identifying (not point-identifying). Wide bands reflect genuine identification uncertainty — the data is consistent with many structural interpretations. This is a feature of the method (Fry & Pagan 2011).

Cumulative IRF is needed for differenced data: If your VAR is estimated on growth rates, the cumulative IRF gives the level response. Use sir.cirf_median instead of sir.irf_median. Verification ————

Sign-restricted posterior IRFs cross-validated against ECB BEAR bear.irfres() output and the Rubio-Ramirez, Waggoner & Zha (2010) analytical examples.

See crossval/12_svar_crossval.R. References ———-

  • Fry, R. and A. Pagan (2011). “Sign restrictions in structural vector autoregressions: A critical review.” Journal of Economic Literature, 49(4), 938-960.

  • Rubio-Ramirez, J.F., D.F. Waggoner, and T. Zha (2010). “Structural vector autoregressions: Theory of identification and algorithms for inference.” Review of Economic Studies, 77(2), 665-696.

  • Uhlig, H. (2005). “What are the effects of monetary policy on output?” Journal of Monetary Economics, 52(2), 381-419.

Library#

timeseries

Source#

svar.src