Hi I have written a program for bootstrapping bond interest rates. The bond price I am getting is 101.99825... when it should be more like 101.999999.....
The inputs to test are Bond Price = 102, ttm = 36, f = 2, face = 100, n = 5.

Heres the program, tried to automate as best as possible.

// ImpliedBondYield.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <cmath>
#include <iomanip>

using namespace std;

double b_est(double x);
double f_deriv(double y);
double midpoint(double t, double t1, double r1, double t2, double r2);

int _tmain(int argc, _TCHAR* argv[])
{
	int B;
	cout << "Enter Bond Price: ";
	cin >> B;
	int ttm;
    cout << "Enter ttm: ";
    cin >> ttm ;
    int f;
    cout << "Enter f: ";
    cin >> f;
    double face;
    cout << "Enter face: ";
    cin >> face ;
    double coupon;
    cout << "Enter coupn: ";
    cin >> coupon;
	

    vector<double> t_cash_flow;
    vector<double> v_cash_flow;
	vector<double> disc;

	vector<double> rates;


    int months_between_cashflows = 12 / f; // Note: integer division
    int initial_cashflow_month = ttm % months_between_cashflows;

    // Assume no payment if t = 0, go to next cashflow time
    if (0 == initial_cashflow_month)
    {
        initial_cashflow_month = months_between_cashflows;
    }

    for (int cashflow_month = initial_cashflow_month;
        cashflow_month <= ttm;
        cashflow_month += months_between_cashflows)
    {
        t_cash_flow.push_back(static_cast<double>(cashflow_month) / 12.0);

        v_cash_flow.push_back(coupon / static_cast<double>(f) +
            static_cast<double>(cashflow_month / ttm) * face);
    }

	double x=0.05;

	

	/* for (unsigned int i = 2; i < t_cash_flow.size(); i++)
	 { 
		 rates.push_back(static_cast<double>(midpoint(t_cash_flow[i], 1, 0.04937, 3, x)));
	 }*/

    for(unsigned int i = 0; i < t_cash_flow.size(); i++)
    {
        cout << "t_cash_flow[" << i << "]    = " << t_cash_flow[i] << endl;
    }

    for(unsigned int i = 0; i < v_cash_flow.size(); i++)
    {
        cout << "v_cash_flow[" << i << "]    = " << v_cash_flow[i] << endl;
    }

	/*for(unsigned int i = 0; i < v_cash_flow.size(); i++)
    {
        cout << "rates[" << i << "]    = " << rates[i] << endl;
    }*/
	
	double best;
	double fderiv;
	double tol = 10E-6;
	double x0 = 0.05;
	double xnew = x0;
	double xold = x0 - 1.0;
	while(abs(xnew - xold) > tol)
	{
		best = 0;
		fderiv = 0;
		rates.clear();
		xold = xnew;
		rates.push_back(2 * log(100/97.5));
		rates.push_back(log(102.5/(100 - 2.5*exp(-(0.5*rates[0])))));
		
		for (unsigned int i = 2; i < t_cash_flow.size(); i++)
		{ 
			rates.push_back(static_cast<double>(midpoint(t_cash_flow[i], 1, rates[1], 3, xold)));
		}
		for(unsigned int i = 0; i < v_cash_flow.size(); i++)
			{
				 cout << "rates[" << i << "]    = " << rates[i] << endl;
			}
		for(unsigned int i=0; i<v_cash_flow.size(); ++i)
		{ 
			best += ( v_cash_flow[i]*exp(-rates[i]*t_cash_flow[i]) );
			fderiv = fderiv + t_cash_flow[i]*v_cash_flow[i]*exp(-rates[i]*t_cash_flow[i]);
		}
		
		xnew = xold + ((best - B)/fderiv);

		

		cout << setprecision (12) << "xnew: " << xnew << " xold: " << xold << endl;
		
		
	}
	for(unsigned int i = 0; i < v_cash_flow.size(); i++)
    {
        cout << "rates[" << i << "]    = " << rates[i] << endl;
    }
	
	
	
	for(unsigned int i=0; i<v_cash_flow.size(); ++i)
	{
		disc.push_back(static_cast<double>(exp(-t_cash_flow[i]*rates[i])));
		Bp = Bp + v_cash_flow[i]*disc[i];
	}
	cout << setprecision (16) << "Implied Yield= " << xnew << endl;
	cout << setprecision (16) << "Bond Price= " << Bp << endl;
	cout << setprecision (16) << "error= " << B - Bp << endl;
	
	system ("pause");

	return 0;
}

double midpoint(double t, double t1, double r1, double t2, double r2)
{
	double func;	
	func = ((t - t1)/(t2 - t1))*r2 + ((t2 - t)/(t2 - t1))*r1;
	return func;
}

Any clues why its not meeting the tol of 10E-6.

Recommended Answers

All 5 Replies

Since I have no idea what a "bootstrapping bond interest rates" is nor how to calculate it, I would suggest letting the program tell you what's wrong.

Before and after key calculations, display values and check them to make sure they are as you expect.

There are several problems:

(i) you haven't given us a piece of code that compiles. What is Bp ?

(ii) you haven't given us the input you use , e.g. what does coupon equal?

(iii) Then you use what I think is the differential equation approximation at each step. Have long look at these two lines

rates.push_back(2 * log(100/97.5));
rates.push_back(log(102.5/(100 - 2.5*exp(-(0.5*rates[0])))));

I am no 100% sure on your algorithm but that is not balanced [i.e. in reverse time it doesn't work.

However, if you algorithm is correct (on paper say) then use a numerical error class instead of double. That was actually what I was going to drop in but the failure to compile killed that. - you have host of potential problems with line like:

func=((t - t1)/(t2 - t1))*r2 + ((t2 - t)/(t2 - t1))*r1

as t2 and t1 are very close to zero.

Sorry I wrote n=5, when I meant coupon = 5. Compiles fine on my comp, using win7 if that makes a difference. I see no problem with either of the functions , both rate and func. Whats a numerical error class?

And bootstrapping bond interest rates is deriving an interest curve given some bonds and their prices, and assuming linearity between the unknown rates and the known to find those unknown.

No its not a matter of the precision of the variable as i have few other newtons method programs. I added another statement to the loop and get the answer i needed, though it seems like it should've met the tolerance without the extra statement.

while(abs(xnew - xold) > tol || abs(best-B) > tol)
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.