Introduction

Subscribe to live asset updates on the Atom platform with a simple WebSocket connection. The timeliness of data will ultimately depend on the asset class; however, for U.S. equities, we provide real-time, up-to-the-second level 1 trade data.

Messages sent to and received from the server always include a messageType. From a user's perspective, outbound Suband Unsub messages also include assets, and inbound Trades include price data. The server will send messageType: error if it receives malformed messages or unknown assets.

The streaming service URL is:
wss://platform-streaming.atom.finance?api_key=<key>

📘

Please note

We recommend subscribing in chunks of 100 assets or fewer per connection for performance reasons, and the absolute maximum is 200. There is no limit to the number of websocket connections you can make.

Subscribing and unsubscribing assets

Upon connection, you can stream prices for a list of assets by providing messageType: Sub and assets: Asset Object[].

{
  "messageType": "Sub", 
   "assets": 
    [
        {
        "value": "ZZZ",
        "identifier": "ticker",
        "assetType": "equity",
        "market": "CAN",
      },
      {
        "value": "BTC",
        "identifier": "ticker",
        "assetType": "crypto",
      },
      { 
        "value": "BBG000N9MNX3",
        "identifier": "figi"
      },
      { 
        "value": "US0378331005",
        "identifier": "isin"
      }
        ]
}

The following shows the shape of the response for a price update. The payload will include messageType: Trades and Trades, an array of price data.

{
  "messageType": "Trades",
  "Trades": 
  [
   {
    "atomAssetId": "e56b20fb-8abd-44f6-a719-9a88f4e13c47",
    "ticker": "AAPL",
    "name": "Apple Inc",
    "market": "USA",
    "assetType": "equity",
    "price": 175.06,
    "bid": 165,
    "ask": 178,
    "changePercent": -0.0189419412687738,
    "change": -3.3799999999999955,
    "extendedPrice": 175.19,
    "extendedChangePercent": 0.0007426025362733402,
    "extendedChange": 0.12999999999999545,
    "marketStatus": "AfterHours",
    "latestTradeTimestamp": 1649188800828,
    "openPrice": 177.88,
    "intradayHigh": 178.36,
    "intradayLow": 174.43,
    "closePrice": 175.06,
    "intradayVolume": 70883594,
    "figi": "BBG000B9XRY4",
    "isin": "US0378331005"
   },
  ]
}
{ 
  "messageType": "Sub",
  "Trades": 
  [
   {
    "ticker": "BTC",
    "name": "Bitcoin",
    "atomAssetId": 92834701298347102938471,
    "price": 94.77,
    "change24hours": -4.060000000000002,
    "change24hoursPercent": -0.04108064352929275,
    "marketStatus": "Open",
    "volume24hours": 1154474823.272791
   },
  ]
}

To cancel subscriptions, send a message with messageType: Unsub and assets: Asset Object[], and the list of assets you wish to unsubscribe.

{
  "messageType": "Unsub", 
   "assets": 
   [
    {
      "value": "ZZZ",
      "identifier": "ticker",
      "assetType": "equity",
      "market": "CAN",
    },
    {
      "value": "BTC",
      "identifier": "ticker",
      "assetType": "crypto",
    }
   ]
}

Connection status

To keep the connection alive, your WebSocket client must send a Ping message every 10 seconds:

{
    "messageType": "Ping"
}

The server will acknowledge each Ping with a Pong:

{
    "messageType": "Pong"
}

Sample code

The following code establishes a WebSocket connection with our server. It subscribes to price streaming for a few assets, unsubscribes, and pings the server every 10 seconds in order to persist the client's connection.

Note: a UI solution wouldn't require an API key for a user that's logged in.

// This is a Node.js script that requires the ws library, which can be installed
// with `npm install ws.`

const WebSocket = require("ws");

const riverWebServerURL = `wss://platform-streaming.atom.finance?api_key=<key>`;
let socket;
let timer;

const sleep = (ms) => {
  return new Promise(resolve => setTimeout(resolve, ms));
};


let subAssets = [
  {
    value: "ZZZ",
    identifier: "ticker",
    assetType: "equity",
    market: "CAN",
  },
  {
    value: "BTC",
    identifier: "ticker",
    assetType: "crypto",
  },
  //TSLA
  {
    value: "BBG000N9MNX3",
    identifier: "figi",
  },
  //AAPL
  {
    value: "US0378331005",
    identifier: "isin",
  },
];

const unsubAssets = [
  {
    value: "BTC",
    identifier: "ticker",
    assetType: "crypto",
  },
  //AAPL
  {
    value: "US0378331005",
    identifier: "isin",
  },
];

const connectStreaming = (nthTry = 1) => {
  socket = new WebSocket(riverWebServerURL);

  socket.onmessage = (msg) => {
    try {
      const data = JSON.parse(msg.data);
      switch (data.messageType) {
        case 'Pong':
          console.log("Received Pong");
          return;
        case  'Trades':
          for (const element of data.trades) {
            console.log("Latest trade for ticker:", element.ticker, element);
          }
          return;
      }
    } catch (e) {
      console.error(e);
    }
  };

  socket.onopen = async (msg) => {
    try {
      //subscribe assets;
      console.log("Subscribing assets");
      socket.send(
        JSON.stringify({
          messageType: 'Sub',
          assets: subAssets,
        })
      );

      //process trade data
      await sleep(5000);
      
      //unsubscribe assets no longer in use
      console.log("Unsubscribing some assets");
      socket.send(
        JSON.stringify({
          messageType: 'Unsub',
          assets: unsubAssets,
        })
      );

      //make sure you ping sever every 10s
      timer = setInterval(async () => {
        socket.send(JSON.stringify({ messageType: 'Ping' }));
      }, 10000);

      await sleep(10000);

      //unsubscribe assets
      console.log("Unsubscribing remaining assets");
      socket.send(
        JSON.stringify({
          messageType: 'Unsub',
          assets: subAssets,
        })
      );

      await sleep(1000);

      socket.close();
    } catch (e) {
      console.error(e);
    }
  };

  socket.onclose = () => {
    clearInterval(timer);
    console.log("Disconnecting");
  };
};

connectStreaming()
Ready to get started? Get your free trial API key ➔