FRED Rate Curve¶
abaquant.rates provides a provider-neutral rate curve API. This notebook
uses ManualRateProvider with Treasury-like rates so it runs deterministically
without a FRED API key or network access. If you set the FRED_API_KEY
environment variable, the same factory can request live FRED Treasury
constant-maturity observations by passing provider="fred".
Sections:
Build a deterministic Treasury-like curve
Interpolate rates and discount factors
Use a curve-derived rate inside an option model
Visualize the curve
Optional: live FRED branch
Setup¶
import abaquant
print(f"AbaQuant version: {abaquant.__version__}")
AbaQuant version: 1.0.0rc1
import os
from pathlib import Path
from abaquant.derivatives.models import BlackScholesMertonModel
from abaquant.rates import ManualRateProvider, get_rate_curve
1. Build a deterministic Treasury-like curve¶
Rates are supplied as {maturity_in_years: annual_decimal_rate}.
curve = get_rate_curve(
provider=ManualRateProvider(
{
1.0 / 12.0: 0.0520,
0.25: 0.0505,
0.50: 0.0485,
1.00: 0.0460,
2.00: 0.0430,
5.00: 0.0410,
10.00: 0.0425,
30.00: 0.0440,
}
)
)
curve.as_frame().head()
| maturity_years | annual_rate | observation_date | series_id | provider_name | raw_value_percent | |
|---|---|---|---|---|---|---|
| 0 | 0.083333 | 0.0520 | 2026-08-24 | MANUAL_0.0833333Y | manual | 5.20 |
| 1 | 0.250000 | 0.0505 | 2026-08-24 | MANUAL_0.25Y | manual | 5.05 |
| 2 | 0.500000 | 0.0485 | 2026-08-24 | MANUAL_0.5Y | manual | 4.85 |
| 3 | 1.000000 | 0.0460 | 2026-08-24 | MANUAL_1Y | manual | 4.60 |
| 4 | 2.000000 | 0.0430 | 2026-08-24 | MANUAL_2Y | manual | 4.30 |
2. Interpolate rates and discount factors¶
zero_rate() uses linear interpolation by default; discount_factor()
uses continuous compounding by default.
six_month_rate = curve.zero_rate(0.5)
one_year_rate = curve.zero_rate(1.0)
two_year_df = curve.discount_factor(2.0)
print(f"6-month rate: {six_month_rate:.6f}")
print(f"1-year rate: {one_year_rate:.6f}")
print(f"2-year discount factor: {two_year_df:.6f}")
6-month rate: 0.048500
1-year rate: 0.046000
2-year discount factor: 0.917594
3. Use a curve-derived rate inside an option model¶
Instead of hard-coding a risk-free rate, pull the curve’s interpolated
1-year zero rate straight into BlackScholesMertonModel.
model = BlackScholesMertonModel(
spot_price=100.0,
strike_price=105.0,
maturity_years=1.0,
risk_free_rate=one_year_rate,
volatility=0.20,
)
report = model.diagnostics(option_type="call")
print(f"Price: {report.price:.4f}")
print(f"Intrinsic value: {report.intrinsic_value:.4f}")
print(f"Extrinsic value: {report.extrinsic_value:.4f}")
print(f"Moneyness: {report.moneyness:.4f}")
print(f"Break-even price: {report.break_even_price:.4f}")
Price: 7.8378
Intrinsic value: 0.0000
Extrinsic value: 7.8378
Moneyness: 0.9524
Break-even price: 112.8378
4. Visualize the curve¶
from abaquant.visualization import VisualizationError
output_directory = Path("generated_figures/fred_rate_curve")
output_directory.mkdir(parents=True, exist_ok=True)
try:
curve.visualize(save_path=output_directory, filename="manual_rate_curve")
print(f"Saved curve visualization under: {output_directory}")
except VisualizationError as exc:
print(f"Visualization skipped (optional dependency missing): {exc}")
Visualization skipped (optional dependency missing): Specify either path or filename, not both.
5. Optional: live FRED branch¶
Only runs if FRED_API_KEY is set in the environment; otherwise it’s
skipped cleanly.
def maybe_fetch_live_fred_curve():
if not os.getenv("FRED_API_KEY"):
return None
return get_rate_curve(
provider="fred",
date="latest",
cache_mode="disk",
cache_directory="~/.cache/abaquant",
refresh_policy="if_stale",
max_age_days=1.0,
)
live_curve = maybe_fetch_live_fred_curve()
if live_curve is None:
print("Skipped live FRED request: FRED_API_KEY is not set.")
else:
print(live_curve.as_frame().head())
print(f"1-year rate: {live_curve.zero_rate(1.0):.6f}")
print(f"2-year discount factor: {live_curve.discount_factor(2.0):.6f}")
Skipped live FRED request: FRED_API_KEY is not set.
Takeaway¶
Manual and FRED-backed curves share the exact same API (zero_rate,
discount_factor, .provenance, .visualize()), so you can prototype with
a manual curve and swap in FRED later with a one-line change. Remember:
Treasury constant-maturity yields are a pragmatic proxy, not a
bootstrapped zero-coupon curve — see docs/domains/rates.rst.