# Understanding how to obtain Nelson Siegel Svensson parameters

I am trying to determine the parameters for the Nelson Siegel Svensson model and am solving a Non- Linear Optimization problem to do this. I am using the procedure presented in this paper.

The way I am currently thinking of the set-up is as follows:

Bond 1 is associated with vector $m_1$ which contains all the differences between times to maturity and times of each of the payments for Bond 1. For example, if Bond 1 has 24 months to maturity and has semi_annual coupons $m_1 = [18,12,6,0]$. However, the paper suggests that even the face value needs to be included in $c_{ij}$. But the equation $\sum\limits_{j=1}^{l_i}c_{ij}*d(m_{ij}, \theta)$ gives a very low value for the price of the bond as the $d(m_{ij}, \theta)$ values are turning out to be very small (of the order 10^-34 through to 10^-1, for each bond, as the differences between times to maturity and time of the payment decreases).

So, am I correct in thinking that each bond is associated with a different discount factor vector as $m_{ij}$ changes for each bond?

I guess my main issue is, am I interpreting $m_{ij}$ correctly and hence correctly calculating the discount factors the right way, as I find that they are very small and hence the prices are very small and only got a reasonable answer for the parameters when I take the discount factor to be 1 when $c_{ij} = Face value + Coupon$

Also, I realize in the paper I have cited they just consider the Nelson Siegel model, however in the code I have written below I account for the extra parameters associated with the Nelson Siegel Svensson model.

This is the code that I am using to determine the prices, where df contains all the observed market data:

def calculatingprices(df, beta_0, beta_1, beta_2, beta_3, tau_1, tau_2):
#I am just creating a dict 'd' which will have the months to maturity for each bond as keys and
#a list as its values. The lists will contain the months to maturity - payments associated
#with the bond
months_to_maturity_matrix = df['months_to_maturity'].values
number_of_rows = df.shape[0]
theoretical_price_for_bonds = np.zeros((number_of_rows, 1))
d = {}
for months_to_maturity_bond in months_to_maturity_matrix:
l = []
#Adding the difference in dates to the dict d. Differences, will just be multiples of 6 upto 360 (i.e. the 30 year bond)
for i in range(6, 360, 6):
if i <= months_to_maturity_bond:
l.append(months_to_maturity_bond - i)
else:
l.append(0)
d[months_to_maturity_bond] = l
d_ordered = collections.OrderedDict(sorted(d.items()))

#I then use the formula for the discount factor as follows
for x, value in np.ndenumerate(months_to_maturity_matrix):
diff_between_maturity_and_payments_array = np.array(d_ordered[value])
years_diff_between_maturity_and_payments_array = diff_between_maturity_and_payments_array/12
theoretical_discount_factor = np.exp(-years_diff_between_maturity_and_payments_array * (beta_0 + ((beta_1 + beta_2)*((1-np.exp(-years_diff_between_maturity_and_payments_array/tau_1))/years_diff_between_maturity_and_payments_array/tau_1))-(beta_2*np.exp(-years_diff_between_maturity_and_payments_array/tau_1)) + (beta_3*(((1-np.exp(-years_diff_between_maturity_and_payments_array/tau_2))/years_diff_between_maturity_and_payments_array/tau_2) -np.exp(-years_diff_between_maturity_and_payments_array/tau_2)))))


Thank You

Say at time $t$ , the cash flows of some bond $b$ can be described by the two vectors $\textbf{c}$ and $\textbf{t}$, containing information about the value of the nominal cash flows and cash flow times in years, respectively. Similarly, if we have a range of bonds $B = \{ b_1, ..., b_n\}$ that trade on a market, the matrices $\textbf{C}$ and $\textbf{T}$ contain information about the cash flows and cash flow times for all bonds on the market (in this example, assume that each bond occupy one row).
Assuming no-arbitrage and term-invariant default risk, the vector $\textbf{p}$ of dirty prices for the bonds trading on the market can be recovered using the expression $$\textbf{p} = diag(\textbf{D(T)} \textbf{C}^T)$$ where $\textbf{D(T)}$ is a matrix of observed discount factors corresponding the the individual entries in $\textbf{T}$; for instance $\textbf{d}_{i, j} = e^{-r(\textbf{t}_{i,j})\textbf{t}_{i,j}}$, where $r(t)$ is some function for the spot (or zero coupon) term structure.
In the real world, instead of solving for $\textbf{p}$, we can in fact observe $\textbf{p}$ through our broker or on our Bloomberg terminals, and so we wish to estimate $\textbf{D(T)}$ instead.
So, you've chosen to model $r(t)$ using the NSS parametric model (sometimes referred to as a parsimonious model when comparing with other models of potentially many more predictors). We then choose an objective function, say $$\min_\theta{\sum{(p_i - \hat p_i)^2}}.$$ Here, $p_i$ is the observed dirty price of the $i^{th}$ bond and $\hat p_i$ is the fitted dirty price of the $i^{th}$ bond and $\theta$ is a vector of estimation parameters in our model. We then simply employ some numerical optimization routine on our parameter vector $\theta$ until we find an optimum.