SDKs

TypeScript SDK

@fathom-charts/sdk handles authentication, the initial snapshot, resuming after a disconnect, duplicates, history pagination, exports and rate-limit retries for you. This page describes every option and method; the behaviour the four SDKs share is in SDKs.

Install

BASH
npm install @fathom-charts/sdk ws
  • ESM only: the package ships no CommonJS build. Your project must declare "type": "module" in its package.json (or use .mjs / .mts files).
  • Node 22 or later, and browsers. exportNdjson() requires Node 22.15 or later (zstd decompression from node:zlib).
  • ws is only needed in Node: it opens the connection with the Authorization header. In a browser, the SDK uses the native WebSocket with a stream token, and never imports ws.

The SDK imports ws dynamically, with the module name in a variable, so that browser bundlers leave it out. Webpack then reports Critical dependency: the request of a dependency is an expression: this warning is harmless.

Indicator types

The SDK is generic: an indicator’s data is typed by the types you generate from the catalog (GET /v1/indicators, no authentication).

BASH
curl "https://api.fathomcharts.com/v1/indicators" -o catalog.json
npx fathom-charts-types catalog.json src/fathom-charts-types.ts

The generated file exports, for each indicator, <Name>Params and <Name>Data, named after its id (big-trades → BigTradesParams, BigTradesData), plus IndicatorParams, IndicatorData and IndicatorId. The catalog descriptions become JSDoc comments. The generator also takes the catalog URL directly: npx fathom-charts-types https://api.fathomcharts.com/v1/indicators src/fathom-charts-types.ts; a footprint level is typed [number, number, number, number?] (the 4th element is optional). The output folder is created if it does not exist. Generate the file again when the catalog changes (its engineFingerprint changes with the computation).

Real time: FathomChartsStream

TS
import { FathomChartsStream } from '@fathom-charts/sdk';
import type { BigTradesData } from './fathom-charts-types.js';

const stream = new FathomChartsStream({
  url: 'wss://stream.fathomcharts.com/v1',
  apiKey: process.env.FATHOM_CHARTS_API_KEY!,
  onStateChange: (state) => console.log('connection', state),
});

const sub = stream.subscribe<BigTradesData>({
  instrument: 'NQ.front',
  indicator: 'big-trades',
  params: { minimum: 30 },
  mode: 'confirmed',
});

for await (const event of sub) {
  if (event.type === 'upsert') console.log(event.cursor, event.data.side, event.data.volume);
}

Options

OptionPurpose
urlRequired. The stream address: wss://stream.fathomcharts.com/v1.
apiKeyAPI key, sent in the Authorization: Bearer header. Server-side only; requires the ws package unless you provide webSocket.
streamTokenIn a browser, instead of apiKey: an async () => string function that asks your server for a stream token. It is called on every connection, reconnections included. Give exactly one of apiKey and streamToken, otherwise the constructor throws CONFIGURATION.
webSocketOptional: a (url, headers) => WebSocket function that opens the connection, to use an implementation other than ws or the browser’s WebSocket. headers holds the Authorization header with apiKey, undefined with streamToken.
reconnectOptional: initialDelayMs (first reconnection delay, 250 ms by default), maxDelayMs (backoff ceiling, 30 s), quotaRetryMs (how long a 4029 close code is retried, 120 s), quotaDelayMs (minimum delay between two attempts after a 4029, 5 s).
heartbeatTimeoutMsSilence after which the connection is considered lost, then reopened. 15,000 ms by default: the server sends an hb every 5 seconds.
highWaterMarkNumber of events waiting to be read, all subscriptions together, above which the SDK pauses reading the socket (with ws) and keeps only the latest version of each object in progress. While paused, the SDK sends ping messages (every third of heartbeatTimeoutMs, 5 s by default) so that the server keeps the connection. 10,000 by default.
maxBufferedWhen the socket cannot be paused (browsers, or Node’s built-in WebSocket): 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 highWaterMark has been read. Nothing waiting is lost, and the resume follows the rules below: no loss when it is served by the stream’s memory or by the history your rights cover, otherwise reset then a snapshot. 4 × highWaterMark by default.
randomOptional, for tests: the source of the reconnection jitter, a function returning a number in [0, 1). Math.random by default.
onStateChangeCalled on every change of connectionState.
onNoticeCalled with each notice message from the server ({ kind, id?, effectiveAt?, endsAt?, message? }): a restart (reconnect, the SDK reconnects on its own), a maintenance window announced (maintenance) or cancelled (maintenance-cancelled). See Updates and maintenance.

subscribe()

stream.subscribe<D>(options) opens a subscription and returns a Subscription object, to read with for await. Its options are those of the subscribe message: instrument, indicator, params ({} by default), mode (live by default) and from ("live" by default, { cursor, engine } or { time }). The SDK picks the sub name itself. The type D is the indicator’s data type (BigTradesData…).

The loop receives events whose type field is the name of the server message (subscribed, snapshot, upsert, remove, status, reset, notice): see Events. An error on the subscription ends the loop: for await throws a FathomChartsError carrying the received code.

Subscription

