DOCS
WebSocket stream
A persistent WebSocket delivers every tick the moment it prints. Subscribe, unsubscribe, and reconnect with confidence.
Streaming is a single long-lived WebSocket connection. Open it once, subscribe to the symbols you care about, and ticks arrive as compact JSON frames. The SDKs wrap all of this — heartbeats, backpressure and reconnection — behind a simple iterator.
Connect & subscribe
from tickstream import Tickstream
ts = Tickstream("sk_live_…")
for tick in ts.stream("ES", "NQ"):
print(tick["symbol"], tick["price"], tick["size"], tick["ts"])import { Tickstream } from "@tickstream/client";
const ts = new Tickstream("sk_live_…");
for await (const tick of ts.stream("ES", "NQ")) {
console.log(tick.symbol, tick.price, tick.size, tick.ts);
}use tickstream::{Client, Channel};
let ts = Client::new("sk_live_…");
let mut s = ts.stream(Channel::Ticks, &["ES", "NQ"]).await?;
while let Some(t) = s.next().await {
println!("{} {} {}", t.symbol, t.price, t.size);
}import ts "github.com/Alx90s/tickstream-go"
c := ts.New("sk_live_…")
ticks, errs := c.Stream(ctx, ts.Ticks, "ES", "NQ")
for t := range ticks {
fmt.Println(t.Symbol, t.Price, t.Size)
}# connect, then send a subscribe frame
wss://stream.tick-stream.xyz/v1/stream?key=sk_live_…
{ "op": "subscribe", "channel": "ticks", "symbols": ["ES", "QQQ", "SPX"] } Subscribe frame
On a raw connection, send a JSON control frame after the socket opens:
| Field | Type | Description |
|---|---|---|
op | string | subscribe or unsubscribe. |
channel | string | ticks (the default when omitted), book (L2), l3 (market-by-order), flash (flagged flash liquidity, L3 package), options or option_trades (the live option tape; ["*"] for every root on Options Pro). |
symbols | string[] | One or more symbols, e.g. ["ES","NQ"]. |
Shortcut for ticks: put the symbols in the URL — …/v1/stream?key=sk_live_…&symbols=ES,NQ — and
the connection subscribes to them on open, no frame needed.
The ticks channel serves every symbol — futures (ES, NQ…), ETFs (QQQ, SPY…) and indices (SPX, VIX…). Futures give real trade prints (with a side); ETFs give live quotes and indices the live level — both with size 0 and side "unknown".
The tick message
Every trade prints a tick frame:
{
"type": "tick",
"symbol": "ES",
"price": 5283.25,
"size": 3,
"side": "buy",
"exch": "CME",
"ts": 1749556800
} | Field | Type | Description |
|---|---|---|
symbol | string | The instrument, e.g. ES. |
price | number | Trade price. |
size | number | Contracts traded. |
side | string | Aggressor side: buy or sell. |
exch | string | Originating exchange (always CME today). |
ts | integer | Exchange timestamp in Unix seconds. |
Other frames
Besides data, every frame has a type you may see on any channel:
| type | Meaning |
|---|---|
welcome | First frame after connecting: your plan, capabilities and the symbols already subscribed. |
feed | Our upstream feed changed state (e.g. restarting). For L3, drop your book and wait for the next opening image. |
warning | E.g. ticks_lagged: prints were dropped because your connection could not keep up — backfill the gap from /v1/ticks. |
error | {"type":"error","error":{"code":…,"message":…}} — e.g. plan_required, unknown_symbol, symbol_limit_reached. The socket stays open. |
ping / pong | Heartbeats, below. |
Heartbeats & reconnection
The server sends a {"type":"ping"} (and a WebSocket ping) every 15 seconds. If nothing
arrives from you for 45 seconds — a frame, or the WebSocket pong most clients send
automatically — the server closes the connection; {"op":"pong"} is a fine reply (the SDKs
handle this). To measure round-trip time, send {"op":"ping","id":1} and you get
{"type":"pong","id":1} back.
If the connection drops, reconnect and re-send your subscribe frame; the SDKs resubscribe automatically.
Connections are capped per account by package — free 1, Realtime 2, Realtime + L2 3, L3 10 — and a dead
socket can hold its slot for up to 45 seconds until the server notices. Over the cap you get a
too_many_connections error and close code 4029; back off and retry. Symbols are
capped across all channels on a connection (free 10, Realtime 25). See limits.
tip Need depth instead of trades? Subscribe to the Level 2 book channel, or go order-by-order with L3. Need to seed history before going live? Use the REST backfill.