intermediatewebsocketmarket-datareal-timestreaming
Real-Time Market Data with WebSockets
Connect to eToro's WebSocket API for live price streaming, handle reconnections, and process real-time market data efficiently.
3 min readBy eToro Developer Relations
Overview
The eToro WebSocket API provides real-time streaming of market data including price quotes, order book updates, and trade notifications. This guide walks through connecting, subscribing to channels, and handling data efficiently.
Connection Setup
Establishing a WebSocket Connection
const WebSocket = require("ws");
const WS_URL = "wss://api.etoro.com/ws/v2";
function connect(token) {
const ws = new WebSocket(WS_URL, {
headers: { Authorization: `Bearer ${token}` },
});
ws.on("open", () => {
console.log("Connected to eToro WebSocket");
});
ws.on("message", (data) => {
const message = JSON.parse(data);
handleMessage(message);
});
ws.on("close", (code, reason) => {
console.log(`Disconnected: ${code} - ${reason}`);
if (code !== 1000) {
setTimeout(() => connect(token), 5000);
}
});
ws.on("error", (error) => {
console.error("WebSocket error:", error.message);
});
return ws;
}
Subscribing to Channels
Once connected, subscribe to specific instrument channels:
function subscribe(ws, instruments) {
ws.send(
JSON.stringify({
action: "subscribe",
channels: ["quotes"],
instruments: instruments,
})
);
}
// Subscribe to Apple, Tesla, and Bitcoin
subscribe(ws, ["AAPL", "TSLA", "BTC"]);
Available Channels
| Channel | Description | Update Frequency |
|---|---|---|
quotes |
Bid/ask prices | Every tick |
candles |
OHLCV candles | Per interval |
orderbook |
Level 2 depth | Every change |
trades |
Executed trades | Per trade |
Processing Messages
function handleMessage(message) {
switch (message.type) {
case "quote":
console.log(
`${message.instrument}: Bid ${message.bid} / Ask ${message.ask}`
);
break;
case "candle":
console.log(
`${message.instrument} ${message.interval}: O${message.open} H${message.high} L${message.low} C${message.close}`
);
break;
case "heartbeat":
// Connection keepalive — no action needed
break;
default:
console.log("Unknown message type:", message.type);
}
}
Reconnection Strategy
Production applications need robust reconnection logic with exponential backoff:
class ReconnectingSocket {
constructor(url, token) {
this.url = url;
this.token = token;
this.attempt = 0;
this.maxDelay = 30000;
this.subscriptions = [];
this.connect();
}
connect() {
this.ws = new WebSocket(this.url, {
headers: { Authorization: `Bearer ${this.token}` },
});
this.ws.on("open", () => {
this.attempt = 0;
this.resubscribe();
});
this.ws.on("close", (code) => {
if (code !== 1000) {
const delay = Math.min(
1000 * Math.pow(2, this.attempt),
this.maxDelay
);
this.attempt++;
console.log(`Reconnecting in ${delay}ms (attempt ${this.attempt})`);
setTimeout(() => this.connect(), delay);
}
});
}
subscribe(channels, instruments) {
this.subscriptions.push({ channels, instruments });
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(
JSON.stringify({ action: "subscribe", channels, instruments })
);
}
}
resubscribe() {
for (const sub of this.subscriptions) {
this.ws.send(
JSON.stringify({
action: "subscribe",
channels: sub.channels,
instruments: sub.instruments,
})
);
}
}
}
Performance Tips
- Batch subscriptions — Subscribe to multiple instruments in a single message
- Throttle UI updates — Use
requestAnimationFrameor debounce for rendering - Use binary frames — Enable MessagePack encoding for lower bandwidth
- Unsubscribe when you no longer need a channel to reduce server load
Next Steps
- Building an Algo Trading Bot — Use real-time data for automated trading
- WebSocket API Reference — Full channel documentation
- Getting Started — First steps with the REST API