SDK TypeScript
@fathom-charts/sdk gère pour vous l’authentification, le snapshot initial, la reprise après coupure, les doublons, la pagination de l’historique, les exports et les retries du rate limit. Cette page décrit toutes ses options et méthodes.
Installer
npm install @fathom-charts/sdk ws- ESM uniquement : le package ne fournit pas de build CommonJS. Votre projet doit déclarer
"type": "module"dans sonpackage.json(ou utiliser des fichiers.mjs/.mts). - Node 22 ou plus récent, et les navigateurs.
exportNdjson()demande Node 22.15 ou plus récent (décompression zstd denode:zlib). wsn’est utile qu’en Node : il ouvre la connexion avec le headerAuthorization. Dans un navigateur, le SDK utilise leWebSocketnatif avec un stream token, et n’importe jamaisws.
Le SDK importe ws dynamiquement, avec un nom de module dans une variable, pour que les bundlers navigateur ne l’embarquent pas. Webpack signale alors Critical dependency: the request of a dependency is an expression : cet avertissement est sans conséquence.
Types des indicateurs
Le SDK est générique : les données d’un indicateur sont typées par les types que vous générez depuis le catalogue (GET /v1/indicators, sans authentification).
curl https://api.fathomcharts.com/v1/indicators -o catalog.json
npx fathom-charts-types catalog.json src/fathom-charts-types.tsLe fichier généré exporte, pour chaque indicateur, <Nom>Params et <Nom>Data (BigTradesData, FootprintData…), ainsi que IndicatorParams, IndicatorData et IndicatorId. Les descriptions du catalogue deviennent des commentaires JSDoc ; un niveau de footprint est typé [number, number, number, number?] (le 4e élément est facultatif). Le dossier de sortie est créé s’il n’existe pas. Régénérez le fichier quand le catalogue change (son engineFingerprint change avec le calcul).
Temps réel : FathomChartsStream
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('connexion', 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
| Option | Rôle |
|---|---|
url | Obligatoire. L’adresse du stream : wss://stream.fathomcharts.com/v1. |
apiKey | Clé API, envoyée dans le header Authorization: Bearer. Côté serveur seulement ; demande le package ws, sauf si vous fournissez webSocket. |
streamToken | Dans un navigateur, à la place de apiKey : une fonction async () => string qui demande un stream token à votre serveur. Elle est appelée à chaque connexion, reconnexions comprises. Donnez exactement l’un de apiKey et streamToken, sinon le constructeur lève CONFIGURATION. |
webSocket | Facultatif : une fonction (url, headers) => WebSocket qui ouvre la connexion, pour utiliser une autre implémentation que ws ou le WebSocket du navigateur. headers contient le header Authorization avec apiKey, undefined avec streamToken. |
reconnect | Facultatif : initialDelayMs (premier délai de reconnexion, 250 ms par défaut), maxDelayMs (plafond du backoff, 30 s), quotaRetryMs (durée pendant laquelle un close code 4029 est réessayé, 120 s), quotaDelayMs (délai minimal entre deux essais après un 4029, 5 s). |
heartbeatTimeoutMs | Silence au-delà duquel la connexion est considérée comme perdue, puis rouverte. Par défaut 15 000 ms : le serveur envoie un hb toutes les 5 secondes. |
highWaterMark | Nombre d’events en attente de lecture, toutes subscriptions confondues, au-delà duquel le SDK ralentit la lecture du socket (avec ws) et ne garde que la dernière version de chaque objet en cours. Par défaut 10 000. |
maxBuffered | Quand le socket ne peut pas être mis en pause (navigateur) : nombre d’events en attente au-delà duquel le SDK ferme la connexion, puis la rouvre au dernier cursor reçu une fois la moitié de highWaterMark lue. Rien n’est perdu. Par défaut 4 × highWaterMark. |
onStateChange | Appelée à chaque changement de connectionState. |
onNotice | Appelée avec chaque message notice du serveur ({ kind, effectiveAt? }), par exemple l’annonce d’une maintenance (kind: "reconnect"). Le SDK se reconnecte de lui-même. |
subscribe()
stream.subscribe<D>(options) ouvre une subscription et renvoie un objet Subscription, à lire avec for await. Ses options sont celles du message subscribe : instrument, indicator, params ({} par défaut), mode (live par défaut) et from ("live" par défaut, { cursor } ou { time }). Le SDK choisit lui-même le nom sub. Le type D est celui des données de l’indicateur (BigTradesData…).
La boucle reçoit des events dont le champ type reprend le nom du message du serveur, sans le champ sub :
type | Champs | Quand |
|---|---|---|
subscribed | topic, instrument, tickSizeNanos | La subscription est acceptée. Arrive de nouveau après chaque reconnexion, et après un reset de raison roll ou entitlement_changed. |
snapshot | cursor, items (chacun { id, final, ts, data }) | L’état de départ. Remplacez tout votre état local par items. |
upsert | cursor, id, final, ts, data | L’objet id est créé ou remplacé entièrement. |
remove | cursor, id, final, ts | L’objet id est supprimé. |
status | state, lagMs | L’état du stream (voir État du stream). Arrive de nouveau après chaque reconnexion. |
reset | reason | Votre état local n’est plus valable : jetez-le, un snapshot suit. |
Les autres messages du serveur ne deviennent pas des events : le SDK traite lui-même les hb (détection d’une connexion muette, cursor de reprise), les pong et les notice (transmis à onNotice). Un error sur la subscription arrête la boucle : for await lève une FathomChartsError qui porte le code reçu (INVALID_PARAMETERS, UNKNOWN_INSTRUMENT, FORBIDDEN, QUOTA_EXCEEDED, NOT_COVERED…).
Le SDK ignore les doublons : après une reprise, aucun upsert ou remove dont le cursor n’est pas strictement supérieur au dernier reçu ne vous est remis.
Subscription
| Membre | Rôle |
|---|---|
cursor | Le cursor du dernier event qui vous a été remis : votre point de reprise. undefined tant qu’aucun cursor n’est arrivé. |
topic | Le topic du dernier subscribed. |
close() | Arrête la subscription : le SDK envoie unsubscribe, et une boucle en attente se termine. |
Sortir de la boucle (break, return ou une exception dans son corps) appelle close().
Cycle de vie de la connexion
Toutes les subscriptions d’un FathomChartsStream partagent une seule connexion, qui compte dans le nombre de connexions de votre offre :
- la connexion s’ouvre au premier
subscribe(); - quand la dernière subscription se ferme (
break,close(), ou unerrordu serveur sur la dernière subscription), le SDK ferme la connexion (close code1000, raisonidle) etconnectionStatepasse àidle. Un nouveausubscribe()la rouvre ; stream.close()ferme toutes les subscriptions et la connexion. L’appeler juste aprèssubscribe(), avant que la connexion soit ouverte, est sans risque. Unsubscribe()aprèsclose()lèveCLOSED;connectionStatevautidle,connecting,open,reconnectingouclosed.
Après une coupure, le SDK se reconnecte avec un backoff exponentiel et du jitter, et renvoie chaque subscribe avec from: { cursor }, le dernier cursor reçu : vous recevez de nouveau subscribed et status, puis les messages manqués, sans snapshot si la reprise réussit, ou un reset suivi d’un snapshot sinon. Une subscription from: { time } qui a déjà reçu un cursor reprend à ce cursor : la période passée n’est jamais rejouée une seconde fois. Seule une coupure pendant warming, avant le premier cursor, la relance depuis le time d’origine, et la partie rejouée depuis l’historique est alors décomptée de nouveau.
| Close code | Ce que fait le SDK |
|---|---|
4001 | Arrête toutes les subscriptions avec UNAUTHORIZED, sans se reconnecter. |
4003 | Arrête toutes les subscriptions avec KEY_REVOKED, ENTITLEMENTS_CHANGED ou FORBIDDEN, selon la raison de la fermeture, sans se reconnecter. |
1002, 1003, 1007, 1009 | Arrête toutes les subscriptions avec PROTOCOL_ERROR, BINARY_NOT_SUPPORTED, INVALID_UTF8 ou MESSAGE_TOO_BIG : les mêmes messages seraient refusés de nouveau. |
4029 | Réessaie pendant reconnect.quotaRetryMs (une connexion perdue sans fermeture expire côté serveur au bout de 90 secondes), puis arrête tout avec TOO_MANY_CONNECTIONS. |
4008 | Se reconnecte immédiatement et reprend au dernier cursor. |
Autres, ou heartbeatTimeoutMs sans message | Se reconnecte avec backoff (au moins 1 seconde après un 1013). |
Après une de ces erreurs définitives, un nouveau subscribe() sur le même FathomChartsStream lève la même erreur : corrigez la cause, puis créez un nouveau FathomChartsStream.
Reprendre après un redémarrage
Le SDK reprend seul après une coupure, tant que votre process tourne. Pour reprendre après un redémarrage de votre process, enregistrez sub.cursor au fil de l’eau (avec l’état que vous en avez tiré), puis rouvrez la subscription avec from: { cursor } :
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
import { FathomChartsStream } from '@fathom-charts/sdk';
import type { BigTradesData } from './fathom-charts-types.js';
// Ici un fichier ; en production, le stockage de votre état (base de données…).
const CURSOR_FILE = 'big-trades.cursor';
const saved = existsSync(CURSOR_FILE) ? readFileSync(CURSOR_FILE, 'utf8') : undefined;
const stream = new FathomChartsStream({
url: 'wss://stream.fathomcharts.com/v1',
apiKey: process.env.FATHOM_CHARTS_API_KEY!,
});
const sub = stream.subscribe<BigTradesData>({
instrument: 'NQ.front',
indicator: 'big-trades',
params: { minimum: 30 },
mode: 'confirmed',
from: saved ? { cursor: saved } : 'live',
});
for await (const event of sub) {
if (event.type === 'upsert') console.log(event.data.side, event.data.volume);
// Le cursor est enregistré une fois l’event traité.
if (sub.cursor) writeFileSync(CURSOR_FILE, sub.cursor);
}Si le cursor est trop ancien, vous recevez un reset puis un nouveau snapshot : repartez de celui-ci.
Historique : FathomChartsRest
import { FathomChartsRest } from '@fathom-charts/sdk';
const rest = new FathomChartsRest({ baseUrl: 'https://api.fathomcharts.com', apiKey: process.env.FATHOM_CHARTS_API_KEY! });| Option | Rôle |
|---|---|
baseUrl | Obligatoire. L’adresse de l’API : https://api.fathomcharts.com. |
apiKey | Obligatoire. Clé API, envoyée dans le header Authorization: Bearer. Côté serveur seulement. |
fetch | Facultatif : une implémentation de fetch à utiliser à la place de celle de la plateforme. |
rateLimitRetries | Nombre de nouvelles tentatives après un 429 RATE_LIMITED. Par défaut 3. |
Méthodes
Chaque méthode qui interroge l’historique prend la requête décrite sur la page Historique (instrument, indicator, params, from, to, mode, et selon la méthode limit, cursor, untilCursor, snapshot), et un AbortSignal facultatif.
| Méthode | Renvoie |
|---|---|
page(query, signal?) | Une page : { instrument, tickSizeNanos, snapshot?, items, next, computeUnits }. |
pages(query, signal?) | Les pages une par une, en suivant next, au fil de votre lecture. |
history(query, signal?) | Les résultats un par un, toutes pages confondues. Avec snapshot: true, le premier élément est l’état à from, { t: 'snapshot', cursor, items }, puis viennent les mises à jour (t vaut upsert ou remove, chacune avec son cursor). |
estimate(query, signal?) | L’estimation du coût, sans rien décompter. Accepte la même requête que page(). |
export(query, signal?) | Une réponse d’export : { body, contentType, filename, token }. body est le fichier compressé en zstd tel quel ; token reprend l’export avec resume. |
exportNdjson(query, options?) | L’export décompressé, en morceaux (Uint8Array) de lignes complètes, avec reprise automatique. Voir Exports. |
streamToken() | Un stream token pour navigateur : { token, expiresAt }. |
usage() | Votre consommation du mois et vos limites. |
instruments() | { instruments } : chaque instrument servi, avec symbol, alias, tickSizeNanos, status et updatedAt. |
status() | { engine: { state }, instruments } : l’état du calcul (up ou down) et celui de chaque instrument. |
offers() | Les offres et les limites de chaque combinaison (GET /v1/offers). |
indicators() | Le catalogue des indicateurs : { version, engineFingerprint, indicators }. |
Les options de exportNdjson() : signal, maxResumes (nombre de reprises consécutives sans nouvelle ligne avant d’abandonner, 5 par défaut) et resumeDelayMs (délai avant la première reprise, 1 s par défaut, doublé à chaque reprise consécutive jusqu’à 30 s). Si la toute première requête échoue (erreur réseau ou 5xx avant le header X-Export-Token), exportNdjson() ne la renvoie jamais : un nouvel export serait facturé de nouveau. Il lève l’erreur, et vous décidez.
Rate limit et retries
Un 429 RATE_LIMITED est réessayé jusqu’à rateLimitRetries fois : après le délai du header Retry-After (60 secondes au plus), ou, sans ce header, après 1, 2, puis 4 secondes. Un AbortSignal interrompt l’attente immédiatement. 429 QUOTA_EXCEEDED (budget du mois épuisé) n’est jamais réessayé : il est levé tout de suite.
Erreurs
Toutes les erreurs du SDK sont des FathomChartsError :
| Champ | Contenu |
|---|---|
code | Le code stable de l’erreur : un code de l’API (voir Erreurs), un code propre au SDK (ci-dessous), ou HTTP_<status> (HTTP_502, par exemple) pour une réponse HTTP d’erreur sans document problem+json. |
message | Une explication lisible. En REST : le detail de la réponse, suivi de chaque champ invalide (<detail>: <path> <message>; …). |
details.status | Le statut HTTP, en REST. |
details.closeCode | Le close code WebSocket, quand la connexion a été fermée. |
details.retryAfter | La valeur du header Retry-After, en secondes, quand la réponse en a un. |
details.problem | Le document problem+json complet de la réponse, avec errors quand l’API liste des champs invalides. |
Codes propres au SDK, en plus de ceux de l’API (la liste complète est exportée dans ERROR_CODES) :
code | Cause |
|---|---|
CONFIGURATION | Options invalides (apiKey et streamToken ensemble, ou aucun des deux), ou fonctionnalité absente de la plateforme : package ws manquant pour une clé API, aucune implémentation de WebSocket, décompression zstd indisponible pour exportNdjson(). |
CLOSED | subscribe() sur un FathomChartsStream fermé par close(). |
KEY_REVOKED | La connexion a été fermée (4003) car la clé a été révoquée ou a expiré. |
ENTITLEMENTS_CHANGED | La connexion a été fermée (4003) car vos offres ne la couvrent plus (offre terminée, compte suspendu, quota de subscriptions dépassé). |
TOO_MANY_CONNECTIONS | Le nombre maximal de connexions de votre offre est resté atteint (4029) pendant reconnect.quotaRetryMs. |
PROTOCOL_ERROR, BINARY_NOT_SUPPORTED, INVALID_UTF8, MESSAGE_TOO_BIG | Le serveur a refusé un message envoyé par le client (close codes 1002, 1003, 1007, 1009). |
HTTP_<status> | Réponse HTTP d’erreur sans document problem+json. |
Une fermeture 4001 donne UNAUTHORIZED, avec un message qui rappelle les causes possibles (clé absente, mal formée, inconnue, révoquée ou expirée, stream token invalide, expiré ou déjà utilisé).
Cursors
compareCursors(a, b) compare deux cursors <utcDay>.<rank>.<k> nombre par nombre et renvoie un nombre négatif, zéro ou positif. Un cursor mal formé (nombres avec des zéros en tête, champ manquant…) lève INVALID_PARAMETERS.
import { compareCursors } from '@fathom-charts/sdk';
compareCursors('20720.111416.0', '20720.111417.0'); // < 0