NarrativeSignRestrictedSVAR#

class cultivars.multivariate.structural.sign_restrictions.NarrativeSignRestrictedSVAR(result, restrictions=None, *, shock_signs=(), contributions=(), horizons=(0,), draws=1000, max_attempts=None, seed=0)[source]

Bases: _IdentificationModel[SignRestrictedSVARResult]

Sign restrictions sharpened by declared history, Antolín-Díaz and Rubio-Ramírez (2018).

Traditional signs restrict what a shock would do; narrative events restrict what the shocks did. Two kinds are declared, both from the paper. A shock-sign event states the sign of a named shock in a named period – the monetary shock was contractionary in the Volcker quarter: \(\varepsilon_{j,t^\ast} = (B^{-1} u_{t^\ast})_j > 0\). A contribution event states that a named shock was the "most" important contributor, or the "overwhelming" one – larger than all others combined – to the unexpected movement of a named variable in a named period:

\[\lvert B_{ij}\, \varepsilon_{j,t^\ast} \rvert > \max_{l \neq j} \lvert B_{il}\, \varepsilon_{l,t^\ast} \rvert \quad\text{or}\quad \lvert B_{ij}\, \varepsilon_{j,t^\ast} \rvert > \sum_{l \neq j} \lvert B_{il}\, \varepsilon_{l,t^\ast} \rvert .\]

Each accepted rotation must reproduce the declared history through its own recovered shocks, which is what makes the resulting set sharper than the traditional one: history is a filter rotations rarely pass by accident. Periods index the effective sample – one row per residual row of the result being identified – exactly as a proxy’s instrument rows do. The events are checked against the point-estimate residuals, and the summary carries the caveat that the full posterior treatment belongs to the sampling backend.

Note

A shock-sign event on a column with no traditional signs is vacuous: the sampler may flip any column, and flipping the column flips the recovered shock, so every draw passes. Shock-sign events bind only alongside traditional signs on the same shock, which fix the column’s orientation; contribution events are flip-invariant and bind on their own.

Parameters:
  • result (ClosedSystemResult) – The fitted closed reduced-form result to identify.

  • restrictions (Mapping[str, Mapping[str, str]] | None) – Traditional sign patterns, mapping shock label to a mapping from variable to "+" or "-". Optional: narrative events alone can identify. Labels declared here occupy the leading columns, in declaration order; labels appearing only in narrative events follow, in order of first appearance.

  • shock_signs (Sequence[tuple[str, int, str]]) – Shock-sign events, each (shock label, period, sign).

  • contributions (Sequence[tuple[str, str, int, str]]) – Contribution events, each (shock label, variable, period, kind) with kind one of "most" or "overwhelming".

  • horizons (Sequence[int]) – Leads at which every traditional sign must hold.

  • draws (int) – Accepted rotations to collect.

  • max_attempts (int | None) – Rotations to try before giving up; defaults to one thousand per requested draw.

  • seed (int | None) – Seed for the rotation draws.

Raises:

SpecificationError – If the result is not a closed system, no narrative event is declared – SignRestrictedSVAR is that model – or any declaration is malformed.

Variables:
  • _source – The closed reduced-form result being identified.

  • _compiled – Per-column traditional sign pairs, length k, empty where a column declares none.

  • _labels – The shock labels, declared first, event-only next, then unrestrictedN.

  • _leads – The horizons at which the traditional signs bind.

  • _shock_events – Per-column (event index, +-1.0) shock-sign pairs.

  • _contribution_events – (column, variable index, event index, overwhelming?) contribution requirements.

  • _periods – The unique residual rows the events reference.

  • _draws – Accepted rotations requested.

  • _budget – Rotations to attempt before giving up.

  • _seed – The seed behind the draws.

  • _restriction – The declaration, stated as a sentence.

See also

  • SignRestrictedSVAR – the traditional signs alone.

  • SignRestrictedSVARResult – the accepted set returned, with the narrative caveat appended to its restriction sentence.

  • ProxySVAR – the other scheme that brings outside information about particular periods, as a series rather than as events.

References

Antolín-Díaz, J., & Rubio-Ramírez, J. F. (2018). Narrative sign restrictions for SVARs. American Economic Review, 108(10), 2802-2829.

Example

The period in which the true demand shock is largest relative to the other shock is declared as a negative demand shock that overwhelmingly drove output. The accepted set shrinks – the acceptance rate halves – and the 16th percentile of output’s impact response moves from under 0.4 to near the true 1.0:

>>> import numpy as np
>>> from cultivars.multivariate.reduced_form.vector_autoregression import VAR
>>> rng = np.random.default_rng(0)
>>> B = np.array([[1.0, 0.5], [0.3, 1.0]])
>>> A = np.array([[0.5, 0.1], [0.0, 0.4]])
>>> eps = rng.standard_normal((402, 2))
>>> y = np.zeros((402, 2))
>>> for t in range(1, 402):
...     y[t] = A @ y[t - 1] + B @ eps[t]
>>> res = VAR(y, order=1, names=("gdp", "infl")).fit()
>>> period = int(np.argmax(np.abs(eps[1:, 0]) - np.abs(eps[1:, 1])))
>>> period, eps[period + 1].round(2).tolist()
(238, [-3.9, 0.46])
>>> signs = {"demand": {"gdp": "+", "infl": "+"}}
>>> plain = SignRestrictedSVAR(res, signs, draws=300, seed=0).identify()
>>> narrative = NarrativeSignRestrictedSVAR(
...     res,
...     signs,
...     shock_signs=(("demand", period, "-"),),
...     contributions=(("demand", "gdp", period, "overwhelming"),),
...     draws=300,
...     seed=0,
... ).identify()
>>> narrative.shock_names, narrative.n_accepted, narrative.attempts
(('demand', 'unrestricted1'), 300, 806)
>>> round(plain.acceptance_rate, 2), round(narrative.acceptance_rate, 2)
(0.75, 0.37)
>>> plain.irf(0)[0, 0, 0, 0].round(3), narrative.irf(0)[0, 0, 0, 0].round(3)
(np.float64(0.387), np.float64(0.948))

Private attributes#