TimeVaryingNelsonSiegel#
- class cultivars.multivariate.reduced_form.term_structure.TimeVaryingNelsonSiegel(panel, maturities)[source]
Bases:
_DecayNelsonSiegelModel[TimeVaryingNelsonSiegelResult]The dynamic Nelson-Siegel model with a time-varying loading decay.
The state is
(level, slope, curvature, log lambda), each a diagonal AR(1); the measurement is the Nelson-Siegel curve at the current \(\lambda_t\). Estimated by maximizing the unscented (default) or extended filter’s likelihood from the constant-decay exact fit, which is run first as the warm start; the three decay parameters are appended to that fit’s vector and the whole vector is re-optimized through the chosen filter. The unscented filter is the default because the loadings are smooth and bounded in \(\lambda\), so its sigma points capture the nonlinearity that a first-order Jacobian flattens; it costs two to three times the extended filter’s running time.- Variables:
_panel – The validated
(nobs, p)yield panel, whole rowsnanwhere missing._maturities – The validated
(p,)maturities.
See also
TimeVaryingNelsonSiegelResult– the recordfit()returns.DynamicNelsonSiegel– the constant-decay model, exact likelihood, and the warm start of this one.nonlinear– the filters this model reads itself through.
References
Koopman, S. J., Mallee, M. I. P., & van der Wel, M. (2010). Analyzing the term structure of interest rates using the dynamic Nelson-Siegel model with time-varying parameters. Journal of Business & Economic Statistics, 28(3), 329-343.
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]) >>> 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 @ _nelson_siegel_loadings(taus, 0.6).T >>> curves = curves + 0.05 * rng.standard_normal((120, 5)) >>> res = TimeVaryingNelsonSiegel(curves, taus).fit() >>> bool(np.corrcoef(res.level, f[:, 0])[0, 1] > 0.95) True