Latency Comparison Between Exchanges

This tutorial shows how to measure and compare data latency across exchanges using CoinAPI’s Market Data WebSocket.

By the end, you will build a Node.js script that:

  • connects to the WebSocket stream
  • subscribes to real-time data from multiple exchanges
  • calculates latency per message using:
    • time_exchange (when the event happened at the exchange)
    • time_coinapi (when CoinAPI processed it)
  • aggregates latency per exchange
  • displays:
    • latest latency
    • average latency
    • min / max latency

Each message includes:

  • time_exchange → timestamp from the exchange
  • time_coinapi → timestamp when CoinAPI processed the data

Latency = time_coinapi - time_exchange

This measures:

  • exchange → CoinAPI ingestion delay
  • normalization / processing delay

👉 It does NOT include your local network latency.

You will compare latency across exchanges for BTC:

  • BINANCE_SPOT_BTC_USDT
  • OKEX_SPOT_BTC_USDT
  • BYBIT_SPOT_BTC_USDT

These are highly active markets, which makes them ideal for observing latency behavior.

  • Node.js installed
  • CoinAPI API key
  • Terminal access

WebSocket endpoint:

1wss://ws.coinapi.io/v1/
1mkdir latency-comparison-demo
2cd latency-comparison-demo
1{
2  "name":"latency-comparison-demo",
3  "version":"1.0.0",
4  "description":"Latency comparison across exchanges using CoinAPI WebSocket",
5  "main":"index.js",
6  "type":"commonjs",
7  "dependencies": {
8    "dotenv":"^16.4.5",
9    "ws":"^8.18.0"
10  }
11}
1npm install
1COINAPI_KEY=YOUR_API_KEY_HERE
1require("dotenv").config();
2const WebSocket = require("ws");
3
4const API_KEY = process.env.COINAPI_KEY;
5const WS_URL = "wss://ws.coinapi.io/v1/";
6
7if (!API_KEY) {
8  console.error("Missing COINAPI_KEY");
9  process.exit(1);
10}
11
12// -------------------------------------
13// CONFIG
14// -------------------------------------
15
16const SYMBOLS = [
17  "BINANCE_SPOT_BTC_USDT",
18  "OKEX_SPOT_BTC_USDT",
19  "BYBIT_SPOT_BTC_USDT"
20];
21
22const RENDER_INTERVAL_MS = 1000;
23
24// -------------------------------------
25// STORAGE
26// -------------------------------------
27
28const exchangeStats = {};
29
30// -------------------------------------
31// HELPERS
32// -------------------------------------
33
34function getExchange(symbolId) {
35  return symbolId.split("_")[0];
36}
37
38function ensureExchange(exchange) {
39  if (!exchangeStats[exchange]) {
40    exchangeStats[exchange] = {
41      count: 0,
42      totalLatency: 0,
43      minLatency: Infinity,
44      maxLatency: -Infinity,
45      lastLatency: null
46    };
47  }
48}
49
50function calculateLatency(msg) {
51  const tExchange = Date.parse(msg.time_exchange);
52  const tCoinapi = Date.parse(msg.time_coinapi);
53
54  if (!tExchange || !tCoinapi) return null;
55
56  return tCoinapi - tExchange;
57}
58
59function updateStats(exchange, latency) {
60  ensureExchange(exchange);
61
62  const stats = exchangeStats[exchange];
63
64  stats.count += 1;
65  stats.totalLatency += latency;
66  stats.lastLatency = latency;
67
68  if (latency < stats.minLatency) stats.minLatency = latency;
69  if (latency > stats.maxLatency) stats.maxLatency = latency;
70}
71
72function getAverageLatency(stats) {
73  if (stats.count === 0) return 0;
74  return stats.totalLatency / stats.count;
75}
76
77// -------------------------------------
78// RENDER
79// -------------------------------------
80
81function render() {
82  process.stdout.write("\x1Bc");
83
84  console.log("=== Exchange Latency Comparison (BTC) ===\n");
85
86  for (const [exchange, stats] of Object.entries(exchangeStats)) {
87    const avg = getAverageLatency(stats);
88
89    console.log(`${exchange}`);
90    console.log(`  Last Latency: ${stats.lastLatency?.toFixed(2)} ms`);
91    console.log(`  Avg Latency:  ${avg.toFixed(2)} ms`);
92    console.log(`  Min Latency:  ${stats.minLatency.toFixed(2)} ms`);
93    console.log(`  Max Latency:  ${stats.maxLatency.toFixed(2)} ms`);
94    console.log(`  Messages:     ${stats.count}`);
95    console.log("");
96  }
97
98  console.log("Press CTRL + C to stop.");
99}
100
101// -------------------------------------
102// WEBSOCKET
103// -------------------------------------
104
105const ws = new WebSocket(WS_URL);
106
107ws.on("open", () => {
108  console.log("Connected");
109
110  ws.send(JSON.stringify({
111    type: "hello",
112    apikey: API_KEY,
113    subscribe_data_type: ["trade"],
114    subscribe_filter_symbol_id: SYMBOLS
115  }));
116
117  console.log("Subscribed to BTC markets");
118});
119
120ws.on("message", (raw) => {
121  try {
122    const msg = JSON.parse(raw.toString());
123
124    if (msg.type !== "trade") return;
125
126    const latency = calculateLatency(msg);
127    if (latency === null) return;
128
129    const exchange = getExchange(msg.symbol_id);
130    updateStats(exchange, latency);
131
132  } catch (err) {
133    console.error("Error:", err.message);
134  }
135});
136
137ws.on("error", (err) => {
138  console.error("WS Error:", err.message);
139});
140
141ws.on("close", () => {
142  console.log("Connection closed");
143});
144
145setInterval(render, RENDER_INTERVAL_MS);
1node index.js
1=== Exchange Latency Comparison (BTC) ===
2
3BINANCE
4  Last Latency: 15.00 ms
5  Avg Latency:  18.40 ms
6  Min Latency:  10.00 ms
7  Max Latency:  40.00 ms
8  Messages:     320
9
10OKEX
11  Last Latency: 32.00 ms
12  Avg Latency:  38.75 ms
13  Min Latency:  20.00 ms
14  Max Latency:  85.00 ms
15  Messages:     290
16
17BYBIT
18  Last Latency: 25.00 ms
19  Avg Latency:  29.10 ms
20  Min Latency:  18.00 ms
21  Max Latency:  65.00 ms
22  Messages:     305
23
24Press CTRL + C to stop.

Using BTC improves:

  • message frequency (more data points)
  • stability of averages
  • clearer comparison between exchanges

You can now easily see:

  • which exchange has the lowest latency
  • which has spikes (max latency)
  • which is most consistent

You can extend this by:

  • adding latency percentiles (p95, p99)
  • plotting latency over time
  • detecting spikes automatically
  • comparing different data types (trade, quote, book)

You now have a real-time BTC-based latency comparison tool.

You were able to:

  • stream high-frequency BTC trade data
  • calculate latency using timestamps
  • aggregate metrics per exchange
  • compare performance across venues

This is especially useful for:

  • evaluating data quality
  • monitoring exchange performance
  • identifying latency anomalies