# Difference in duration between zero 0 rate fixed coupon bond and zero coupon bond in Quantlib

I am trying the following example of calculating duration and convexity for a zero coupon bond. For the sake of an easy example, I set the Interest rate to be zero.

In the first attempt, I try using the object ZeroCouponBond(), shown in code below:

maturity_date = ql.Date(1,6,2025)
settlement_date = ql.Date(20,4,2013)
interest_rate_float = 0
coupon_rate = 0

start_date = settlement_date
schedule = ql.Schedule()

day_counter = ql.ActualActual(ql.ActualActual.Bond)
created_bond = ql.ZeroCouponBond(0, ql.NullCalendar(), float(100), maturity_date)
Interest_Rate = ql.InterestRate(interest_rate_float/100, day_counter, ql.Compounded, 2)

Convexity = ql.BondFunctions.convexity(created_bond, Interest_Rate, settlement_date)
print(Convexity/100)

mod_dur = ql.BondFunctions.duration(created_bond, Interest_Rate, ql.Duration.Modified, settlement_date)
print(mod_dur)

sim_dur = ql.BondFunctions.duration(created_bond, Interest_Rate, ql.Duration.Simple, settlement_date)
print(sim_dur)


This gives me the following values:

convexity: 1.5283241884030772

modified duration: 12.115068493150684

simple duration: 12.115068493150684

I repeat this process with a FixedRateBond() with coupon rate set to zero, as shown below:

maturity_date = ql.Date(1,6,2025)
settlement_date = ql.Date(20,4,2013)
interest_rate_float = 0
coupon_rate = 0

start_date = settlement_date

day_counter = ql.ActualActual(ql.ActualActual.Bond)
created_bond = ql.FixedRateBond(0, float(100), schedule, [float(coupon_rate/100)], day_counter)
Interest_Rate = ql.InterestRate(interest_rate_float/100, day_counter, ql.Compounded, 2)

Convexity = ql.BondFunctions.convexity(created_bond, Interest_Rate, settlement_date)
print(Convexity/100)

mod_dur = ql.BondFunctions.duration(created_bond, Interest_Rate, ql.Duration.Modified, settlement_date)
print(mod_dur)

sim_dur = ql.BondFunctions.duration(created_bond, Interest_Rate, ql.Duration.Simple, settlement_date)
print(sim_dur)


This time, I get the following results:

convexity: 1.528402366863905

modified duration: 12.115384615384615

simple duration: 12.115384615384615

Why is there a difference in the two ways? Am I doing something wrong?

P.S: I checked the results against bloomberg and the values match with those that I get when I use Method 2 (i.e. FixedRateBond())

My guess is that Quantlib is mixing the stated compounding frequencies.

If I run this,

# PYTHON v3.12
from rateslib import *  # v 1.4.0

frb = FixedRateBond(
effective=dt(2013, 4, 20),
termination=dt(2025, 6, 1),
fixed_rate=0.0,
convention="ActActBond",
frequency="S",
modifier="none",
)
frb.convexity(ytm=0, settlement=dt(2013, 4, 20))
# 1.528402366863905
frb.duration(ytm=0, settlement=dt(2013, 4, 20), metric="modified")
# 12.115384615384615
frb.duration(ytm=0, settlement=dt(2013, 4, 20), metric="duration")
# 12.115384615384615


whilst,


frb = FixedRateBond(
effective=dt(2013, 4, 20),
termination=dt(2025, 6, 1),
fixed_rate=0.0,
convention="ActActBond",
frequency="A",    # <- NOTE THIS CHANGE
modifier="none",
)
frb.convexity(ytm=0, settlement=dt(2013, 4, 20))
# 1.588899530868831
frb.duration(ytm=0, settlement=dt(2013, 4, 20), metric="modified")
# 12.115068493150686
frb.duration(ytm=0, settlement=dt(2013, 4, 20), metric="duration")
# 12.115068493150686


You can match these figures against your output and note that in Quantlib the convexity doesn't change from one to the another so that leads to my guess.

• In QuantLib, the convexity does change, although by a smaller amount. I get your point. I test it out by changing the day count convention to Actual365Fixed() in both the methods and get the same durations and convexities Commented Jul 10 at 13:46
• On further thought, I wonder why changing the compounding frequency is changing the duration of zero coupon bond at all. The duration of a zero coupon bond is simply the time to maturity, so this should be independent of compounding frequency Commented Jul 10 at 14:05