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
I run the function above for different values of
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)) #Calculating Spot Rates for x, value in np.ndenumerate(yields): index = x if index == 0: spot_rate[index] = (yields[index]/face_values[index]) * 100 else: adding_negatives = 0 if index < spot_rate.shape: 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: 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) 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