Pricing CDOR-Linked Housing Trust Floaters with Separate Curves
Summary
The document presents a QuantLib pricing question about Canada Housing Trust floating-rate notes. The requester builds a CDOR forward curve from market forward rates, creates a three-month CDOR index, constructs a floating-rate bond using the contractual spread, and discounts its cash flows on a curve bootstrapped from fixed-rate housing trust bonds. The computed prices are higher than market quotes.
The reply clarifies the intended roles of the curves and spread: a curve built from fixed-rate trust bonds can serve as a discount curve, while the floater coupons use CDOR plus the contractual spread. Under that setup, the valuation is only an approximation and should not be expected to match market prices exactly. The exchange does not diagnose the specific coding or calibration error, and it cautions that adding the index spread again to CDOR may be inconsistent with the described setup. Curve construction, conventions, fixing dates, and instrument details remain possible sources of discrepancy.
Key ideas
- Forecast floating coupons from the relevant CDOR forward curve.
- Discounting can use a curve bootstrapped from fixed-rate housing trust bonds.
- The floater coupon should reflect CDOR plus its contractual spread.
- This curve setup provides an approximate valuation rather than a guaranteed market match.
- The exchange does not identify the precise source of the reported pricing difference.
Tags
Full text
# Canada House Trust Floater pricing
# Canada House Trust Floater pricing
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()
```
## Answer by Mike (score 0)
https://quant.stackexchange.com/a/63398
Bill, you are?
- Building cht discount curve from the fixed rate cht bonds,
- Creating a cht floating rate bond using the contractual spread over cdor
- Pricing the bonds? This will only approximately price them, but shouldn't be totally awful.
If you also add that index spread to cdor I'm not sure what you are doing... Mike. Yes, datavault mike.Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.