getanirao/central-bank-speech-alpha

Extracts tradeable EUR/USD signals from Federal Reserve speech sentiment using CentralBankRoBERTa, validated through rigorous event-study backtesting at 99.8% confidence over 10 years.

Python

0

21 commits

updated Jun 27, 2026

See the code

README

Central Bank Speech Alpha — EUR/USD Event Study

Fed speech sentiment → EUR/USD directional signal using CentralBankRoBERTa-sentiment-classifier, validated through 5-hole robustness framework: execution lag, transaction costs, regime dependence, parameter overfit, and NLP temporal drift.

Champion strategy: W=13 step_4tier with next-day entry — statistically significant at p=0.0022 (99.8% confidence), survives all 5 tests.

python src/event_study.py    # Full robustness report

Approach

  1. Data: istat-ai/ECB-FED-speeches (HuggingFace) + yfinance EUR/USD daily bars (10y)
  2. Sentiment: CentralBankRoBERTa-sentiment-classifier — 88% sentiment accuracy, 93% agent classifier
  3. Scoring: Agent whitelist {'Central Bank'}, keyword ≥2, strict_score ≥3, mean daily aggregation
  4. Entry: Next-day Open (conservative, no lookahead bias)
  5. Validation: Permutation placebo (5,000–10,000 shuffles), regime-split, parameter sensitivity heatmap

5-Hole Robustness Results

Hole #1: Execution Lag

Concern: Same-day close entry creates lookahead bias — speech priced in before backtest entry.

Entry MethodHit RateAvg ReturnSharpep-value
Same-day Close57.8%0.002881.3730.0006
Next-day Open58.7%0.002661.3610.0022

Verdict: Signal survives next-day entry with virtually identical metrics. The alpha is real macro drift, not lookahead.

Hole #2: Transaction Costs

Concern: Thin edge (0.28%/event) wiped by slippage, spread widening, and 13-day swap costs.

Cost ModelNet Return (10y)% of Gross
Static 0.5pip (baseline)+28.5%98%
Slippage + Spread + Swap x13 (0.00082)+20.1%69%
2x Stress test (0.00164)+11.1%38%

Verdict: Realistic costs consume 31% of gross edge. Net p=0.0268 — still significant at p<0.05.

Hole #3: Regime Dependence

Concern: 71% dovish events may reflect 2016-2021 ZIRP artifact, not genuine alpha.

RegimeEventsHit RateGross AvgNet Avg
ZIRP 2016-20215658.9%0.001860.00104
Hiking 2022-20232853.6%0.003870.00305
Norm. 2024-20262564.0%0.003110.00229

Verdict: Hiking regime shows the highest gross alpha (0.00387). The signal is NOT a ZIRP artifact — it works across all rate environments.

Hole #4: Parameter Overfit

Concern: W=13 + 0.2 floor is hyper-specific — change one parameter and signal disappears.

Sensitivity heatmap (p-values across W × floor):

Wfl=0.00fl=0.15fl=0.25fl=0.35
80.0520.0620.0520.036
100.0080.0180.0120.012
120.0040.0020.0020.008
140.0080.0040.0120.014
160.0320.0340.0280.028
180.0500.0340.0500.078

Verdict: W=10..16 forms a smooth cluster of significance across all floors. 18/28 configs (64%) p<0.05. Parameters are robust, not overfit.

Hole #5: Static NLP Model

Concern: CentralBankRoBERTa pre-trained on static corpus — can't handle Powell vs Yellen language.

Chair PeriodEventsActiveHit RateAvg Ret
Yellen (2016-2018)291855.6%0.00180
Early Powell (2018-2022)694052.5%0.00150
Late Powell (2022-2026)845064.0%0.00361

Verdict: Model performs best in the most recent period (64% hit, 0.00361 avg). Central bank language is formulaic enough that static RoBERTa handles chair transitions well.

Champion Configuration

ParameterValue
Window13 trading days
Position functionstep_4tier (floor 0.2, step 0.4, step 0.6)
EntryNext-day Open
Cost model0.0001 slip + 0.0002 spread + 0.00004/day swap
p-value (5,000 perm)0.0022 ***
Validated acrossW=10..16, floors 0.0..0.35, 3 rate regimes, 3 chair periods

Project Structure

├── src/
│   ├── event_study.py            # Optimization engine + 5-hole robustness report
│   ├── sentiment_pipeline.py     # CentralBankRoBERTa scoring pipeline
│   ├── align_and_merge.py        # Daily alignment + feature engineering
│   ├── backtest_engine.py        # Daily regression backtests
│   ├── causality_analysis.py     # Granger causality + feature importance
│   ├── placebo_test.py           # Permutation tests for daily model
│   ├── fetch_data.py             # FX + speech ingestion
│   └── fred_controls.py          # FRED macro shocks
├── data/                          # merged_daily.csv, speeches_scored.csv
├── main.py                        # Full pipeline orchestrator
└── requirements.txt

Reproducibility

All scripts use seed=42 with enforce_strict_reproducibility() across random, numpy, and torch. Placebo tests shuffle speech scores (not returns) to preserve market microstructure while destroying the speech-return relationship. All 5-hole tests are reproducible by running python src/event_study.py.

