Polymarket 15 Minute Backtest: Tick-Level Up/Down Data
Fifteen-minute Up/Down windows are the default research interval — 96 independent markets per day with enough path for mid and imbalance signals.
Each 15m window is its own market. Backtests that treat the family slug as a single series will mix regimes; always iterate concrete window ids.
Use btc-updown-15m as the starter family, then expand to ETH/SOL. Platform Polymarket total ~207.0M messages since 2025-06-01.
Inputs
What you need for a 15-minute Polymarket backtest
What a serious backtest needs beyond candles.
96 windows/day structure
Open on quarter-hour boundaries. Sample once near the open or on a schedule inside the window — document which.
Book + settlement pair
Decision from /v1/book; P&L from /v1/settlement. Optional /v1/trades for flow filters.
Cross-venue spot (optional)
Join Binance BTCUSDT when measuring lag between spot and Up price.
Coverage
Live 15-minute coverage
Exact BTC/ETH/SOL/XRP 15m event counts are on the matching /data/polymarket/*-updown-15m pages.
Windows / day / coin
96
15-minute family
BTC 15m data page
Event rates
/data/polymarket/btc-updown-15m
Polymarket total
~207.0M
As of
2026-10-25
Code
End-to-end 15-minute backtest (REST + requests)
Family btc-updown-15m — mid threshold strategy with settlement check.
import os
import requests
API = "https://api.aymardata.com/v1"
KEY = os.environ["AYMARDATA_API_KEY"] # export AYMARDATA_API_KEY=ad_live_…
H = {"Authorization": f"Bearer {KEY}", "User-Agent": "aymardata-backtest/1.0"}
def list_windows(q: str, interval: str, limit: int = 40):
r = requests.get(
f"{API}/markets",
headers=H,
params={"source": "polymarket", "q": q, "interval": interval, "limit": limit},
timeout=30,
)
r.raise_for_status()
# De-dupe Up/Down rows that share the same window slug
seen, out = set(), []
for row in r.json()["data"]:
m = row["market"]
if m in seen:
continue
seen.add(m)
out.append(row)
return out
def book(market: str, outcome: str, at: str, depth: int = 5):
r = requests.get(
f"{API}/book",
headers=H,
params={
"source": "polymarket",
"market": market,
"outcome": outcome,
"at": at,
"depth": depth,
},
timeout=30,
)
r.raise_for_status()
return r.json()
def settlement(market: str):
r = requests.get(
f"{API}/settlement",
headers=H,
params={"source": "polymarket", "market": market},
timeout=30,
)
if r.status_code == 404:
return None
r.raise_for_status()
return r.json()
def mid(snap):
bids, asks = snap.get("bids") or [], snap.get("asks") or []
if not bids or not asks:
return None
return (bids[0]["price"] + asks[0]["price"]) / 2
THRESHOLD = 0.45
rows = []
for w in list_windows("btc-updown-15m", "15m"):
market = w["market"]
hist = w.get("history_from")
if not hist:
continue
# Sample ~60s after history starts
at = hist.replace("+00:00", "Z")
if at.endswith("Z") is False and "T" in at:
at = at + ("Z" if "+" not in at else "")
snap = book(market, "up", at if "T" in at else hist)
m = mid(snap)
if m is None or m >= THRESHOLD:
continue
# Buy Up at the ask; score later against settlement when resolved
entry = (snap["asks"] or [{}])[0].get("price")
sett = settlement(market)
won = None
if sett:
outcome = str(sett.get("outcome") or sett.get("winner") or "").lower()
won = outcome in ("up", "yes", "1")
rows.append({"market": market, "mid": m, "entry": entry, "won": won})
# Counts only — label any P&L/win-rate/edge you add:
# "Illustrative output — not a real result"
print(f"signals={len(rows)} sample={rows[:3]}")
API base https://api.aymardata.com. Set AYMARDATA_API_KEY from your dashboard. Examples use requests. Any P&L, win-rate, or edge figure derived from these snippets is illustrative output — not a real result.
Free samples
Download sample CSV / Parquet
No key required — small files for schema and local smoke tests.
FAQ
Common questions
Why 15 minutes instead of 5?
Fifteen minutes balances sample count with time to act on a signal. Use the 5-minute page when latency and final-minute collapse are the research target.
Related
Data pages and guides
Catalog leaves for schema and samples; guides for longer walkthroughs.
Run your first backtest with real ticks
Get a key, paste the snippet above, then expand to the full catalog.
Educational content, not trading or investment advice. Past data doesn't predict future results.