MemberPurpose
cursorThe cursor of the last event handed to you: your resume point. undefined until a cursor has arrived. It also moves forward with hb messages when no event is waiting to be read.
topicThe topic of the latest subscribed.
engineThe engine of the latest subscribed: the computation your state comes from. Save it with cursor to resume later.
idThe sub name the SDK chose for this subscription (s1, s2…).
requestThe options of subscribe(), completed with the default values (params, mode, from).
close()Stops the subscription: the SDK sends unsubscribe, and a pending loop ends.

Leaving the loop (break, return or an exception in its body) calls close().

Connection lifecycle

The connection opens on the first subscribe() and closes (1000, idle) when the last subscription closes; stream.close() closes everything, and a subscribe() after it throws CLOSED. connectionState is idle, connecting, open, reconnecting or closed. Reconnection, resuming and close codes: see Connection lifecycle. To resume after your process restarts, save sub.cursor and sub.engine and subscribe again with from: { cursor, engine }: see Resume after a restart.

Maintenance windows

stream.maintenance lists the maintenance windows announced on the connection and not over, by start: { id, startsAt, endsAt, message } (times in nanoseconds, as strings). Every new connection receives the windows already announced. See Updates and maintenance.

History: FathomChartsRest

TS
import { FathomChartsRest } from '@fathom-charts/sdk';

const rest = new FathomChartsRest({ baseUrl: 'https://api.fathomcharts.com', apiKey: process.env.FATHOM_CHARTS_API_KEY! });
OptionPurpose
baseUrlRequired. The API address: https://api.fathomcharts.com.
apiKeyRequired. API key, sent in the Authorization: Bearer header. Server-side only.
fetchOptional: a fetch implementation to use instead of the platform’s.
rateLimitRetriesNumber of retries of a request the server did not process, or of a read that failed (see below). 3 by default.

Methods

Every method that reads history takes the query described on the History page (instrument, indicator, params, from, to, mode, and depending on the method limit, cursor, untilCursor, snapshot), and an optional AbortSignal.

MethodReturns
page(query, signal?)One page: { instrument, tickSizeNanos, snapshot?, items, next, computeUnits }.
pages(query, signal?)The pages one at a time, following next, as you read them.
history(query, signal?)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).
estimate(query, signal?)The cost estimate, charging nothing. Takes the same query as page().
export(query, signal?)One export response: { body, contentType, filename, token }. body is the zstd-compressed file as is; token resumes the export with resume.
exportNdjson(query, options?)The decompressed export, in chunks (Uint8Array) of whole lines, with automatic resume. See Exports.
streamToken()A browser stream token: { token, expiresAt }.
usage()Your usage this month and your limits.
instruments(){ instruments }: every instrument served, with symbol, alias, tickSizeNanos, status and updatedAt.
status(){ engine: { state }, instruments, maintenance }: the state of the computation (up or down), of each instrument, and the maintenance windows announced.
offers()The plans and the limits of each combination (GET /v1/offers).
indicators()The indicator catalog: { version, engineFingerprint, indicators }.

The options of exportNdjson(): signal, maxResumes (consecutive resumes without a new line before giving up, 5 by default) and resumeDelayMs (delay before the first resume, 1 s by default, doubled on each consecutive resume up to 30 s). If the very first request fails (network error or 5xx before the X-Export-Token header), exportNdjson() never sends it again: a new export would be charged again. It throws the error, and you decide. A resume refused with CURSOR_EXPIRED means the computation changed since the export started: the lines already received cannot be continued, start the export again.

Rate limit and retries

rateLimitRetries bounds the retries described in Rate limit and retries. An AbortSignal ends a call, and the wait for a retry, right away (ABORTED).

Errors

Every error the SDK throws, or ends a loop with, is a FathomChartsError; the error it stems from, if any, is its cause. Its fields:

FieldContent
codeThe stable error code: an API code (see Errors), an SDK code (below), or HTTP_<status> (HTTP_502, for example) for an HTTP error response without a problem+json document.
messageA human-readable explanation. Over REST: the detail of the response, followed by each invalid field (<detail>: <path> <message>; …).
details.statusThe HTTP status, over REST.
details.closeCodeThe WebSocket close code, when the connection was closed.
details.retryAfterThe value of the Retry-After header, in seconds, when the response has one.
details.problemThe full problem+json document of the response, with errors when the API lists invalid fields; undefined when the response is not a problem+json document.
causeThe original error, when there is one: the signal’s reason, the error of fetch…

The codes, the API’s and the SDK’s own, are listed in Errors (exported as ERROR_CODES; the WebSocket close codes, as CloseCode). CONFIGURATION also covers, in TypeScript, the ws package missing for an API key, no WebSocket implementation, and zstd decompression missing for exportNdjson().

Cursors

compareCursors(a, b) compares two cursors <utcDay>.<rank>.<k> number by number and returns a negative number, zero or a positive number. A malformed cursor (numbers with leading zeros, a missing field…) throws INVALID_PARAMETERS.

TS
import { compareCursors } from '@fathom-charts/sdk';

compareCursors('20720.111416.0', '20720.111417.0'); // < 0