Class Svensson

java.lang.Object
com.quantfinlib.rates.Svensson

public final class Svensson extends Object
SVENSSON (Nelson-Siegel-Svensson) yield-curve fit — NelsonSiegel with a SECOND curvature hump, the form most central banks actually publish (the ECB's daily curve is exactly this):
   z(t) = b0 + b1 * f1(t/l1) + b2 * f2(t/l1) + b3 * f2(t/l2)
   f1(x) = (1 - e^-x)/x        f2(x) = (1 - e^-x)/x - e^-x
 
  • b0 — the LEVEL: z(infinity);
  • b1 — the SLOPE: z(0) = b0 + b1 (b1 > 0 is inversion);
  • b2, lambda1 — the FIRST hump and where it sits;
  • b3, lambda2 — the SECOND hump: the long-end flex a single hump cannot bend into — real curves routinely show a short-end bump (policy expectations) AND a 10y+ dip (convexity demand), and plain Nelson-Siegel must split the difference.

Fitting mirrors NelsonSiegel exactly: for FIXED (l1, l2) the model is LINEAR in (b0, b1, b2, b3) — an exact 4-regressor OLS solve — so the fit is a 2-D log-spaced grid over the lambdas with an OLS solve per node, deterministic and free of local-minimum roulette. Nodes with lambda2 <= lambda1 are skipped: the two f2 regressors collide as the lambdas meet (exact collinearity at equality), and the ordering makes the parameterization identifiable — hump one is always the shorter-dated one. Betas are NOT sign-constrained: an inverted or double-dipped curve is data, not an error.

With b3 = 0 the model IS Nelson-Siegel, so with the lambdas free Svensson can always match NS in-sample; the two FITTERS search different lambda grids (NS: 80 nodes 1-D; here: 50 nodes 2-D with lambda1 < 10), so on data whose best single lambda falls between this grid's nodes NS can win by a grid-granularity sliver (rmse differences at the 1e-8 level, tested to agree within tolerance). The price of the extra hump is two more parameters — on sparse or single-hump curves prefer NS and let InformationCriteria referee. Research lane.

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final record 
    Fitted parameters plus the fit's root-mean-square error.
  • Method Summary

    Modifier and Type
    Method
    Description
    fit(double[] tenorYears, double[] zeroRates)
    Fits by 2-D log-spaced lambda grid (0.1y-10y, 50 nodes per axis, lambda2 > lambda1 only) + exact 4-regressor OLS per node.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Method Details

    • fit

      public static Svensson.Fit fit(double[] tenorYears, double[] zeroRates)
      Fits by 2-D log-spaced lambda grid (0.1y-10y, 50 nodes per axis, lambda2 > lambda1 only) + exact 4-regressor OLS per node.
      Parameters:
      tenorYears - observation tenors, ≥ 6 distinct, all > 0
      zeroRates - observed zero rates (continuously compounded)