Documentation

Data Format Reference

Complete reference for all ImpliedData files — column definitions, data types, interpretation guide, and working code examples. Read this before using the data.

Overview

ImpliedData provides historical prediction market data from Polymarket, Manifold, and Myriad in a unified schema. All prices are normalized to win probability (0 to 1) — not dollars, not percentages. All timestamps are UTC. All platforms use the same column names.

There are three types of files you can download:

Candles

OHLCV aggregated price data. One row per time bucket per market. Best starting point for most analysis.

Trades

Raw tick-level trade history. Every individual transaction. Use when you need exact execution times or microstructure analysis.

Markets

Market metadata — titles, categories, resolution outcomes, open/close dates. Join this against candles or trades to get market context.

File Formats

ParquetRecommended

Apache Parquet is a columnar binary format. It is 5–10× smaller than CSV and preserves exact data types (timestamps stay as datetime, floats stay as float64). Python, R, DuckDB, Spark, and most modern data tools read it natively. Always prefer Parquet unless you need to open the file in Excel.

CSV

Plain text, comma-separated. Opens in Excel, Google Sheets, Numbers, and any language. Timestamps are ISO 8601 strings ("2024-06-01T14:00:00+00:00"). Floats are written with full precision. Larger file sizes than Parquet (no compression, no columnar storage).

Note on CSV and Excel: Excel may auto-convert market IDs that look like numbers to scientific notation (e.g. 0x1a2b3c stays fine, but a pure numeric ID like 123456789012 may be corrupted). Import via Data → From Text/CSV and set the column type to Text to prevent this.

Understanding Prices (0–1)

All price fields (open, high, low, close, price) are win probability expressed as a decimal between 0 and 1, not dollars or percentages.

0.62
62% chance of YES — taker paid 0.62 for a contract settling at 1.00
0.04
4% chance — very unlikely outcome
0.98
98% chance — market near resolution

To convert to percentage: price × 100. To convert to implied odds: 1 / price.

Multi-outcome markets (e.g. “Who wins the 2024 election?” with 10 candidates): each candidate is a separate market_id/outcome row. Prices across all outcomes in an event should sum to approximately 1.0 (the difference is the platform’s margin).

Gaps & Sparse Markets

Candle files do not insert rows for empty periods. If no trades occurred during a 1h bucket, that bucket simply does not exist in the file. This is by design — inserting NULL rows would inflate file sizes by 10–100× for low-volume markets.

Manifold markets are especially sparse — many have only a handful of trades over their entire lifetime. A market open for 6 months may have only 20–30 candles at 1d resolution if trading was infrequent.

How to handle gaps in your analysis:

python
import pandas as pd

df = pd.read_parquet("implieddata_polymarket_1h.parquet")

# Forward-fill missing hours (last known price)
df = df.set_index("timestamp").sort_index()
full_range = pd.date_range(df.index.min(), df.index.max(), freq="1h", tz="UTC")
df = df.reindex(full_range)
df["close"] = df["close"].ffill()   # carry last close forward
df["volume"] = df["volume"].fillna(0)  # no trades = zero volume

Candles Schema

OHLCV candle data. Files are named implieddata_{platform}_{resolution}.parquet (e.g. implieddata_polymarket_1h.parquet). One row per time bucket per market. All resolutions (1m, 5m, 15m, 1h, 1d) are available to every signed-in account.

Note: Bulk 1m/5m/15m downloads for Polymarket markets before December 2022 may return no data for markets not yet backfilled into the continuous aggregate. Per-market downloads (selecting a specific market) always fall back to on-demand computation from raw trades and are not affected by this gap.

ColumnTypeNullableDescription
timestampdatetime (UTC)NOStart of the candle bucket. UTC timezone. 1h candles start at the top of the hour (e.g. 2024-06-01 14:00:00+00).
platformstringNOSource platform slug: polymarket, manifold, or myriad.
market_idstringNOPlatform-specific market identifier. For Polymarket this is the condition_id (hex string). For Manifold the slug/contract ID.
resolutionstringNOCandle resolution: 1m, 5m, 15m, 1h, or 1d. Matches the file you downloaded.
openfloat64 [0–1]NOWin probability at the start of the candle, derived from the first trade in the bucket.
highfloat64 [0–1]NOHighest win probability traded during the candle period.
lowfloat64 [0–1]NOLowest win probability traded during the candle period.
closefloat64 [0–1]NOWin probability at the end of the candle, derived from the last trade in the bucket.
volumefloat64NOTotal notional traded during the candle period. Currency depends on the platform — see volume_currency. Computed as Σ(price × size) across all trades in the bucket.
volume_currencystringNOCurrency of the volume field: USD for Polymarket, MANA for Manifold. Manifold uses play-money (Mana) — volumes are not directly comparable across platforms.
trade_countint64NONumber of individual trades that occurred during the candle period.
market_titlestringYESHuman-readable title of the market (e.g. 'Will Trump win the 2024 election?'). Joined from market metadata.
market_open_timedatetime (UTC)YESWhen the market was created / opened for trading.
market_close_timedatetime (UTC)YESWhen the market resolved or closed. NULL for markets still open.

