# How do I create a term structure of a bond using QuantLib?

Has anyone used QuantLib to create term structure (i.e bootstrapping process to produce spots) in python? I have been using the below example http://gouthamanbalaraman.com/blog/quantlib-term-structure-bootstrap-yield-curve.html

Now looks like the assumption is that coupon bonds are trading at par (i.e. price of 100) ?

'The rest of the points are coupon bonds. We assume that the YTM given for the bonds are all par rates. So we have bonds with coupon rate same as the YTM.'

But what if they aren't bonds we use are not trading at par? i.e. YTM and coupon rates are different?

Any help is greatly appreciated.

thanks,


import matplotlib
matplotlib.use('macosx')
import matplotlib.pyplot as plt
import QuantLib as ql
import pandas as pd

# Deposit rates
depo_maturities = [ql.Period(1,ql.Months), ql.Period(2,ql.Months),ql.Period(3,ql.Months),ql.Period(6,ql.Months),
ql.Period(9,ql.Months), ql.Period(12, ql.Months)]
depo_cpn = [.08,.24,.40,.68,.34,.52] #yields they are trading at

# Coupon Bonds
bond_maturities = [ql.Period(i, ql.Years) for i in range(2,11)]
bond_cpn = [.5,.75,.1,.625,1.5,1.25,1.625,.875,4.75]
bond_rates = [.114,.151,.187,.252,.214,.272,.311,.4089,4.74]
bond_quotes = [100.896,101.987,103.301,101.926,108.078,107.088,111.111,104.374,144.568]

bond_long_maturities = [ql.Period(12,ql.Years),ql.Period(15,ql.Years),ql.Period(20,ql.Years),ql.Period(25,ql.Years),
ql.Period(30,ql.Years),ql.Period(40,ql.Years),ql.Period(50,ql.Years)]
bond_long_cpn = [4.25,4.5,4.25,3.25,1.75,1.75,1.625] #coupons
bond_long_rates = [.593,.667,.767,.858,.848,.669,.543] #yields
bond_long_quotes = [142.974,152.719,162.806,151.432,123.016,135.634,148.58,]

'''####### Depo Helpers #########'''

calc_date = ql.Date(24, 3, 2020)
ql.Settings.instance().evaluationDate = calc_date

calendar = ql.UnitedKingdom()
day_count = ql.Thirty360()
end_of_month = True
settlement_days = 0
face_amount = 100
coupon_frequency = ql.Period(ql.Annual)

#Create depo bondhelps
depo_helpers = [ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(r/100.0)),
m,
settlement_days,
calendar,
end_of_month,
day_count )
for r, m in zip(depo_cpn, depo_maturities)]

'''####### Bonds Helpers #########'''

day_count = ql.Thirty360()
end_of_month = True
settlement_days = 2

# create fixed rate bond helpers from fixed rate bonds
bond_cpn += bond_long_cpn
bond_maturities += bond_long_maturities
bond_quotes += bond_long_quotes
bond_rates += bond_long_rates

bond_helpers = []
for r, m, q in zip(bond_cpn, bond_maturities,bond_quotes):
termination_date = calc_date + m
quote = ql.QuoteHandle(ql.SimpleQuote(q))
schedule = ql.MakeSchedule(calc_date,termination_date,m)

bond_helpers.append(helper)

#The yield curve is constructed by putting the two helpers together.

rate_helpers = depo_helpers + bond_helpers
yieldcurve = ql.PiecewiseLogCubicDiscount(calc_date,rate_helpers, day_count)

#The spot cpn is obtined from yieldcurve object using the zeroRate method.
spots = []
tenors = []
for d in yieldcurve.dates():
yrs = day_count.yearFraction(calc_date, d)
compounding = ql.Compounded
freq = ql.Annual
zero_rate = yieldcurve.zeroRate(yrs, compounding, freq)
tenors.append(yrs)
eq_rate = zero_rate.equivalentRate(day_count,
compounding,
freq,
calc_date,
d).rate()
spots.append(100*eq_rate)

spotcurve = pd.DataFrame(dict(tenors=tenors,spots=spots))
spotcurve.set_index('tenors',inplace=True)

print('\n')
spotcurve = spotcurve.iloc[1:]
pars = depo_cpn+bond_rates
spotcurve['pars'] = pars
spotcurve['spots'] = round(spotcurve['spots'],3)
print(spotcurve)

plt.figure(figsize=(7,4))
plt.plot(spotcurve)#,'b',lw=1.5)
plt.plot(spotcurve,'ro')
plt.grid(True)
plt.xlabel('Tenor')
plt.ylabel('Curves')
plt.show()
$$$$


You should look at the inputs for the helpers. I believe the example you pointed to is an aproximation to build the curve with the yields, but the inputs are actually in prices. Check this example that is hopefully self explanatory.

quote = ql.QuoteHandle(ql.SimpleQuote(115.5))
settlementDays = 2
faceAmount = 100
schedule = ql.MakeSchedule(ql.Date(15,6,2020), ql.Date(15,6,2021), ql.Period('1y'))
coupons = [0.0195]
dayCounter = ql.ActualActual()
ql.FixedRateBondHelper(quote, settlementDays, faceAmount, schedule, coupons, dayCounter)
`
• great thanks @David I think am getting it now. As you can see I have just started using QL probably will have to try some more examples to get my head around it properly. – TRex Mar 24 '20 at 15:46
• btw what's the difference between ql.Schedule and ql.MakeSchedule? – TRex Mar 24 '20 at 23:49
• Schedule is the class and MakeSchedule is a helper to create an instance of the class – David Duarte Mar 24 '20 at 23:56
• thanks again David – TRex Mar 25 '20 at 0:08
• hi David, my bootstrapped curve is really all over the place. any chance you could have a look at the codes (added above) and advise where am going wrong? Also, wanted to confirm for 'bond_cpn' I am using the coupon rate (not the yield). appreciate your help again. The spot curve is really different from the curve I see on my Bloomberg screen. – TRex Mar 25 '20 at 0:49