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)
                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


1 Answer 1


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.

I hope this helps to not only see how to estimate parameters in the NSS model, but also why it is theoretically more consistent to model spot rates over nominal coupon YTMs (the latter of which I believe you've tried to model, if I interpret your question correctly).

  • $\begingroup$ Thanks. I am aware of some of what you said and am using the spot rates. However, it does answer one of my questions as to whether each bond is associated with a different factor array, which they are. $\endgroup$
    – Jojo
    Jul 23, 2015 at 20:28
  • $\begingroup$ @PhysicsEnvy Would you be able to shed some light on my other question: Should I take the variable m_ij (time to maturity - time of payment for the bond) described in the paper as 0 at the time to maturity, as this results in a discount factor of 1? $\endgroup$
    – Jojo
    Jul 23, 2015 at 20:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.