TVAR#
- class cultivars.multivariate.nonlinear.threshold.TVAR(endog, *, order, transition_variable, delay=None, trim=_DEFAULT_TRIM, n_grid=_DEFAULT_GRID, trend='c', names=None)[source]
Bases:
_ThresholdVectorAutoRegressionModel[TVARResult]Two-regime threshold vector autoregression, after Tsay (1998).
The regime is decided by an observable – a named column’s own lag, or an external series you supply – against a threshold estimated by grid search. Each regime gets its own coefficient stack, deterministic terms, and innovation covariance. The likelihood is a step function of the threshold, piecewise constant and nowhere differentiable in it, so the search is exhaustive: candidate thresholds are the quantiles of the delayed transition variable between
trimand1 - trim, each regime at each candidate is one multivariate least-squares solve, and the candidate maximizing the total Gaussian log-likelihood \(\ell_L(\hat\Sigma_L) + \ell_U(\hat\Sigma_U)\) wins. A separate covariance per regime is the multivariate replacement for total sum of squares: it weights each equation by its own noise rather than letting the noisiest series choose the split, and lets the volatility shift that is usually half the finding be part of the fit.- Variables:
_endog – The observed panel, from the base model.
_order – The autoregressive order
p, from the base model._trend – The deterministic specification, from the base model.
_names – The variable labels, from the base model.
_delays – The candidate delays – one when fixed,
1..orderwhen searched – from the observed-regime base._threshold_name – The transition variable’s label, from the observed-regime base.
_transition_series – The aligned transition series, from the observed-regime base.
_trim – Fraction trimmed from each tail of the quantile grid.
_n_grid – Candidate thresholds per delay.
- Parameters:
endog (
ArrayLike) – The observed panel, shape(nobs, k).order (
int) – Autoregressive order within each regime.transition_variable (
str|ArrayLike) – A variable name fromnames(self-exciting: the regime is driven by that variable’s lag) or an aligned external series.delay (
int|None) – Threshold delay.None– allowed only when self-exciting – searches1..orderjointly with the threshold; with an external driver the lag is a modelling choice with economic content, so it must be stated.trim (
float) – Fraction trimmed from each tail of the quantile grid, so that neither regime is estimated from a handful of extreme points.n_grid (
int) – Candidate thresholds per delay.trend (
Literal['n','c','ct']) – Deterministic terms per regime.names (
Sequence[str] |None) – One label per variable. Defaults toy1 ... yk.
- Raises:
SpecificationError – If the specification is malformed,
trimis outside(0, 0.5),n_gridis below one, or the delay is left to be searched with an external transition variable.DimensionError – If the sample cannot support the lags and delay.
See also
TVARResult– the recordfitreturns.STVAR– the smooth blend of the same two regimes.MarkovSwitchingVAR– regimes inferred from a latent chain rather than read off an observable.SETAR– the univariate self-exciting model.
References
Tsay, R. S. (1998). Testing and modeling multivariate threshold models. Journal of the American Statistical Association, 93(443), 1188-1202.
Balke, N. S. (2000). Credit and economic activity: Credit regimes and nonlinear propagation of shocks. Review of Economics and Statistics, 82(2), 344-349.
Hansen, B. E. (1996). Inference when a nuisance parameter is not identified under the null hypothesis. Econometrica, 64(2), 413-430.
Example
>>> import numpy as np >>> rng = np.random.default_rng(0) >>> y = np.zeros((300, 2)) >>> for t in range(1, 300): ... a = 0.6 if y[t - 1, 0] <= 0.0 else -0.3 ... y[t] = a * y[t - 1] + rng.standard_normal(2) >>> res = TVAR(y, order=1, transition_variable="y1", delay=1).fit() >>> res.n_lower + res.n_upper == res.nobs True >>> res.irf(4, regime="lower").shape (5, 2, 2) >>> searched = TVAR(y, order=2, transition_variable="y1").fit() >>> searched.searched_delay, searched.delay (True, 1) >>> external = TVAR(y, order=1, transition_variable=np.sin(np.arange(300) / 10), delay=1) >>> external.fit().self_exciting False >>> TVAR(y, order=1, transition_variable=np.sin(np.arange(300) / 10)) Traceback (most recent call last): cultivars.exceptions.SpecificationError: the delay is searched only for a self-exciting ...