I am using python quantlib, according to one of the Quantlib sample code to evaluate the CHT (Canada Housing Trust) Floaters, and the index I am using is CDOR, and somehow the price I got is always higher than the market, so I post my code below, please help me whether I made something wrong.
- First, the CDOR forward rates I am using in the code was downloaded
from this site:
https://www.chathamfinancial.com/technology/canadian-forward-curves#contact
; - And then I build the CDOR forward curve using ql.ForwardCurve
- Build the 3 month CDOR index using the CDOR forward curve
- Find out the index spread from this web site for each CHT floater:
https://www.cmhc-schl.gc.ca/en/professionals/project-funding-and-mortgage-financing/securitization/canada-mortgage-bonds/list-of-outstanding-cht-debt-issues
- Construct each FRN schedule and bond
- Price the FRN using the Bootstrap CHT curve I built
# 1. build CDOR forward curve term structure
rates = [0.0043574, 0.0044015, 0.0044471, 0.0044961, 0.0045767, 0.0046476, 0.0047762, 0.0049175, 0.0050456,
0.0051272, 0.005215, 0.0052943, 0.0054934, 0.0058323, 0.0061394, 0.0065789, 0.007122, 0.0076312,
0.0079265, 0.0085458, 0.009145, 0.0098384, 0.0105592, 0.0112552, 0.0120167, 0.0127172, 0.0133951,
0.014063, 0.0146859, 0.0153088, 0.0159396, 0.0164637, 0.0170059, 0.0175708, 0.0180457, 0.0185048,
0.0189963, 0.0193824, 0.0197952, 0.020192, 0.0205116, 0.0208632, 0.021149, 0.0214018, 0.0216628,
0.0218877, 0.0220687, 0.0222321, 0.0224091, 0.0225604, 0.0227268, 0.0228641, 0.0229961, 0.0231323,
0.0232522, 0.0233617, 0.0234712, 0.0235739, 0.0236691, 0.0237499, 0.0238338, 0.0239213, 0.0240147,
0.0240994, 0.0241908, 0.0242822, 0.0243707, 0.024468, 0.0245506, 0.0246429, 0.0247457, 0.0248357,
0.0249312, 0.0250218, 0.0251154, 0.025205, 0.0252976, 0.0253789, 0.0254632, 0.0255553, 0.0256387,
0.0257273, 0.0258128, 0.0258928, 0.0259805, 0.0260832, 0.0261826, 0.026284, 0.0264028, 0.0265216,
0.0266478, 0.0267761, 0.0269088, 0.027054, 0.0272047, 0.0273454, 0.0275008, 0.0276, 0.0277098,
0.0278129, 0.0278731, 0.0279375, 0.0279934, 0.0280133, 0.0280332, 0.0280468, 0.0280241, 0.0280035,
0.0279915, 0.0280254, 0.0280617, 0.0281093, 0.0282009, 0.0283017, 0.0283966, 0.0285495, 0.0287074,
0.0288604, 0.0290749, 0.0292687, 0.0294786]
dates = ['2021-04-14', '2021-05-14', '2021-06-14', '2021-07-14', '2021-08-16', '2021-09-14', '2021-10-14',
'2021-11-15', '2021-12-14', '2022-01-14', '2022-02-14', '2022-03-14', '2022-04-14', '2022-05-16',
'2022-06-14', '2022-07-14', '2022-08-15', '2022-09-14', '2022-10-14', '2022-11-14', '2022-12-14',
'2023-01-16', '2023-02-14', '2023-03-14', '2023-04-14', '2023-05-15', '2023-06-14', '2023-07-14',
'2023-08-14', '2023-09-14', '2023-10-16', '2023-11-14', '2023-12-14', '2024-01-15', '2024-02-14',
'2024-03-14', '2024-04-15', '2024-05-14', '2024-06-14', '2024-07-15', '2024-08-14', '2024-09-16',
'2024-10-14', '2024-11-14', '2024-12-16', '2025-01-14', '2025-02-14', '2025-03-14', '2025-04-14',
'2025-05-14', '2025-06-16', '2025-07-14', '2025-08-14', '2025-09-15', '2025-10-14', '2025-11-14',
'2025-12-15', '2026-01-14', '2026-02-16', '2026-03-16', '2026-04-14', '2026-05-14', '2026-06-15',
'2026-07-14', '2026-08-14', '2026-09-14', '2026-10-14', '2026-11-16', '2026-12-14', '2027-01-14',
'2027-02-15', '2027-03-15', '2027-04-14', '2027-05-14', '2027-06-14', '2027-07-14', '2027-08-16',
'2027-09-14', '2027-10-14', '2027-11-15', '2027-12-14', '2028-01-14', '2028-02-14', '2028-03-14',
'2028-04-14', '2028-05-15', '2028-06-14', '2028-07-14', '2028-08-14', '2028-09-14', '2028-10-16',
'2028-11-14', '2028-12-14', '2029-01-15', '2029-02-14', '2029-03-14', '2029-04-16', '2029-05-14',
'2029-06-14', '2029-07-16', '2029-08-14', '2029-09-14', '2029-10-15', '2029-11-14', '2029-12-14',
'2030-01-14', '2030-02-14', '2030-03-14', '2030-04-15', '2030-05-14', '2030-06-14', '2030-07-15',
'2030-08-14', '2030-09-16', '2030-10-14', '2030-11-14', '2030-12-16', '2031-01-14', '2031-02-14',
'2031-03-14', '2031-04-14']
ql_dates = [utils.to_quantlib_date(utils.string_to_date(d)) for d in dates]
cdor_forward_curve = ql.ForwardCurve(ql_dates, rates, ql.Actual365Fixed(), ql.Canada(), ql.BackwardFlat())
ql_forecast_curve = ql.RelinkableYieldTermStructureHandle()
ql_forecast_curve.linkTo(cdor_forward_curve)
# 2. create Cdor index using the CDOR forward curve
ql_index = ql.Cdor(ql.Period(3, ql.Months), ql_forecast_curve)
ql_index.addFixing(ql.Date(15, ql.March, 2021), 0.004375)
# 3. instantiate FRN schedule and bond
interest_accrual_date = calendar.advance(quantlib_business_date, ql.Period(-1, ql.Years))
schedule = ql.Schedule(interest_accrual_date,
quantlib_maturity_date,
tenor,
calendar,
business_day_convention,
business_day_convention, # termination convention
date_generation,
end_of_month)
floating_bond = ql.FloatingRateBond(settlement_days,
face_value,
schedule,
ql_index,
ql.Actual365Fixed(),
business_day_convention,
ql_index.fixingDays(),
[], # Gearings
[initial_margin], # Spreads
[], # Caps
[], # Floors
False, # Fixing in arrears
face_value,
interest_accrual_date)
# 4. Using the CHT bootstrap curve I have built (detail code is skipped), I evaluate the CHT floaters
floating_bond.setPricingEngine(ql.DiscountingBondEngine(ql.YieldTermStructureHandle(cht_curve)))
clean_price = floating_bond.cleanPrice()