ShortRunSVAR#
- class cultivars.multivariate.structural.zero_restrictions.ShortRunSVAR(result, *, a=None, b=None, shock_names=None)[source]
Bases:
_IdentificationModel[SVARResult]General short-run zero restrictions: the AB model, Amisano-Giannini (1997).
\[A u_t = B \varepsilon_t, \qquad \mathbb{E}\varepsilon_t \varepsilon_t' = I, \qquad \Sigma_u = A^{-1} B B' A^{-\top},\]with \(A\) carrying the contemporaneous relations among the innovations, \(B\) the loadings of the shocks, and the impact matrix \(A^{-1} B\). Restrictions are declared cell by cell – a finite entry fixes a coefficient,
nanfrees it – which is what lifts the scheme pastRecursiveSVAR: zeros can sit anywhere, not only above a diagonal, at the price of a likelihood search where the triangle had a closed form.The order condition is enforced at construction: the covariance supplies \(k(k+1)/2\) equations, so at most that many coefficients can be free. Fewer means over-identification, and the likelihood-ratio statistic against the unrestricted covariance – the classical over-identification test – is computed and reported on the result. The rank condition has no clean a-priori check for arbitrary patterns; it shows up at
identifytime as a just-identified model that cannot reproduce the covariance, and is reported as exactly that.- Parameters:
result (
ClosedSystemResult) – The fitted closed reduced-form result to identify.a (
ArrayLike|None) –(k, k)pattern for the contemporaneous relations,nanfor a free coefficient.NonefixesAto the identity, the B-model of Bernanke (1986). Diagonal entries must be fixed – conventionally one – because a free diagonal trades scale withBand nothing identifies the split.b (
ArrayLike|None) –(k, k)pattern for the shock loadings,nanfor a free coefficient.Nonefrees the diagonal and fixes the rest to zero, the A-model in which each equation has its own shock.shock_names (
Sequence[str] |None) – One label per shock column. Defaults to the variable names.
- Raises:
SpecificationError – If the result is not a closed system, both patterns are omitted, a pattern is malformed, the diagonal of
ais free, no coefficient is free, or the order condition fails.- Variables:
_source – The closed reduced-form result being identified.
_a_base – The fixed values of
Awith zeros in the free cells._a_free – Row-major coordinates of the free cells of
A._b_base – The fixed values of
Bwith zeros in the free cells._b_free – Row-major coordinates of the free cells of
B._overid_df – Restrictions beyond exact identification.
_labels – The shock labels.
See also
SVARResult– the complete result returned, with the over-identification test in its diagnostics.RecursiveSVAR– the triangular special case, in closed form.MixedSVAR– when some zeros belong at the long run.
References
Amisano, G., & Giannini, C. (1997). Topics in Structural VAR Econometrics (2nd ed.). Springer.
Bernanke, B. S. (1986). Alternative explanations of the money-income correlation. Carnegie-Rochester Conference Series on Public Policy, 25, 49-99.
Example
A three-variable B-model. A lower-triangular pattern is exactly identified and reproduces the recursive factorization; fixing one more cell over-identifies the structure, and the likelihood-ratio test says whether the data object:
>>> import numpy as np >>> from cultivars.multivariate.reduced_form.vector_autoregression import VAR >>> rng = np.random.default_rng(0) >>> B = np.array([[0.45, -0.1, 0.0], [0.27, 0.58, -0.1], [0.11, 0.14, 0.7]]) >>> eps = rng.standard_normal((802, 3)) >>> y = np.zeros((802, 3)) >>> for t in range(1, 802): ... y[t] = 0.4 * y[t - 1] + B @ eps[t] >>> res = VAR(y, order=1, names=("prod", "hours", "rate")).fit() >>> nan = np.nan >>> exact = ShortRunSVAR(res, b=[[nan, 0, 0], [nan, nan, 0], [nan, nan, nan]]) >>> exact.n_free, exact.overidentifying_restrictions (6, 0) >>> svar = exact.identify() >>> dict(svar.diagnostics)["Identification"], svar.scheme ('exact', 'short-run') >>> bool(np.allclose(svar.impact, RecursiveSVAR(res).identify().impact)) True >>> over = ShortRunSVAR(res, b=[[nan, 0, 0], [nan, nan, 0], [nan, 0, nan]]).identify() >>> {key: value for key, value in over.diagnostics if key.startswith("Over-ID")} {'Over-ID restrictions': '1', 'Over-ID LR': '1.251', 'Over-ID p-value': '0.2634'}