AllTick
-
real-time market datafinancial data apistock api

Real-Time Market Data API in Practice: Build a Real-Time Market Monitoring Dashboard with WebSocket

Learn how to build a stock market monitoring dashboard using a real-time market data API, WebSocket, and Node.js. Covers multi-stock subscriptions, live quote updates, data forwarding, and automatic reconnection.

AllTick5 min read

Your stock market monitoring dashboard is already connected to an API, so why do some stock prices keep updating while others remain stuck at old prices? When the number of monitored instruments grows from two or three to dozens, issues such as inconsistent quote updates, overwritten subscriptions, and data updates stopping after a network disconnection may gradually appear.

These problems are not necessarily caused by a failure of the stock market data API itself. They may also be related to the WebSocket subscription method, data processing logic, or frontend update mechanism.

For financial applications that need to display the latest stock prices continuously, receiving real-time market data through WebSocket is more suitable than repeatedly querying prices through HTTP requests. This article uses the AllTick real-time market data API as an example to build a market data receiving service with Node.js and then pass the data to a frontend monitoring dashboard. It focuses on three key issues: subscribing to multiple stocks, updating market data, and restoring connections.

Why Do Quotes for Multiple Stocks Often Become Out of Sync?

Consider a common scenario: a stock monitoring page displays the latest prices of 700.HK, 1288.HK, and other stocks simultaneously. A developer retrieves market data through scheduled requests, and the page displays the data correctly. However, as the number of monitored instruments increases, so does the number of requests.

With WebSocket, the client establishes a connection and subscribes to the required stocks. The server can then continuously push new trade data without requiring another HTTP request every time the price changes.

The two types of APIs can be assigned different responsibilities:

Data RequirementSuitable InterfaceMain Purpose
Latest traded priceWebSocketContinuously receive tick-level market data
Bid and ask depthWebSocketDisplay order book changes
Historical K-linesREST APILoad historical price movements
Initial quote retrievalREST APIInitialize page data

It is important to note that using WebSocket does not automatically guarantee that the page will update. After receiving market data, the server still needs to parse, cache, and forward it to the frontend. If these steps are not handled properly, the browser may continue displaying outdated data even though the API has already received a new price.

Subscribe to Multiple Stocks with the WebSocket API

AllTick provides a dedicated WebSocket endpoint for stock markets. A valid Token must be included in the connection URL.

The latest traded price subscription uses protocol number 22004, the subscription response uses 22005, and the server pushes the latest trade data through 22998.

First, install the WebSocket dependency for Node.js:

text
npm install ws

Configure the API Token in the server-side environment variable ALLTICK_API_TOKEN, then establish the connection:

const WebSocket = require("ws");
const crypto = require("crypto");

const token = process.env.ALLTICK_API_TOKEN;

if (!token) {
  throw new Error("Missing API Token");
}

const symbols = [
  { code: "700.HK" },
  { code: "1288.HK" }
];

let ws;
let reconnectTimer;
let heartbeatTimer;
let stopped = false;

function send(data) {
  if (ws && ws.readyState === WebSocket.OPEN) {
    ws.send(JSON.stringify(data));
  }
}

function subscribe() {
  send({
    cmd_id: 22004,
    seq_id: 1,
    trace: crypto.randomUUID(),
    data: {
      symbol_list: symbols
    }
  });
}

function connect() {
  ws = new WebSocket(
    `wss://quote.alltick.co/quote-stock-b-ws-api?token=${encodeURIComponent(token)}`
  );

  ws.on("open", () => {
    console.log("WebSocket connected");

    subscribe();

    // Heartbeat messages should be sent according to the current official heartbeat protocol.
    // An unverified heartbeat payload is not presented here as a validated implementation.
  });

  ws.on("message", (raw) => {
    try {
      const message = JSON.parse(raw.toString());

      if (message.cmd_id === 22005) {
        if (message.ret !== 200) {
          console.error("Subscription failed", message.msg);
        } else {
          console.log("Subscription successful");
        }
        return;
      }

      if (message.cmd_id === 22998) {
        updateQuote(message.data);
      }
    } catch (error) {
      console.error("Message parsing failed", error);
    }
  });

  ws.on("close", () => {
    console.log("WebSocket disconnected");

    clearInterval(heartbeatTimer);

    if (!stopped && !reconnectTimer) {
      reconnectTimer = setTimeout(() => {
        reconnectTimer = null;
        connect();
      }, 10000);
    }
  });

  ws.on("error", (error) => {
    console.error("WebSocket error:", error.message);
  });
}

function updateQuote(tick) {
  const quote = {
    code: tick.code,
    price: Number(tick.price),
    volume: Number(tick.volume),
    tickTime: tick.tick_time
  };

  console.log("Latest quote:", quote);

  // Update the market data cache here and forward the data to the frontend.
}

connect();

This code demonstrates the basic logic for establishing a connection, subscribing to stocks, parsing messages, and reconnecting after disconnection. It is a core example of a market data receiving service, not a complete production-ready project. For actual deployment, scheduled heartbeat messages must be added according to the official heartbeat protocol, along with the logic for forwarding market data from the server to the browser.

One point requires particular attention: subscription responses and market data pushes are two different types of messages. 22005 is used to determine whether a subscription request was successful, while 22998 carries the actual latest traded price updates. Receiving a successful subscription response does not mean that market data is already being received continuously.

How to Update the Monitoring Dashboard After Receiving Market Data

Once market data reaches the Node.js service, it is recommended to store the latest quote by stock symbol and then forward the data to the browser.

