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_KEYThe 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
type | When | Fields |
|---|---|---|
request | A 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. |
deal | A deal on the account: a fill, a close, a stop loss or take profit, a balance operation. | deal, as in deal history. |
transaction | MT5'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. |
account | Every second. | connected, trade_allowed, balance, equity, credit, margin, margin_free, positions, orders, server_time. |
status | The account's status changed, the terminal connecting and disconnecting included. | status, detail (see Accounts and ids). |
tick | A price change of a symbol you asked for (see Ticks). | symbol, time_msc, bid, ask, last, volume, flags (MT5's MqlTick). |
lagged | The stream fell behind and dropped events. | missed: how many. Read the state over REST. |
engine_disconnected | The 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" }idis your own string, and comes back on the answer:{ "type": "response", "id": "o1", "status": 200, "body": {...} }.statusandbodyare exactly what the REST call answers.idempotency_keyis theIdempotency-Keyheader.pathmay 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,methodorpath) is refused withinvalid_message, and a call while the host is away withengine_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 /ticksreads them back. - A
tickevent 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 is422 invalid_request, and a method other thanGETorPUTis405 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 sameidempotency_keyonce 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
/ticksset 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.