Concepts¶
Document¶
Every adapter produces the same pydantic model (cbtone.schema.Document):
| Field | Meaning |
|---|---|
bank |
bank code (fed, ecb, boe, rba, mas, bi, bnm, bot, pboc) |
date |
the decision or meeting date the document belongs to (not necessarily the release date) |
published_at_utc |
release instant, only when the bank documents it; otherwise None |
doc_type |
statement, minutes, press_conference, mps, communique, other |
language |
en, id, ms, zh, th |
parallel_id |
shared by translations of the same document |
title, text, sections |
cleaned text, and the same text as paragraph-level Sections (with optional headings) |
url, sha256, fetched_at |
provenance: public URL, hash of the raw bytes, fetch time |
doc_id is bank:date:doc_type:language, for example fed:2026-01-28:statement:en.
The corpus snapshot is three parquet tables (documents, sentences, manifest) plus a
VERSION file whose value includes a hash of the manifest. Where a source's terms forbid
redistribution, the committed text columns are null and the full text is rebuilt locally from
the fetch cache.
ToneScore¶
Every scorer returns a cbtone.scorers.ToneScore:
hawkish_p,dovish_p,neutral_p: probabilities that sum to 1;index = hawkish_p - dovish_p, in [-1, 1];label: the argmax class (ties resolve to neutral);scorer_id, plusmodel_digestandprompt_idwhen the scorer has them, so a result can be traced to an exact model and prompt;evidence_spans: optional quotes from the text (LLM scorer with--evidence).
Document scores are computed on the pre-registered policy text: paragraphs tagged
decision, forward_guidance, outlook or risks, capped at a character budget (3,000 by default
in the CLI after budget-ladder decision D18; the pre-registered original was 6,000). All scorers read the
same input so they can be compared fairly.
The decision table¶
decisions.parquet (built by cbtone decisions) has one row per policy decision or scheduled
meeting outcome, so tone can be tested against what happened next.
| Column | Meaning |
|---|---|
bank, date |
bank and announcement/meeting date |
direction |
hike, hold or cut |
magnitude_bp |
signed change in basis points (0 for a hold) |
rate_after, policy_instrument |
policy rate after the decision and which rate it is |
next_direction, next_date |
the following decision, the target of the RQ1 prediction tests |
source |
bis, bank, mas_table or mas_text |
unscheduled, effective_date |
out-of-meeting changes and the date the new rate shows in the series |
Rates and meeting dates come from public sources (BIS policy-rate series and meeting calendars). MAS rows come from MAS's own decision table.
Events¶
An event is a document release with a timestamp. cbtone events computes it as follows.
- If
published_at_utcis set, that instant is the event time (timing = exact). - Otherwise the event time is 00:00 local time on the release date (
timing = day), so the window is wider (more noise) but never looks ahead. - The event day t is the first daily close strictly after the event time. The market move is the change from the close at t-1 to the close at t+1, signed so that positive means hawkish-consistent (domestic-currency appreciation, higher yields).
The regression of market moves on tone surprise (tone minus its AR(1) forecast fitted on prior
documents only) uses Newey-West standard errors with lag 1, and is always reported next to
placebos (shuffled-date tone, permuted labels, non-announcement days). Market data are fetched
with cbtone markets and are not committed.
The pre-registration workflow¶
- Before scoring: hypotheses, metrics, decision thresholds, power rules and the budget
ladder are written in RESEARCH_QUESTIONS.md
and tagged
prereg-v1. - Amendments are dated entries in DECISIONS.md (what, why, alternatives rejected). Nothing is silently changed.
- Contamination checks accompany every LLM result: a masked-text variant (bank names, dates, rate levels and country names replaced with placeholders) and a post-training-cutoff split.
- Sanity rules: a headline metric exactly at 0, 1 or 100 %, a correlation above 0.95, or a value more than 2x outside the literature's range fails the build until explained in ANOMALIES.md.
- Underpowered cells are reported separately and excluded from multiple-comparison families and majority rules. A research question with too few powered banks is reported as untestable.
- Contradicting results are reported as refuted, not re-framed.