cultivars.multivariate.large_dim.factor_volatility#
Factor stochastic volatility: a moving covariance matrix built from a few paths.
A multivariate GARCH of even moderate dimension drowns in parameters; a factor model with stochastic volatility does not. Let \(r\) common factors drive the panel’s comovement and give each factor and each idiosyncratic error its own latent log-AR(1) variance,
and likewise for the \(k\) idiosyncratic log variances in \(D_t\). The \((k, k)\) covariance at every date is then \(\Sigma_t = \Lambda H_t \Lambda' + D_t\) – \(k + r\) volatility paths and one loading matrix, whatever \(k\) is (Pitt and Shephard, 1999; Chib, Nardari and Shephard, 2006). The time variation in correlations comes from the factor volatilities moving against the idiosyncratic ones, which is the mechanism, and it is readable rather than implicit: when a factor’s variance rises relative to the noise, every pair that loads on it correlates more.
Estimation is Bayesian, by an exact Gibbs sampler. Given everything else the factors are one Gaussian per period, the free loadings one weighted regression per row, and every log-variance path with its three parameters follows the Kim-Shephard-Chib mixture blocks the univariate model uses, so no step is approximate beyond the seven-component mixture for \(\log \chi^2_1\). What comes back is a posterior and the record holds it as draws; the conditional covariance, the correlations and the communalities are posterior means computed from those draws on demand.
Two commitments shape the surface. First, identification is stated, not
hidden: \(\Lambda\) is lower triangular with a unit diagonal in its
leading \(r\) rows, so factor \(j\) is scaled and signed by
series \(j\), the order of the columns is a modelling choice the
user makes and the summary says so. Second, mixing is reported rather
than assumed. The sampler is the plain Gibbs scheme without the ancillary
interweaving of Kastner, Fruehwirth-Schnatter and Lopes (2017), so
loadings and factor scales mix slowly; every *_draws field shares the
kept-draw axis and convergence assesses all of them, the fixed
loadings are reported as never having moved rather than flagged, and the
summary carries no likelihood or information criteria because a
posterior has none.
Layout. FactorSV validates the panel through
_validate_wide_panel and the factor count and labels on
_FactorVolatilityModel in _internals; its _sample runs the
sweep with _draw_factors, _draw_loading_rows,
_draw_stationary_volatility_path and _draw_volatility_parameters
from _core._samplers under a
VolatilityPrior, and packs a
_FactorVolatilityFit. FactorSVResult takes the summary from
_SummaryMixin and the chain diagnostics from _ConvergenceMixin.
The constant-variance factor model is
dynamic_factor; the vector
autoregression with stochastic volatility on its innovations is
volatility; the univariate law
each path follows is stochastic_volatility.
References
Pitt, M. K., & Shephard, N. (1999). Time-varying covariances: A factor stochastic volatility approach. In Bayesian Statistics 6 (pp. 547-570). Oxford University Press.
Chib, S., Nardari, F., & Shephard, N. (2006). Analysis of high dimensional multivariate stochastic volatility models. Journal of Econometrics, 134(2), 341-371.
Kim, S., Shephard, N., & Chib, S. (1998). Stochastic volatility: Likelihood inference and comparison with ARCH models. Review of Economic Studies, 65(3), 361-393.
Kastner, G., Fruehwirth-Schnatter, S., & Lopes, H. F. (2017). Efficient Bayesian inference for multivariate factor stochastic volatility models. Journal of Computational and Graphical Statistics, 26(4), 905-917.
Example
One factor whose variance swells in the middle of the sample; the posterior conditional correlation between two series that load on it rises there and falls back:
>>> import numpy as np
>>> rng = np.random.default_rng(0)
>>> n, k = 300, 4
>>> h = np.where((n // 3 <= np.arange(n)) & (np.arange(n) < 2 * n // 3), 2.0, 0.0)
>>> f = np.exp(h / 2) * rng.standard_normal(n)
>>> y = np.outer(f, [1.0, 0.8, 0.6, 0.4]) + 0.6 * rng.standard_normal((n, k))
>>> res = FactorSV(y, n_factors=1).fit(n_draws=300, n_burn=100, seed=0)
>>> corr = res.conditional_correlation()[:, 0, 1]
>>> middle = corr[n // 3 : 2 * n // 3].mean()
>>> edges = np.r_[corr[: n // 3], corr[2 * n // 3 :]].mean()
>>> bool(middle > edges + 0.1)
True
>>> vol = res.factor_volatility(0)[1]
>>> bool(vol[n // 3 : 2 * n // 3].mean() > 1.5 * vol[: n // 3].mean())
True
Classes#
Factor stochastic volatility, Chib-Nardari-Shephard. |
|
The posterior of a factor stochastic-volatility model. |