Trades Schema

Raw tick-level trades. Files are named implieddata_{platform}_trades.parquet. One row per individual transaction. Use this for microstructure analysis, custom aggregations, or building your own candle resolution.

ColumnTypeNullableDescription
trade_idstringNOPlatform-assigned unique trade identifier. Used for deduplication.
timestampdatetime (UTC)NOExact trade execution time in UTC. Precision varies by platform (ms or µs).
platformstringNOSource platform: polymarket, manifold, or myriad.
market_idstringNOPlatform-specific market identifier, same as in the candles file.
pricefloat64 [0–1]NOExecution price expressed as win probability. A trade at 0.62 means the taker paid 0.62 for a contract settling at 1.00 if YES resolves.
sizefloat64NONotional size of the trade. USD-denominated for Polymarket (shares × 1.00). For Manifold, this is raw Mana — Manifold uses play-money and sizes are not USD-equivalent.
sidestringYESTrade side: buy or sell from the taker's perspective. NULL when platform does not report this field.
outcomestringYESWhich outcome token was traded (YES, NO, or candidate name for multi-outcome markets).

Multi-Outcome Markets

Most markets are binary (Yes/No) — one number matters: P(YES), the close value in the candle schema above. But some markets have several mutually-exclusive outcomes — a football match (1 / X / 2), a multi-candidate election, a “which option wins” market. These ship as a separate dataset with one extra column, outcome — they are never mixed into the clean binary 0–1 files.

The grain becomes (market_id, outcome, timestamp) — one row per outcome per time bucket — and close is now the implied probability of that specific outcome. So for “Arsenal vs Chelsea” you get three rows at each timestamp:

timestampmarket_idoutcomeclosemeaning
14:0012310.55P(Arsenal win) = 55%
14:00123X0.27P(draw) = 27%
14:0012320.18P(Chelsea win) = 18%

Every other column is identical to the binary candle schema (open/high/low/close/volume/trade_count). What to know:

  • One outcome’s price path: filter market_id = 123 AND outcome = '1'.
  • The whole market: filter market_id = 123 → every outcome at every timestamp.
  • Prices ≈ sum to 1 across a market’s outcomes (they’re mutually exclusive) — but not exactly: prices are sampled from an order book with a spread, so the sum drifts a few percent around 1.0. We report observed prices and do not renormalize (divide by the row-sum yourself if you want a clean distribution).
  • Outcome labels are the raw traded labels — for Azuro football, betting convention: 1 = home win, X = draw, 2 = away win. Join market_id → the markets file (outcomes column) for the full human meaning.
  • At resolution the winning outcome converges to ~1, the losers to ~0 — same convergence guarantee as the binary set.

Raw trades for these markets follow the same rule: the trades schema gains the same outcome column, with price = that outcome’s probability at the fill. Coverage at launch: Azuro (sports, 2023–2025 historical archive), multi-candidate Polymarket, and multi-option Myriad.

Markets Schema

Market metadata catalog. Files named implieddata_{platform}_markets.parquet. Join against candles or trades on platform_market_id = market_id.

ColumnTypeNullableDescription
idint64NOImpliedData internal market ID. Stable across updates.
platform_market_idstringNOPlatform-assigned market identifier. Use this to join against candle/trade files.
platformstringNOSource platform slug.
titlestringNOFull market question as listed on the platform.
categorystringYESTopic category (politics, sports, crypto, science, …). Normalized across platforms.
statusstringNOMarket status: open, resolved, or closed. Resolved markets have a resolution_result.
resolution_resultstringYESResolution outcome: YES, NO, or a candidate name for multi-outcome markets. NULL if not yet resolved.
open_timedatetime (UTC)YESMarket creation timestamp.
close_timedatetime (UTC)YESMarket resolution timestamp. NULL for open markets.
trade_countint64NOTotal number of trades ever recorded for this market in ImpliedData.
raw_metadata column: A JSON object containing platform-specific fields that don’t fit the normalized schema. Examples: Polymarket’s neg_risk flag, Manifold’s resolution_probability. Parse with json.loads(row["raw_metadata"]).

