Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
This post introduces Nelson-Siegel-Svensson (NSS) yield curve model which is an extension of Nelson-Siegel (NS) model with an additional curvature factor. It aims to fit longer term maturities well.

# Nelson-Siegel-Svensson model

Svensson (1995) suggests an extended NS model which is typically called NSS model. Many central bank use NSS model and Gürkaynak et al. (2007) also use it to fit U.S. Treasury yield curve. The reason why NSS model is widely used is evident. As can be seen the following dynamic figure, It fits yields at long-term maturities well.

For your information, this blog has dealt with Nelson-Siegel model as follows.

### Nelson-Siegel-Svensson model

Nelson-Siegel model is a non-linear least square problem with 6 parameters with some inequality constraints.
\begin{align} y(\tau) &= \beta_1 + \beta_2 \left( \frac{1-e^{- \tau \lambda_1 }}{\tau \lambda_1 }\right) \\ &+ \beta_3 \left(\frac{1-e^{- \tau \lambda_1 }}{\tau \lambda_1 }-e^{- \tau \lambda_1 }\right) \\ &+ \beta_4 \left(\frac{1-e^{- \tau \lambda_2 }}{\tau \lambda_2 }-e^{- \tau \lambda_2 }\right) \end{align} \begin{align} \beta_1 > 0, \beta_1 + \beta_2 >0 \\ \lambda_1 > \lambda_2 > 0 \end{align}
Here, $$\tau$$ is a maturity and $$y(\tau)$$ is a continuously compounded spot rate with $$\tau$$ maturity. $$\beta_1, \beta_2, \beta_3\, \beta_4$$ are coefficient parameters. $$\lambda_1$$ and $$\lambda_2$$ are the decay parameters.

$$\lambda_1$$ and $$\lambda_2$$ determine the shapes of slope and two curvature factor loadings as follows.

In the above figure, I use $$\lambda_1 = 0.0609$$ and $$\lambda_2 = 0.01$$, which represent the maximum of curvature loadings are attained at nearly 30-month and 180-month respectively. Smaller $$\lambda_2$$ fits the yield curve at longer maturities well but it lowers the interpretability of the level factor. For this reason too small $$\lambda_2$$ is not appropriate and is needed to be constrained by some reasonable upper and lower bounds.

### Restrictions on $$\lambda_1$$ and $$\lambda_2$$

The most difficult part of the estimation of NSS model is how to choose $$\lambda_1$$ and $$\lambda_2$$. Without suitable restrictions on these two parameters, estimates of these parameters exhibit too excessive or erratic. It is typical to determine $$\lambda_1$$ from ranges of medium-term maturities and $$\lambda_2$$ from ranges of long-term maturities. I set two ranges of maturities as 1 ~ 5 years and 6 ~ 20 year for example.

However, reasonable constrains on two decay parameters are dependent on which data is used.

### R code

