Python SDK
fathom-charts handles authentication, the initial snapshot, resuming after a disconnect, duplicates, history pagination, exports and rate-limit retries for you, on asyncio. This page describes every option and method; the behaviour the four SDKs share is in SDKs.
Install
pip install fathom-chartsOr uv add fathom-charts. Python 3.11 or later, asyncio only: in a notebook (Jupyter), await works at the top level of a cell. Its dependencies are websockets, httpx and zstandard. The package is typed (py.typed): mypy --strict checks your code against it.
Indicator types
fathom-charts-types https://api.fathomcharts.com/v1/indicators fathom_charts_types.pyThe command, installed with the package, takes the catalog’s URL or a file saved from GET /v1/indicators. Each indicator gets <Name>Params and <Name>Data (TypedDict), named after its id (big-trades → BigTradesParams, BigTradesData), with the catalog’s descriptions as docstrings; IndicatorParams, IndicatorData and IndicatorId cover them all. A tuple whose last elements are optional is the union of its allowed lengths (tuple[int, int, int] | tuple[int, int, int, int] for a footprint level); JSON arrays still arrive as lists. Generate the file again when the catalog changes.
Real time: FathomChartsStream
import asyncio
import os
from fathom_charts import FathomChartsStream, Subscription, Upsert
from fathom_charts_types import BigTradesData
async def main() -> None:
async with FathomChartsStream(url="wss://stream.fathomcharts.com/v1", api_key=os.environ["FATHOM_CHARTS_API_KEY"]) as stream:
big_trades: Subscription[BigTradesData]
async with stream.subscribe(instrument="NQ.front", indicator="big-trades", params={"minimum": 30}, mode="confirmed") as big_trades:
async for event in big_trades:
if isinstance(event, Upsert):
print(event.cursor, event.data["side"], event.data["volume"])
asyncio.run(main())Options
Durations are in seconds.
| Option | Purpose |
|---|---|
url | Required. The stream address: wss://stream.fathomcharts.com/v1. |
api_key | API key, sent in the Authorization: Bearer header. |
stream_token | Instead of api_key, in an application distributed to end users, which must not hold the key: an async function returning a fresh single-use token that your backend gets from POST /v1/stream-tokens (FathomChartsRest.stream_token()). It is called on every connection, reconnections included. Give exactly one of api_key and stream_token, otherwise the constructor raises CONFIGURATION. |
web_socket | Optional: a function that opens the connection, to use another socket; a socket it returns with pausable false takes the max_buffered path below. |
reconnect | Optional: Reconnect(initial_delay=0.25, max_delay=30.0, quota_retry=120.0, quota_delay=5.0): first reconnection delay, backoff ceiling, how long a 4029 close code is retried, minimum delay between two attempts after a 4029. |
heartbeat_timeout | Silence after which the connection is considered lost, then reopened. 15 by default: the server sends an hb every 5 seconds. |
high_water_mark | Number of events waiting to be read, all subscriptions together, above which the SDK stops reading the socket and keeps only the latest version of each object in progress. While it waits, it sends ping messages so that the server keeps the connection. 10,000 by default. |
max_buffered | For a socket that cannot be paused: number of waiting events above which the SDK closes the connection (close code 4000, reason client buffer full), then reopens it from the last cursor received once half of high_water_mark has been read. Nothing waiting is lost. 4 × high_water_mark by default. |
random | Optional, for tests: the source of the reconnection jitter, a function returning a number in [0, 1). random.random by default. |
on_state_change | Called on every change of connection_state. |
on_notice | Called with each notice from the server (kind, id, effective_at, ends_at, message): a restart, a maintenance window announced or cancelled. See Updates and maintenance. |
async with FathomChartsStream(…) as stream closes the stream at the end of the block; await stream.close() does the same. stream.connection_state is idle, connecting, open, reconnecting or closed; stream.maintenance lists the maintenance windows announced on the connection and not over, by start.
subscribe()
stream.subscribe(instrument=…, indicator=…, params=None, mode="live", from_="live") opens a subscription and returns a Subscription, to read with async for. Its arguments are those of the subscribe message; from_ (from is a Python keyword) is "live", {"cursor": …, "engine": …} or {"time": …}. The SDK picks the sub name itself. Annotate the result with the indicator’s data type: big_trades: Subscription[BigTradesData].
The events are frozen dataclasses: Subscribed, Snapshot (its items are Item), Upsert, Remove, Status, Reset and Notice, each with its type ("upsert"…), to test with isinstance or match. Their fields are those of Events, in snake case (tick_size_nanos, lag_ms). An error on the subscription ends the loop: async for raises a FathomChartsError carrying the received code.
Subscription
| Member | Purpose |
|---|---|
cursor | The cursor of the last event handed to you: your resume point. None until a cursor has arrived. It also moves forward with hb messages when no event is waiting to be read. |
topic | The topic of the latest subscribed. |
engine | The engine of the latest subscribed: the computation your state comes from. Save it with cursor to resume later. |
id | The sub name the SDK chose for this subscription (s1, s2…). |
request | The arguments of subscribe(), completed with the default values. |
close() | Async: stops the subscription; the SDK sends unsubscribe, and a pending loop ends. |
Leaving the async with block of a subscription closes it. Leaving an async for loop alone does not, in Python: use async with, or await sub.close(). Reconnection, resuming and close codes: see Connection lifecycle; to resume after your process restarts, see Resume after a restart.
History: FathomChartsRest
from fathom_charts import FathomChartsRest
async with FathomChartsRest(base_url="https://api.fathomcharts.com", api_key=os.environ["FATHOM_CHARTS_API_KEY"]) as rest:
usage = await rest.usage()| Option | Purpose |
|---|---|
base_url | Required. The API address: https://api.fathomcharts.com. |
api_key | Required. API key, sent in the Authorization: Bearer header. |
rate_limit_retries | Number of retries of a request the server did not process, or of a read that failed (see Rate limit and retries). 3 by default. |
http_client | Optional: your own httpx.AsyncClient (proxy, timeouts…). |
Methods
Queries are dictionaries with the fields of the API, as on the History page (instrument, indicator, params, from, to, mode, and depending on the method limit, cursor, untilCursor, snapshot): PageQuery and RangeQuery type them. Responses are TypedDicts with the fields of the API.
| Method | Returns |
|---|---|
await page(query) | One page: instrument, tickSizeNanos, snapshot, items, next, computeUnits. |
pages(query) | The pages one at a time, following next, as you read them (async for). |
history(query) | The results one at a time, across pages. With "snapshot": True, the first element is the state at from, {"t": "snapshot", "cursor", "items"}, then come the updates (t is upsert or remove, each with its cursor). |
await estimate(query) | The cost estimate, charging nothing. |
await export(query, resume=None) | One export response: body (the zstd-compressed file as is), content_type, filename, token (resumes the export with resume). |
export_ndjson(query, max_resumes=5, resume_delay=1.0) | The decompressed export, in chunks (bytes) of whole lines, with automatic resume. See Exports. |
await stream_token() | A stream token: token, expiresAt. |
await usage() | Your usage this month and your limits. |
await instruments() | instruments: every instrument served. |
await status() | The state of the computation, of each instrument, and the maintenance windows announced. |
await offers() | The plans and the limits of each combination. |
await indicators() | The indicator catalog. |
A call is stopped by cancelling its task (asyncio.timeout(), Task.cancel()), a wait for a retry included: the asyncio.CancelledError goes through untouched, as asyncio requires. Close an async generator you leave early (contextlib.aclosing), as with any async generator.
Errors
Every error the SDK raises, or ends a loop with, is a FathomChartsError. Its codes are listed in Errors (ERROR_CODES; the WebSocket close codes, CloseCode).
| Field | Content |
|---|---|
code | The stable error code. |
message | A human-readable explanation. |
status | The HTTP status, over REST. |
close_code | The WebSocket close code, when the connection was closed. |
retry_after | The value of the Retry-After header, in seconds, when the response has one. |
problem | The full problem+json document of the response, with errors when the API lists invalid fields; None otherwise. |
__cause__ | The original error, when there is one (the error of httpx…). |
Cursors
from fathom_charts import compare_cursors
compare_cursors("20720.111416.0", "20720.111417.0") # < 0