Software companion
FOMC Statement Sentiment vs. 2Y Yield Reaction
Overview
The measurement chain here is long — statement text, sentence segmentation, a transformer sentiment score, an event window, a market series, a regression — and every link can move the result. The repository answers that by writing the scientific contract down as code: statement text is the mandatory baseline signal, the event timestamp is the published release minute, the baseline window is [−15, +15] minutes, the baseline regression is Δyield = α + β · Δsentiment + ε with HAC standard errors, and the daily FRED DGS2 series is a reference that cannot substitute for the intraday leg.
Sensitivity belongs to the same contract rather than to a robustness appendix. src/modeling.py exposes window sensitivity, per-cycle estimates and outlier sensitivity as first-class functions alongside the headline fit, so alternative reaction windows are produced whenever the event study runs.
Implementation
- Core libraries
- transformers and torch for FinBERT, statsmodels for HAC OLS, BeautifulSoup and lxml for scraping, pydantic for schemas, pandas, pyarrow, Matplotlib, Plotly
- Text corpus
- 138 cleaned FOMC statements, 2010 to 2026, committed as processed text
- Scoring
- Sentence-level FinBERT with a pinned model name and revision, a hawkish/neutral/dovish label map, and a recorded scorer version
- Market leg
- A Barchart
ZTY00nearby-futures intraday export, ingested from 15 numbered raw chunks; daily FREDDGS2as reference only - Tests
- 9 modules covering schemas, event windows, modelling and a pipeline smoke path
Components
src/fomc_scraper.py- Statement acquisition and release-date extraction
src/text_cleaning.py, src/sentence_splitter.py- Boilerplate removal and the sentence segmentation FinBERT consumes
src/sentiment.py- The FinBERT scorer wrapper, pinning model name, revision, label mapping and scorer version into the artifact
src/yield_data.py- Intraday market-leg ingestion and the daily reference series
src/event_windows.py- Release-minute alignment and the baseline and alternate reaction windows
src/event_dataset.py- The joined event panel every regression reads
src/cycle_labels.py- Tightening, easing and hold labels for the per-cycle breakdown
src/modeling.py- HAC OLS plus window, cycle and outlier sensitivity and the headline metric
src/validation.py, src/schemas.py- Schema contracts and the sentiment validation pass against manual labels
scripts/preflight_checks.py- The gate run before a report is rendered
Pipeline
ingest-statementsScrape, clean and store statement text with release timestamps.ingest-yieldsIngest the intraday market leg from the numbered raw chunks.scoreScore every sentence with FinBERT and aggregate to a per-statement signal.validateCheck schemas and compare scored sentiment against the manual label set.event-studyBuild the event panel and fit the baseline and sensitivity regressions.reportRender figures and the brief, behind preflight checks.
Reproducibility and validation
- The scorer records its model name, revision and version into every artifact, so a silent upstream model change cannot be mistaken for a change in the data.
- Sentiment scores are validated against a manually labelled subset following a documented labelling guide, rather than being trusted because the model is well known.
- Forty-eight releases lack verified minute-level timestamps and are excluded from the baseline regression instead of being assigned an approximate time.
- The intraday leg is a nearby-futures proxy rather than a cash two-year yield feed; legacy
yield_*field names are kept for schema compatibility, but the rendered report interprets them as proxy moves, and the finished run is frozen as a dated bundle underreports/published/.
Availability
Not publicly released. The cleaned statement corpus derives from public Federal Reserve releases, but the intraday market leg comes from a licensed export that cannot be redistributed. Publishing would mean shipping the text pipeline and the regression code against a market series the reader has to supply.