[WSS] WebSockets

WebSocket is a protocol that allows for real-time, two-way communication between a client and a server. It’s particularly well-suited for technical indicators because it enables instant updates, ensuring traders have the most current data for making timely decisions in fast-paced markets.

NOTE: IN BETA! This feature is new, thus no plans support this feature yet. If you’re interested to try it out, please get in contact with us, and we’ll set you up!

You will need at least a pro or expert plan which supports Web Socket Subscriptions, if you’re not on one of these plans, please get in touch today.

Getting started

To get started, you’ll need to make a connection to one of our socket servers. We provide a server pool per exchange:

wss://ws-<exchange>.taapi.io

Please visit our exchanges page for valid exchanges.

At the moment we have:

  • US Stocks: wss://ws-stocks.taapi.io
  • Binance Futures: wss://ws-binancefutures.taapi.io
  • Gate.IO: wss://ws-gateio.taapi.io

Messages

All messages sent to and from the server must always be in valid JSON format and string serialized. And all messages must have a type property.

Authentication

Once you’re connected, you have to authenticate with your secret key by sending a message to the server:

{
    "type": "auth", 
    "secret": "MY_SECRET"
}

If you have a valid secret, and your plan allows for socket subscriptions, you should see a response like:

{
    "type":"auth",
    "success":true,
    "message":"Welcome John, you have 10 allowed subscriptions!"
}

Subscribing

To subscribe to updates, you will need to send a subscribe message. Subscribing to updates means that you will start receiving real-time data.

A subscription is exactly equal to 1 calculation. This might mean the RSI for AAPL on the 5m timeframe, or the EMA(200) for TSLA on the daily.

You can subscribe and unsubscribe to updates as much as you want, as long as you stay within the subscription rate-limits outlined below.

{
    "type": "subscribe",
    "channel": {
        "id": "apple-1m-fast-ema",
        "symbol": "AAPL",
        "interval": "1m",
        "indicator": "ema",
        "params": {
              "period": 20
        }
    }
}
{
  "type": "subscribed",
  "channel": "AAPL-1m-ema-period-20",
  "remainingSubscriptions": 9,
  "id": "bitcoin-1m-fast-ema"
}

Unsubscribing

To stop the real-time data, and free up a subscription slot, all you have to do is send the same request as when subscribing but simply change the type to ‘unsubscribe’

{
    "type": "unsubscribe",
    "channel": {
        "id": "apple-1m-fast-ema",
        "symbol": "AAPL",
        "interval": "1m",
        "indicator": "ema",
        "params": {
              "period": 20
        }
    }
}

You will receive a message of type: 'unsubscribed' back.

Connections & Rate limits

Connections

Every user is allowed 1 connection.

Subscribing / unsubscribing

Subscribing and un-subscribing may not be done at a faster rate than 5 times / second, or use a 200ms delay in between multiple subscriptions. If exceeded, you will receive a ‘Rate-limits exceeded’ error.

{
    "type": "error",
    "message": "Rate limits exceeded"
}

Ping / pong

Every 30 seconds the server will send you a ping, you must respond to this ping with a ‘pong’, otherwise your connection will be closed. Most Web Socket clients will actually handle this for you, so you most likely don’t need to worry about it. However, if you keep getting disconnected for some reason, then try responding with a pong().

Kicks

If your connection for some reason didn’t close properly and you find yourself locked out, you can send a kick request to reset your own connection.

[GET] https://ws-<exchange>.taapi.io/api/kick?secret=MY_SECRET
{
    "success": true,
    "message": "User kicked"
}

Examples

NodeJS / Javascript

Below a Crypto example receiving [1d Candle, MACD, EMA200, RSI] for Bitcoin to USDT on various timeframes:

import WebSocket from 'ws';

// Create a WebSocket client instance
const client = new WebSocket('wss://ws-gateio.taapi.io');

client.on('open', (connection) => {
  console.log('Connected to server');

  // Authenticate with the server
  client.send(JSON.stringify({ type: 'auth', secret: "MY_SECRET" }));

});

/* client.on('ping', (encodedMessage) => {
  client.pong(); // This is usually handled automatically, enable this if you get disconnected often
}); */

