UCSV#

class cultivars.univariate.stochastic_volatility.UCSV(endog, *, gamma=0.2)[source]

Bases: _TrendVolatilityModel[_UCSVPosterior]

Stock and Watson’s unobserved-components stochastic-volatility model.

\[y_t = \tau_t + \exp(h_t / 2)\,\varepsilon_t, \qquad \tau_{t+1} = \tau_t + \exp(q_t / 2)\,\eta_t,\]

with \(h_t\) and \(q_t\) random walks of innovation standard deviation \(\gamma\), so the irregular’s variance and the trend’s variance each drift freely. It is the workhorse of trend-inflation measurement: the trend is a local level whose signal-to-noise ratio is itself time-varying, and the fitted \(\tau_t\) is the permanent component under that reading. Its estimator is a Gibbs sampler – the trend drawn exactly by the simulation smoother under the current variance paths, the two log variances by the Kim-Shephard-Chib mixture – so fit returns a posterior.

Variables:
  • _endog – The validated series.

  • _gamma – The fixed vol-of-vol, or None when estimated.

Parameters:
  • endog (ArrayLike) – The observed series (inflation, typically).

  • gamma (float | None) – The vol-of-vol standard deviation held fixed for both log variances (Stock and Watson use 0.2), or None to estimate both under inverse-gamma priors.

Raises:

See also

References

Stock, J. H., & Watson, M. W. (2007). Why has U.S. inflation become harder to forecast? Journal of Money, Credit and Banking, 39(s1), 3-33.

Kim, S., Shephard, N., & Chib, S. (1998). Stochastic volatility: Likelihood inference and comparison with ARCH models. Review of Economic Studies, 65(3), 361-393.

Example

>>> import numpy as np
>>> rng = np.random.default_rng(0)
>>> n = 200
>>> trend = np.cumsum(0.2 * rng.standard_normal(n))
>>> y = trend + 0.7 * rng.standard_normal(n)
>>> post = UCSV(y).fit(n_draws=300, n_burn=100, seed=0)
>>> bool(np.corrcoef(post.trend, trend)[0, 1] > 0.9)
True
>>> post.n_kept, post.gamma_fixed, post.trend.shape
(200, True, (200,))
>>> UCSV(y, gamma=0.0)
Traceback (most recent call last):
    ...
cultivars.exceptions.SpecificationError: gamma must be strictly positive; got 0.0.