For example, the frontend can use a Map to maintain the latest quotes:

text
const latestQuotes = new Map();

function updateQuote(tick) {
  latestQuotes.set(tick.code, {
    price: Number(tick.price),
    volume: Number(tick.volume),
    tickTime: tick.tick_time
  });

  renderQuote(tick.code, latestQuotes.get(tick.code));
}

The renderQuote() function updates the display area for the corresponding stock instead of re-rendering the entire monitoring dashboard.

For example, if the page contains an area displaying Tencent's stock price, the corresponding element can be located using the stock symbol:

text
function renderQuote(code, quote) {
  const row = document.getElementById(`quote-${code}`);

  if (!row) return;

  row.querySelector(".price").textContent =
    quote.price.toFixed(2);

  row.querySelector(".volume").textContent =
    quote.volume;

  row.querySelector(".time").textContent =
    quote.tickTime;
}

The corresponding HTML elements should be created in advance:

text
<div id="quote-700.HK">
  <span class="price">--</span>
  <span class="volume">--</span>
  <span class="time">--</span>
</div>

Here, tickTime is displayed as its original value for now. The timestamp format described in the official field specifications and shown in the examples should be checked against the current API version. In an actual project, confirm the unit before converting it into a date and time.

Another important architectural consideration is that the browser should not store the server-side API Token directly. A more secure approach is to let the Node.js server connect to AllTick and forward market data to the frontend through your own WebSocket service. This protects authentication credentials and also makes it easier to manage subscriptions across multiple pages centrally.

What Issues Are Easy to Overlook When Subscribing to Multiple Stocks?

As a monitoring dashboard needs to display more stocks, subscription rules and connection management directly affect whether market data can continue updating.

The subscription list is not automatically appended to.

This is something developers should pay particular attention to when using the AllTick stock WebSocket.

For example, suppose you initially subscribe to 700.HK and 1288.HK, and later want to add AAPL.US. You cannot send only the newly added stock symbol. When another subscription request is sent through the same WebSocket connection, the new list replaces the previous subscription list.

The correct approach is to submit the complete list again:

text
const symbols = [
  { code: "700.HK" },
  { code: "1288.HK" },
  { code: "AAPL.US" }
];

This prevents existing stocks from unexpectedly stopping their data updates after a new stock is added.

The number of subscriptions must match your plan.

AllTick plans have different limits on the number of instruments that can be subscribed to simultaneously for the latest traded price:

PlanMaximum Number of Simultaneous Subscriptions
Free5
Basic100
Premium200
Professional3000

These limits apply to tick-level trade data subscriptions. They do not mean that every plan allows an unlimited number of WebSocket connections. Actual deployments must also consider connection limits and account permissions.

Subscription requests should not be sent too frequently.

AllTick's WebSocket interface limitations also specify clear requirements for request intervals:

  • Within the same WebSocket connection, different interface requests must be separated by at least 1 second.
  • Across multiple WebSocket connections, subscription requests must be separated by at least 3 seconds.
  • After a subscription succeeds, there is no need to repeatedly send subscription requests. Maintain the heartbeat according to the interface requirements.

Therefore, if the monitoring dashboard supports dynamically adding stocks, it is recommended to update the local subscription list first and then send the complete subscription list in a single request. Avoid sending multiple requests immediately every time a user clicks on a stock.

How to Troubleshoot When Market Data Stops Updating

One issue that is easily overlooked in a monitoring dashboard is that, after a connection is disconnected, the page may continue displaying the last price it received.

The fact that a price is still visible on the page does not mean that market data is being updated normally. It is recommended to display the connection status, last update time, and latest traded price together on the monitoring dashboard.

The following troubleshooting order can be used:

SymptomWhat to Check First
All stocks stop updatingWebSocket connection status, heartbeat, and network
Only some stocks stop updatingStock symbols, subscription scope, and trading status
Existing stocks stop updating after adding a new stockWhether the complete subscription list was resubmitted
The server receives data but the page does not changeCache updates and frontend message forwarding
Market data does not resume after reconnectionWhether the subscription request was sent again

When implementing automatic reconnection, the data state after the connection is restored must also be considered. Re-establishing the connection and subscribing again can restore subsequent market data pushes, but it does not automatically recover tick data missed during the disconnection.

If your business requires complete historical records or continuous data for backtesting, you should retrieve the missing data separately through a supported historical data interface. WebSocket reconnection should not be treated as a mechanism for recovering historical data.

How Should Real-Time Market Data APIs Be Used Together?

For a monitoring dashboard that needs to display the latest stock prices and historical price movements, a practical design is to use REST API and WebSocket API for different purposes.

The REST API handles page initialization and historical K-line queries, while the WebSocket API continuously receives the latest traded prices. By combining the two, developers do not need frequent polling to maintain the latest prices, nor do they need to use tick-level push data as a replacement for historical market data queries.

AllTick provides stock real-time trade price and order book subscription capabilities. Developers can select the appropriate interface according to the actual requirements of their monitoring dashboard. Note that subscribing to the latest traded price is not the same as subscribing to order book data, and the stock WebSocket interface cannot directly replace historical K-line queries.

If you are developing a stock market monitoring dashboard, start with a small number of stocks. Verify subscription responses, tick data pushes, data updates, and reconnection recovery before expanding the monitoring scope according to your plan limits.

You can also refer to the following documentation:

Start streaming market data today

Generate a free API key in seconds and connect to every market from one endpoint.