getanirao/central-bank-speech-alpha

Extracts tradeable EUR/USD signals from Federal Reserve speech sentiment using CentralBankRoBERTa, validated through rigorous event-study backtesting at 99.8% confidence over 10 years.

Python

0

21 commits

updated Jun 27, 2026

See the code

README

Central Bank Speech Alpha — EUR/USD Event Study

Fed speech sentiment → EUR/USD directional signal using CentralBankRoBERTa-sentiment-classifier, validated through 5-hole robustness framework: execution lag, transaction costs, regime dependence, parameter overfit, and NLP temporal drift.

Champion strategy: W=13 step_4tier with next-day entry — statistically significant at p=0.0022 (99.8% confidence), survives all 5 tests.

python src/event_study.py    # Full robustness report

Approach

  1. Data: istat-ai/ECB-FED-speeches (HuggingFace) + yfinance EUR/USD daily bars (10y)
  2. Sentiment: CentralBankRoBERTa-sentiment-classifier — 88% sentiment accuracy, 93% agent classifier
  3. Scoring: Agent whitelist {'Central Bank'}, keyword ≥2, strict_score ≥3, mean daily aggregation
  4. Entry: Next-day Open (conservative, no lookahead bias)
  5. Validation: Permutation placebo (5,000–10,000 shuffles), regime-split, parameter sensitivity heatmap

5-Hole Robustness Results

Hole #1: Execution Lag

Concern: Same-day close entry creates lookahead bias — speech priced in before backtest entry.

Entry MethodHit RateAvg ReturnSharpep-value
Same-day Close57.8%0.002881.3730.0006
Next-day Open58.7%0.002661.3610.0022

Verdict: Signal survives next-day entry with virtually identical metrics. The alpha is real macro drift, not lookahead.

Hole #2: Transaction Costs

Concern: Thin edge (0.28%/event) wiped by slippage, spread widening, and 13-day swap costs.

Cost ModelNet Return (10y)% of Gross
Static 0.5pip (baseline)+28.5%98%
Slippage + Spread + Swap x13 (0.00082)+20.1%69%
2x Stress test (0.00164)+11.1%38%

Verdict: Realistic costs consume 31% of gross edge. Net p=0.0268 — still significant at p<0.05.

Hole #3: Regime Dependence

Concern: 71% dovish events may reflect 2016-2021 ZIRP artifact, not genuine alpha.

RegimeEventsHit RateGross AvgNet Avg
ZIRP 2016-20215658.9%0.001860.00104
Hiking 2022-20232853.6%0.003870.00305
Norm. 2024-20262564.0%0.003110.00229

Verdict: Hiking regime shows the highest gross alpha (0.00387). The signal is NOT a ZIRP artifact — it works across all rate environments.

Hole #4: Parameter Overfit

Concern: W=13 + 0.2 floor is hyper-specific — change one parameter and signal disappears.

Sensitivity heatmap (p-values across W × floor):

Wfl=0.00fl=0.15fl=0.25fl=0.35
80.0520.0620.0520.036
100.0080.0180.0120.012
120.0040.0020.0020.008
140.0080.0040.0120.014
160.0320.0340.0280.028
180.0500.0340.0500.078

Verdict: W=10..16 forms a smooth cluster of significance across all floors. 18/28 configs (64%) p<0.05. Parameters are robust, not overfit.

Hole #5: Static NLP Model

Concern: CentralBankRoBERTa pre-trained on static corpus — can't handle Powell vs Yellen language.

Chair PeriodEventsActiveHit RateAvg Ret
Yellen (2016-2018)291855.6%0.00180
Early Powell (2018-2022)694052.5%0.00150
Late Powell (2022-2026)845064.0%0.00361

Verdict: Model performs best in the most recent period (64% hit, 0.00361 avg). Central bank language is formulaic enough that static RoBERTa handles chair transitions well.

Champion Configuration

ParameterValue
Window13 trading days
Position functionstep_4tier (floor 0.2, step 0.4, step 0.6)
EntryNext-day Open
Cost model0.0001 slip + 0.0002 spread + 0.00004/day swap
p-value (5,000 perm)0.0022 ***
Validated acrossW=10..16, floors 0.0..0.35, 3 rate regimes, 3 chair periods

Project Structure

├── src/
│   ├── event_study.py            # Optimization engine + 5-hole robustness report
│   ├── sentiment_pipeline.py     # CentralBankRoBERTa scoring pipeline
│   ├── align_and_merge.py        # Daily alignment + feature engineering
│   ├── backtest_engine.py        # Daily regression backtests
│   ├── causality_analysis.py     # Granger causality + feature importance
│   ├── placebo_test.py           # Permutation tests for daily model
│   ├── fetch_data.py             # FX + speech ingestion
│   └── fred_controls.py          # FRED macro shocks
├── data/                          # merged_daily.csv, speeches_scored.csv
├── main.py                        # Full pipeline orchestrator
└── requirements.txt

Reproducibility

All scripts use seed=42 with enforce_strict_reproducibility() across random, numpy, and torch. Placebo tests shuffle speech scores (not returns) to preserve market microstructure while destroying the speech-return relationship. All 5-hole tests are reproducible by running python src/event_study.py.