I have been working on getting input parameters to the Non-Linear Optimization which gives the Nelson Siegel Svensson model parameters and am carrying out the OLS regression as described in this answer. However, the input parameters obtained from the OLS are too far off the actual parameters, which I checked against some parameters I actually do have. I am using the equations shown in 'Figure 5' on Page 12 of this paper, and obtain the yield data, by choosing Par Bonds and using their coupons as Par Yields to bootstrap from to get the Spot Rates, which appears to be an okay method based on Page 3 of this paper. The code that I use is below, where I've just implemented the formula in the previous link and have carried out the regression in Python. My query is if there is an issue with the way I set matrix_of_params or if it could be to do with the data in df itself.

I run the function above for different values of tau_1 and tau_2. I then have a function to get the params associated with the lowest residuals, which I am positive is correct.

#df is a Dataframe containing all the data about the Bonds
def obtainingparams(self, df, tau_1, tau_2, residuals):
    values = []
    face_values = df['FACE_VALUE'].values #Writing face values to an array
    yields = (df['coupon'].values) #COUPON = YTM for Par Bonds         
    spot_rate = np.zeros((yields.shape[0]))   

    #Calculating Spot Rates
    for x, value in np.ndenumerate(yields):
        index = x[0]
        if index == 0:
            spot_rate[index] = (yields[index]/face_values[index]) * 100

            adding_negatives = 0
            if index < spot_rate.shape[0]:
                for i in range (0, index, 1):
                    adding_negatives = adding_negatives + (value*face_values[index]/200)/np.power((1+(spot_rate[i]/200)),i+1)
                    term_1 = face_values[index] - adding_negatives 
                    spot_rate[index] = (2 * ((np.power(((((face_values[index] + ((value*face_values[index]/200)))/term_1))),1/(index+1)))-1))*100

    matrix_of_params = np.empty(shape=[1, 4])
    months_to_maturity_matrix = df.months_to_maturity.values #Writing months to maturity to an array

    #Populating the Matrix of Parameter Coefficients
    count = 0
    for x, value in np.ndenumerate(months_to_maturity_matrix):
        if count < months_to_maturity_matrix.shape[0]:
            months_to_maturity = months_to_maturity_matrix[count]
            years_to_maturity = months_to_maturity/12.0  

            #Applying the equation in the link
            newrow = [1, ((1-np.exp(-years_to_maturity/tau_1))/(years_to_maturity/tau_1)), ((1-np.exp(-years_to_maturity/tau_1))/(years_to_maturity/tau_1))-(np.exp(-years_to_maturity/tau_1)), ((((1-np.exp(-years_to_maturity/tau_2))/(years_to_maturity/tau_2))))-(np.exp(-years_to_maturity/tau_2))] 
            count = count + 1

            #Just adding the new row to the matrix of parameter coefficients
            matrix_of_param_coefficients = np.vstack([matrix_of_params, newrow]) 

    #Carrying out OLS Regression                
    params = np.linalg.lstsq(matrix_of_params,spot_rate)[0] 
    residuals = np.sqrt(((spot_rate - matrix_of_params.dot(params))**2).sum())  

   #To keep track of which params are associated with which residuals
   values.append((tau_1, tau_2, residuals, params)) 
   return values

Thank You

  • $\begingroup$ @haginile With reference to your answer here would I need to divide newrow in the code above by 100? Thank You. $\endgroup$
    – Jojo
    Commented Aug 5, 2015 at 21:56

1 Answer 1


First of all you need to get the YTM. The parametric model has an economic interpretation so coupons would mess the estimation and the interpretation of your model. Because of that the values of both taus must be restricted so you can avoid multicoliniarity. If they are the same you are saying that both curvatures are on the same tenor but then your model is reduced to the Nelson Siegel.

  • $\begingroup$ I actually left out that part initially when I wrote the question, so I apologize. I've edited the question to include the YTM calcs for Zero-Coupon Bonds. $\endgroup$
    – Jojo
    Commented Aug 5, 2015 at 22:51

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.