Nelson-Siegel-Svensson Yield Curve Fitting
The Nelson-Siegel-Svensson (NSS) model represents the zero-rate curve as a small set of economically interpretable level, slope, and hump factors. It is a smoothing model, not an arbitrage-free curve construction method: use bootstrapped discount factors for pricing, and use NSS where a stable low-dimensional representation is useful for reporting, scenarios, and relative value.
The functional form
For maturity τ, a continuously compounded NSS zero rate is:
y(τ) = β0 + β1 L1(τ, λ1) + β2 L2(τ, λ1) + β3 L2(τ, λ2)
L1 = (1 - exp(-λτ)) / (λτ)
L2 = L1 - exp(-λτ)
β0 is the long-run level because all loading terms decay to zero. β1 controls the short-end slope, while β2 and β3 create medium- and long-dated humps. The locations of those humps are governed by λ1 and λ2; their effects are nonlinear and are the source of most fitting fragility.
| Parameter | Limiting or primary effect | Practical interpretation |
|---|---|---|
β0 | y(∞) | long-end level |
β1 | short rate relative to β0 | slope |
β2 | hump near 1.8 / λ1 | medium curvature |
β3 | second hump near 1.8 / λ2 | long curvature |
λ1, λ2 | loading decay | hump locations |
Fit rates with one compounding convention and maturities expressed in year fractions. Feeding a mix of par yields, bond yields, and zero rates into the same regression gives parameters a misleading appearance of precision. Start with an arbitrage-consistent curve from yield-curve bootstrapping, then sample its zero rates at a deliberate maturity grid.
Conditional linear estimation
Conditional on λ1 and λ2, the betas are ordinary weighted least squares. This separates a difficult six-dimensional optimization into a two-dimensional nonlinear search plus a stable linear solve.
import numpy as np
def nss_loadings(tau, lam1, lam2):
def l1(lam):
x = lam * np.asarray(tau)
return -np.expm1(-x) / x
a = l1(lam1)
return np.column_stack([np.ones_like(a), a, a - np.exp(-lam1*tau),
l1(lam2) - np.exp(-lam2*tau)])
def fit_betas(tau, zeros, weights, lam1, lam2):
X = nss_loadings(np.asarray(tau), lam1, lam2)
W = np.sqrt(np.asarray(weights))[:, None]
return np.linalg.lstsq(W * X, W[:, 0] * zeros, rcond=None)[0]
Search on transformed positive parameters, for example log(λ1) and log(λ2), and impose an ordering such as λ1 > λ2 to avoid label-switching. Multi-start optimization matters: very different lambdas can generate nearly identical in-sample curves but unstable extrapolation. Weighting should reflect the use case. Equal weights overemphasize a dense short-end grid; inverse bid-offer or DV01 weights better connect residuals to economically meaningful error.
Residuals are risk signals
The root-mean-square residual is insufficient. Inspect residuals in basis points by maturity, changes in fitted parameters through time, and forward-rate behavior outside the observed nodes. A smooth zero curve can imply oscillating instantaneous forwards, especially when the two hump loadings nearly coincide.
| Diagnostic | Failure signature | Response |
|---|---|---|
| parameter time series | lambda jumps with little curve move | constrain or regularize |
| residual by tenor | persistent local cluster | add a knot or revise weights |
| implied forwards | negative/oscillating tails | shorten extrapolation or constrain |
| holdout repricing | errors at liquid benchmarks | fit discount factors more carefully |
An NSS fit should not replace the production discount curve. Discounting a swap with a curve that does not reprice its input instruments introduces P&L unrelated to the market. A robust workflow stores both: the bootstrapped curve for valuation and the NSS factors for state compression.
Relative value and scenarios
NSS makes a cross-sectional residual observable: compare a bond's market-implied zero or spread-adjusted yield with the fitted curve at its duration-equivalent maturity. That residual is only a candidate signal. It can reflect liquidity, tax treatment, repo specialness, credit, or a cash-flow approximation rather than a mispricing.
For risk, shock betas and lambdas separately. A β0 shock is approximately parallel only at long maturities; β1 is concentrated at the front end. Lambda shocks move the locations of curvature and are nonlinear, so calculate full repriced P&L rather than attaching a fixed “curvature DV01.” Combine factor shocks with the key-rate perspective in duration and convexity.
Key takeaways
- NSS is a compact descriptive factor model, not a substitute for an instrument-repricing curve.
- Conditional least squares makes calibration more stable than unconstrained six-parameter fitting.
- Parameter bounds, ordering, and economically motivated weights prevent spurious humps.
- Validate residual patterns, forward curves, and out-of-sample behavior—not RMSE alone.
- Treat fitted residuals as hypotheses after controlling for liquidity and instrument-specific effects.
