# 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.

---


## 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

```javascript skip-test
const WebSocket = require("ws");

const WS_URL = "wss://ws.etoro.com/ws";

function connect(apiKey, userKey) {
  const ws = new WebSocket(WS_URL, {
    headers: {
      "x-api-key": apiKey,
      "x-user-key": userKey,
    },
  });

  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(apiKey, userKey), 5000);
    }
  });

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

  return ws;
}
```

## Subscribing to Channels

Once connected, subscribe to specific instrument channels:

```javascript skip-test
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

```javascript skip-test
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:

```javascript skip-test
class ReconnectingSocket {
  constructor(url, apiKey, userKey) {
    this.url = url;
    this.apiKey = apiKey;
    this.userKey = userKey;
    this.attempt = 0;
    this.maxDelay = 30000;
    this.subscriptions = [];
    this.connect();
  }

  connect() {
    this.ws = new WebSocket(this.url, {
      headers: {
        "x-api-key": this.apiKey,
        "x-user-key": this.userKey,
      },
    });

    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

1. **Batch subscriptions** — Subscribe to multiple instruments in a single message
2. **Throttle UI updates** — Use `requestAnimationFrame` or debounce for rendering
3. **Use binary frames** — Enable MessagePack encoding for lower bandwidth
4. **Unsubscribe** when you no longer need a channel to reduce server load

## Next Steps

- [Building an Algo Trading Bot](/learn/building-an-algo-trading-bot) — Use real-time data for automated trading
- [WebSocket API Reference](https://api-portal.etoro.com/api-reference) — Full channel documentation
- [Getting Started](/learn/getting-started-with-etoro-api-v2) — First steps with the REST API
