tickstreamdocs

DOCS

Historical data archive

Full tick, Level 2 and option-chain history since 2019 over REST — for backtesting and research.

requiresRealtime or above — the window depends on the package

The historical archive serves the complete record — every trade tick, every Level 2 book update, and daily option-chain snapshots (full greeks & open interest) — back to 2019, straight from our Parquet stores as JSON. It's the same data our own research and live-tested algos run on. Base URL: https://api.tick-stream.xyz/v1.

plans

These endpoints are open to any package that sells history — the window is your package’s, and a request further back is clamped to it rather than refused: /history/ticks and /history/book need the NQ ticks archive, /history/options needs the options archive. Each package comes in two forms — a one-time purchase (the archive up to your purchase date, yours forever; ranges past your snapshot date are clamped and the response carries snapshot_until) or the updates subscription (same price up front, then $10/mo; the archive always reaches live). Cancelling the updates subscription converts it into a snapshot at the end of the last paid month — you keep everything you paid for. Want to evaluate first? A free 2-month NQ tick sample (Feb – Mar 2025, 22.9M trades, plus two full days of Level-2 depth, same schemas) is downloadable without signup. The live snapshot endpoints (/quote, /ticks) are separate and come with any package that streams live.

Common parameters

All three endpoints share the same range and paging contract.

ParamRequiredDescription
start / endnoISO-8601 (2022-06-13 or 2022-06-13T13:30:00Z) or Unix seconds. Defaults to a short window ending now — pass an explicit range for the archive.
limitnoMax rows per call (default 50,000, max 500,000).

Every response carries count and truncated. When truncated is true, fetch the next page by setting start to the last returned ts (rows are time-ordered, oldest first). Timestamps are Unix seconds (UTC).

GET /history/ticks

Full trade-tick archive for a futures symbol. NQ ticks plan.

ParamRequiredDescription
symbolyesFutures root, e.g. NQ, ES.
curl "https://api.tick-stream.xyz/v1/history/ticks?symbol=NQ&start=2022-06-13&end=2022-06-14" \
  -H "Authorization: Bearer sk_live_…"
from tickstream import Client
c = Client("sk_live_…")
rows = c.history_ticks("NQ", start="2022-06-13", end="2022-06-14")
print(len(rows), "ticks")
{
  "symbol": "NQ",
  "start": 1655085600, "end": 1655172000,
  "count": 48213, "truncated": false,
  "ticks": [
    { "ts": 1655127000, "price": 12043.25, "size": 2, "side": "buy" }
  ]
}

Each tick: ts, price, size, and side (the aggressor — "buy" or "sell").

Aggressor provenance. From March 2026 onward, ticks are our own live capture and side is the exchange-reported aggressor. For the archived years (ES from Jan 2014, NQ from Mar 2019, up to Feb 2026; GC, SI and CL from 2017 are being added) the archive is built from a historical BBO tape (every trade print plus the prevailing best bid/ask); side is inferred with the standard quote rule — trade at the ask = "buy", at the bid = "sell", tick rule inside the spread (<1% of prints remain "unknown"). Re-encoded 2026-07-03; daily volume now matches real contract volume across the whole archive. If you downloaded tick history before that date, re-pull it — the earlier encoding exposed raw quote updates alongside trades.

Known gaps

The tick archive is not gap-free. Since 2017 there are 21 ES sessions and 9 NQ sessions (all between 2017 and early 2020, about 0.6 % of regular sessions) with no prints for part of the regular session — recording holes in the vendor archive. Every affected session is listed with the missing UTC hours in tick-history-gaps.csv; historical /v1/gex?at= answers no_futures_price inside these windows rather than guessing a price. 46 further sessions (2020 – 2026) and the June 2026 roll days were refilled in September 2026 from a second exchange feed, so those days carry prints from two sources with identical fields; our own recording holes of 2 – 4 September 2026 were refilled the same way, ticks and book alike. US market holidays and exchange closures are not in the list.

GET /history/book

Level 2 order-book depth archive — every bid/ask update. NQ ticks plan.