The following R code estimates parameters of NSS model with yield curves at four dates and compares these results with that of NS model.

 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 #========================================================## Quantitative ALM, Financial Econometrics & Derivatives # ML/DL using R, Python, Tensorflow by Sang-Heon Lee ## https://kiandlee.blogspot.com#——————————————————–## Estimation of Nelson-Siegel-Svensson model#========================================================# graphics.off(); rm(list = ls())library(alabama) #———————————————–# Nelson-Siegel-Svensson function#———————————————– # NSS factor loadingnss_loading <– function(la,m) {    la1 <– la[1]; la2 <– la[2]    C  <– cbind(        rep(1,length(m)),            (1–exp(–la1*m))/(la1*m),                     (1–exp(–la1*m))/(la1*m)–exp(–la1*m),        (1–exp(–la2*m))/(la2*m)–exp(–la2*m))    return(C)} # fitting functionnss_fit <– function(para, m) {    beta <– para[1:4]    return(nss_loading(para[5:6],m)%*%beta)} # objective functionnss_objf <– function(para, y, m) {    return(sqrt(mean((y – nss_fit(para, m))^2)))} # constrOptim.nl constraint function ( > )nss_constf <– function(para, y, m) {        beta <– para[1:4]     la1  <– para[5]; la2 <– para[6]    h    <– rep(NA, 6)        # b1 > 0, b1+b2 > 0    h[1] <– beta[1]             h[2] <– beta[1]+beta[2]        # 0.15 > la1 > 0.03    h[3] <– 0.15–la1    h[4] <– la1–0.03        # 0.025 > la2 > 0.0075    h[5] <– 0.025–la2    h[6] <– la2–0.0075        return(h)} #===========================================================# 1. Read data#===========================================================    # Estimated parameters of Nelson-Siegel (Benchmark)str.ns_est<– “    beta1      beta2       beta3     lambda       rmse    7.949446  0.2933681 -0.08749462 0.11555381 0.07665367    7.052864 -1.5778886 -0.42253575 0.01823114 0.06432032    5.586903 -0.5600670 -1.43976821 0.03357762 0.06423196    6.011739  0.3470154 -1.00018107 0.04565435 0.09314726″ m.ns_est <– read.table(text = str.ns_est, header=TRUE) str.zero <– “    mat 19890630 19950929 19980831 20000929    3   8.171964 5.413123 4.931036 6.180960    6   8.143305 5.509881 4.949141 6.207158    9   8.123782 5.592753 4.962873 6.204367    12  8.111922 5.654558 4.962513 6.176521    24  7.974091 5.782513 4.824109 5.932045    36  7.943757 5.841313 4.868401 5.862433    48  7.959505 5.920732 4.888494 5.825789    60  7.942511 5.967207 4.900205 5.799035    72  8.000704 6.013260 4.980854 5.826354    84  8.010956 6.055806 4.977891 5.847383    96  8.020059 6.151399 5.007556 5.859937    108 8.027901 6.224049 5.054961 5.875451    120 8.037343 6.265079 5.100250 5.912506    144 8.063573 6.364383 5.200412 6.002328    180 8.052892 6.512078 5.347487 6.093959    240 7.971860 6.718515 5.482335 6.091155    300 7.861711 6.789321 5.422557 5.972525    360 7.721083 6.599990 5.246325 5.697709″ df <– read.table(text = str.zero, header=TRUE)m  <– df$mat; nmat <– length(m) #===========================================================# 2. Parameter estimation#=========================================================== ctrl.optim <– list(maxit=50000, trace=0, reltol = 1e–10, abstol = 1e–10)ctrl.outer <– list(eps = 1e–10, itmax = 50000, method = “Nelder-Mead”, NMinit = TRUE) # output containerm.nss_est <– matrix(NA, 4, 7)m.nss_fit <– matrix(NA, length(m), 4) # Estimation of Nelson-Siegel-Svenssonfor(i in 1:4) { y <– df[,1+i] x_init <– c(y[nmat], y[1]–y[nmat], 2*y[6] –y[1]–y[nmat], 2*y[15]–y[1]–y[nmat], 0.0609, 0.01) opt <– constrOptim.nl(y = y, m = m, par=x_init, fn=nss_objf, hin=nss_constf, control.optim =ctrl.optim, control.outer=ctrl.outer) m.nss_est[i,] <– c(opt$par, opt$value) m.nss_fit[,i] <– nss_fit(opt$par, m)    colnames(m.nss_est) <– c(“beta1”, “beta2”,         “beta3”, “beta4”, “lambda1”, “lambda2”,“rmse”)} colnames(m.nss_fit) <– paste0(“fitting-“,1:4) #=======================================================# 3. Estimation results#======================================================= # NSS factor loadingmi <– 1:360x11(width = 16/2.5, height = 5); matplot(mi, nss_loading(c(0.0609, 0.01),mi),         type = “l”, lwd=6, xlab = “Maturity (month)”,        ylab = “Factor loading”)legend(“right”,        legend=c(“Level”, “Slope”, “Curvature1”, “Curvature2”),       pch = c(15,16), border=“white”, box.lty=0, cex=1,       col = c(“black”,“#DF536B”, “#61D04F”, “#2297E6”)) # Parameter estimatesm.ns_estm.nss_est # data and fitted yieldsround(cbind(df[,–1], m.nss_fit),3)    Colored by Color Scripter cs

The following estimation results show that NSS model provides good in-sample fit than NS model except the second date. This is related to the restrictions on the decay parameters. When these constraints are relaxed, the results will changed. I expect that.

Four selected dates, fitting results of NSS model show relative good fitting results. Instead, we can find that level factor ($$\beta_1$$) is affected by the introduction of the second curvature factor ($$\beta_4$$). In other words, there is some distinct difference in level factors between NS model and NSS model.

Using the same data, it seems that NS model has some difficulties in fitting yields at longer-term maturities. Unlike NSS model, the level factor of NS model represent current long-term rate well.
However, in most cases, NS model is sufficiently good fitting results. In other words, it is likely that the second curvature factor can be a superfluous factor in many normal days, which is considered an overfitting.

In particular, when the second curvature factor is not identified by data, so called compounding effect can take place. This is the case when two curvature estimates are too large in magnitude with the opposite signs. This compounding effect can be occurred between the slope and the curvature factors.

### Concluding Remarks

This post estimates Nelson-Siegel-Svensson yield curve model which aims to fit longer term maturities well. It is worth noting that to get reasonable parameter estimates, proper restrictions on two decay parameters are needed. I think that research on estimation of NSS model is under way.

### Reference

Gürkaynak, R. S., B. Sack, and J. H. Wright (2007), “The U.S. Treasury Yield Curve: 1961 to the Present,” Journal of Monetary Economics 54-8, 2291–2304.

Svensson, L.E. (1995), “Estimating Forward Interest Rates with the Extended Nelson and Siegel Method,” Sveriges Riksbank Quarterly Review 3, 13–26.