QuantLib
QuantLib copied to clipboard
Bloomberg bond clean price and accrued amount differs from Quantlib
I'm getting the different bond clean price from Bloomberg and from QL but surprisingly Bloomberg price matches with excel price() function
I have the following bond : GETC21117030. The parameters are given below:
Parameter Name | Value |
---|---|
Settlment Date | 30-12-20 |
Bond Issue Date | 17-Jan-19 |
Interest Acrual date | 17-Jan-19 |
Maturity Date | 17-Jan-21 |
Last Coupon Date | 17-Jul-20 |
Coupon Rate | 7.25% |
Coupon Frequency | 2 |
Day Count | ACT/ACT |
Redemption | 100 |
Yield | 7.95% |
Calendar | NullCalendar |
Convention | Unadjusted |
TermPayConv | Unadjusted |
GenRule | Backward |
if you look at the parameters you'll notice that there is only one payment left on maturity date. If I calculate price and accrued interest in QLXL I'm getting different results from Bloomberg. But surprisingly Bloomberg numbers match if I use excel native price calculation function.
I looked into the excel formula and it looks that the price calculate formula is different when there is only one payment left (see below)
When N > 1 (N is the number of coupons payable between the settlement date and redemption date), PRICE is calculated as follows:
When N = 1 (N is the number of coupons payable between the settlement date and redemption date), PRICE is calculated as follows:
DSR = number of days from settlement to next coupon date.
E = number of days in coupon period in which the settlement date falls.
A = number of days from beginning of coupon period to settlement date.
It seems that for the last payment calculation excel is moving from compounded yield to simple yield.
I calculated the clean price both with compounded yield and with simple yield. While the clean price with simple yield is close to the Bloomberg/Excel price it still does not match.
With 7.95% yield and settlement date 30 Dec 2020:
Bloomberg/Excel clean price is 99.953226, Accrued Amount 3.270380
QLXL(semiannually compounded yield) clean price is 99.95983172, Accrued Amount 3.288251366
QLXL(simple yield) clean price is 99.95278714, Accrued Amount 3.288251366
I'm not C++ specialist but the QL code I've checked does not change the price calculation algorithm when only one payment is left.
The question is: Is it possible with current implementation of QuantLib to match the price and accrued amount for the above mentioned bond (and in general with all coupon bonds when there is only one cashflow is left)?
Thanks for posting! It might take a while before we look at your issue, so don't worry if there seems to be no feedback. We'll get to it.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Never used QLXL but I encountered similar issue recently (on python). Seems related to a difference between the calculated coupon amount compared to the actual bond. There is related discussion in this quant stackexchange question but I think none of the suggestions solves the issue completely.
For most bonds, the coupon amounts are just a fraction (1/half/quarter) of the coupon rate but there is difficulty setting that up on QuantLib. Currently for FixedRateBond looks like the day count and business day convention for calculating the coupon amounts are tied to same arguments for generating the coupon payment dates. Perhaps we can have another constructor for separately specifying those.
Using your situation as example (expect 3.625 coupon payments but not the case):
bond = ql.FixedRateBond(3, ql.NullCalendar(), 100.0, ql.Date(17,1,2019), ql.Date(17,1,2021), ql.Period('6M'), [0.0725], ql.ActualActual())
print('Cashflows:')
for c in bond.cashflows():
print('%20s %12f' % (c.date(), c.amount()))
print('Accrual: %.9f' % bond.accruedAmount(ql.Date(30,12,2020)))
Result:
Cashflows:
July 17th, 2019 3.595205
January 17th, 2020 3.653926
July 17th, 2020 3.605191
January 17th, 2021 3.645677
January 17th, 2021 100.000000
Accrual: 3.288251366
There are a bunch of different act/act conventions, and for historical reasons, unfortunately, the default you get when you write ql.ActualActual()
is not the one you expect. This gives you exact half-coupons:
bond = ql.FixedRateBond(3, ql.NullCalendar(), 100.0, ql.Date(17,1,2019), ql.Date(17,1,2021),
ql.Period('6M'), [0.0725], ql.ActualActual(ql.ActualActual.Bond))
print('Cashflows:')
for c in bond.cashflows():
print('%20s %12f' % (c.date(), c.amount()))
print('Accrual: %.9f' % bond.accruedAmount(ql.Date(30,12,2020)))
Results:
Cashflows:
July 17th, 2019 3.625000
January 17th, 2020 3.625000
July 17th, 2020 3.625000
January 17th, 2021 3.625000
January 17th, 2021 100.000000
Accrual: 3.270380435
Thanks lballabio, solves the problem for me though in that case I am not sure about OP's.
Hopefully — I'm getting the expected numbers quoted by the OP with:
import QuantLib as ql
bond = ql.FixedRateBond(3, ql.NullCalendar(), 100.0, ql.Date(17,1,2019), ql.Date(17,1,2021),
ql.Period('6M'), [0.0725], ql.ActualActual(ql.ActualActual.Bond))
ql.Settings.instance().evaluationDate = ql.Date(27,12,2020) # trade date
print(bond.settlementDate()) # check that the settlement is on the 30th
print(bond.accruedAmount())
print(bond.cleanPrice(0.0795, ql.ActualActual(ql.ActualActual.Bond), ql.Simple, ql.Semiannual))
Outputs:
December 30th, 2020
3.270380434782605
99.9532255971963
for bonds where the compounding changes from Compounded to Simple if the settlement date falls within the last coupon period, is it up to the QuantLib user to manually handle this change in compounding?
A different issue #256 gave the suggestion of checking if ql.BondFunctions.nextCashFlowDate(fixedRateBond, QL_settle_date) == ql.BondFunctions.maturityDate(fixedRateBond):
. This seems quite cumbersome. It's also rather inefficient because nextCashFlowDate loops over most if not all the cashflows.
this compounding method is used for all AUD bonds.