MarkovSwitchingSVARResult#

class cultivars.multivariate.regime_switching.markov_switching.MarkovSwitchingSVARResult(*, msvar, structurals)[source]

Bases: _SummaryMixin

An identified Markov-switching system, one structural result per regime.

Conditional on regime \(m\) the reduced form is a linear VAR with innovation covariance \(\Sigma_m\), so an identification is a factorization \(\Sigma_m = B_m B_m'\) under restrictions that hold in every regime:

\[u_t = B_{S_t}\, \varepsilon_t, \qquad \varepsilon_t \sim (0, I).\]

Composition on both sides: msvar is the reduced form with its chain, posteriors and regime views, and structurals holds each regime’s identification with its whole surface – impact matrix, responses, diagnostics. This object owns the join: the guarantee of a common identifying declaration, and per-regime answers under one roof.

Note

Every structural quantity here is within-regime. irf() holds the chain frozen in the chosen regime, which is the same linearization the observed-regime families use; a response over a horizon longer than that regime’s expected duration is an extrapolation, and the summary says so. Responses that integrate over the chain’s future path are not offered.

Variables:
  • msvar – The fitted Markov-switching reduced form.

  • structurals – One structural result per regime, in label order.

See also

References

Sims, C. A., Waggoner, D. F., & Zha, T. (2008). Methods for inference in large multiple-equation Markov-switching models. Journal of Econometrics, 146(2), 255-274.

Example

A recursive identification applied to both regimes of a fitted MS-VAR. Each regime’s impact matrix factorizes its own covariance, and the shock labels are shared:

>>> import numpy as np
>>> rng = np.random.default_rng(0)
>>> s = np.repeat([0, 1, 0, 1], 100)
>>> y = np.array([[-1.0, -0.5], [1.5, 1.0]])[s] + 0.4 * rng.standard_normal((400, 2))
>>> res = MarkovSwitchingVAR(y, order=1, n_regimes=2, names=("a", "b")).fit(seed=0)
>>> svar = MarkovSwitchingSVAR(res).identify()
>>> svar.n_regimes, svar.names, svar.shock_names
(2, ('a', 'b'), ('a', 'b'))
>>> all(
...     np.allclose(svar.impact(m) @ svar.impact(m).T, res.regime(m).sigma_u)
...     for m in range(2)
... )
True
>>> svar.irf(4, regime=1).shape, svar.structural(0).source is res.regime(0)
((5, 2, 2), True)

Private methods#

_summary_table()

Structured summary rendered by every display path.