Open Data
Bell tracks every political prediction market on Polymarket and Kalshi, updated daily. Request access to the full dataset below.
political_markets_master.csv — One row per market outcome. All markets are classified into 15 political categories.
| Field | Type | Description |
|---|---|---|
| market_id | string | Unique identifier for the market (platform-specific) |
| platform | string | Source platform: "polymarket" or "kalshi" |
| pm_condition_id | string | Polymarket condition ID (for price lookups) |
| pm_token_id_yes | string | Polymarket YES token ID |
| pm_token_id_no | string | Polymarket NO token ID |
| k_event_ticker | string | Kalshi event ticker symbol |
| Field | Type | Description |
|---|---|---|
| question | string | Full market question text |
| political_category | string | One of 15 categories: Electoral, Monetary Policy, Party Politics, Military Security, International, Appointments, Regulatory, Political Speech, etc. |
| volume_usd | float | Total trading volume in USD |
| tags | string | Comma-separated list of market tags from the platform |
| date_added | datetime | When the market was first added to our database |
| Field | Type | Description |
|---|---|---|
| election_type | string | Type of election: Presidential, Senate, House, Governor, Primary, etc. |
| country | string | Country of election |
| location | string | State/region (for sub-national elections) |
| office | string | Office being contested (e.g., "President", "Senate", "House") |
| election_year | float | Year of the election (e.g., 2024.0) |
| is_primary | boolean | Whether the market is for a primary election (vs. general) |
| party | string | Political party: "R", "D", or null |
| candidate | string | Candidate name (if applicable) |
| election_eve_price | float | Market price at 00:00 UTC on election day |
| Field | Type | Description |
|---|---|---|
| is_closed | boolean | Whether market has stopped trading |
| resolution_outcome | float | Resolution: 1.0 if outcome occurred, 0.0 if not, null if unresolved |
| winning_outcome | string | The outcome that won (e.g., "Yes", "Trump") |
| trading_close_time | datetime | When trading closed |
| scheduled_end_time | datetime | Scheduled market end time |
| Field | Type | Description |
|---|---|---|
| k_last_price | float | Most recent trade price (0-1) |
| k_yes_bid | float | Current best bid for YES |
| k_yes_ask | float | Current best ask for YES |
| k_volume_contracts | int | Total contracts traded |
| k_open_interest | int | Current open interest |
| k_liquidity | float | Platform-reported liquidity measure |
| k_status | string | Market status: "active", "closed", "settled" |
| k_result | string | Settlement result: "yes", "no", null |
How we measure prediction accuracy and why the choice of when to sample prices is a first-order decision.
The Brier score measures forecast accuracy: (prediction − outcome)².
A score of 0 is perfect; 0.25 is equivalent to random guessing. We calculate Brier scores at multiple
time horizons (60, 30, 14, 7, 3, 1 days before the event) and, for electoral markets, using the election eve price.
For electoral markets, we use the market price at 00:00 UTC on election day as our primary forecast evaluation price. We call this the election eve price. For U.S. elections on November 5, this corresponds to approximately 7–8 PM Eastern on November 4—before any polls have closed.
This is an event-anchored truncation rule, not a resolution-anchored one. The distinction matters because Polymarket and Kalshi settle contracts at different speeds after outcomes are known (24–48 hours for Polymarket, 3–12 hours for Kalshi). Any truncation rule defined relative to resolution time mixes genuine forecasts with post-outcome convergence and introduces a platform-specific bias into cross-platform comparisons.
The election eve price avoids this. The same election produces the same measurement timestamp on both platforms. The price reflects what the market believed before the outcome was known—which is what forecast accuracy should measure. For full discussion, see our methodological note.
Different market types use different reference dates, reflecting the information available to researchers and the settlement characteristics of each platform:
| Market Type | Reference Date | Rationale |
|---|---|---|
| Electoral Markets | 00:00 UTC on election day | Event-anchored. Uses verified election dates from our lookup table. Price is queried at exact UTC midnight via the Dome API. This is pre-outcome for all U.S. elections and unambiguous across platforms. |
| Non-Electoral (Polymarket) | trading_close_time − 2 days | Resolution-anchored with offset. Polymarket markets typically close 24–48 hours after event outcomes are known. The 2-day offset is a conservative pre-event estimate. |
| Non-Electoral (Kalshi) | trading_close_time − 1 day | Resolution-anchored with offset. Kalshi markets settle within 3–12 hours. The 1-day offset provides a conservative pre-event window. |
Note: For non-electoral markets, we do not have event dates and must rely on resolution-relative offsets. These offsets are less precise than event-anchored dates and may include some post-outcome trading, particularly on Polymarket. We document this limitation transparently. Where possible, we use the electoral approach as the benchmark.
Our methodology accounts for documented platform settlement procedures:
Election eve prices are queried from the Dome API at exact Unix timestamps (UTC midnight on election day). This provides point-in-time prices rather than daily candle approximations. For time-horizon Brier scores (1d, 7d, etc.), we use daily price observations at 00:00 UTC intervals.
Free for academic research. Enter your details and we'll send you access to the latest data.
If you use this dataset in your research, please cite:
BibTeX:
@misc{hall2026bellwether,
author = {Hall, Andrew B. and Paschal, Elliot J.},
title = {Bellwether Political Prediction Markets Dataset},
year = {2026},
publisher = {Stanford Graduate School of Business},
howpublished = {\url{https://elliotjames-paschal.github.io/Bellwether/data.html}}
}