Code Examples

Load candles with pandas (Python)

python
import pandas as pd

# Load 1h candles for Polymarket
df = pd.read_parquet("implieddata_polymarket_1h.parquet")

# Basic info
print(df.dtypes)
print(df.head())

# Filter to a single market
market = df[df["market_id"] == "0x1234abcd..."]

# Plot the close probability over time
import matplotlib.pyplot as plt
market.set_index("timestamp")["close"].plot(title=market["market_title"].iloc[0])

Load with polars (Python) — faster for large files

python
import polars as pl

df = pl.read_parquet("implieddata_polymarket_1h.parquet")

# Filter markets that resolved YES and had high volume
winners = (
    df.filter(pl.col("resolution_result") == "YES")
    .group_by("market_id")
    .agg([
        pl.col("close").last().alias("final_price"),
        pl.col("volume").sum().alias("total_volume"),
        pl.col("market_title").first(),
    ])
    .filter(pl.col("total_volume") > 10_000)
    .sort("total_volume", descending=True)
)
print(winners.head(20))

Query with DuckDB — SQL on Parquet without loading into memory

sql
-- Install: pip install duckdb
-- Then in Python:

import duckdb

# Query directly from file — DuckDB reads only the columns/rows it needs
result = duckdb.query("""
    SELECT
        market_id,
        market_title,
        MIN(low)  AS min_prob,
        MAX(high) AS max_prob,
        LAST(close ORDER BY timestamp) AS final_price,
        SUM(volume) AS total_volume_usd
    FROM 'implieddata_polymarket_1h.parquet'
    WHERE market_title ILIKE '%election%'
      AND timestamp >= '2024-01-01'
    GROUP BY market_id, market_title
    ORDER BY total_volume_usd DESC
    LIMIT 20
""").df()

print(result)

Load in R

r
# install.packages("arrow")
library(arrow)
library(dplyr)

df <- read_parquet("implieddata_polymarket_1h.parquet")

# Summary by market
summary <- df |>
  group_by(market_id, market_title) |>
  summarise(
    first_price  = first(open),
    last_price   = last(close),
    total_volume = sum(volume),
    n_candles    = n()
  ) |>
  arrange(desc(total_volume))

head(summary, 20)

Join candles with market metadata

python
import pandas as pd

candles = pd.read_parquet("implieddata_polymarket_1h.parquet")
markets = pd.read_parquet("implieddata_polymarket_markets.parquet")

# Join on the platform market identifier
merged = candles.merge(
    markets[["platform_market_id", "title", "category", "resolution_result"]],
    left_on="market_id",
    right_on="platform_market_id",
    how="left"
)

# Filter to politics markets only
politics = merged[merged["category"] == "politics"]

Convert to percentage / implied odds

python
import pandas as pd

df = pd.read_parquet("implieddata_polymarket_1h.parquet")

# Prices are 0–1 probabilities. Convert:
df["close_pct"]         = df["close"] * 100       # e.g. 0.62 → 62.0%
df["close_implied_odds"]= 1 / df["close"]         # e.g. 0.62 → 1.61x
df["close_decimal_odds"]= 1 / df["close"]         # same as implied odds for binary markets

# For a YES/NO market, the NO probability is:
df["no_prob"] = 1 - df["close"]

API Reference

Programmatic access is free and open to every signed-in account. Generate a key in your account (shown once — store it securely), then authenticate every request with a Bearer header. API downloads count towards the same fair-use export ceiling as website downloads.

EndpointDescriptionRate limit
GET /v1/marketsMarket catalog — filter by platform, category, status, search120 / min
GET /v1/candlesOHLCV candles as JSON (max 10,000 rows per call)60 / min
GET /v1/downloadBulk Parquet/CSV export (counts against monthly volume)20 / 10 min
GET /v1/outcome-candlesPer-outcome candles for multi-outcome markets, incl. the Azuro archive — market_id required60 / min
GET /v1/outcome-downloadParquet/CSV export of multi-outcome / Azuro candles — market_id required20 / 10 min
GET /v1/event-linksConfirmed cross-platform links for a market, with polarity120 / min
GET /v1/event-clustersOne event across every platform, aligned to a canonical YES120 / min
GET /v1/onchain-tradesRaw tick-level Polymarket fills — market_id required20 / 10 min
GET /v1/usageYour current month's row usage and remaining volume60 / min

