Download and replay Binance spot and perpetual L2 order book history with AymarData — snapshots, deltas, Python, and cURL.
Binance order book history: download and replay
Binance spot and USDⓈ-M perpetual books are core inputs for crypto market making, execution research, and prediction-market hedges. AymarData stores L2 history so you can download point-in-time books and replay deltas offline. This guide covers source ids, market symbols like BTCUSDT, and a working replay loop.
Coverage: Binance data hub. Example market: BTCUSDT.
Sources
| Product | source id |
|---|---|
| Spot | binance-spot |
| USDⓈ-M perps | binance-perps |
Market ids typically look like BTCUSDT (see /v1/markets). Perps also expose funding and mark concepts — see the funding rate and mark price glossary entries and Hyperliquid guide for cross-venue funding work.
Spot vs perps: when to use which
| Use case | Source | Notes |
|---|---|---|
| Spot hedge for Polymarket Up/Down | binance-spot | Simple cash reference; see Polymarket hub |
| Basis / funding research | binance-perps | Join with Hyperliquid funding studies |
| Execution TCA on perps | binance-perps | Replay full depth around your fills |
Never omit source: BTCUSDT exists on both spot and perps with different books and trade tapes.
Authenticate
export AYMARDATA_API_KEY=ad_live_YOUR_KEY
List markets
curl -s "https://api.aymardata.com/v1/markets" \
-H "Authorization: Bearer $AYMARDATA_API_KEY" \
-G \
--data-urlencode "source=binance-spot" \
--data-urlencode "q=BTC" \
--data-urlencode "limit=20"
Swap source=binance-perps for perpetual contracts. Confirm history_from before scheduling multi-day jobs.
Download a snapshot
curl -s "https://api.aymardata.com/v1/book" \
-H "Authorization: Bearer $AYMARDATA_API_KEY" \
-G \
--data-urlencode "source=binance-spot" \
--data-urlencode "market=BTCUSDT" \
--data-urlencode "at=2026-10-23T10:00:00Z" \
--data-urlencode "depth=50"
Python helper:
import os
import requests
from collections import defaultdict
API = "https://api.aymardata.com/v1"
H = {"Authorization": f"Bearer {os.environ['AYMARDATA_API_KEY']}"}
def get_book(source: str, market: str, at: str, depth: int = 50):
r = requests.get(
f"{API}/book",
headers=H,
params={"source": source, "market": market, "at": at, "depth": depth},
timeout=30,
)
r.raise_for_status()
return r.json()
snap = get_book("binance-spot", "BTCUSDT", "2026-10-23T10:00:00Z")
print(snap["spread"], snap["bids"][0], snap["asks"][0])
Unlike Polymarket binaries, spot/perp books usually do not need an outcome parameter.
Interpreting Binance book fields
Bids and asks follow the common AymarData schema: best bid first (highest price), best ask first (lowest price), sizes in base-asset units as normalized from the venue feed. spread is ask − bid in price units. ts_exchange vs ts_recv matter when you compare against Polymarket clocks — align on exchange time for economic features, receive time for latency studies. See schemas.
Download deltas for replay
def get_deltas(source: str, market: str, start: str, end: str):
r = requests.get(
f"{API}/book/deltas",
headers=H,
params={"source": source, "market": market, "start": start, "end": end},
timeout=120,
)
r.raise_for_status()
return r.json()["data"]
Each delta includes side, price, size, ts_exchange, and seq. size: 0 deletes the level.
Endpoint choice
- Sparse mid sampling (1–60s) →
/v1/book?at=only - Continuous replay / impact models → snapshot seed +
/v1/book/deltas - Multi-hour offline →
/v1/filesthen local apply (Bulk, Pro/Enterprise)
Replay engine (minimal)
def levels_from_snapshot(book):
bids = {lvl["price"]: lvl["size"] for lvl in book["bids"]}
asks = {lvl["price"]: lvl["size"] for lvl in book["asks"]}
return bids, asks
def apply_delta(bids: dict, asks: dict, d: dict):
book = bids if d["side"] == "bid" else asks
px, sz = d["price"], d["size"]
if sz == 0:
book.pop(px, None)
else:
book[px] = sz
def replay(source: str, market: str, t0: str, t1: str, depth: int = 1000):
book = get_book(source, market, t0, depth=depth)
bids, asks = levels_from_snapshot(book)
last_seq = None
for d in sorted(get_deltas(source, market, t0, t1), key=lambda x: x["seq"]):
if last_seq is not None and d["seq"] <= last_seq:
raise RuntimeError(f"non-increasing seq {last_seq} -> {d['seq']}")
apply_delta(bids, asks, d)
last_seq = d["seq"]
best_bid = max(bids) if bids else None
best_ask = min(asks) if asks else None
return best_bid, best_ask, len(bids), len(asks)
print(replay(
"binance-spot",
"BTCUSDT",
"2026-10-23T10:00:00Z",
"2026-10-23T10:01:00Z",
))
Production replay should checkpoint periodically, handle crossed books as data-quality events, and verify seq continuity. After a long apply, compare top-of-book to a fresh GET /v1/book?at=t1 as a unit test. Conceptual background: Order book deltas vs snapshots and L2 order book.
Pitfalls specific to Binance replay
- Shallow seed depth — Far levels never enter your maps; later deltas look wrong. Seed deep enough for the model.
- Sorting by timestamp only — Tied timestamps need
seq. - Ignoring deletes —
size: 0must remove the level or you leave ghost liquidity. - Crossed book — Treat as resync trigger, not as arb signal by default.
- Hour-long REST delta pulls — Prefer chunking (for example 1–5 minutes) or bulk files to avoid timeouts and rate limits.
Perps: mark and funding context
For binance-perps, join book paths with funding/mark fields when your plan and schemas expose them on market or settlement-adjacent endpoints. Cross-check Hyperliquid funding via Hyperliquid historical data and funding rates. Data pages under /data/binance call out which symbols are indexable.
def spot_vs_perp_mids(at: str, market: str = "BTCUSDT"):
spot = get_book("binance-spot", market, at, depth=1)
perp = get_book("binance-perps", market, at, depth=1)
def mid(b):
return (b["bids"][0]["price"] + b["asks"][0]["price"]) / 2
return {"spot": mid(spot), "perp": mid(perp), "basis": mid(perp) - mid(spot), "at": at}
Bulk download
curl -s "https://api.aymardata.com/v1/files" \
-H "Authorization: Bearer $AYMARDATA_API_KEY" \
-G \
--data-urlencode "source=binance-spot" \
--data-urlencode "prefix=BTCUSDT"
Load Parquet into Polars/DuckDB for multi-hour replays without hammering REST. Platform: Bulk. Files are a Pro/Enterprise capability.
Trades alongside books
curl -s "https://api.aymardata.com/v1/trades" \
-H "Authorization: Bearer $AYMARDATA_API_KEY" \
-G \
--data-urlencode "source=binance-spot" \
--data-urlencode "market=BTCUSDT" \
--data-urlencode "start=2026-10-23T10:00:00Z" \
--data-urlencode "end=2026-10-23T10:01:00Z" \
--data-urlencode "limit=500"
Use trades to validate replayed top-of-book and to model queue priority assumptions. A trade printing through several levels is a useful check that your reconstructed depth was not truncated too aggressively.
Join with prediction markets
When hedging Polymarket Up/Down, sample Binance mid at the same UTC decision time as the Polymarket book. Store both venues’ ts_exchange values. Guide: How to backtest Polymarket Up/Down.
Tips for large jobs
- Partition by day and symbol on disk
- Replay hour-long chunks; persist checkpoints
- Respect rate limits; prefer files for backfills
- Align clocks when joining Polymarket Up/Down hedges
- Store both
ts_exchangeandts_recvfor latency studies - Unit-test reconstructed books against
/v1/book?at=at chunk boundaries - Keep spot and perps in separate partitions even when symbols match
Interpreting depth for execution research
Binance books are deep relative to most prediction-market ladders, which tempts people to request full depth on every call. For signal research that only needs microprice or top-five imbalance, high depth wastes bandwidth and slows notebooks. For market-impact and queue models, shallow depth silently corrupts results because far-touch updates never enter your local maps when the seed was truncated. Choose depth as a model parameter, not as a default of “whatever the example used.”
When you validate replay, compare not only best bid and ask but also cumulative size within a fixed notional or tick distance from the touch. Tops can match while the shape below them diverges if deletes were dropped or sequences were applied out of order. Crossed books after apply almost always mean a missed delete, a seq gap, or a seed taken from the wrong source id (spot vs perps). Resync from /v1/book?at= at the failure timestamp rather than inventing repair heuristics in a first version.
Latency studies should keep ts_exchange and ts_recv side by side. Exchange time is the economic clock for joining Polymarket or Hyperliquid features; receive time approximates your research warehouse’s notion of “when we knew.” Mixing them inside one join is a common source of spurious lead–lag. If you hedge Polymarket Up/Down with spot, read the Polymarket hub and backtest guide for outcome handling, then join Binance mids on UTC at= only.
Operational playbook for a new symbol
- Confirm the symbol on /data/binance and decide
binance-spotvsbinance-perps. - List markets and record
history_from. - Pull a one-minute snapshot-plus-delta replay and assert tops against a second snapshot.
- Pull trades for the same minute and check that prints sit near the reconstructed touch.
- If the job spans days, list
/v1/filesand prefer Parquet when present on your plan. - Only after the canary passes, schedule chunked backfills with checkpoint files on disk.
That playbook scales from BTCUSDT to thinner pairs: the failure mode on thin symbols is usually sparse trades, not a different API shape. Keep the same endpoints; tighten your continuity checks.
Snapshots, deltas, and files in one mental model
Think of AymarData’s Binance delivery as three layers of the same tape. Snapshots answer “what did the book look like at time t?” Deltas answer “how did it change between t0 and t1?” Files answer “give me a day of that tape without chatting to the API.” Research velocity comes from picking the layer that matches the question. A dashboard widget should not download deltas. A queue simulator should not poll full depth every 50ms. A week-long training job should not open one HTTPS call per second if Parquet partitions exist on your plan.
When you graduate from REST to files, keep the apply function identical. The only thing that should change is the iterator that yields delta records. That discipline prevents “it worked in the notebook” bugs where file partitions use a slightly different field name and your silent d.get("size", 0) masks the break. Read schemas when something looks off, and cross-check a single timestamp with GET /v1/book before blaming the venue.
If you also consume Polymarket or Kalshi, isolate Binance helpers behind a small client module that always requires source. The cost of one extra argument is far lower than the cost of a week of mixed spot/perp features. For conceptual apply rules that transcend venues, keep Order book deltas vs snapshots nearby while you implement.
FAQ
Spot vs perps source mix-ups?
Always set source explicitly. BTCUSDT exists on both; books differ.
Depth caps?
Use depth for lighter payloads; omit or raise for full replay seeds within plan limits (book docs).
Do I need outcome?
Not for standard spot/perp books. Outcome is for two-sided prediction-market tokens (Polymarket/Kalshi).
Next
Docs · Pricing · Compare Tardis.dev alternative
Educational content, not trading or investment advice. Past data doesn't predict future results.