Production-ready queries for common prediction market analysis tasks. All queries include platform and date filters for optimal performance.
Market Discovery
Search Markets by Keyword
SELECT
id,
platform,
title,
status,
created_at
FROM markets
WHERE platform = 'POLYMARKET'
AND created_at >= now() - INTERVAL 90 DAY
AND (
title ILIKE '%bitcoin%'
OR title ILIKE '%btc%'
)
ORDER BY created_at DESC
LIMIT 50;
Markets Closing Soon
Find active markets closing in the next 7 days—useful for time-sensitive analysis.
SELECT
id,
platform,
title,
closes_at,
dateDiff('hour', now(), closes_at) as hours_until_close
FROM markets
WHERE platform = 'POLYMARKET'
AND status = 'ACTIVE'
AND closes_at BETWEEN now() AND now() + INTERVAL 7 DAY
ORDER BY closes_at ASC
LIMIT 100;
Recently Created Markets
SELECT
id,
platform,
title,
category,
created_at
FROM markets
WHERE platform = 'POLYMARKET'
AND created_at >= now() - INTERVAL 24 HOUR
ORDER BY created_at DESC
LIMIT 50;
Most Traded Markets (Last 7 Days)
SELECT
t.market_id,
m.title,
m.platform,
count() as trade_count,
sum(t.volume) as total_volume,
uniq(t.trader_id) as unique_traders
FROM trades t
JOIN markets m ON t.market_id = m.id
WHERE t.platform = 'POLYMARKET'
AND t.created_at >= now() - INTERVAL 7 DAY
GROUP BY t.market_id, m.title, m.platform
ORDER BY total_volume DESC
LIMIT 25;
Price Analysis
Price History for a Market
Get all trades for a specific market to plot price over time.
SELECT
created_at,
outcome.name as outcome,
price,
volume,
side
FROM trades
WHERE platform = 'POLYMARKET'
AND market_id = 'your-market-uuid-here'
AND created_at >= now() - INTERVAL 30 DAY
ORDER BY created_at ASC;
OHLC Candles (Hourly)
Build candlestick data for charting. Grouped by outcome for multi-outcome markets.
SELECT
toStartOfHour(created_at) as hour,
outcome.name as outcome,
argMin(price, created_at) as open,
max(price) as high,
min(price) as low,
argMax(price, created_at) as close,
sum(volume) as volume,
count() as trade_count
FROM trades
WHERE platform = 'POLYMARKET'
AND market_id = 'your-market-uuid-here'
AND created_at >= now() - INTERVAL 7 DAY
GROUP BY hour, outcome
ORDER BY hour ASC, outcome;
OHLC Candles (Daily)
SELECT
toDate(created_at) as date,
outcome.name as outcome,
argMin(price, created_at) as open,
max(price) as high,
min(price) as low,
argMax(price, created_at) as close,
sum(volume) as volume
FROM trades
WHERE platform = 'POLYMARKET'
AND market_id = 'your-market-uuid-here'
AND created_at >= now() - INTERVAL 90 DAY
GROUP BY date, outcome
ORDER BY date ASC, outcome;
Volume-Weighted Average Price (VWAP)
SELECT
outcome.name as outcome,
sum(price * volume) / sum(volume) as vwap,
sum(volume) as total_volume
FROM trades
WHERE platform = 'POLYMARKET'
AND market_id = 'your-market-uuid-here'
AND created_at >= now() - INTERVAL 24 HOUR
GROUP BY outcome;
Latest Price per Outcome
Get the most recent trade price for each outcome in a market.
SELECT
outcome.name as outcome,
argMax(price, created_at) as latest_price,
max(created_at) as last_trade_time
FROM trades
WHERE platform = 'POLYMARKET'
AND market_id = 'your-market-uuid-here'
GROUP BY outcome;
Trading Activity
Recent Trades on a Market
SELECT
created_at,
outcome.name as outcome,
side,
price,
amount,
volume,
trader_id
FROM trades
WHERE platform = 'POLYMARKET'
AND market_id = 'your-market-uuid-here'
ORDER BY created_at DESC
LIMIT 100;
Hourly Volume Over Time
SELECT
toStartOfHour(created_at) as hour,
count() as trades,
sum(volume) as volume,
uniq(trader_id) as unique_traders
FROM trades
WHERE platform = 'POLYMARKET'
AND market_id = 'your-market-uuid-here'
AND created_at >= now() - INTERVAL 7 DAY
GROUP BY hour
ORDER BY hour ASC;
Large Trades (Whale Watching)
Find trades above a volume threshold.
SELECT
t.created_at,
m.title,
t.outcome.name as outcome,
t.side,
t.price,
t.volume,
t.trader_id
FROM trades t
JOIN markets m ON t.market_id = m.id
WHERE t.platform = 'POLYMARKET'
AND t.created_at >= now() - INTERVAL 24 HOUR
AND t.volume > 1000 -- adjust threshold
ORDER BY t.volume DESC
LIMIT 100;
Buy vs Sell Pressure
SELECT
toStartOfHour(created_at) as hour,
outcome.name as outcome,
sumIf(volume, side = 'BUY') as buy_volume,
sumIf(volume, side = 'SELL') as sell_volume,
sumIf(volume, side = 'BUY') - sumIf(volume, side = 'SELL') as net_flow
FROM trades
WHERE platform = 'POLYMARKET'
AND market_id = 'your-market-uuid-here'
AND created_at >= now() - INTERVAL 7 DAY
GROUP BY hour, outcome
ORDER BY hour ASC;
Maker vs Taker Distribution
SELECT
liquidity_role,
count() as trade_count,
sum(volume) as total_volume,
avg(fee) as avg_fee
FROM trades
WHERE platform = 'POLYMARKET'
AND market_id = 'your-market-uuid-here'
AND created_at >= now() - INTERVAL 30 DAY
GROUP BY liquidity_role;
Trader Analysis
Top Traders by Volume
SELECT
trader_id,
count() as trade_count,
sum(volume) as total_volume,
uniq(market_id) as markets_traded,
min(created_at) as first_trade,
max(created_at) as last_trade
FROM trades
WHERE platform = 'POLYMARKET'
AND created_at >= now() - INTERVAL 30 DAY
GROUP BY trader_id
ORDER BY total_volume DESC
LIMIT 100;
Trader Activity on a Specific Market
SELECT
trader_id,
count() as trades,
sum(volume) as total_volume,
sumIf(volume, side = 'BUY') as buy_volume,
sumIf(volume, side = 'SELL') as sell_volume,
avg(price) as avg_price
FROM trades
WHERE platform = 'POLYMARKET'
AND market_id = 'your-market-uuid-here'
GROUP BY trader_id
ORDER BY total_volume DESC
LIMIT 50;
Trader’s Position (Net Shares per Outcome)
Estimate a trader’s current position by summing buys minus sells.
SELECT
outcome.name as outcome,
sumIf(amount, side = 'BUY') - sumIf(amount, side = 'SELL') as net_shares,
sumIf(volume, side = 'BUY') as total_bought,
sumIf(volume, side = 'SELL') as total_sold
FROM trades
WHERE platform = 'POLYMARKET'
AND market_id = 'your-market-uuid-here'
AND trader_id = 'trader-id-here'
GROUP BY outcome;
Trader’s Recent Activity Across Markets
SELECT
t.created_at,
m.title,
t.outcome.name as outcome,
t.side,
t.price,
t.volume
FROM trades t
JOIN markets m ON t.market_id = m.id
WHERE t.platform = 'POLYMARKET'
AND t.trader_id = 'trader-id-here'
AND t.created_at >= now() - INTERVAL 7 DAY
ORDER BY t.created_at DESC
LIMIT 100;
Market Resolution
Recently Resolved Markets
SELECT
id,
platform,
title,
resolution_type,
resolution_resolved_at,
resolution_winning_outcome_id
FROM markets
WHERE platform = 'POLYMARKET'
AND status = 'RESOLVED'
AND resolution_resolved_at >= now() - INTERVAL 7 DAY
ORDER BY resolution_resolved_at DESC
LIMIT 50;
Resolution with Winning Outcome Name
SELECT
m.id,
m.title,
m.resolution_resolved_at,
m.resolution_type,
winning.name as winning_outcome
FROM markets m
ARRAY JOIN m.outcomes as winning
WHERE m.platform = 'POLYMARKET'
AND m.status = 'RESOLVED'
AND m.resolution_resolved_at >= now() - INTERVAL 30 DAY
AND winning.id = m.resolution_winning_outcome_id
ORDER BY m.resolution_resolved_at DESC
LIMIT 50;
Aggregated Statistics
SELECT
toDate(created_at) as date,
platform,
count() as trades,
sum(volume) as volume,
uniq(trader_id) as unique_traders,
uniq(market_id) as active_markets
FROM trades
WHERE created_at >= now() - INTERVAL 30 DAY
GROUP BY date, platform
ORDER BY date DESC, platform;
Markets by Category
SELECT
category,
count() as market_count,
countIf(status = 'ACTIVE') as active_markets,
countIf(status = 'RESOLVED') as resolved_markets
FROM markets
WHERE platform = 'POLYMARKET'
AND created_at >= now() - INTERVAL 90 DAY
GROUP BY category
ORDER BY market_count DESC;
Outcome Count Distribution
How many markets have 2 outcomes vs 3+ outcomes?
SELECT
length(outcomes) as outcome_count,
count() as market_count
FROM markets
WHERE platform = 'POLYMARKET'
AND created_at >= now() - INTERVAL 90 DAY
GROUP BY outcome_count
ORDER BY outcome_count;
Advanced Patterns
Price Movement Detection
Find markets where price moved significantly in the last hour.
WITH recent_prices AS (
SELECT
market_id,
outcome.name as outcome,
argMin(price, created_at) as price_1h_ago,
argMax(price, created_at) as current_price
FROM trades
WHERE platform = 'POLYMARKET'
AND created_at >= now() - INTERVAL 1 HOUR
GROUP BY market_id, outcome
)
SELECT
m.title,
r.outcome,
r.price_1h_ago,
r.current_price,
r.current_price - r.price_1h_ago as price_change,
(r.current_price - r.price_1h_ago) / r.price_1h_ago * 100 as pct_change
FROM recent_prices r
JOIN markets m ON r.market_id = m.id
WHERE abs(r.current_price - r.price_1h_ago) > 0.05 -- 5+ point move
ORDER BY abs(pct_change) DESC
LIMIT 25;
Markets with Unusual Volume
Find markets trading above their 7-day average.
WITH volume_stats AS (
SELECT
market_id,
sum(volume) / 7 as avg_daily_volume
FROM trades
WHERE platform = 'POLYMARKET'
AND created_at BETWEEN now() - INTERVAL 8 DAY AND now() - INTERVAL 1 DAY
GROUP BY market_id
),
today_volume AS (
SELECT
market_id,
sum(volume) as today_volume
FROM trades
WHERE platform = 'POLYMARKET'
AND created_at >= now() - INTERVAL 1 DAY
GROUP BY market_id
)
SELECT
m.title,
t.today_volume,
v.avg_daily_volume,
t.today_volume / v.avg_daily_volume as volume_ratio
FROM today_volume t
JOIN volume_stats v ON t.market_id = v.market_id
JOIN markets m ON t.market_id = m.id
WHERE v.avg_daily_volume > 100 -- filter low-volume markets
ORDER BY volume_ratio DESC
LIMIT 25;
Spread Between Outcomes
For binary markets, calculate the bid-ask implied spread.
SELECT
m.title,
sumIf(latest_price, outcome_index = 0) as yes_price,
sumIf(latest_price, outcome_index = 1) as no_price,
sumIf(latest_price, outcome_index = 0) + sumIf(latest_price, outcome_index = 1) as total,
abs(1 - (sumIf(latest_price, outcome_index = 0) + sumIf(latest_price, outcome_index = 1))) as spread
FROM (
SELECT
market_id,
outcome.index as outcome_index,
argMax(price, created_at) as latest_price
FROM trades
WHERE platform = 'POLYMARKET'
AND created_at >= now() - INTERVAL 1 DAY
GROUP BY market_id, outcome_index
) t
JOIN markets m ON t.market_id = m.id
WHERE m.market_type = 'BINARY'
GROUP BY m.id, m.title
HAVING spread > 0.02 -- markets with >2% spread
ORDER BY spread DESC
LIMIT 25;
Time-Weighted Average Price (TWAP)
Weight prices by time between trades, not volume.
WITH trade_intervals AS (
SELECT
created_at,
price,
leadInFrame(created_at) OVER (ORDER BY created_at) as next_trade_time,
dateDiff('second', created_at,
leadInFrame(created_at) OVER (ORDER BY created_at)
) as seconds_until_next
FROM trades
WHERE platform = 'POLYMARKET'
AND market_id = 'your-market-uuid-here'
AND outcome.name = 'Yes'
AND created_at >= now() - INTERVAL 24 HOUR
)
SELECT
sum(price * seconds_until_next) / sum(seconds_until_next) as twap
FROM trade_intervals
WHERE seconds_until_next > 0;
Exporting Data
Add FORMAT CSV or FORMAT CSVWithNames to any query:
SELECT
created_at,
price,
volume,
side
FROM trades
WHERE platform = 'POLYMARKET'
AND market_id = 'your-market-uuid-here'
AND created_at >= now() - INTERVAL 30 DAY
ORDER BY created_at
FORMAT CSVWithNames;
Export to JSON
SELECT
id,
title,
status,
created_at
FROM markets
WHERE platform = 'POLYMARKET'
AND created_at >= now() - INTERVAL 7 DAY
FORMAT JSONEachRow;
When using programmatic clients, the format is usually handled by the client library. These FORMAT clauses are useful for CLI exports or direct HTTP queries.