Graduate mathematical finance project by Zechuan (Leo) Li.
This repository analyzes Canadian government bond prices, constructs yield-to-maturity and bootstrapped spot curves, derives forward rates starting at year 1, and applies principal component analysis to daily curve changes.
- Analyzed 100 observations across 10 Canadian government bonds and 10 trading dates from January 5 to January 16, 2026.
- Calculated daily YTM values from semiannual coupon cash flows using numerical root solving.
- Bootstrapped daily 1-5 year spot curves and derived forward rates beginning at year 1.
- Estimated 5 x 5 yield and 4 x 4 forward-rate covariance matrices.
- Found that PC1 explained approximately 83.6% of yield variation and 82.8% of forward-rate variation.
- Interpreted PC1 as a broad level-like curve factor, while avoiding the stronger and unsupported claim that every tenor moved in a strict parallel shift.
.
|-- MAT1856_Bond_Curve_Analysis.ipynb
|-- README.md
|-- requirements.txt
|-- data/
| |-- MAT1856_A1_bond_data.xlsx
| `-- README.md
|-- src/
| `-- bond_curve_analysis.py
|-- outputs/
| |-- figures/
| |-- tables/
| `-- summary.json
|-- report/
| `-- MAT1856_Project_Summary.pdf
`-- tools/
|-- build_notebook.py
`-- build_report.py
- Select ten Canadian government bonds with maturities distributed from 2026 to 2031.
- Construct future semiannual coupon cash flows using ACT/365 year fractions.
- Solve for daily YTM using Brent's numerical root-finding method.
- Build daily yield curves with piecewise-linear interpolation.
- Bootstrap discount factors and convert them to semiannually compounded spot rates.
- Calculate annualized multi-period forward rates beginning at year 1.
- Compute daily log changes, covariance matrices, eigenvalues, and eigenvectors.
Create a virtual environment and install the dependencies:
python -m venv .venvOn Windows:
.venv\Scripts\activate
pip install -r requirements.txtRun the complete analysis:
python src/bond_curve_analysis.pyOr open and run MAT1856_Bond_Curve_Analysis.ipynb from top to bottom.
The first principal component explains most of the observed variation for both curve families. This is consistent with broad level movements being dominant. However, some first-component loadings have the opposite sign, so the result should not be described as a mathematically strict parallel shift.
- The project preserves the submitted coursework price convention: close prices are used directly as present-value inputs without a separate accrued-interest adjustment.
- The first bootstrap node has no earlier curve anchor; earlier cash flows before that node are not assigned a separately estimated discount factor.
- Labels such as
1y-2ymean a rate starting at year 1 with a two-year tenor, not a one-year rate starting in year 2. - PCA is based on only ten trading dates and is intended as an academic demonstration, not a production risk model.
- The source workbook contains third-party market-data source URLs. Redistribution and reuse remain subject to the original providers' terms.
Bond reference information and close-price observations are stored in the source workbook. The workbook contains the original bond-page and chart-data URLs for auditability. See data/README.md.
This public portfolio version contains no student number. It includes only Zechuan Li's Python/Jupyter analysis; an unrelated R Markdown file authored by another student is intentionally excluded.
No open-source license has been selected. Copyright remains with the author. Third-party data is not licensed by this repository.
