DOCS
SDKs & libraries
Official Python, Node, Go and Rust clients covering every endpoint — REST and WebSocket, with the timestamp and symbol conventions handled for you.
Four official clients — Python, Node, Go and Rust — over the same protocol. Each one covers all 21 endpoints, the 12 option-history request types and all 6 streaming channels, manages reconnection and backoff, and authenticates with your API key.
Published versions. The surface on this page is the current source, published as
Python tickstream 1.1.0. Node (@tickstream/client), Rust
(tickstream) and Go are at 1.0.0 on their registries; 1.1.0 is pending publication.
Node 1.0.0 lacks the option_trades and flash channels and the
at_time, chain and root option request types.
How that list is kept current, precisely: it is generated from the gateway's router into
sdk/api-manifest.json, and the site refreshes it when it builds — but that refresh
never fails the build. Where the generator is not in the build context it falls back to the copy
committed in the repo, so the table can lag the router. The check that compares all four clients
against it, and the conformance run that exercises the calls against production, are steps in the
publish script we run by hand before a release; neither is enforced by CI, and the conformance
step is skipped unless an API key is set. If a client method no longer matches the API, that is
possible rather than hypothetical — tell us and it
gets fixed in the next release.
Install
pip install "tickstream[stream]"
# omit [stream] for REST only — then it has zero dependenciesnpm i @tickstream/client
# Node 22+ needs nothing else; on older Node also: npm i wsgo get github.com/Alx90s/tickstream-gocargo add tickstream Browser: the Node package works unchanged in a browser through any bundler — it
uses the platform's own fetch and WebSocket. Never ship a live key to a
browser, though: put your key behind your own endpoint and proxy what the page needs.
Quickstart
from tickstream import Tickstream
ts = Tickstream() # reads TICKSTREAM_API_KEY
print(ts.quote("NQ"))
# dealer gamma as it stood on a past session
gex = ts.gex("NQ", date="2026-07-15")
print(gex["callWall"], gex["flipLevel"])
for tick in ts.stream("NQ", "ES"):
print(tick["symbol"], tick["price"])import { Tickstream } from "@tickstream/client";
const ts = new Tickstream(); // reads TICKSTREAM_API_KEY
console.log(await ts.quote("NQ"));
const gex = await ts.gex("NQ", { date: "2026-07-15" });
console.log(gex.callWall, gex.flipLevel);
for await (const tick of ts.stream("NQ", "ES")) {
console.log(tick.symbol, tick.price);
}ts := tickstream.New("") // "" reads TICKSTREAM_API_KEY
q, err := ts.Quote(ctx, "NQ")
gex, err := ts.GEX(ctx, "NQ", tickstream.Params{"date": "2026-07-15"})
ticks, errs := ts.Stream(ctx, tickstream.Ticks, "NQ", "ES")
for t := range ticks {
fmt.Println(t.Symbol, t.Price)
}let ts = tickstream::Client::from_env()?;
let q = ts.quote("NQ").await?;
let gex = ts.gex("NQ", &[("date", "2026-07-15".into())]).await?;
let mut stream = ts.stream(Channel::Ticks, &["NQ", "ES"]).await?;
while let Some(t) = stream.next().await {
println!("{} {}", t.symbol, t.price);
} The whole surface
Method names are shown in Python form; Node matches it, Go and Rust use their own casing.
| What | Call |
|---|---|
| Latest quote | quote(symbol) |
| Streamable roots | symbols() |
| Recent ticks (7-day window) | ticks(symbol, start, end) |
| Deep tick archive | history.ticks(symbol, start, end) |
| Deep Level 2 book | history.book(symbol, start, end) |
| Live option chain with greeks | options.chain(underlying) |
| Option history — 12 request types | options.eod(…) · options.greeks_history(…) · … |
| Dealer gamma, live | gex(underlying) |
| Dealer gamma, a past session | gex(underlying, date) · gex(underlying, at) |
| Participant flow | participants(underlying) |
| CFTC positioning | cot(symbol, weeks) |
| Algo catalogue, record, signals | algos.list() · algos.track(id) · algos.signal(id) |
| Orders, positions, fills | exec.orders() · exec.positions() · exec.fills() |
| Place, close, protect | exec.order(…) · exec.close(…) · exec.protect(…) |
| Stream ticks, book, L3, options | stream(…symbols, channel) |
Three things that will bite you otherwise
1. ticks() without start returns one hour. Not seven
days — one hour. The window reaches back seven days on any plan, and years with an archive plan,
but you have to ask for it. This is the most common integration surprise we see.
2. Timestamps come in two units. Range arguments are unix seconds; tick
rows are stamped in microseconds. They differ by a factor of a million, and comparing
them returns nothing rather than raising — so the SDKs convert for you
(as_datetime(), asDate(), Tick.Time(),
Tick::time()) instead of documenting it and hoping.
3. Two opposite symbol conventions. gex() and
participants() take the futures or stock symbol
(NQ, ES, AAPL) and map onto the deep ETF surface
internally. options and history.options take the
ETF or index root (QQQ, SPY, SPX).
Passing QQQ to gex() is a 400 bad_symbol.
Streaming, and why silence is not always a bug
Every frame carries a type, ticks included. A filter that skips
anything with a type therefore drops all the data and leaves a socket that looks
connected and delivers nothing — the SDKs handle that for you. Error frames are never swallowed
either: a refused symbol is exactly the failure that reads as a quiet market.
Index levels (SPX, VIX, NDX, RUT) are quotes
rather than trade prints — they update on change, roughly every two seconds, so a flat VIX
genuinely sends nothing. A liquid future going quiet for minutes is worth reporting.
The welcome frame lists what was actually subscribed, so check it against what you asked for.
Errors
Every failure carries the API's machine-readable code — stable, and worth branching
on. A 403 whose code ends in _required means the endpoint works and
your key does not hold that package, which is a different problem from an invalid key and
should not need prose-parsing to tell apart.
Endpoints and what they need
| Endpoint | Needs | Parameters |
|---|---|---|
GET /v1/algos | included | — |
GET /v1/algos/:id/events | algo | — |
GET /v1/algos/:id/signal | algo | — |
GET /v1/algos/:id/track | included | — |
GET /v1/cot | included | symbol, weeks |
POST /v1/exec/close | execution | — |
GET /v1/exec/fills | execution | — |
POST /v1/exec/order | execution | — |
GET /v1/exec/orders | execution | — |
GET /v1/exec/positions | execution | — |
POST /v1/exec/protect | execution | — |
GET /v1/gex | gex | underlying, symbol, weight, dte, at, date, key, full |
GET /v1/history/book | nq-ticks archive | end, limit, start, symbol |
GET /v1/history/options | options-data archive | end, limit, source, start, underlying |
GET /v1/history/ticks | nq-ticks archive | end, limit, start, symbol |
GET /v1/options | options stream | underlying |
GET /v1/options/:req | options | — |
GET /v1/participants | gex | underlying |
GET /v1/quote | included | symbol |
GET /v1/symbols | included | — |
GET /v1/ticks | included | end, order, start, symbol |
included means any plan that can reach the API. The rest are product packages — see
pricing. Option-history request types:
at_time, chain, eod, greeks, greeks_history, ohlc, oi, quote, root, trade, trade_greeks, trade_quote.
No client for your stack? The WebSocket and REST APIs are plain JSON — anything that speaks HTTP works. For AI agents, llms-full.txt is the whole API in one machine-readable file, and there is an MCP server too.