PyTermStructure Documentation
Educational Python library for interest rate term structure estimation
Version 0.1.0
By Marco Gigante | Inspired by Damir Filipović’s “Interest Rate Models” (EPFL)
Note
Educational implementation suitable for learning and research. Bootstrap method achieves sub-basis-point accuracy on benchmark data. See Accuracy & Validation for validation details.
Quick Start
Installation
pip install pytermstructure
First Example
import pytermstructure as pts
from pytermstructure.core import MarketInstrument, InstrumentType
from datetime import datetime
# Create bootstrap with spot date
spot = datetime(2024, 1, 15)
bootstrap = pts.BootstrapMethod(verbose=True, spot_date=spot)
# Add LIBOR with exact date
bootstrap.add_instrument(MarketInstrument(
instrument_type=InstrumentType.LIBOR,
maturity=datetime(2024, 4, 15),
quote=0.15,
spot_date=spot
))
# Add swap with exact date
bootstrap.add_instrument(MarketInstrument(
instrument_type=InstrumentType.SWAP,
maturity=datetime(2026, 1, 15),
quote=0.50,
spot_date=spot
))
# Fit discount curve
discount_curve = bootstrap.fit()
zero_rates = bootstrap.get_zero_rates()
Accuracy & Validation
v0.1.0 Improvements
Version 0.1.0 brings significant accuracy improvements to the bootstrap method:
Exact calendar date support with ACT/360 day-count convention
Automatic curve densification with interpolated swap rates
Three-phase bootstrap algorithm for long-term instruments
Improved accuracy: from ~13 bps to <1 bps on benchmark data
Test Results
Validation using academic benchmark data:
Method |
Test Case |
Result |
Target |
Deviation |
|---|---|---|---|---|
Bootstrap |
30Y forward rate |
2.56% |
2.56% |
0.00 bps |
Bootstrap |
30Y discount factor |
0.483144 |
0.483194 |
0.50 bps |
Lorimier |
6Y Swiss yield |
-0.44% |
-0.41% |
3.0 bps |
Expected Tolerances
Bootstrap method: typically <1 bps on benchmark data
Lorimier method: typically ±3 bps on interpolated yields
Pseudoinverse: uses bootstrap as baseline
Recommendation: Suitable for educational purposes and research. Always validate results against your specific dataset before use in applications.
What’s New in v0.1.0
Bootstrap Enhancements
Exact Date Support
You can now use real calendar dates instead of year fractions:
from datetime import datetime maturity_date = datetime(2025, 12, 15) inst = MarketInstrument( InstrumentType.SWAP, maturity_date, 2.50, spot_date=datetime(2024, 12, 15) )
Automatic Densification
The bootstrap method automatically adds intermediate points:
bootstrap.fit() # Automatically densifies curve # Example: 17 market instruments → 38 curve points
Three-Phase Algorithm
Phase 1: Bootstrap LIBOR, Futures, and swaps up to 20Y
Phase 2: Add intermediate dates with interpolated swap rates
Phase 3: Calculate long swaps using densified curve
ACT/360 Day-Count
Exact day-count calculations for all periods:
days = (maturity_date - spot_date).days year_fraction = days / 360.0 # ACT/360
Methods
Bootstrap Method
Sequential construction from LIBOR to Futures to Swaps.
Example:
from pytermstructure import BootstrapMethod
from pytermstructure.core import MarketInstrument, InstrumentType
from datetime import datetime
spot = datetime(2024, 10, 3)
bootstrap = BootstrapMethod(verbose=True, spot_date=spot)
# LIBOR 3M
bootstrap.add_instrument(MarketInstrument(
InstrumentType.LIBOR,
datetime(2025, 1, 3),
0.15,
spot_date=spot
))
# Swap 2Y
bootstrap.add_instrument(MarketInstrument(
InstrumentType.SWAP,
datetime(2026, 10, 3),
0.50,
spot_date=spot
))
curve = bootstrap.fit()
Lorimier Method
Smoothing splines for yield curve interpolation.
Example:
import numpy as np
from pytermstructure import LorimierMethod
# Swiss government bond yields
maturities = np.array([2, 3, 4, 5, 7, 10, 20, 30])
yields = np.array([-0.79, -0.73, -0.65, -0.55,
-0.33, -0.04, 0.54, 0.73]) / 100
lorimier = LorimierMethod(alpha=0.1, verbose=True)
curve = lorimier.fit(yields, maturities)
# Interpolate at 6 years
y_6y = lorimier.get_yield_at(6.0)
PCA Analysis
Principal component analysis of yield curve movements.
import numpy as np
from pytermstructure import PCAAnalysis
# Historical yield changes
yield_changes = np.random.randn(100, 5) * 0.01
pca = PCAAnalysis(verbose=True)
eigenvalues, eigenvectors, explained_var = pca.fit(yield_changes)
Built-in Help System
import pytermstructure as pts
pts.help() # General help
pts.help("bootstrap") # Bootstrap method
pts.help("lorimier") # Lorimier method
pts.help("quickstart") # Quick start guide
pts.help("accuracy") # Accuracy information
Common Issues
Import Error
If you get import errors:
pip install -e . # Development mode
# or
pip install pytermstructure # From PyPI
Accuracy Concerns
Version 0.1.0 typically achieves <1 bps accuracy on benchmark data. If you observe larger deviations:
Check date format: use
datetimeobjectsVerify spot date matches your data
Check instrument order (bootstrap processes sequentially)
Confirm day-count convention (ACT/360 assumed)
See Accuracy & Validation for expected tolerances.
API Reference
Core Classes
- class pytermstructure.core.MarketInstrument(instrument_type: InstrumentType, maturity: float | datetime, quote: float, name: str | None = None, spot_date: datetime | None = None, convention: DayCountConvention = DayCountConvention.ACT_360)
Market instrument with support for dates or year fractions.
Supports two modes: 1. Year fraction mode (backward compatible) 2. Date mode (recommended for accuracy)
Parameters
- instrument_typeInstrumentType
Type of instrument (LIBOR, FUTURE, SWAP, BOND)
- maturityfloat or datetime
If float: year fraction from spot (e.g., 0.25 for 3M) If datetime: actual maturity date (preferred)
- quotefloat
Market quote in % (e.g., 0.15 for 0.15%)
- namestr, optional
Instrument name/identifier
- spot_datedatetime, optional
Spot date (required if maturity is datetime)
- conventionDayCountConvention, optional
Day-count convention (default: ACT/360)
Attributes
- maturityfloat
Year fraction calculated using day-count convention
- maturity_datedatetime or None
Original maturity date (if provided)
- spot_datedatetime or None
Original spot date (if provided)
Examples
>>> # Method 1: Year fraction (old way, still works) >>> libor = MarketInstrument(InstrumentType.LIBOR, 0.25, 0.15) >>> print(f"Delta: {libor.maturity}") # 0.25
>>> # Method 2: Actual dates (new way, more accurate) >>> from datetime import datetime >>> spot = datetime(2012, 3, 10) >>> mat = datetime(2012, 4, 10) >>> libor = MarketInstrument(InstrumentType.LIBOR, mat, 0.15, ... spot_date=spot) >>> print(f"Delta: {libor.maturity:.6f}") # 0.086111 (31/360)
Notes
Using actual dates improves accuracy by ~5-10 basis points because it accounts for exact calendar days instead of approximate year fractions.
- class pytermstructure.core.InstrumentType(value)
Market instrument types.
Methods
- class pytermstructure.methods.BootstrapMethod(verbose=False, spot_date=None)
Bootstrap Method - Excel-exact implementation
Replicates Filipović’s Excel spreadsheet row by row: - Uses ACT/360 day count - Linear interpolation for rates (PREVISIONE) - Exact delta calculations - Sequential calculation with intermediate dates
- fit()
Bootstrap following Excel logic exactly.
Steps: 1. Process LIBOR/Futures (direct calculation) 2. Process Swaps UP TO 20Y 3. Fill intermediate dates with interpolated rates (20-30Y) 4. Process long swaps (>20Y) using densified curve
Academic Reference
This library implements methods from:
Filipović, D. (2009). Term-Structure Models: A Graduate Course. Springer Finance.
Online Course: Interest Rate Models
École Polytechnique Fédérale de Lausanne (EPFL)
Contributing
Contributions are welcome. Areas for improvement include:
Enhanced numerical methods
Additional day-count conventions
Business day calendars
Curve analytics
Additional validation tests
See CONTRIBUTING.md.
License
GNU General Public License v3.0 or later.
See LICENSE for details.
Links
Acknowledgments
Prof. Damir Filipović (EPFL)
École Polytechnique Fédérale de Lausanne
NumPy, SciPy communities
Contents
User Guide