DynamicNelsonSiegel#
- class cultivars.multivariate.reduced_form.term_structure.DynamicNelsonSiegel(panel, maturities, *, decay=None)[source]#
One-step maximum-likelihood dynamic Nelson-Siegel estimation.
The Diebold-Rudebusch-Aruoba state space: level, slope and curvature follow diagonal autoregressions around their means with a full innovation covariance, curves observe them through the Nelson-Siegel loadings at the panel’s maturities with per-maturity measurement noise, and the decay \(\lambda\) is either estimated with everything else or held at a supplied value. The parameter vector – \(\log\lambda\) when free, the three means, the three tanh-bounded persistences, the six entries of a log-diagonal Cholesky factor and the \(p\) log measurement variances – is maximized from the Diebold-Li two-step estimate as the warm start, with the decay seeded where the curvature loading peaks at the median maturity.
- Variables:
_panel – The validated
(nobs, p)yield panel,nanwhere missing._maturities – The validated
(p,)maturities._fixed_decay – The decay to hold fixed, or
Noneto estimate it.
See also
DynamicNelsonSiegelResult– the recordfit()returns.TimeVaryingNelsonSiegel– the extension with a random-walk decay.FunctionalVAR– the two-step route, withbasis="nelson-siegel", when the factor VAR should be unrestricted rather than diagonal.
References
Diebold, F. X., & Li, C. (2006). Forecasting the term structure of government bond yields. Journal of Econometrics, 130(2), 337-364.
Diebold, F. X., Rudebusch, G. D., & Aruoba, S. B. (2006). The macroeconomy and the yield curve: A dynamic latent factor approach. Journal of Econometrics, 131(1-2), 309-338.
Example
>>> import numpy as np >>> from cultivars.engine._core._polynomials import _nelson_siegel_loadings >>> rng = np.random.default_rng(0) >>> taus = np.array([0.25, 1.0, 2.0, 5.0, 10.0]) >>> basis = _nelson_siegel_loadings(taus, 0.6) >>> f = np.zeros((120, 3)) >>> mu = np.array([5.0, -1.5, 0.5]) >>> f[0] = mu >>> for t in range(1, 120): ... f[t] = mu + 0.9 * (f[t - 1] - mu) + 0.2 * rng.standard_normal(3) >>> curves = f @ basis.T + 0.05 * rng.standard_normal((120, 5)) >>> res = DynamicNelsonSiegel(curves, taus, decay=0.6).fit() >>> bool(np.corrcoef(res.level, f[:, 0])[0, 1] > 0.95) True
Methods#
|
Maximize the exact likelihood from the two-step warm start. |