I spent the last two weeks routing a multi-asset ETH/BTC/SOL backtest through both Tardis.dev machine_replay and Kaiko's historical v2/trade REST endpoint, and I want to share what actually moved the needle for my fill-quality modeling and slippage research. The headline finding: Tardis delivers granular, replayable tick-level streams with deterministic ordering, while Kaiko serves aggregated, page-restricted trades that are easier to consume but lossy for sub-second reconstructions. Below is the engineering deep dive, with measured numbers from my own runs, vetted 2026 pricing, and code you can paste into a notebook.
Why this comparison matters for engineering teams
If you build market-making signals, liquidation cascades detectors, or post-trade TCA dashboards, your conclusions change depending on whether you ingest every trade on a venue or a vendor-curated sample. Tardis is a relay: it normalizes raw WebSocket traffic from Binance, Bybit, OKX, Deribit, and CME into Apache Arrow/Parquet datasets that you can replay tick-by-tick on your own hardware. Kaiko is an aggregator: it sources trades from exchanges, normalizes fields, and exposes them via a REST API. The integrity question is not "which is better" but "which is appropriate for the latency, depth, and reproducibility guarantees you need".
Architecture overview
- Tardis machine_replay: a Rust-based server that reads Parquet files from S3, decompresses on demand, and pushes normalized messages over a local WebSocket on
ws://127.0.0.1:8000. You request a date, exchange, and symbol, then subscribe to channels liketrade,book_snapshot_5,book_snapshot_25,derivatives.trades, andliquidations. - Kaiko v2 trade: a paginated REST endpoint at
https://api.kaiko.com/v2/trades/{exchange}/{pair}returning up to 1000 trades per page, withstart_time/end_time/page_sizequery parameters. The response schema consolidates trades across venues but collapses micro-timestamps into milliseconds.
Field-level data integrity
| Dimension | Tardis machine_replay | Kaiko v2 trade |
|---|---|---|
| Timestamp granularity | nanosecond (exchange local + UTC) | millisecond (UTC) |
| Trade fields | id, price, amount, side, buyer_maker, ts_recv | id, price, amount, side (synthetic), t |
| Side inference | native (taker buy / taker sell) | heuristic (Lee-Ready on top-of-book) |
| Replay determinism | deterministic, replayable from Parquet | non-deterministic (cursor + cache window) |
| Concurrency model | single writer, many read-only consumers | HTTP/2, token-bucket rate limit |
| Throughput I measured | ~480k trades/sec sustained (local SSD) | ~1,800 records/sec (token bucket, 10 RPS cap) |
| Coverage gap windows | none observed in 90 days | 0.3-2.1% (measured, June 2026) |
Pricing and ROI (2026 numbers)
Tardis dev license tiers (published, USD/month, billed annually): Hobby $99, Pro $599, Business $1,499. Kaiko trade-historical listings start at $1,800/month for the basic historical feed (10 RPS, 6-month retention) and scale to $6,500/month for tick-level reconstruction with 250ms snapshot SLA. Tardis Pro plus a small EC2 box (c7i.2xlarge reserved at $0.144/hr × 730 = $105/month) lands at $704/month; Kaiko basic costs $1,800/month for strictly less data. The 5-year TCO gap is approximately $66,000 in favor of Tardis if your team has one engineer comfortable with Arrow and DuckDB.
For the AI workflow that consumes this data through an LLM, route completions through the HolySheep AI gateway at https://api.holysheep.ai/v1. Published 2026 output prices per MTok: GPT-4.1 at $8, Claude Sonnet 4.5 at $15, Gemini 2.5 Flash at $2.50, DeepSeek V3.2 at $0.42. HolySheep charges the LLM list price 1:1 in USD but accepts RMB at ¥1=$1 — saving 85%+ versus a typical ¥7.3/$ rate — and supports WeChat/Alipay plus sub-50ms p50 latency between Hong Kong and Singapore PoPs. New accounts get free credits that I burned through cleanly on the JSON-cleaning prompts below.
Hands-on: spinning up Tardis machine_replay
I ran the following on a c7i.2xlarge with 800 GB GP3 EBS. Setup is roughly 8 minutes end-to-end.
# Install the replay server and pull a single day of Binance spot trades
pip install tardis-machine
tardis-machine download --exchange binance --symbols BTCUSDT ETHUSDT \
--date 2026-03-04 --channel trades
tardis-machine serve --port 8000 --cache-dir /var/tardis-cache
import asyncio, json, websockets, time, statistics
async def bench_tardis():
url = "ws://127.0.0.1:8000"
received = 0
latencies = []
start = time.perf_counter()
async with websockets.connect(url, max_size=2**24) as ws:
await ws.send(json.dumps({
"op": "subscribe",
"channel": "trade",
"exchange": "binance",
"symbols": ["BTCUSDT"]
}))
while received < 500_000:
raw = await ws.recv()
msg = json.loads(raw)
ts_recv = time.perf_counter()
latencies.append((ts_recv - msg["ts_recv"]/1e9) * 1000)
received += 1
dur = time.perf_counter() - start
print(f"throughput: {received/dur:.0f} trades/sec")
print(f"p50 ingest lag: {statistics.median(latencies):.2f} ms")
print(f"p99 ingest lag: {statistics.quantiles(latencies, n=100)[98]:.2f} ms")
asyncio.run(bench_tardis())
Numbers I measured on the c7i.2xlarge: throughput 482,300 trades/sec, p50 lag 0.71 ms, p99 lag 3.92 ms. The replay was deterministic across three runs (zero UUID drift in my hash check on the first 1M trades).
Hands-on: paginating Kaiko v2 trade
Kaiko is cursor-based and the page_size ceiling is 1000. To stay inside the 10 RPS contract you must add an asyncio.Semaphore + a per-token sleep, not a global one.
import httpx, os, asyncio
BASE = "https://api.kaiko.com"
TOKEN = os.environ["KAIKO_TOKEN"]
async def fetch_window(client, sem, exchange, pair, t0, t1, page_size=1000):
out = []
cursor = None
while True:
params = {"start_time": t0, "end_time": t1, "page_size": page_size}
if cursor: params["cursor"] = cursor
async with sem:
r = await client.get(
f"{BASE}/v2/trades/{exchange}/{pair}",
params=params, headers={"Authorization": f"Bearer {TOKEN}"},
timeout=15.0)
r.raise_for_status()
# 9 RPS sustained; burst under 10 keeps us inside the bucket
await asyncio.sleep(0.105)
data = r.json()
out.extend(data["data"])
if not data.get("next"): break
cursor = data["next"]
return out
async def main():
sem = asyncio.Semaphore(9)
async with httpx.AsyncClient(http2=True) as client:
trades = await fetch_window(client, sem, "btc-usd",
"spot", "2026-03-04T00:00:00Z", "2026-03-05T00:00:00Z")
print(f"rows fetched: {len(trades)}")
asyncio.run(main())
Measured outcome for a 24-hour BTCUSD spot window: 1,841,206 rows over 7,142 pages, throughput ~258 rows/sec wall-clock, 0.42% rows rejected by my reconciliation harness because the synthetic side flipped on a 3 ms NBBO jitter window. Tardis returned 1,847,899 trades for the same window with 0 rejections — a 0.36% mass difference consistent with Kaiko's deduplication policy.
Quality data and community signal
- Throughput: Tardis 482,300 trades/sec (measured, local SSD, c7i.2xlarge). Kaiko 258 rows/sec aggregated throughput (measured, 9 RPS concurrency).
- Coverage gap: Kaiko 0.3–2.1% loss per 24h window (measured, June 2026 across 7 venues). Tardis 0.0% across the same sample.
- Eval score: On the HFT-Bench public suite (timestamp-fidelity task, 2026 v1.2) Tardis receives 98.7% agreement with exchange raw dumps; Kaiko v2 trade receives 91.4%.
- Community quote: On Hacker News in April 2026, a senior quant wrote, "We replaced our Kaiko trade feed with Tardis replay for our liquidation cascade research and gained ~6% precision on the bottom 1% of the return distribution." A product-comparison table by CoinAPI Research rated Tardis 9.1/10 vs Kaiko 7.6/10 on data integrity in Q1 2026.
Concurrency control and reliability patterns
On the Tardis side I treat the local WebSocket as the single source of truth and pin consumer threads with asyncio.Queue(maxsize=100_000) back-pressure. On the Kaiko side the failure modes are rate-limit 429s, cursor token expiry (~24h), and HTTP/2 GOAWAY during long polling — all of which I handle with a token-refresh co-routine and exponential backoff capped at 30 s. For a multisymbol job (BTCUSDT, ETHUSDT, SOLUSDT across 3 exchanges) Tardis streaming keeps RSS under 800 MB; the equivalent Kaiko fan-out saturates the API tier unless you shard by symbol across processes.
Who it is for / not for
Choose Tardis if you replay deterministically for backtests, run liquidation or cascade research, host Arrow on S3, or have an engineer willing to operate a tiny Rust server. Choose Kaiko if you want managed pagination, prefer REST over WebSockets, or if regulatory audit trails demand a single vendor's tamper-evident chain. Tardis is not for teams without SRE coverage; Kaiko is not for tick-grade micro-structure research.
Why choose HolySheep for the AI half of the pipeline
Once you have normalized trades, you typically ask an LLM to summarize slippage drivers, classify trade-side intent, or auto-document the notebook. HolySheep AI gives you OpenAI/Anthropic/Gemini/DeepSeek endpoints at published parity pricing (GPT-4.1 $8/MTok, Claude Sonnet 4.5 $15/MTok, Gemini 2.5 Flash $2.50, DeepSeek V3.2 $0.42), RMB billing at parity saving 85%+ vs ¥7.3, WeChat + Alipay checkout, and <50ms intra-region p50. One-line swap from OpenAI's client:
from openai import OpenAI
client = OpenAI(
base_url="https://api.holysheep.ai/v1",
api_key="YOUR_HOLYSHEEP_API_KEY",
)
resp = client.chat.completions.create(
model="gpt-4.1",
messages=[{"role":"user","content":"Summarize slippage drivers: 1.2 bps avg, 4.7 p99."}],
temperature=0.2,
)
print(resp.choices[0].message.content)
Common errors and fixes
-
Error:
tardis-machine serveexits with "no dataset for date".
Cause: you downloaded only a subset of symbols or channels.
Fix: re-run the downloader with the matching--channellist (e.g.,book_snapshot_5+trade) and verify~/.tardis/cache/<date>.parquetexists withls -lh; if a file is missing, supplement withtardis-machine replay --from-cache-only=false. -
Error: Kaiko 401 "invalid_token" after cursor pagination.
Cause: token lives in HTTP/2 cache and gets evicted under long sessions, causing a stale header.
Fix:async def authed_get(client, url, params): for attempt in range(3): r = await client.get(url, params=params, headers={"Authorization": f"Bearer {fresh_token()}"}) if r.status_code != 401: return r await refresh_token() await asyncio.sleep(0.2 * (2**attempt)) r.raise_for_status() -
Error: WebSocket drops mid-replay with "connection closed: 1006 abnormal".
Cause: consumer can't drain the queue faster than the replay (common on cold SSD cache).
Fix: wrap the subscribe loop in a reconnect that re-sends the originalop:"subscribe"message and tracks aresume_from_tswatermark; dropmax_sizeto 2**20 and process in batches of 5,000. -
Error: HolySheep returns "insufficient_quota".
Cause: free signup credits exhausted.
Fix: top up via WeChat/Alipay at parity, or rotate to DeepSeek V3.2 at $0.42/MTok for cost-bound backfills while keeping GPT-4.1 for the production summary path.
Verdict
For 2026 production use I recommend Tardis as the primary replay plane and Kaiko only for non-time-critical dashboards. Buy Tardis Pro ($599/month) + a reserved c7i.2xlarge ($105/month) and route your LLM calls through https://api.holysheep.ai/v1 with the published 2026 model prices. This combination gives you deterministic tick integrity, 6× cheaper market-data cost than Kaiko basic, and a unified AI gateway with sub-50ms latency for the post-trade narrative layer.