Quick start (curl)

bash
# Catalog: newest open Polymarket politics markets
curl -H "Authorization: Bearer idk_live_YOUR_KEY" \
  "https://api.implieddata.com/v1/markets?platform=polymarket&category=politics&status=open&limit=50"

# Candles: 1-minute resolution for one market
curl -H "Authorization: Bearer idk_live_YOUR_KEY" \
  "https://api.implieddata.com/v1/candles?platform=polymarket&market_id=12345&resolution=1m&start=2026-05-01&end=2026-06-01"

# Bulk export: all Manifold 1h candles for May as Parquet
curl -OJ -H "Authorization: Bearer idk_live_YOUR_KEY" \
  "https://api.implieddata.com/v1/download?platform=manifold&resolution=1h&start=2026-05-01&end=2026-06-01&fmt=parquet"

# Multi-outcome (e.g. the Azuro sports archive): per-outcome candles for one market
curl -OJ -H "Authorization: Bearer idk_live_YOUR_KEY" \
  "https://api.implieddata.com/v1/outcome-download?market_id=49021136&resolution=1h&fmt=csv"

# Check your remaining monthly volume
curl -H "Authorization: Bearer idk_live_YOUR_KEY" "https://api.implieddata.com/v1/usage"

Python

python
import io, requests, pandas as pd

KEY = "idk_live_YOUR_KEY"
H = {"Authorization": f"Bearer {KEY}"}
BASE = "https://api.implieddata.com"

# Download straight into a DataFrame
r = requests.get(f"{BASE}/v1/download", headers=H, params={
    "platform": "polymarket", "resolution": "1h",
    "start": "2026-01-01", "end": "2026-06-01", "fmt": "parquet",
})
r.raise_for_status()
df = pd.read_parquet(io.BytesIO(r.content))
print(df.head())

Errors: 401 missing/invalid key · 403 fair-use export limit exceeded · 429 rate limit — retry after the Retry-After header · 404 no data for the given filters. Keys can be revoked any time from your account page.

Common Gotchas

⚠ Prices above 1.0 or below 0.0

Should not happen in cleaned data. If you see them, they are anomalies from erroneous platform data that we have flagged but not deleted. Filter with df[df['close'].between(0, 1)] to exclude them.

⚠ Multi-outcome markets inflate row counts

An election market with 10 candidates generates 10× the rows of a binary market. Each candidate is a separate market_id. When computing platform-level volume, be aware that an event's total volume is the sum across all its outcome market_ids.

⚠ Manifold volume is in Mana, not USD

Manifold uses play-money (Mana), not real money. The volume and size columns for Manifold files contain raw Mana amounts — they are NOT converted to USD. The volume_currency column tells you the currency: 'USD' for Polymarket, 'MANA' for Manifold. Filter with df[df['volume_currency'] == 'USD'] if you want real-money platforms only. Price/probability columns (open, high, low, close) ARE unified across all platforms — only volume differs.

⚠ The same event appears across platforms

The 2024 US Presidential Election is on both platforms as separate market_ids. There is no cross-platform event ID — you need to match by title substring or by manually mapping condition_ids.

⚠ 1d candles use UTC day boundaries

A 1d candle timestamped 2024-11-05 00:00:00+00 covers trades from midnight to midnight UTC. US market events (debates, election results) often occur in the US evening = UTC next day, so a result announced at 11pm ET lands in the next day's 1d candle.

⚠ Timestamps in CSV files are strings

In CSV files, timestamp is written as an ISO 8601 string: 2024-06-01T14:00:00+00:00. Always parse with timezone awareness: pd.read_csv(..., parse_dates=['timestamp']). With Parquet, timestamps are already datetime64[ns, UTC] — no parsing needed.

⚠ resolution field in candles

The resolution column in candle files repeats the resolution label on every row (e.g. '1h'). This is useful when you concatenate files from multiple resolutions into one DataFrame — it lets you filter without checking filename.

Data Sources & Attribution

PolymarketCollected via Polymarket's public Gamma API (market metadata) and Data API (trade history). Coverage: Oct 2020 – present (historical bootstrap + continuous direct collection).
ManifoldCollected via the Manifold public API (no auth required). Coverage: Sep 2023 – present. Volume is Mana-denominated (play money).
MyriadCollected via the public Myriad Protocol API (api-v2.myriadprotocol.com). On-chain markets on Abstract and Linea. Coverage: Jan 2025 – present.
Historical bootstrap data includes work by Jonathan Becker (MIT License — github.com/Jon-Becker/prediction-market-analysis).