Metadata-Version: 2.4
Name: tickstream
Version: 1.1.0
Summary: CME futures, options and dealer-gamma data — REST and WebSocket client
Author-email: tickstream <support@tick-stream.xyz>
License: MIT
Project-URL: Homepage, https://tick-stream.xyz
Project-URL: Documentation, https://tick-stream.xyz/docs/sdks
Project-URL: Source, https://github.com/Alx90s/tickstream-python
Keywords: futures,market-data,options,gex,cme,tick-data
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Office/Business :: Financial :: Investment
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Provides-Extra: stream
Requires-Dist: websocket-client>=1.6; extra == "stream"

# tickstream (Python)

CME futures, options and dealer-gamma data over REST and WebSocket.

**21 endpoints, 12 option-history request types, 6 streaming channels** — the complete API. Coverage is asserted by
`sdk/check-coverage.mjs` against a manifest generated from the gateway's own router, and every
call in the table below is exercised against production before release.

## Install

```sh
pip install "tickstream[stream]"      # omit [stream] for REST only — zero dependencies
```

## Quickstart

```python
from tickstream import Tickstream

ts = Tickstream()                       # reads TICKSTREAM_API_KEY
print(ts.quote("NQ"))

for tick in ts.stream("NQ", "ES"):
    print(tick["symbol"], tick["price"])
```

## Everything you can call

| what | call |
| --- | --- |
| quote | `ts.quote("NQ")` |
| symbols | `ts.symbols()` |
| recent ticks | `ts.ticks("NQ", start=…)` |
| deep ticks | `ts.history.ticks("NQ", start=…, end=…)` |
| deep L2 book | `ts.history.book("NQ", start=…, end=…)` |
| legacy chain archive | `ts.history.options("QQQ", source="archive")` |
| live chain | `ts.options.chain("QQQ")` |
| option history (12 types) | `ts.options.eod(underlying="QQQ", date="20260715")` |
| dealer gamma, live | `ts.gex("NQ")` |
| dealer gamma, past | `ts.gex("NQ", date="2026-07-15")` |
| participant flow | `ts.participants("NQ")` |
| CFTC positioning | `ts.cot("NQ", weeks=8)` |
| algo catalogue / record | `ts.algos.list() · ts.algos.track(id)` |
| orders, positions, fills | `ts.exec.positions()` |
| place / close / protect | `ts.exec.order({...})` |
| stream | `for t in ts.stream("NQ","ES"): …` |

## 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:
pass `start`. This is the single most common integration surprise.

**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 this SDK converts for you rather than 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 unsupported_symbol`.

## Errors

Every failure carries the API's machine-readable `code`, which is stable and worth branching
on. A `403` whose code ends in `_required` means the endpoint works and your key does not hold
that package — distinct from an invalid key, without parsing prose.

## Entitlements per endpoint

| endpoint | needs | parameters |
| --- | --- | --- |
| `GET /v1/algos` | included | — |
| `GET /v1/algos/:id/events` | included | — |
| `GET /v1/algos/:id/signal` | included | — |
| `GET /v1/algos/:id/track` | included | — |
| `GET /v1/cot` | included | symbol, weeks |
| `POST /v1/exec/close` | execution | — |
| `GET /v1/exec/fills` | included | — |
| `POST /v1/exec/order` | execution | — |
| `GET /v1/exec/orders` | included | — |
| `GET /v1/exec/positions` | included | — |
| `POST /v1/exec/protect` | execution | — |
| `GET /v1/gex` | gex | underlying, symbol, weight, dte, at, date |
| `GET /v1/history/book` | data:nq-ticks | end, limit, start, symbol |
| `GET /v1/history/options` | data:options-data | end, limit, source, start, underlying |
| `GET /v1/history/ticks` | data:nq-ticks | 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, start, symbol |

`included` means every plan that can reach the API at all. `data:*` is an archive window,
`gex`/`options`/`execution` are the product packages — see <https://tick-stream.xyz/pricing>.

## Streaming, and why silence is not 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 —
this SDK handles that. 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, not trade prints: they update on change, roughly
every two seconds. A flat VIX genuinely sends nothing. A liquid future going quiet for minutes
is worth reporting.

## Docs

<https://tick-stream.xyz/docs/sdks> · machine-readable: <https://tick-stream.xyz/llms-full.txt>
