Skip to content

Methodology

Capitol_Signals is an open-source correlation engine for congressional financial activity. Each week it ingests:

The engine joins these across indices to produce correlations (trade ↔ contract, trade ↔ bill, trade ↔ lobbying) and aggregates them into rollups (one rollup per member-ticker-trade) with a 0-100 composite suspiciousness score. The score weights six factors: jurisdiction alignment (member’s committee vs. ticker’s sector), event timing, trade dollar amount, disclosure lag (days between transaction and STOCK Act disclosure), count of distinct correlated signals, and lobbying intensity in the relevant sector during the trade quarter. (Abnormal price movement vs. SPY was removed from the composite in v1.2 to eliminate data leakage; it is reported separately as an informational field.)

A second layer runs two ML heads in annotation mode alongside the composite:

ml_agreement enum. Each rollup carries an agreement label summarizing how the two heads relate:

ValueMeaning
high-confidenceBoth heads flag suspicious; composite and distillation align, forward-CAR also elevated.
agreedHeads concur within normal tolerance.
divergedComposite says suspicious-by-correlation; forward-CAR says the trade did not pay off. The disagreement is often the most interesting editorial signal.
partialDistillation head scored; forward-CAR window (30d) not yet elapsed.
unscoredRollup predates dual-head deployment or lacked sufficient features.

The composite score remains the primary ranking signal. ML heads are annotations that add editorial context, not replacements for the rule-based score.

What correlation does and does not mean. A high composite score means multiple independent signals align in time and topic. It does not prove the member used non-public information, breached fiduciary duty, or violated the STOCK Act. The signals are public, the explanations are public, and the inferences are circumstantial. We publish them so the public, journalists, and policymakers can decide what is worth following up on.

Source code, data sources, and licensing.

Capitol_Signals is built and maintained by Brian Chaplow. No subscription, no copy-trading, no affiliate links. Reach out via the GitHub repo for corrections or methodology questions.

Per-brief data sidecar schema

Every editorial brief at /briefs/{slug}/ ships a co-located data/ directory with the trades, correlations, and scores it cites. Files:

FileColumnsNotes
trades.csv / trades.jsonltrade_id, bioguide_id, member_name, ticker, transaction_date, amount_range, amount_min, amount_max, sector, industryThe headline trade plus any sibling cited
correlations.csv / correlations.jsonlcorrelation_id, trade_id, bioguide_id, ticker, transaction_date, composite_score, severity_tier, scored_atSupporting rollups for same member + ticker
scores.csv / scores.jsonlcorrelation_id, trade_id, composite_score, ml_score_distill, ml_score_car, ml_agreement, ml_shap_top3, abnormal_return_30d, abnormal_return_60d, abnormal_return_90dComposite + ML head outputs

License: CC0 1.0. Reproducibility: every file is keyed by the rollup’s correlation_id; cross-reference with the weekly snapshot for the same ISO-year-week to confirm the brief’s claims.

Weekly snapshot schema

Every Monday at 02:30 UTC the engine writes a full snapshot to /data/{YYYY}-W{WW}/. The snapshot contains:

TableSource indexRow count (approx)Why included
tradescs-trades1,300+Primary signal
correlationscs-correlations (rollups only)500+Pair-level + rollup correlations
profilescs-member-profiles170+Aggregated member-level metrics

File formats per table:

What we exclude

The weekly snapshot does NOT include:

These constraints are enforced at the script level in analytics/publish_weekly_snapshot.py. A future Phase 20.5 may publish trimmed projections (bill id + sector + sponsor only, ~5 MB) or a Datasette-style live query endpoint on a separate object store if the data community requests.

Reproducibility

Each weekly snapshot directory is committed to github.com/brianchaplow/capitolsignals-astro under public/data/{YYYY}-W{WW}/. The directory contents are deterministic for a given OpenSearch state: columns are sorted, rows are sorted by primary key, SQLite indexes are deterministic, and floats are rounded to 4 decimals before serialization. Rerunning the script for the same year-week against the same OpenSearch state produces byte-identical CSV output.

To reproduce a specific brief’s claims:

  1. Find the brief at /briefs/{slug}/.
  2. Read the sidecar at /briefs/{slug}/data/.
  3. Cross-reference with the matching weekly snapshot at /data/{iso_year_week}/.
  4. The brief’s iso_year_week frontmatter pins the snapshot to use.

Member opt-out posture

Capitol Signals correlates public data. Member trades are disclosed under the STOCK Act; contracts are public via USAspending; bills are public via Congress.gov; lobbying is public via lda.gov. The project does not invite member opt-out requests because the underlying disclosures are mandated by law. If a current member of Congress identifies a factual error in a brief, the editorial process accepts corrections; corrections are noted in the brief body and the brief’s git history.

Slug and iso_year_week convention

Brief slugs follow the pattern {YYYY-WW}-{lastname_lower}-{ticker_lower}, where iso_year_week refers to the ISO week the underlying trade or alert event occurred (transaction_date), NOT the brief publication week. For example, the Moskowitz GD archetype brief at /briefs/2026-W13-moskowitz-gd/ derives W13 from the underlying trade on 2026-03-23 (ISO week 13), even though the brief was published in 2026-W21. This keeps the slug pinned to the editorial subject so the same correlation never gets a different slug across republications, and so auto-generated slugs from generate_weekly_brief.py:emit_astro_brief are deterministic. The derivation order is transaction_date first, scored_at fallback (per the Plan 05 implementation and the test in tests/test_brief_content_schema.py).