Nelson-Siegel or Svensson model with fixed lambda
Nelson-Siegel (NS) model is of the following yield function with positive dacay parameter (\(\lambda > 0 \)).
\[\begin{align} y(\tau) = \beta_1 + \beta_2 \left( \frac{1-e^{- \tau \lambda}}{\tau \lambda}\right) + \beta_3 \left(\frac{1-e^{- \tau \lambda}}{\tau \lambda}-e^{- \tau \lambda}\right) \end{align}\] Svensson (SV) model has the following yield function with positive dacay parameters (\( \lambda_1 > \lambda_2 > 0 \)).
\[\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}\]
Here, \(\tau\) is a maturity and \(y(\tau)\) is a continuously compounded spot rate with \(\tau\) maturity. \(\beta_1, \beta_2, \beta_3\) or \(\beta_4\) are coefficient parameters.
Given decay parameter(s), NS or SV model can be estimated easily by using OLS.
Library and user-defined functions
I implemented two functions: f_get_ns_factor_fixed_lambda() for the period-by-period OLS and f_draw_ns_factor() for drawing yield factors.
import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.linear_model import LinearRegression %matplotlib inline from IPython.core.interactiveshell import InteractiveShell InteractiveShell.ast_node_interactivity = "all" # function for estimate NS or SV yield factors # by using period by period OLS def f_get_ns_factor_fixed_lambda(vm, mrate, vla, type = 'ns'): nrow, ncol = mrate.shape out_fac = list() if type == 'ns': X = np.vstack([np.ones(len(vm)), (1-np.exp(-vla[0]*vm))/(vla[0]*vm), (1-np.exp(-vla[0]*vm))/(vla[0]*vm) - np.exp(-vla[0]*vm)]) elif type == 'sv': X = np.vstack([np.ones(len(vm)), (1-np.exp(-vla[0]*vm))/(vla[0]*vm), (1-np.exp(-vla[0]*vm))/(vla[0]*vm) - np.exp(-vla[0]*vm), (1-np.exp(-vla[1]*vm))/(vla[1]*vm) - np.exp(-vla[1]*vm)]) for t in range(nrow): model = LinearRegression(fit_intercept=False) model.fit(np.transpose(X), mrate[t]) out_fac.append(model.coef_) return np.array(out_fac) # function for drawing a graph of yield factors def f_draw_ns_factor(y, ylegend, x_ticks_no, x_ticks_label): fig, ax = plt.subplots(1,1,figsize=(8, 3)) # fig.set_figwidth(8) ax.plot(y) ax.set_xlabel('Year') ax.set_ylabel('Yield (%)') ax.legend(ylegend) # Set number of ticks for x-axis ax.set_xticks(x_ticks_no) # Set ticks labels for x-axis ax.set_xticklabels(x_ticks_label, rotation='horizontal', fontsize=11) plt.show() | cs |
Estimated yield factors and their movements
Using the above functions, we can easily extract NS yield factors over time.
# maturities in months vm = np.array([3,6,9,12,15,18,21,24,30,36,48,60,72,84,96,108,120]) nmat = len(vm) # US Yield Curve 1972 - 2000 url = 'https://www.dropbox.com/s/inpnlugzkddp42q/bonds.csv?dl=1' df = pd.read_csv(url,sep=';',index_col=0); df # Nelson-Siegel model with a fixed lambda vla = [0.0609] out_ns_fac = f_get_ns_factor_fixed_lambda(vm, rates, vla) pd.DataFrame(out_ns_fac) # Svensson model with two fixed lambda vla = [0.07, 0.02] out_sv_fac = f_get_ns_factor_fixed_lambda(vm, rates, vla, type='sv') pd.DataFrame(out_sv_fac) # Graph x_ticks_no = np.arange(36,nrow,36) x_ticks_label = np.array([x[:4] for x in df.index])[x_ticks_no] f_draw_ns_factor(out_ns_fac, ['L', 'S', 'C'], x_ticks_no, x_ticks_label) f_draw_ns_factor(out_sv_fac, ['L', 'S', 'C1', 'C2'], x_ticks_no, x_ticks_label) | cs |
For example, NS 3 factors are estimated as follows.
0 1 2 0 6.532632 -3.450285 0.500544 1 6.715889 -3.435264 -0.410948 2 6.160223 -2.541603 2.346223 3 6.468915 -3.048362 0.783350 4 6.553063 -2.800586 -0.252667 ... ... ... ... 343 5.548216 0.709016 0.665006 344 5.737054 0.568882 -0.243924 345 5.698509 0.774611 -0.634403 346 5.426825 0.919011 -0.970996 347 5.294994 0.720964 -1.854887 | cs |
Using the drawing function, 3 or 4 yield factors are depicted in the following two graphs sequentially.
As can be seen in the above figures, in general, 4 factors are more noisy than 3 factors since the period-by-period OLS does not impose a temporal restriction on their dynamics. NS models with a higher number of yield factors tend to generate higher volatility of estimated yield factors with jumps and lumpy behaviors.
Concluding Remarks
This post implemented Nelson-Siegel or Svensson model with fixed lambda since it's never around when we need it. \(\blacksquare\)
No comments:
Post a Comment