ParamRequiredDescription
symbolyesFutures root, e.g. NQ.
curl "https://api.tick-stream.xyz/v1/history/book?symbol=NQ&start=2024-01-10T14:30:00Z&end=2024-01-10T15:00:00Z" \
  -H "Authorization: Bearer sk_live_…"
{
  "symbol": "NQ", "count": 12044, "truncated": false,
  "book": [
    { "ts": 1704897000, "side": "bid", "level": 1, "price": 16942.50, "size": 14, "flag": 0 }
  ]
}

Each row: ts, side ("bid"/"ask"), level (1-based depth rank, 1 = best level in the stream's window), price, size, and flag.

Two eras, two models. From June 2026 onward rows are our own live capture: full-book snapshots at a ~250 ms cadence (≈4/s) — all levels of both sides re-stated in each snapshot, flag always 0. Group rows by ts and replace the whole book; no event-sourcing needed. A few refilled windows in September 2026 carry one snapshot per book update instead of the 250 ms cadence — same shape, denser.

For the 2019 – Feb 2026 archive the source is an incremental depth tape and flag is the book action: 0 = add, 1 = update, 2 = remove. The replay rules below were derived empirically against two full days (24M events) and are the best-performing of ~10 candidate rule sets we measured:

  • remove → delete by price; the level field on removes is window bookkeeping (reads 10) — ignore it. A miss is a no-op (measured miss rate ~2–4%).
  • add → dedupe the price, then insert sorted (bids descending, asks ascending). An add is "a level entered the visible window" — do not insert at the level index (bottom entries report as level 9).
  • update at level L with price P — three cases vs. the current occupant of slot L: same price → size update; P better (closer to the touch) → insert at L (upward ladder shift); P worse → overwrite slot L (downward shift — the displaced level dies implicitly, no remove is sent for it). Always drop any other slot holding P.
  • Apply no cap and no re-sort of your own — the window maintains itself through the feed's add/remove flow (depth settles at ~9 per side).

Measured on full-day replays (2025-03-03 / 2025-06-13): whole-book consistency 72% / 61% of observations, top-3 levels clean 89% / 82%. The residual inconsistency lives in the lower ranks and is inherent to the vendor tape; for a guaranteed-consistent view, optionally drop any level that breaks strict monotonicity (top-down walk). Rows are stored and served in exact event order; replay each day from its first row (each day opens with an add-sequence snapshot, L1…L9 per side).

Archive window caveat. In the archive era the depth window sits behind the touch: the vendor streams best bid/ask separately, and the book stream's level 1 is typically one tick behind the true best (mode +1 tick, ~75% of the time). Treat the archive book as depth/liquidity structure, not as an exact top-of-book reference — for touch-sensitive work use the trade prints from the tick dataset alongside it, or the June-2026+ snapshot era, which is exact.

no L3 in the archive

This archive is aggregated depth. It contains no order-level (market-by-order) data, and neither does any vendor archive we know of — CME MBO history is simply not sold back in time. Order-level data exists only going forward, from the day we started recording it: see L3 / market-by-order.

GET /history/options

Option-chain snapshot archive with full greeks. Options plan.

ParamRequiredDescription
underlyingyesOption underlying — historical archive covers QQQ, SPY, DIA, IWM.
curl "https://api.tick-stream.xyz/v1/history/options?underlying=QQQ&start=2024-01-10&end=2024-01-11" \
  -H "Authorization: Bearer sk_live_…"
{
  "underlying": "QQQ", "count": 8800, "truncated": false,
  "options": [
    { "ts": 1704902400, "expiry": "2024-01-19", "strike": 410, "right": "C",
      "bid": 2.41, "ask": 2.44, "last": 2.42, "oi": 15234, "volume": 812,
      "iv": 0.142, "delta": 0.55, "gamma": 0.04, "theta": -0.08, "vega": 0.21 }
  ]
}

Each row: ts, expiry, strike, right ("C"/"P"), bid, ask, last, oi, volume, iv, and Black-76 greeks delta, gamma, theta, vega.

tip

Pulling a large range? Page in chunks (e.g. one trading day at a time) and watch truncated. For continuous live data use the WebSocket stream; for recent backfill without the archive plan use /v1/ticks.