Methodology
How disclosures become rows, how rows become tickers, and how tickers become an estimated portfolio. The parameters below are the pipeline's own, captured with the data snapshot.
Truth hierarchy
Everything derived can be traced to a filing: portfolio positions → normalized transactions → raw rows → the official document.
- Official fields: filer name, office, filing date, transaction date, notification date, asset description, transaction type, reported dollar range, owner.
- Derived / estimated fields: ticker match and confidence, midpoint dollars, estimated shares, current value, weights, returns, sector allocation, reporting-lag statistics.
Nothing derived is ever written back onto a raw row.
How this is calculatedmodel parameters · click to expand
- Shares formula
- amount_mid / close(tx_date)
- Return index
- 100 * (value + realized) / invested
- Benchmark
- SPY
- Portfolio start date
- 2020-01-01
- Price provider
- yfinance
- Price lookup window (days)
- 5
- Ticker publish threshold
- 0.9
- Positions floored at zero
- Yes
- Cash modelled
- No
- Dividends modelled
- No
Full method, tiers of ticker matching, and the review queue are documented on the methodology page.
Smart portfolio (estimated) — v1 methodology
For each politician, over portfolio-eligible rows (published ticker, asset_class in (stock, etf), tx_date, amount_mid, tx_type in buy/sell/partial_sale), in date order:
1. est_shares_traded = amount_mid / close(tx_date) — close on the transaction date, else the next trading day within 5 days, else the row is excluded (no_price). 2. Buy: position += shares; invested_cum += amount_mid; cost basis += amount_mid. 3. Sell / partial sale: shares_sold = min(position, est_shares_traded); realized_cum += shares_sold × close; cost basis reduced pro-rata. Any excess (sell with no modelled shares) is recorded as unmatched_sell_dollars and does not create a short — positions are floored at zero. 4. Exchange / unknown rows are excluded from modelling and counted in excluded. 5. Daily revaluation: est_value(t) = Σ position × close(t) from first trade to latest price date. 6. Cash is not modelled (we only see trades, never balances). Dividends are not modelled. 7. Benchmark: a shadow SPY portfolio receives the identical cash flows — each buy of $X on date d buys X / SPY_close(d) SPY shares; each modelled sell of $Y sells Y / SPY_close(d) SPY shares (floored at 0). 8. Return index (money-in / money-out neutral): index(t) = 100 × (value(t) + realized_cum(t)) / invested_cum(t); portfolio_return_pct = index(latest)/100 − 1; same formula for the SPY shadow. This answers "what did each disclosed dollar turn into" and is comparable across the two. 9. est_value_change_30d = value(t) − value(t−30d) − (buys − modelled sell proceeds in the window).
Politician stats: - avg_reporting_lag_days = mean(filing_date − tx_date). - avg_filing_interval_days = mean gap between distinct filing dates. - days_since_last_filing = today − max(filing_date). - top_holdings = est_value / total; sector_allocation = Σ est_value by sector (security_metadata, else "Unclassified").
Prices are for enrichment; the filing tells us a dollar range, not shares — every share figure is a model output.
Normalization rules
- Transaction type → buy | sell | partial_sale | exchange | unknown. House codes P / S / S (partial) / E; Senate Purchase / Sale (Full) / Sale (Partial) / Exchange.
- Amount "$15,001 - $50,000" → amount_low=15001, amount_high=50000, amount_mid=32500.5. "Over $50,000,000" → low=50000001, high=NULL, mid=low and reason open_ended_amount.
- Owner → self | spouse | joint | dependent | unknown (House SP/JT/DC, blank = self; Senate Self/Spouse/Joint/Child).
- Asset class → stock | etf | mutual_fund | option | bond | crypto | other | unknown from House [XX] codes, Senate "Asset Type", then text hints.
- Reporting lag = filing_date − tx_date in days (official dates, derived number).
Review queue: a normalized row gets needs_review=true (and is kept, never discarded) when any of: amount_missing, amount_unparseable, amount_single_value, open_ended_amount, tx_date_missing, tx_type_unknown, ticker_below_threshold, ticker_conflict (printed ticker ≠ matched ticker), low_parser_confidence, asset_class_unknown.
Scanned filings (House paper PTRs and their broker attachments, Senate paper filings) are read by OCR (parser_version ocr_grid_v3): each page is straightened, the form's grid recovered, text read by OCR and the X or check in each choice cell read as ink. Every OCR row carries a confidence and the reasons it may be wrong (for example ocr_owner_unreadable, ocr_date_uncertain); below 0.8 it goes to review, and the site marks rows from scans with an OCR tag. Filings with raw_status in (needs_ocr, needs_review, error) appear in the filing review list: not yet read, read without recoverable rows (often handwriting), or failed. Analysts fix rows through manual_overrides (raw row untouched; normalization re-applies).
Truth hierarchy: official fields (filer, office, filing date, transaction date, asset text, transaction type, reported dollar range, owner) are copied from the filing; everything else (ticker match, midpoint dollars, shares, values, weights, returns, sector allocation, stats) is derived and labelled Estimated. Every derived row traces back: portfolio_positions → transactions_normalized → transactions_raw → filings.source_document_url.
Entity resolution (ticker matching)
Tiers, first hit wins; each tier has a fixed confidence:
1. Ticker printed in the filing (Senate Ticker column, or (NVDA) / NYSEARCA: DIA in House text) AND exists in securities_master — 0.98 (0.95 if the issuer name similarity < 0.5, reason ticker_conflict). 2. Exact normalized issuer-name match (clean_issuer_name) — 0.95. 3. Alias match (curated aliases + SEC name variants) — 0.92. 4. Fuzzy (rapidfuzz token-set ratio on cleaned names, top-1 ≥ 90 and margin ≥ 5 over top-2) — 0.90 × ratio/100 (so ≥ 0.81, i.e. below the publish threshold → review). 5. None — 0.0.
Published ticker is set only when confidence ≥ 0.90. Otherwise the row displays as text-only with ticker_candidate visible in the review queue. Options, bonds, mutual funds without a ticker, and other classes are never modelled in portfolios even if a ticker matches.
Ticker symbols get reused after a company is delisted or renamed (FB is now an ETF's symbol). When the symbol printed on a filing names a different company than the filing does, the company named wins if it matches confidently; if the symbol now belongs to a fund, a blank-check company, or sits on a bond row, no ticker is published. A name shared by different companies is never matched on the name alone. Every such row stays flagged ticker_conflict for review.
Securities universe: SEC company_tickers_exchange.json (~10.4K issuers). Sector / industry / market cap come from the market-data provider (yfinance by default, Polygon optional).
Leaderboard: who beats the market (estimated)
Each member's estimated stock and ETF portfolio is compared with an S&P 500 shadow that makes the same buys and sells on the same days for the same dollars, so the difference is what the member's picks added or cost. Options are not modelled.
The main table covers the last 12 months with the simple Dietz method, so money added or withdrawn during the year does not count as return: (end value - start value - net money in) / (start value + half the net money in). The same formula is applied to the shadow. Members need at least 5 modelled trades and $25,000 of capital at work in the window to be ranked.
The second table runs from each member's first modelled trade, as a money multiple against the shadow's; longer histories compound further, so each row states its start date. It needs 10 modelled trades and $50,000 bought.
All figures are built from disclosed dollar ranges at their midpoints; they are estimates, not the members' actual results.
Most held by Congress (estimated)
The sum of every member's estimated position, per security: members holding it, the party split, the estimated value, the largest holder and their share of the total, and members buying or selling it in the last 90 days. A position is what a member's disclosed trades since the portfolio start date add up to, valued at the latest close. Holdings owned before a member's disclosed trades began are not visible, so this measures what Congress has been buying, not a full balance sheet. A large value can rest on a single member, which is why the top holder's share is always shown.
Options trades
Strike, expiry, call or put, and contract count are read from each option trade's filed text; a field the filer did not state is left empty. Most filers state strike and expiry; few state the number of contracts.
Where the contract count is stated, a bought contract is valued at its intrinsic value: what it would be worth exercised at the stock's close on its expiry date, or today if still open (max(0, price - strike) x 100 x contracts for calls, the reverse for puts). This leaves out the premium paid, time value and any early sale, so it is an estimate, not profit; the disclosed dollar range is the only official figure.
Stock prices are adjusted for splits and filed strikes are not, so the price is restated in the share terms of the trade date using the stock's split history before comparing it with the strike.
"Went their way" counts bought contracts whose stock then moved in the direction the contract bets. "Open" means unexpired with no later sale or exercise of the same contract filed.
Against the S&P 500, an option trade is scored on its stock in the direction it bets: a bought call like a share buy, a bought put like a sale (it pays when the stock falls), and a sale of either the other way. An option whose filing does not say call or put has no known direction and is not scored.
Dates and hindsight
Three dates belong to every trade: when it happened, when the member was notified (when filed), and when the filing was made public. Only the last is when anyone outside could know of it.
Return figures shown against the S&P 500 start from the disclosure by default: what someone following the filings could have captured. The figure from the trade date is shown second and labelled hindsight, since no outsider could have earned it. The estimated portfolios and the leaderboard are modelled from trade dates, so they describe the members' picks, not returns available to the public.
Unusual-activity events are dated by when they became public: one trade by its filing date, a cluster when the last of its trades was filed, an overlap with an executive's trade when both filings were public, and a move after a trade only once its 30 trading days were over. The trade date is shown beside the event as context.
Each published snapshot lists the version of every parser and model behind it, so a figure that moved because the method changed can be told from one that moved because the data did.
Legal
Independent third-party platform; not affiliated with or endorsed by any member of Congress.
Data sourced from publicly available filings and records.
Portfolio, holdings, returns, and allocations are estimates and may differ from actual values.
Informational and educational only; not investment advice.
Insider data (SEC Form 4)
Corporate insiders (officers, directors and 10% owners) report their transactions on SEC Form 4. The company universe is the S&P 500, the Nasdaq-100 and the 150 tickers Congress trades most (extendable by hand). Per company the pipeline reads the EDGAR submissions index, takes every Form 4 and 4/A, and parses the ownership XML into non-derivative and derivative rows (holdings-only rows are flagged). Values are exact as filed and carry a Filed label, never an Estimated one.
- Filed fields: shares, price, transaction value, post-transaction holdings, transaction code, direct/indirect ownership, the Rule 10b5-1 plan flag, and the filing and report dates.
- Transaction kind from the Form 4 code: P →
open_market_buy, S →open_market_sale, A →award, M/X →option_exercise, F →tax_withholding, G →gift, C →conversion, anything else →other. Only open-market buys and sales enter the buy, sell and net figures. - Executive = the title matches CEO, CFO, COO, President (not Vice), Chair, Founder or CTO. Insider and company stats (12-month and 90-day buy, sell and net value, share of sale value under a 10b5-1 plan, last trade) are sums of filed values.
- Every insider row links to its EDGAR filing folder and to the Form 4 XML. SEC fair-access limits are respected and raw XML is cached.
Congressional figures remain disclosed dollar ranges and range midpoints; the two tiers are never mixed in one number.
Whale layer
Everything in the whale layer is derived and labelled Estimated. Politician activity score (365-day window): volume_12m is the sum of range midpoints over buys and sells; largest_trade_mid and median_trade_mid likewise; late_filings counts trades filed after the STOCK Act deadline (the earlier of 45 days after the trade and 30 days after notification; amendments and low-confidence scanned dates are never counted); the forward return is close(t + 30 trading days) / close(t) − 1, sign-adjusted (buys positive, sells negative); a trade is a hindsight move when that sign-adjusted return is at least +15%. That describes what the stock did after the trade, which nobody could know when it was disclosed; it is not evidence of foresight.
- Whale score = 100 × (0.5 × percentile of 12-month volume + 0.3 × percentile of largest trade + 0.2 × percentile of 12-month trade count), percentiles taken among members with at least one trade in the window.
- Notable = a curated list, plus the top 10 by volume, plus any score of 90 or more; the reason is shown with the flag.
Unusual events are scored 0–100 (clamped) and de-duplicated:
whale_trade— range low of $250,001 or more; score 40 + 20 × log10(midpoint / 250,000).cluster_buy/cluster_sell— three or more distinct members, same ticker and side, within a rolling 14 days; 30 + 15 × (n − 3), +10 if it contains a whale trade.late_filing— filed after the STOCK Act deadline above; 30 + (days late) / 3, +15 if a whale trade.well_timed(shown as Hindsight move) — sign-adjusted 30-day forward return of +15% or more; 40 + 100 × (return − 0.15), +10 if a whale trade.first_time_ticker— a member's first-ever trade in a ticker with a range low of $50,001 or more; 25 + 15 × log10(midpoint / 50,000).exec_open_market_buy— an executive open-market buy of $100K or more; 45 + 15 × log10(value / 100,000).exec_large_sale— an executive open-market sale of $5M or more; 40 + 15 × log10(value / 5,000,000), −15 under a 10b5-1 plan.insider_politician_overlap— a member trade within ±30 days of an executive open-market trade in the same ticker; 50, +15 if the directions are opposite, +10 if a whale trade.
Insider events use exact filed values; congressional events use range midpoints. Every event links to the congressional filing or the Form 4 behind it.
Dating. Every event is dated by when the public could first have known of it, never by the trade date: one trade by its filing (or Form 4) date, a cluster when the last of its trades was filed, an overlap when both filings were public, a hindsight move once its 30 trading days were over. The trade date is shown beside it. Option trades follow their direction: a bought put is a bet on a fall, so options never join a cluster of share trades, and an overlap is "opposite" only when the bets point opposite ways.
Committee overlap
Committee rosters come from unitedstates/congress-legislators (committees-current.json, committee-membership-current.json), joined to members by Bioguide id — no name matching. Titles and leadership seats (chair, ranking member, vice chair) come from the same source.
The committee-to-sector map is our editorial judgement, not an official classification, and every surface that shows it says so. A committee is mapped where its published jurisdiction covers an industry's regulation, funding or oversight: Armed Services → Industrials; Banking → Financial Services and Real Estate; Ways and Means → Healthcare and Financial Services; Judiciary → Technology and Communication Services. Broad money committees — Appropriations, Budget, Rules, Ethics, Foreign Affairs — are deliberately unmapped, because a jurisdiction that touches everything would flag everything and mean nothing.
committee_conflictfires when a trade has a published ticker with a known sector, an amount low of $15,001 or more, and the member sits on a parent (not sub-) committee whose mapped sectors include that sector.- One event per trade. Where several committees qualify, the most pointed wins: a leadership seat first, then the committee with the fewest mapped sectors — the most specific jurisdiction.
- Coverage limit. The upstream roster is current membership only, so an overlap is asserted only for trades dated on or after 2025-01-03, the start of the current Congress. Earlier trades are never judged against today's committee seats, and former members carry no seats at all.
This describes an overlap of duty and holding: a member traded a stock in a sector a committee they sit on oversees. An overlap of duty and holding is not an allegation of insider trading or of any other violation. Nothing on these pages should be read as one, and the scores rank how large and how specific an overlap is, nothing more.
Method versions in this snapshot
A number that changes between snapshots because a version below changed moved because of the method, not the data.
- House filing reader
- house_pdf_v2
- Senate filing reader
- senate_html_v1
- Scanned-filing reader (OCR)
- ocr_grid_v3
- Row normalizer
- norm_v1
- Ticker matcher
- 2026-11-03
- Estimated portfolios
- 2026-11-03
- Returns vs the S&P 500
- 2026-11-03
- Unusual-activity events
- 2026-11-03