ShortRunSVAR#

class cultivars.multivariate.structural.zero_restrictions.ShortRunSVAR(result, *, a=None, b=None, shock_names=None)[source]#

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, nan frees it – which is what lifts the scheme past RecursiveSVAR: 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 identify time 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, nan for a free coefficient. None fixes A to the identity, the B-model of Bernanke (1986). Diagonal entries must be fixed – conventionally one – because a free diagonal trades scale with B and nothing identifies the split.

  • b (ArrayLike | None) – (k, k) pattern for the shock loadings, nan for a free coefficient. None frees 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 a is 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 A with zeros in the free cells.

  • _a_free – Row-major coordinates of the free cells of A.

  • _b_base – The fixed values of B with 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'}

Attributes#

k_endog

Number of variables in the source system.

n_free

Free coefficients across both matrices.

names

Variable labels of the source system.

overidentifying_restrictions

Restrictions beyond the count needed for exact identification.

source

The fitted reduced-form result being identified.

Methods#

identify()

Estimate the free coefficients by maximum likelihood.