pythonquantlibquantlib-swig

Error with cashflows of Canadian bonds that have a short first coupon using QuantLib


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)]

Solution

  • 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:

    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.)