A PyTorch LSTM + XGBoost ensemble that predicts weekly directional moves in US Treasury yields (2Y, 10Y, 2s10s spread), built on 19 years of FRED macro data with walk-forward validation, SHAP interpretability, and statistical significance testing.
No Bloomberg terminal. No paid data feeds. Just a free API key and PyTorch.
The 2s10s spread direction (steepening vs. flattening) is predictable at 55.0% accuracy (p = 0.008), statistically significant at the 99% confidence level. Outright yield direction is indistinguishable from noise. The LSTM's sequential processing of 60-day lookback windows is the sole source of predictive power.
| Target | XGBoost | LSTM | Ensemble | p-value | Significant at 99%? |
|---|---|---|---|---|---|
| 2Y Yield Direction | 48.8% | 52.0% | 52.0% | 0.1735 | No |
| 10Y Yield Direction | 47.0% | 48.2% | 48.2% | 0.8265 | No |
| 2s10s Spread Direction | 49.8% | 55.0% | 55.0% | 0.0079 | Yes (99%) |
Baseline (coin flip): 50.0%
The yield curve is the most watched indicator in fixed income. Its shape drives portfolio positioning, curve trades, and macro regime classification. Most forecasting is still discretionary - PMs reading dot plots and payrolls prints.
This project tests whether a machine can beat a coin flip at predicting the direction of weekly yield moves using only free public data. The answer: outright yield direction is indistinguishable from noise, but curve spread direction carries statistically significant signal that the LSTM captures at 55.0% accuracy (p = 0.008).
A single Jupyter notebook that runs the complete pipeline:
| Stage | Description |
|---|---|
| Data Collection | 12 FRED macro series, 2007-2026 |
| Feature Engineering | 90 features (rolling changes, volatility, z-scores, momentum) |
| XGBoost Baseline | Optuna-tuned gradient boosting (100 trials per target), SHAP interpretability |
| LSTM | 2-layer LSTM (64->32), 60-day lookback, early stopping, weight decay |
| Ensemble | Weighted blend optimized per target on validation set |
| Significance Test | Binomial test on each target (H0: accuracy = 50%) |
| Evaluation | ROC curves, confusion matrices, rolling accuracy, calibration, hypothetical P&L |
git clone https://github.com/lenamonj/yield-curve-prophet.git
cd yield-curve-prophet
pip install -r requirements.txtRegister for a free key at fred.stlouisfed.org.
export FRED_API_KEY="your-key-here"Or on Windows PowerShell:
$env:FRED_API_KEY = "your-key-here"jupyter notebook yield_curve_prophet.ipynbFull execution takes 10-15 minutes (Optuna tuning + LSTM training).
All data comes from the FRED API (free, 120 requests/minute).
| Category | Series ID | Description | Frequency |
|---|---|---|---|
| Treasury Yields | DGS2, DGS5, DGS10, DGS30 | Constant maturity yields | Daily |
| Monetary Policy | DFF | Effective federal funds rate | Daily |
| Inflation | T10YIE | 10-year breakeven inflation | Daily |
| Inflation | T5YIFR | 5Y5Y forward inflation expectation | Daily |
| Labor | UNRATE | Unemployment rate | Monthly |
| Growth | INDPRO | Industrial production index | Monthly |
| Sentiment | UMCSENT | Consumer sentiment | Monthly |
| Volatility | VIXCLS | CBOE VIX | Daily |
| Dollar | DTWEXBGS | Trade-weighted dollar index | Daily |
See final_features.txt for the complete feature dictionary (90 engineered features with definitions).
- 70/15/15 walk-forward split - Train (70%), validation (15%), test (15%) with 63-day leakage gaps between each split. No random shuffling, no future information leakage.
- XGBoost as point-in-time baseline - Sees only today's feature snapshot. Regularized (L1/L2, gamma, min_child_weight 5-50, early stopping) to prevent overfitting. Collapses to near-random accuracy, confirming that point-in-time features alone are insufficient.
- LSTM as primary model - 2-layer (64->32) with 60-day lookback, dropout 0.5, weight decay 1e-3, and gradient clipping. Captures momentum shifts, volatility clustering, and regime transitions. The sequential architecture is the sole source of predictive power on 2s10s.
- Ensemble - Weighted blend of both models, optimized per target on validation set. On 2s10s the ensemble assigns 95% weight to LSTM, producing identical predictions to LSTM alone (McNemar p = 1.0).
- Optuna over grid search - 100-trial Bayesian optimization per target for XGBoost hyperparameters with 9-dimensional search space.
- Binary classification over regression - Predicting "up or down" is more actionable than predicting exact basis point moves.
- SHAP for interpretability - Every XGBoost prediction is explainable via feature attribution.
- Binomial significance test - Statistical rigor: the null hypothesis (50% accuracy) is formally tested for each target.
- SEED=42 locked - numpy, PyTorch, and Optuna seeds fixed for full reproducibility.
yield-curve-prophet/
|-- README.md
|-- LICENSE
|-- requirements.txt
|-- .gitignore
|-- final_features.txt # Complete feature dictionary (90 features)
|-- yield_curve_prophet.ipynb # Full pipeline - one notebook
+-- *.png # Generated charts (8 figures)
| Package | Purpose |
|---|---|
pandas |
Data manipulation and time series alignment |
numpy |
Numerical computation |
requests |
FRED API calls |
torch |
LSTM neural network |
torchinfo |
Model architecture summary |
xgboost |
Gradient boosting baseline |
optuna |
Bayesian hyperparameter optimization |
shap |
Model interpretability (feature attribution) |
scikit-learn |
Metrics, preprocessing, calibration |
matplotlib |
Visualization |
scipy |
Statistical significance testing (binomial test) |
statsmodels |
Statistical tests (McNemar's test) |
seaborn |
Statistical plots |
This project is licensed under the MIT License.
Built with PyTorch, XGBoost, and the FRED API. No proprietary data feeds required.