I'm creating Canadian fixed rate bond objects and noticed that for bonds with a short first coupon, the first cashflow is wrong if using the ActualActual(ActualActual.Bond)
day counter, but correct for the rest. This is because with a short stub, Canadian bonds calculate accrued using the Actual365Fixed(Actual365Fixed.Canadian)
day counter. The problem is, Canadian bonds only use this for short coupon periods. Therefore, the rest of the cashflows would be incorrect using the Actual365Fixed(Actual365Fixed.Canadian)
day counter.
Is there a day counter that accounts for this that I'm unaware of? This is a semi annual bond, with an issue date April 3rd, 2020 and maturity Sept. 1, 2025.
CashFlows with ActualActual(ActualActual.Bond) day counter: \
[(Date(1,9,2020), 0.20516304347826253),
(Date(1,3,2021), 0.24999999999999467),
(Date(1,9,2021), 0.24999999999999467),
(Date(1,3,2022), 0.24999999999999467),
(Date(1,9,2022), 0.24999999999999467),
(Date(1,3,2023), 0.24999999999999467),
(Date(1,9,2023), 0.24999999999999467),
(Date(1,3,2024), 0.24999999999999467),
(Date(1,9,2024), 0.24999999999999467),
(Date(1,3,2025), 0.24999999999999467),
(Date(1,9,2025), 0.24999999999999467),
(Date(1,9,2025), 100.0)]
Cashflows with Actual365Fixed(Actual365Fixed.Canadian) day counter:\
[(Date(1,9,2020), 0.20684931506849136),
(Date(1,3,2021), 0.24794520547946064),
(Date(1,9,2021), 0.24999999999999467),
(Date(1,3,2022), 0.24794520547946064),
(Date(1,9,2022), 0.24999999999999467),
(Date(1,3,2023), 0.24794520547946064),
(Date(1,9,2023), 0.24999999999999467),
(Date(1,3,2024), 0.24999999999999467),
(Date(1,9,2024), 0.24999999999999467),
(Date(1,3,2025), 0.24794520547946064),
(Date(1,9,2025), 0.24999999999999467),
(Date(1,9,2025), 100.0)]
Actual cashflows of a Canadian Fixed bond with a short first stub:\
[(Date(1,9,2020), 0.20684931506849136),
(Date(1,3,2021), 0.24999999999999467),
(Date(1,9,2021), 0.24999999999999467),
(Date(1,3,2022), 0.24999999999999467),
(Date(1,9,2022), 0.24999999999999467),
(Date(1,3,2023), 0.24999999999999467),
(Date(1,9,2023), 0.24999999999999467),
(Date(1,3,2024), 0.24999999999999467),
(Date(1,9,2024), 0.24999999999999467),
(Date(1,3,2025), 0.24999999999999467),
(Date(1,9,2025), 0.24999999999999467),
(Date(1,9,2025), 100.0)]
There's no single day counter that does that, but you can build a correct bond with a bit of work. What you'll have to do is:
build a bond bond1
with act/365 Canadian day count, extract its coupons and keep the first, as in first = bond1.cashflows()[0]
;
build a bond bond2
with act/act day count, extract its coupons and discard the first and the redemption, as in rest = bond2.cashflows()[1:-1]
;
put the coupons together and build the final bond as an instance of the generic Bond
class, as in:
bond = ql.Bond(settlement_days, calendar, issue_date, [first]+rest)
(the redemption will be re-added by the Bond constructor).
Of course, if you find yourself doing this a lot of times, you can write a function to do that. (Or, if you're comfortable with changing the underlying C++ library, you can create a specific bond subclass and export it to Python.)