Yield to Maturity for Bond Pricing

Yield to Maturity in Fixed Income

The Yield to Maturity basically poses the following question:

What r or YTM when applied solves to produce a Present Value = $1010.77? The equation can not be solved algebraically so we will have to rely on numerical or grid search techniques like goal seek in Excel. Below we will also employ the bisection technique which is heavily utilized in Finance.

What r or discount rate can be applied so that the present value of coupons and Face equate to the current market price of bond of $1010.77.

More generally, yield to maturity is the discount rate at which the sum of all future cash flows from the bond (coupons and principal) is equal to the current price of the bond. The yield to maturity provides us with an estimate of the internal rate of return for the bond. This can be important for investors when comparing one bond relative to another. Below, we estimate the Yield of Maturity (YTM) of a Bond using Excel Goal Seek and then introduce the Bisection technique to verify results.

VBA code for Bisection Technique when estimating Yield to Maturity

In the video above we estimate yield to maturity using Goal Seek in Excel. We then automate estimate this estimation using the Bisection technique. This same technique is used for estimating Implied Volatility. When there is closed form formula - we arrive at estimate using trial and error. This can be accomplished by using Bisection

' PV of Bond using PV of Annuity

Function PVBm(cpr, r, T, Face, m)

coup = Face * cpr / m

PVBm = (coup * (1 - (1 + r / m) ^ (-T * m)) / (r / m)) + Face * (1 + r / m) ^ (-T * m)

End Function

' YTM of Bond using Bisection

Function PVBmIRR(cpr, T, Face, m, Target)

H = 2

L = 0

Do While (H - L) > 0.0001

If PVBm(cpr, ((H + L) / 2), T, Face, m) > Target Then

L = (H + L) / 2

Else: H = (H + L) / 2

End If

Loop

PVBmIRR = (H + L) / 2

End Function

Yield to Maturity using Interpolation

For exam purposes and quizzes where manual estimation is relied upon students are generally obliged to use interpolation. For completeness, we introduce the interpolation below using the numerical example set out above

More on Bisection

Below, we create a single unified non-referenced VBA function to estimate Yield to maturity.

Function PVBmIRR(cpr, T, Face, m, Target)


Coup = Face * cpr / m

' PVBm = (Coup * (1 - (1 + r / m) ^ (-T * m)) / (r / m)) + Face * (1 + r / m) ^ (-T * m)


H = 2

L = 0

Do While (H - L) > 0.0001

If (Coup * (1 - (1 + ((H + L) / 2) / m) ^ (-T * m)) / (((H + L) / 2) / m)) + Face * (1 + ((H + L) / 2) / m) ^ (-T * m) > Target Then

L = (H + L) / 2

Else: H = (H + L) / 2

End If

Loop

PVBmIRR = (H + L) / 2

End Function

C++ code for Yield to Maturity for Bond using Bisection

#include <cmath>

#include <iostream>

using namespace std;

double PVB(double Face,double cr,double r,int m, double T)

{

// store the value of the bond

double BV=0.;

// add in coupons

int TNC=T*m;

double cpn = (cr/m)*Face;

for(int i=1;i<=TNC; i++)

{

BV = BV + cpn*pow((1+r/m),-i);

}

BV = BV + Face*pow((1+r/m),-T*m);

return BV;

}

// Bisection Algorithm

double BisecYTM(double Face, double cr, double Target, double T, int m, double a, double b) {

const int MaxIter = 50000;

double Tol = 0.0000001;

double midP = 0.0, midCdif;

double lowCdif = Target - PVB(Face, cr,a, m, T);

double highCdif = Target - PVB(Face, cr, b, m, T);

if (lowCdif*highCdif > 0)

return -1;

else

for (int i = 0; i <= MaxIter; i++) {

midP = (a + b) / 2.0;

midCdif = Target - PVB(Face,cr,midP,m,T);

if (abs(midCdif)<Tol) goto LastLine;

else {

if (midCdif>0) b = midP;

else a = midP;

}

}

LastLine:

return midP;

}

int main()

{

double Face = 1000;

double cr = 0.06;

double Target = 1010.91;

double T = 3;

int m = 2;

double a = 0.000001;

double b = 10;

double YTM = BisecYTM(Face,cr,Target,T, m,a,b);

cout << " YTM = " << YTM << " " << endl;

}

Python Code for Yield to Maturity from Jeffrey Liang Repository based on Bernt Odegaard Financial recipes

The python code below comes Jeffrey Liang github. The examples are based on the workings of Bernt Arne Ødegaard. A copy of Financial Recipes you can be found here. We estimate Yield to Maturity.

# https://bit.ly/2R0yRy5

def bonds_price_discrete(times, cashflows, r):

p = 0

for i in range(len(times)):

p += cashflows[i] / np.power((1 + r), times[i])

return p


def bond_yield_to_maturity_discrete(times, cashflows, bondprice):

ACCURACY = 1e-5

MAX_ITERATIONS = 200

bot = 0

top = 1.

while bonds_price_discrete(times, cashflows, top) > bondprice:

top = top * 2

r = .5 * (top + bot)

for _ in range(MAX_ITERATIONS):

diff = bonds_price_discrete(times, cashflows, r) - bondprice

if np.abs(diff) < ACCURACY:

return r

if diff > 0:

bot = r

else:

top = r

r = .5 * (top + bot)

return r

import numpy as np


c = np.array([60, 60, 1060])

t = np.arange(1, 4)

r = .056

b = np.sum(c * (1. / np.power((1 + r), t)))

print('Bond price, 5.6% percent discretely compounded interest = {:.3f}'.format(

bonds_price_discrete(t, c, r)))


print('bond yield to maturity = {:.4f}'.format(bond_yield_to_maturity_discrete(t, c, b)))