STXWebSocket
Phoenix-channels client for the documented STX topics. Build it from an
STX client, which supplies the host, the key and your user id:
const client = new STX();const ws = await client.websocket().connect();const book = await ws.orderbook(["<market-id>"], { onMessage: console.log });const orders = await ws.orders();console.log(await orders.waitSnapshot());await ws.runForever();or standalone with the same settings options as STX.
Constructor
Section titled “Constructor”new STXWebSocket(opts?: STXWebSocketOptions)| Parameter | Type | Description |
|---|---|---|
opts (optional) |
STXWebSocketOptions |
|
opts.channelPingIntervalMs (optional) |
number | null |
Milliseconds between channel ping frames on every joined topic; null disables them. orders with cancel-on-disconnect pings faster, from the granted timeout. Default 30000. |
opts.env (optional) |
string | null |
"production" or "demo" ("prod" and "live" are accepted). |
opts.environment (optional) |
string | STXEnvironment |
A published environment, Environments.OntarioDemo, or its name, "ontario-demo". Instead of region + env; host still wins. |
opts.heartbeatIntervalMs (optional) |
number |
Milliseconds between socket heartbeats. The server closes a socket silent for 60 s. Default 25000. |
opts.host (optional) |
string | null |
A hostname or URL, overriding region/env: "demo.stxapp.ca", "http://localhost:4000". |
opts.joinTimeoutMs (optional) |
number |
Milliseconds to wait for a join or push reply. Default 10000. |
opts.keyId (optional) |
string | null |
The API key ID. |
opts.logger (optional) |
Logger |
|
opts.onReconnect (optional) |
() => void | Promise<void> |
Called after every successful reconnect and rejoin: the moment to read open orders and anything else you loaded with STX again. |
opts.privateKey (optional) |
PrivateKeyInput | null |
The Ed25519 private key: PEM text, a path to a PEM file, PEM bytes, or a KeyObject. |
opts.profile (optional) |
string | null |
A section of ~/.stx/credentials to read. |
opts.queueSize (optional) |
number |
Messages buffered per channel for iteration; the oldest is dropped when full. Default 10000. |
opts.reconnect (optional) |
boolean |
Reconnect after a drop. Default true. |
opts.reconnectPolicy (optional) |
ReconnectPolicy |
|
opts.region (optional) |
string | null |
A known region, e.g. "ontario" or "us". With env, picks the host. |
opts.rest (optional) |
STX |
An STX client to take host, key and user id from. |
opts.signer (optional) |
Signer |
Instead of privateKey: signs message bytes, for keys in an HSM or KMS. |
opts.userId (optional) |
string |
Your user id, if you already have it (skips GET /me). |
opts.verifyTls (optional) |
boolean | null |
Set false only for a local server. Honoured by the WebSocket; for HTTP requests, pass a fetch whose dispatcher skips verification (Node’s global fetch has no per-call switch). |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
channelPingIntervalMs |
number | null |
|
heartbeatIntervalMs |
number |
|
joinTimeoutMs |
number |
|
onReconnect |
() => void | Promise<void> | undefined |
|
queueSize |
number |
|
reconnect |
boolean |
|
reconnectPolicy |
ReconnectPolicy |
|
reconnects |
number |
Successful reconnects so far. |
url |
string |
|
closed |
boolean |
|
connected |
boolean |
Methods
Section titled “Methods”account()
Section titled “account()”account(opts?: { marketIds?: readonly string[]; onMessage?: MessageHandler }): Promise<Channel>account:{user_id}: everything the five channels above carry, on one
join. Do not also join a per-type channel (you would get every message
twice), and use orders if you need cancel-on-disconnect.
| Parameter | Type | Description |
|---|---|---|
opts (optional) |
{ marketIds?: readonly string[]; onMessage?: MessageHandler } |
|
opts.marketIds (optional) |
readonly string[] |
|
opts.onMessage (optional) |
MessageHandler |
Returns Promise<Channel>.
accountView()
Section titled “accountView()”accountView(opts?: AccountViewOptions): Promise<AccountView>A live view of your account: joins balances, orders, fills and
positions, seeds each from its join snapshot and applies every pushed
update, re-seeding from the new snapshots after a reconnect. Resolves once
all four snapshots have arrived. See AccountView.
| Parameter | Type | Description |
|---|---|---|
opts (optional) |
AccountViewOptions |
|
opts.accountId (optional) |
string |
Which of your accounts the balance is for; omit for your only account. |
opts.keepFlatPositions (optional) |
boolean |
Keep positions whose quantity is zero. Default false: a flat position leaves positions. |
opts.marketIds (optional) |
readonly string[] |
Restrict orders, fills and positions to these markets. The balance is always the whole account. |
opts.maxFills (optional) |
number |
The most fills held; the oldest go first. Default 1000. |
opts.onChange (optional) |
(change: AccountChange) => void |
Called after every applied message, snapshots included. |
opts.snapshotTimeoutMs (optional) |
number | null |
Wait this long for the four join snapshots before accountView() rejects. Default 15000; null waits forever. |
Returns Promise<AccountView>.
balances()
Section titled “balances()”balances(opts?: { accountId?: string; onMessage?: MessageHandler }): Promise<Channel>balances:{user_id}: balances on join, then update and payment_update. accountId picks one of your accounts.
| Parameter | Type | Description |
|---|---|---|
opts (optional) |
{ accountId?: string; onMessage?: MessageHandler } |
|
opts.accountId (optional) |
string |
|
opts.onMessage (optional) |
MessageHandler |
Returns Promise<Channel>.
close()
Section titled “close()”close(): Promise<void>Leave every channel and close the socket. Safe to call twice.
Returns Promise<void>.
connect()
Section titled “connect()”connect(): Promise<STXWebSocket>Open the socket. Idempotent; resolves to this socket.
Returns Promise<STXWebSocket>.
fills()
Section titled “fills()”fills(opts?: { marketIds?: readonly string[]; onMessage?: MessageHandler }): Promise<Channel>fills:{user_id}: all_trades on join, then one trade per execution or status change.
| Parameter | Type | Description |
|---|---|---|
opts (optional) |
{ marketIds?: readonly string[]; onMessage?: MessageHandler } |
|
opts.marketIds (optional) |
readonly string[] |
|
opts.onMessage (optional) |
MessageHandler |
Returns Promise<Channel>.
join()
Section titled “join()”join(topic: string, payload?: Record<string, unknown>, onMessage?: MessageHandler, opts?: { pingIntervalMs?: number | null }): Promise<Channel>Join topic with payload and wait for the reply. Rejects with
STXChannelException carrying the server’s reason (for example
market_ids_required or unauthorized) if the join is refused.
| Parameter | Type | Description |
|---|---|---|
topic |
string |
|
payload (optional) |
Record<string, unknown> |
|
onMessage (optional) |
MessageHandler |
|
opts (optional) |
{ pingIntervalMs?: number | null } |
|
opts.pingIntervalMs (optional) |
number | null |
Returns Promise<Channel>.
market()
Section titled “market()”market(marketId: string, opts?: { onMessage?: MessageHandler }): Promise<Channel>market:<id>: one market in full. The join reply (channel.reply) is the
market’s current state, every market field plus ob, its aggregated book
({b, o}, each level {p, q, l, tc, tl}). Then market_update carries the
fields that changed and order_book_update a fresh {ob} about every
200 ms. The event’s live status text rides along: event_brief and
detailed_event_brief (the score and clock while in play, e.g.
"CHC 3 - 4 BOS : Bottom 8th 1 Outs", the start time before), with
event_status. marketId is the market id or symbol. Prices are
converted from cents to dollar strings; book levels are written as strings.
A resulted or voided market sends one last market_update and the server
closes the topic.
| Parameter | Type | Description |
|---|---|---|
marketId |
string |
|
opts (optional) |
{ onMessage?: MessageHandler } |
|
opts.onMessage (optional) |
MessageHandler |
Returns Promise<Channel>.
markets()
Section titled “markets()”markets(opts?: { messageTypes?: readonly string[]; onMessage?: MessageHandler; ruleFilters?: readonly string[] }): Promise<Channel>markets: market_created and market_updated for every market. Each
payload maps market id to a market object; market_updated carries only
the changed fields. Prices arrive in cents on the wire and are converted
to dollar strings here.
| Parameter | Type | Description |
|---|---|---|
opts (optional) |
{ messageTypes?: readonly string[]; onMessage?: MessageHandler; ruleFilters?: readonly string[] } |
|
opts.messageTypes (optional) |
readonly string[] |
|
opts.onMessage (optional) |
MessageHandler |
|
opts.ruleFilters (optional) |
readonly string[] |
Returns Promise<Channel>.
marketStats()
Section titled “marketStats()”marketStats(marketIds: readonly string[], opts?: { onMessage?: MessageHandler; range?: string }): Promise<Channel>market_stats: a price series per market. The history is in the join
reply (channel.reply.markets); market_stats pushes changed buckets
(upsert by timestamp_us) and market_stats_snapshot replaces a series.
| Parameter | Type | Description |
|---|---|---|
marketIds |
readonly string[] |
|
opts (optional) |
{ onMessage?: MessageHandler; range?: string } |
|
opts.onMessage (optional) |
MessageHandler |
|
opts.range (optional) |
string |
Returns Promise<Channel>.
marketUpdates()
Section titled “marketUpdates()”marketUpdates(opts?: { onMessage?: MessageHandler; watch?: readonly string[] }): Promise<Channel>market_updates: created and updated for the markets you watch.
Nothing arrives until you watch something; pass watch or call
channel.watch([...]). Prices are converted from cents to dollar strings.
| Parameter | Type | Description |
|---|---|---|
opts (optional) |
{ onMessage?: MessageHandler; watch?: readonly string[] } |
|
opts.onMessage (optional) |
MessageHandler |
|
opts.watch (optional) |
readonly string[] |
Returns Promise<Channel>.
orderbook()
Section titled “orderbook()”orderbook(marketIds: readonly string[], opts?: { onMessage?: MessageHandler }): Promise<Channel>orderbook: the aggregated book, one book push per market. Each push
is a full snapshot of that market’s book; replace what you hold rather
than merging. marketIds is required.
| Parameter | Type | Description |
|---|---|---|
marketIds |
readonly string[] |
|
opts (optional) |
{ onMessage?: MessageHandler } |
|
opts.onMessage (optional) |
MessageHandler |
Returns Promise<Channel>.
orders()
Section titled “orders()”orders(opts?: { cancelOnDisconnect?: boolean; marketIds?: readonly string[]; onMessage?: MessageHandler; pingTimeout?: number }): Promise<Channel>orders:{user_id}: all_orders on join, then new_open_order.
cancelOnDisconnect: true arms cancel-on-disconnect for orders placed
with cancelOnDisconnect: true. pingTimeout is in milliseconds,
clamped by the server to 5000 to 20000; the granted value is in
channel.reply.ping_timeout and the SDK pings at 60% of it for as long
as the channel is joined.
| Parameter | Type | Description |
|---|---|---|
opts (optional) |
{ cancelOnDisconnect?: boolean; marketIds?: readonly string[]; onMessage?: MessageHandler; pingTimeout?: number } |
|
opts.cancelOnDisconnect (optional) |
boolean |
|
opts.marketIds (optional) |
readonly string[] |
|
opts.onMessage (optional) |
MessageHandler |
|
opts.pingTimeout (optional) |
number |
Returns Promise<Channel>.
positions()
Section titled “positions()”positions(opts?: { marketIds?: readonly string[]; onMessage?: MessageHandler }): Promise<Channel>positions:{user_id}: all_positions on join, then updated_positions deltas with only the changed positions.
| Parameter | Type | Description |
|---|---|---|
opts (optional) |
{ marketIds?: readonly string[]; onMessage?: MessageHandler } |
|
opts.marketIds (optional) |
readonly string[] |
|
opts.onMessage (optional) |
MessageHandler |
Returns Promise<Channel>.
runForever()
Section titled “runForever()”runForever(): Promise<void>Resolve once close() is called (or reconnects are exhausted).
Returns Promise<void>.
settlements()
Section titled “settlements()”settlements(opts?: { marketIds?: readonly string[]; onMessage?: MessageHandler }): Promise<Channel>settlements:{user_id}: new_settlements as they are recorded. No snapshot; history is STX.settlements().
| Parameter | Type | Description |
|---|---|---|
opts (optional) |
{ marketIds?: readonly string[]; onMessage?: MessageHandler } |
|
opts.marketIds (optional) |
readonly string[] |
|
opts.onMessage (optional) |
MessageHandler |
Returns Promise<Channel>.
ticker()
Section titled “ticker()”ticker(opts?: { competitions?: readonly string[]; onMessage?: MessageHandler; sports?: readonly string[] }): Promise<Channel>ticker: a ticker push whenever a market’s price, top of book, volume or open interest moves.
| Parameter | Type | Description |
|---|---|---|
opts (optional) |
{ competitions?: readonly string[]; onMessage?: MessageHandler; sports?: readonly string[] } |
|
opts.competitions (optional) |
readonly string[] |
|
opts.onMessage (optional) |
MessageHandler |
|
opts.sports (optional) |
readonly string[] |
Returns Promise<Channel>.
trades()
Section titled “trades()”trades(opts?: { eventIds?: readonly string[]; marketIds?: readonly string[]; onMessage?: MessageHandler }): Promise<Channel>trades: every execution on the exchange, anonymised. action is the taker’s side. Not your fills: see fills.
| Parameter | Type | Description |
|---|---|---|
opts (optional) |
{ eventIds?: readonly string[]; marketIds?: readonly string[]; onMessage?: MessageHandler } |
|
opts.eventIds (optional) |
readonly string[] |
|
opts.marketIds (optional) |
readonly string[] |
|
opts.onMessage (optional) |
MessageHandler |
Returns Promise<Channel>.
userId()
Section titled “userId()”userId(): Promise<string>Your user id, from userId or GET /api/v1/me.
Returns Promise<string>.
userInfo()
Section titled “userInfo()”userInfo(opts?: { onMessage?: MessageHandler }): Promise<Channel>user_info:{user_id}: user_updated right after joining, then on every profile change.
| Parameter | Type | Description |
|---|---|---|
opts (optional) |
{ onMessage?: MessageHandler } |
|
opts.onMessage (optional) |
MessageHandler |
Returns Promise<Channel>.

