Latency Comparison Between Exchanges
Overview
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
What latency means in this context
Each message includes:
time_exchange→ timestamp from the exchangetime_coinapi→ timestamp when CoinAPI processed the data
Latency calculation:
Latency = time_coinapi - time_exchange
This measures:
- exchange → CoinAPI ingestion delay
- normalization / processing delay
👉 It does NOT include your local network latency.
What you will build
You will compare latency across exchanges for BTC:
BINANCE_SPOT_BTC_USDTOKEX_SPOT_BTC_USDTBYBIT_SPOT_BTC_USDT
These are highly active markets, which makes them ideal for observing latency behavior.
Prerequisites
- Node.js installed
- CoinAPI API key
- Terminal access
WebSocket endpoint:
1wss://ws.coinapi.io/v1/Step 1 — Create project folder
1mkdir latency-comparison-demo
2cd latency-comparison-demoStep 2 — Create package.json
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}Step 3 — Install dependencies
1npm installStep 4 — Create .env
1COINAPI_KEY=YOUR_API_KEY_HEREStep 5 — Create index.js
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);Step 6 — Run the script
1node index.jsStep 7 — Sample output
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.Step 8 — What this shows
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
Step 9 — Optional improvements
You can extend this by:
- adding latency percentiles (p95, p99)
- plotting latency over time
- detecting spikes automatically
- comparing different data types (
trade,quote,book)
Congratulations!
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