DynamicNelsonSiegelResult#

class cultivars.multivariate.reduced_form.term_structure.DynamicNelsonSiegelResult(*, panel, maturities, decay, decay_fixed, mu, ar, state_innovation_cov, measurement_var, factors, factor_cov, llf, nobs, n_params)[source]

Bases: _SummaryMixin, _ComparisonMixin

A fitted dynamic Nelson-Siegel model: factors, decay, and noise.

The yield at maturity \(\tau\) on date \(t\) is three factors through fixed exponential loadings,

\[y_t(\tau) = L_t + S_t\,\frac{1 - e^{-\lambda\tau}}{\lambda\tau} + C_t\Bigl(\frac{1 - e^{-\lambda\tau}}{\lambda\tau} - e^{-\lambda\tau}\Bigr) + \varepsilon_t(\tau), \qquad f_t - \mu = \Phi\,(f_{t-1} - \mu) + \eta_t,\]

with \(f_t = (L_t, S_t, C_t)'\), diagonal \(\Phi\), full innovation covariance \(Q\) and per-maturity measurement variances \(\sigma^2_\tau\). Everything here was estimated in one step by exact maximum likelihood through the Kalman filter, and the factor paths are the smoothed states given the whole panel.

Note

Three things to read correctly. The factors are smoothed, so factors at date \(t\) uses curves after \(t\); forecast() re-filters to the one-sided state before propagating, which is why its first step does not equal the last fitted curve pushed forward. Standard errors are reported for the forecast only, from factor uncertainty and measurement noise, never for the parameters – there is no coefficient covariance on this record. And the decay \(\lambda\) sets where the curvature loading peaks, at \(\tau \approx 1.79 / \lambda\); a fitted decay far from the Diebold-Li value for the panel’s time unit (0.0609 per month, 0.73 per year) usually means the unit, not the curve, is unusual.

Variables:
  • panel – The observed (nobs, p) yield panel (missing entries numpy.nan).

  • maturities – The (p,) maturities.

  • decay – The fitted loading decay lambda.

  • decay_fixed – Whether the decay was held fixed rather than estimated.

  • mu – (3,) factor means (level, slope, curvature).

  • ar – (3,) diagonal factor persistences.

  • state_innovation_cov – (3, 3) factor innovation covariance.

  • measurement_var – (p,) per-maturity measurement variances.

  • factors – (nobs, 3) smoothed factor paths.

  • factor_cov – (nobs, 3, 3) smoothed factor covariances.

  • llf – Exact Gaussian log-likelihood.

  • nobs – Curve dates.

  • n_params – Free parameters the likelihood was maximized over.

See also

References

Nelson, C. R., & Siegel, A. F. (1987). Parsimonious modeling of yield curves. Journal of Business, 60(4), 473-489.

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

Curves on four maturities generated from persistent level, slope and curvature factors at decay 0.6 and read with 5 basis points of noise. The one-step fit tracks each factor, reproduces the panel to within the noise, prices a maturity it never saw, and forecasts with standard errors that grow with the horizon:

>>> import numpy as np
>>> from cultivars.engine._core._polynomials import _nelson_siegel_loadings
>>> rng = np.random.default_rng(0)
>>> taus = np.array([0.5, 2.0, 5.0, 10.0])
>>> basis = _nelson_siegel_loadings(taus, 0.6)
>>> mu = np.array([5.0, -1.5, 0.5])
>>> f = np.tile(mu, (40, 1))
>>> for t in range(1, 40):
...     f[t] = mu + 0.9 * (f[t - 1] - mu) + 0.2 * rng.standard_normal(3)
>>> curves = f @ basis.T + 0.05 * rng.standard_normal((40, 4))
>>> res = DynamicNelsonSiegel(curves, taus, decay=0.6).fit()
>>> res.nobs, res.n_maturities, res.n_params, res.decay_fixed
(40, 4, 16.0, True)
>>> bool(np.corrcoef(res.level, f[:, 0])[0, 1] > 0.95)
True
>>> bool(np.sqrt(np.mean((res.fitted_curves() - curves) ** 2)) < 0.1)
True
>>> res.curve(-1, maturities=[7.0]).shape
(1,)
>>> mean, std = res.forecast(6)
>>> mean.shape, bool(np.all(std[-1] > std[0]))
((6, 4), True)

Private attributes#

_params

The parameter record, rebuilt for the system builder.

Private methods#

_comparison_label()

Specification label used when this result appears in a ranking.

_summary_table()

Structured summary rendered by every display path.