Top-of-book updates: best bid and best ask with their sizes, one row per change.
/api/v1/data/raw/quotes
exchange_timestamptimestampWhen the venue says the event happened (UTC, µs). Exact.local_timestamptimestampWhen the event reached our capture machine (UTC, µs).bid_pricefloat64Best bid pricebid_amountfloat64Size at the best bid. Base asset on Binance USDⓈ-M and Hyperliquid, contracts on OKXask_pricefloat64Best ask priceask_amountfloat64Size at the best ask. Base asset on Binance USDⓈ-M and Hyperliquid, contracts on OKX| Venue | Symbols | From |
|---|---|---|
| Binance | 983 | Jan 2020 |
| OKX | 700 | Sep 2019 |
| Hyperliquid | 528 | Jan 2025 |
One file per calendar month before 2026-08-01, one per day from then on, in the aperiodic-raw-quotes bucket. Example key:
v1/quotes/exchange=binance-futures/symbol=perpetual-BTC-USDT:USDT/year=2025/month=06/data.parquet
The shared DEMO-KEY gets the 2025-06 file of each venue's BTC perpetual. No account needed.
# Install the Aperiodic CLI into ~/.local/bin
mkdir -p "$HOME/.local/bin"
curl -fsSL https://raw.githubusercontent.com/aperiodic-io/cli/main/install.sh | INSTALL_DIR="$HOME/.local/bin" bash
export PATH="$HOME/.local/bin:$PATH"
# Download the 2025-06 quotes file into ./raw — no API key needed
aperiodic raw quotes --preview \
--exchange binance-futures \
--symbol perpetual-BTC-USDT:USDT \
--output-dir ./raw && echo "Saved to $PWD/raw"pip install "aperiodic[polars]"from datetime import date
import aperiodic as ap
# Into one DataFrame (monthly files are trimmed to your range)
df = ap.get_raw(api_key="YOUR_KEY", dataset="quotes",
exchange="binance-futures", symbol="perpetual-BTC-USDT:USDT",
start_date=date(2025, 6, 1), end_date=date(2025, 6, 30))
print(df.head())
# Or stream the files to disk, skipping ones you already have
ap.download_raw(api_key="YOUR_KEY", dataset="quotes",
exchange="binance-futures", symbol="perpetual-BTC-USDT:USDT",
start_date=date(2025, 1, 1), end_date=date(2025, 12, 31),
output_dir="raw")Read the folder back one dataset at a time, with a glob:
# DuckDB, from the folder that holds ./raw
duckdb -c "SELECT * FROM read_parquet('raw/quotes/**/data.parquet')
WHERE exchange_timestamp >= '2025-06-01' LIMIT 10"from datetime import datetime, timezone
import polars as pl
df = (
pl.scan_parquet("raw/quotes/**/data.parquet")
.filter(pl.col("exchange_timestamp") >= datetime(2025, 6, 1, tzinfo=timezone.utc))
.collect()
)
print(df.head())exchange_timestamp is the venue's own time. local_timestamp is when the event reached our capture machine.