# QuantLib returns slightly different bondYield when backtested

I am just starting to get familiar with QuantLib (in particular, fixed rate bond pricing functions). I read a number of examples, from which I am able to calculate bond price and bond yield.

The following script uses an input yield (0.057154825761367800000) to calculate a bond price (96.9073930899788536), using bond.cleanPrice.

I then took that calculated bond price, and fed it back into a bond.bondYield calculation (other inputs unchanged), expecting to get back my original input yield.

I found the back-calculated yield was close, but not as close as I would naively expect (it matched to 8 decimal places). Did I do something wrong? Is this acceptable precision based on the numerical solver max iterations? Something else?

import QuantLib as ql

def calculate_bond_price():

settlementDays = 0
faceValue = 100

issueDate = ql.Date(11, 2, 2020)
maturityDate = ql.Date(11, 2, 2025)
tenor = ql.Period(ql.Quarterly)
calendar = ql.NullCalendar()
dateGeneration = ql.DateGeneration.Backward
monthEnd = False

coupon_rate = 0.05
coupons = [coupon_rate]

dayCount = ql.Thirty360()

bond = ql.FixedRateBond(settlementDays, faceValue, schedule, coupons, dayCount)

## manually specify a yield rate to 16 decimal places
## this is the value I expect to get back from bond.bondYield calculation
yield_rate = 0.057154825761367800000

bond_price = bond.cleanPrice(yield_rate, dayCount, ql.Simple, ql.Quarterly)
print(f'PRICE >> calculated={bond_price:20,.16f}')
# OUTPUTS: PRICE >> calculated= 96.9073930899788536

# feed the calculated bond price back into a bond.bondYield calculation with exact same (dayCount, Simple, Quarterly) inputs
# expect to get back the yield_rate (16 decimal); but only match to 8 decimals
back_calculate_bond_yield = bond.bondYield(bond_price, dayCount, ql.Simple, ql.Quarterly)
print(f'YIELD >> calculated={back_calculate_bond_yield:20,.16f} | expected={yield_rate:20,.16f} | diff={back_calculate_bond_yield-yield_rate:20,.16f}')
# OUTPUTS: YIELD >> calculated=  0.0571548314094543 | expected=  0.0571548257613678 | diff=  0.0000000056480865

if __name__ == '__main__':
calculate_bond_price()

• IMHO, matching beyond 8 decimal places seems economically absolutely irrelevant. – skoestlmeier Feb 12 at 6:58
• @skoestlmeier - in real life, yes. But showing a "perfect" match will make it easier to convince Vetting my code is doing what it should. – Roberto Feb 12 at 12:20

I would start by saying that yes, this is an acceptable precision.

However, the reason you are not getting the same result is because, by default, QuantLib has accuracy=1.0e-8 and maxEvaluations=100.

You can set these parameters like this:

bond.bondYield(bond_price, dayCount, ql.Simple, ql.Quarterly, ql.Date(), 1.0e-16, 100)

This will get you much closer...

YIELD >> calculated= 0.0571548257613679 | expected= 0.0571548257613678 | diff= 0.0000000000000001

• Thanks, that almost certainly explains it! I will run some tests tomorrow and mark your answer. Looks like those precision parameters you mentioned are in the reference manual (quantlib.org/reference/…), but I am still finding my way around there and missed it. – Roberto Feb 12 at 2:49