client.on('message', (encodedMessage) => {

  const receivedBuffer = Buffer.from(encodedMessage, 'hex');
  const message = receivedBuffer.toString('utf8');

  const data = JSON.parse(message);

  if (data.type === 'auth') {
    if (data.success) {
      console.log('Authenticated successfully!', data.message);      

      // Define subscriptions
      let subscriptions = [];
      
      subscriptions.push({ type: 'subscribe', channel: {
        id: "BTC/USDT-1d-candle",
        symbol: "BTC/USDT",
        interval: "1d",
        indicator: "candle"
      }});

      subscriptions.push({ type: 'subscribe', channel: {
        id: "BTC/USDT-1h-macd",
        symbol: "BTC/USDT",
        interval: "1h",
        indicator: "macd"
      }});

      subscriptions.push({ type: 'subscribe', channel: {
        id: "BTC/USDT-1h-ema-200",
        symbol: "BTC/USDT",
        interval: "1h",
        indicator: "ema",
        params: {
          period: 200
        }
      }});

      subscriptions.push({ type: 'subscribe', channel: {
        id: "LTC/BTC-5m-rsi",
        symbol: "LTC/BTC",
        interval: "5m",
        indicator: "rsi"
      }});

      // Subscribe respecting the rate-limits of 5 per second
      for(let i = 0; i < subscriptions.length; i++) {
        setTimeout(() => {
          client.send(JSON.stringify(subscriptions[i]));
        }, 200 * i);
      }

      
    } else {
      console.log('Authentication failed', data.message);
    }
  } else if(data.type === 'update') {
    console.log('Received update:', data);
  } else {
    console.log('Unhandled message:', data);
  }
});

// Close the connection
client.on('close', (reasonCode, description) => {
  console.log('Connection closed:', reasonCode, description);
});

Let’s try a Stocks example, receiving [1h Candle, StochRSI, EMA50] for AAPL on various timeframes:

import WebSocket from 'ws';

// Create a WebSocket client instance
const client = new WebSocket('wss://ws-stocks.taapi.io');

client.on('open', (connection) => {
  console.log('Connected to server');

  // Authenticate with the server
  client.send(JSON.stringify({ type: 'auth', secret: "MY_SECRET" }));

});

/* client.on('ping', (encodedMessage) => {
  client.pong(); // This is usually handled automatically, enable this if you get disconnected often
}); */

client.on('message', (encodedMessage) => {

  const receivedBuffer = Buffer.from(encodedMessage, 'hex');
  const message = receivedBuffer.toString('utf8');

  const data = JSON.parse(message);

  if (data.type === 'auth') {
    if (data.success) {
      console.log('Authenticated successfully!', data.message);      

      // Define subscriptions
      let subscriptions = [];
      
      subscriptions.push({ type: 'subscribe', channel: {
        id: "AAPL-1h-candle",
        symbol: "AAPL",
        interval: "1h",
        indicator: "candle"
      }});

      subscriptions.push({ type: 'subscribe', channel: {
        id: "AAPL-15m-stochrsi",
        symbol: "AAPL",
        interval: "15m",
        indicator: "stochrsi"
      }});

      subscriptions.push({ type: 'subscribe', channel: {
        id: "AAPL-1m-ema-50",
        symbol: "AAPL",
        interval: "1m",
        indicator: "ema",
        params: {
          period: 50
        }
      }});

      // Subscribe respecting the rate-limits of 5 per second
      for(let i = 0; i < subscriptions.length; i++) {
        setTimeout(() => {
          client.send(JSON.stringify(subscriptions[i]));
        }, 200 * i);
      }

      
    } else {
      console.log('Authentication failed', data.message);
    }
  } else if(data.type === 'update') {
    console.log('Received update:', data);
  } else {
    console.log('Unhandled message:', data);
  }
});

// Close the connection
client.on('close', (reasonCode, description) => {
  console.log('Connection closed:', reasonCode, description);
});

That’s it

You can now receive real-time indicator values and only receive updates as the market changes. As always, any / all feedback is always welcome.