pipsocketDOCS
Guides / Streaming

The WebSocket stream

Fills, deals, prices and the account as they happen, and calls over the same socket.

Each account has a stream: a WebSocket that pushes what happens on the account as it happens, and takes the API's calls as messages.

wss://wss.pipsocket.com/v1/accounts/{account}/stream
Authorization: Bearer $PIPSOCKET_KEY

The key goes in the Authorization header of the upgrade request, as on REST, so connect from your server (browsers can't set that header). It is checked when the stream connects, not on each call: see rolling the key. Before the upgrade, a missing or wrong key answers 401 and an account your workspace doesn't have 404, as on REST; a request that isn't a WebSocket upgrade answers 426 upgrade_required.

// npm install ws
import WebSocket from "ws"

const socket = new WebSocket("wss://wss.pipsocket.com/v1/accounts/acc_01m6tx3k9f2qw8r7bznd5yvh4c/stream", {
  headers: { Authorization: `Bearer ${process.env.PIPSOCKET_KEY}` },
})

socket.on("open", () => {
  socket.send(JSON.stringify({ id: "t1", method: "PUT", path: "/ticks", body: { symbols: ["EURUSD"] } }))
})
socket.on("message", (data) => console.log(JSON.parse(data.toString())))

The first message is { "type": "subscribed", "account": "acc_..." }. Every message is a JSON object with a type.

Events

typeWhenFields
requestA trade request settled (filled, rejected, refused), however it was sent: REST, this stream, or the kill switch.As GET /requests/{request} shows it: request, state, sent, result, message.
dealA deal on the account: a fill, a close, a stop loss or take profit, a balance operation.deal, as in deal history.
transactionMT5's trade transaction (OnTradeTransaction): orders and positions changing.transaction (MT5's type, such as deal_add or position), order, deal, position, position_by, symbol, order_type, order_state, deal_type, volume, price, sl, tp.
accountEvery second.connected, trade_allowed, balance, equity, credit, margin, margin_free, positions, orders, server_time.
statusThe account's status changed, the terminal connecting and disconnecting included.status, detail (see Accounts and ids).
tickA price change of a symbol you asked for (see Ticks).symbol, time_msc, bid, ask, last, volume, flags (MT5's MqlTick).
laggedThe stream fell behind and dropped events.missed: how many. Read the state over REST.
engine_disconnectedThe account's host lost its connection to Pipsocket.None. See Disconnections.

Your own fill arrives as a request event whichever way you sent the order, so a client can send over REST and listen here.

Calls

Send any API call as a message, with path as under /v1/accounts/{account}:

{ "id": "o1", "method": "POST", "path": "/orders", "body": { "symbol": "EURUSD", "type": "buy", "volume": 0.01, "type_filling": "ioc" }, "idempotency_key": "rebalance-0412" }
  • id is your own string, and comes back on the answer: { "type": "response", "id": "o1", "status": 200, "body": {...} }. status and body are exactly what the REST call answers.
  • idempotency_key is the Idempotency-Key header. path may carry a query: /history/deals?from=1794019000&to=1794021000. The account itself is /.
  • A call runs through the same checks, kill switch and idempotency as REST. Calls run side by side, so a slow one doesn't hold up the next.
  • At most 16 calls can wait for their answer on one stream. Another is refused: { "type": "error", "id": "o2", "error": "too_many_calls", "message": "..." }.
  • A message that isn't a call (no string id, method or path) is refused with invalid_message, and a call while the host is away with engine_unavailable. The stream stays open.

Ticks

Ask for prices with a call to /ticks, kept by the stream itself:

{ "id": "t1", "method": "PUT", "path": "/ticks", "body": { "symbols": ["EURUSD", "XAUUSD"] } }
  • Send all the symbols you want each time, up to 100; [] stops. The answer is the stream's symbols: { "type": "response", "id": "t1", "status": 200, "body": { "symbols": ["EURUSD", "XAUUSD"] } }. GET /ticks reads them back.
  • A tick event follows for each symbol's current price, then one for each price change as the broker sent it. Of changes closer together than 10 ms, only the latest is sent.
  • An account's streams share the 100 symbols between them: a set that would pass that is 422 too_many_symbols. A list that isn't up to 100 symbol names is 422 invalid_request, and a method other than GET or PUT is 405 method_not_allowed.

Keeping it open

Send the text message ping and the stream answers pong, without a call: use it to keep idle connections (and proxies between you) from timing out.

Disconnections

  • The host goes away. You get engine_disconnected, and calls still waiting get no answer. A trade among them may or may not have reached the host. Send it again with the same idempotency_key once the host is back: you get the first request if the host recorded it (it settles all the same), and the trade is sent if it never arrived. A trade sent without a key can't be retried safely: check positions and history first. Your stream stays open; events and ticks resume when the host reconnects.
  • Your socket closes. Connect again and send your /ticks set again: it belonged to the closed stream. Events that happened meanwhile aren't sent again, so read what you need over REST: positions, pending orders, history, and requests you were waiting for.
  • lagged. The stream dropped events: read the state over REST, as above.