A live dashboard that tracks US corporate credit spreads, classifies each day's regime against rolling history, and surfaces where the quality premium is moving. Built to work the way a credit analyst actually reads markets: not just the level, but where the level sits in its own distribution.
- Fixed income data work end to end: FRED API ingestion, regime classification, percentile and z-score analytics, credit curve decomposition.
- Thinking in spreads relative to history rather than absolute levels. Daily 10 year rolling percentile and 5 year rolling z-score per series, with a four bucket regime classifier (Tight, Normal, Wide, Stressed).
- Python data engineering. Reproducible package, pinned dependencies, unit tests on the transform layer.
- Tableau dashboard published to Tableau Public covering today's read, 40 year history, ratings stack, credit curves, and a regime calendar heatmap.
- Handling a real data licensing curveball mid build. FRED capped ICE BofA OAS to 3 years in April 2026 as part of an ICE Data Indices licensing change. I pivoted the long history backbone to Moody's Aaa and Baa yield spreads, which are the canonical US credit spread measures in academic finance and predate ICE BofA by decades. Documented the design choice transparently in the methodology.
-
Top of US credit is trading rich. Moody's Baa minus 10Y at 170 bps sits in the 17th percentile of the last decade. US HY Corporate OAS at 285 bps is in the 19th percentile of the last three years. The headline screen says late cycle complacency.
-
The quality premium inside HY is stretched. CCC OAS at 913 bps is in the 56th percentile of its three year window, while BB at 174 bps is in the 19th. The CCC minus BB curve sits at 739 bps in the 78th percentile (Wide regime). Markets are pricing complacency at the top of HY and discriminating sharply on distressed credit. That gap usually widens before a default wave.
-
Regime context. BAA10Y has spent about 13% of the last 40 years in the Stressed regime (1,321 of 10,075 trading days), with peaks at the GFC (616 bps, 4 Dec 2008), COVID (431 bps, 23 Mar 2020), and the Euro sovereign crisis (339 bps, 27 Sep 2011). Today's 170 bps print is firmly Tight by any historical measure.
Full write up at docs/methodology.md. Short version:
- Daily OAS data pulled from FRED for ICE BofA US and European corporate indices, split by rating.
- Long history regime backbone uses Moody's Aaa and Baa minus 10Y Treasury (1983 and 1986 onwards), because FRED restricted ICE BofA OAS to 3 years of history in April 2026.
- Per series: 5 year rolling z-score, 10 year rolling percentile rank with a 1 year expanding warmup, four bucket regime classifier on percentile thresholds at 20, 60 and 90.
- Credit curves are spread differentials: HY minus IG, BBB minus A, CCC minus BB, Baa minus Aaa.
Federal Reserve Bank of St Louis (FRED) API. Full series catalogue, known gaps and limitations in docs/data_dictionary.md. Headline series:
| Series | Coverage | Role |
|---|---|---|
| AAA10Y | 1983 to present | Long history Aaa minus 10Y Treasury |
| BAA10Y | 1986 to present | Long history Baa minus 10Y Treasury, regime backbone |
| BAMLC0A0CM and ratings split | 3 years | US IG OAS by rating |
| BAMLH0A0HYM2 and ratings split | 3 years | US HY OAS by rating |
| BAMLHE00EHYIOAS | 3 years | Euro HY OAS |
| BAMLEMCBPIOAS | 3 years | EM Corporate OAS |
From a fresh clone on macOS or Linux with Python 3.11+:
git clone https://github.com/amant0923/credit-spread-tracker.git
cd credit-spread-tracker
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# edit .env and paste your FRED API key, free at https://fred.stlouisfed.org/docs/api/api_key.html
python -m src.build_datasetThe processed dataset writes to data/processed/credit_spreads.csv. The full Tableau dashboard build spec is at docs/dashboard_spec.md. Runtime is about 20 seconds.
.venv/bin/python -m pytest tests/ -vFour unit tests on the transform layer cover regime threshold mapping, rolling z-score on a stationary series, rolling percentile on a monotonic series, and credit curve subtraction.
credit-spread-tracker/
├── README.md
├── LICENSE
├── .gitignore
├── .env.example
├── requirements.txt
├── docs/
│ ├── methodology.md
│ ├── data_dictionary.md
│ └── dashboard_spec.md
├── src/
│ ├── __init__.py
│ ├── config.py
│ ├── fetch_spreads.py
│ ├── transform.py
│ └── build_dataset.py
├── data/
│ ├── raw/ (gitignored, populated on fetch)
│ └── processed/
│ └── credit_spreads.csv
├── tableau/
└── tests/
└── test_transform.py
Aman Takhar, MSc Investments (Distinction predicted), University of Birmingham.
- Email: aman.takhar31@outlook.com
- LinkedIn: linkedin.com/in/amantakhar11
- GitHub: github.com/amant0923