How to stream live ticks via Kite WebSocket
The Kite Connect API provides a binary WebSocket feed for real-time market data through a class called KiteTicker in the kiteconnect Python SDK. Unlike the REST endpoints, which are request-response, KiteTicker maintains a persistent connection and pushes price updates as they occur. This guide explains how to establish that connection, subscribe to instruments, decode ticks, and handle network interruptions reliably.
How the KiteTicker WebSocket works
Kite Connect’s WebSocket endpoint at wss://ws.kite.trade streams binary-encoded tick packets. Each packet contains price, volume, and depth data for one or more instruments. The KiteTicker class handles the binary decoding, connection lifecycle, and reconnection internally, so your application receives clean Python dictionaries.
The connection is authenticated via the access_token and api_key passed as query parameters in the initial HTTP upgrade request. There is no separate authentication handshake after the WebSocket connection is established.
A single connection can subscribe to up to 3,000 instrument tokens simultaneously. Tokens are numeric identifiers, distinct from the human-readable tradingsymbol. You must look up tokens from the instruments master file.
Tick modes
| Mode | Constant | Fields included |
|---|---|---|
| LTP | MODE_LTP | Last traded price only |
| Quote | MODE_QUOTE | LTP, OHLC, volume, buy/sell quantity |
| Full | MODE_FULL | Quote fields plus 5-level market depth (order book) |
You can mix modes across subscriptions on the same connection. Instruments subscribed at MODE_FULL generate more data per tick and consume more bandwidth.
Step-by-step procedure
Find instrument tokens
Download the instruments master:
import os
import csv
import requests
resp = requests.get("https://api.kite.trade/instruments")
resp.raise_for_status()
lines = resp.text.splitlines()
reader = csv.DictReader(lines)
# Find token for RELIANCE on NSE
for row in reader:
if row["tradingsymbol"] == "RELIANCE" and row["exchange"] == "NSE":
print("instrument_token:", row["instrument_token"])
break
Instrument tokens change only rarely (on corporate actions or expiry), but it is best practice to refresh the instruments file daily before the session starts.
Define callbacks
def on_ticks(ws, ticks):
"""Called on every incoming tick packet."""
for tick in ticks:
print(
tick["instrument_token"],
tick.get("last_price"),
tick.get("volume"),
)
def on_connect(ws, response):
"""Called once the WebSocket connection is established."""
tokens = [738561, 341249] # RELIANCE, INFY instrument tokens
ws.subscribe(tokens)
ws.set_mode(ws.MODE_FULL, tokens)
print("Subscribed to", tokens)
def on_close(ws, code, reason):
"""Called when the connection closes."""
print(f"Connection closed: {code} {reason}")
def on_error(ws, code, reason):
"""Called on WebSocket error."""
print(f"Error: {code} {reason}")
def on_reconnect(ws, attempts_count):
"""Called before each reconnection attempt."""
print(f"Reconnecting, attempt {attempts_count}")
def on_noreconnect(ws):
"""Called when KiteTicker gives up reconnecting."""
print("Reconnection exhausted. Exiting.")
Instantiate and start KiteTicker
import os
from kiteconnect import KiteTicker
API_KEY = os.environ["KITE_API_KEY"]
ACCESS_TOKEN = os.environ["KITE_ACCESS_TOKEN"]
ticker = KiteTicker(API_KEY, ACCESS_TOKEN)
ticker.on_ticks = on_ticks
ticker.on_connect = on_connect
ticker.on_close = on_close
ticker.on_error = on_error
ticker.on_reconnect = on_reconnect
ticker.on_noreconnect = on_noreconnect
# Start in threaded mode so the main thread stays free
ticker.connect(threaded=True)
threaded=True runs the WebSocket event loop in a daemon thread. The main thread continues executing. If your main thread exits, the daemon thread also exits automatically.
Process ticks in the main thread
A common pattern is to push ticks into a queue.Queue from on_ticks and consume them in the main thread:
import queue
import threading
tick_queue = queue.Queue()
def on_ticks(ws, ticks):
for tick in ticks:
tick_queue.put(tick)
def process_ticks():
while True:
tick = tick_queue.get()
# Your strategy logic here
ltp = tick.get("last_price")
token = tick["instrument_token"]
print(f"Token {token}: LTP = {ltp}")
ticker.on_ticks = on_ticks
ticker.connect(threaded=True)
# Run processing on the main thread
process_ticks()
This pattern prevents slow strategy logic from blocking the WebSocket receive loop.
Full working example
import os
import queue
import time
from kiteconnect import KiteTicker
API_KEY = os.environ["KITE_API_KEY"]
ACCESS_TOKEN = os.environ["KITE_ACCESS_TOKEN"]
TOKENS = [738561, 341249] # RELIANCE, INFY on NSE
tick_queue = queue.Queue()
def on_ticks(ws, ticks):
for tick in ticks:
tick_queue.put(tick)
def on_connect(ws, response):
ws.subscribe(TOKENS)
ws.set_mode(ws.MODE_FULL, TOKENS)
def on_close(ws, code, reason):
print("Closed:", code, reason)
def on_error(ws, code, reason):
print("Error:", code, reason)
ticker = KiteTicker(API_KEY, ACCESS_TOKEN)
ticker.on_ticks = on_ticks
ticker.on_connect = on_connect
ticker.on_close = on_close
ticker.on_error = on_error
ticker.connect(threaded=True)
print("Streaming. Press Ctrl-C to stop.")
try:
while True:
try:
tick = tick_queue.get(timeout=1)
print(tick["instrument_token"], tick.get("last_price"))
except queue.Empty:
pass
except KeyboardInterrupt:
ticker.close()
print("Stopped.")
Understanding the tick dictionary
A MODE_FULL tick dictionary contains:
| Key | Description |
|---|---|
instrument_token | Numeric token identifying the instrument |
last_price | Last traded price |
last_quantity | Quantity in the last trade |
average_price | Volume-weighted average price for the day |
volume | Total volume traded for the day |
buy_quantity | Total pending buy quantity in the order book |
sell_quantity | Total pending sell quantity in the order book |
ohlc | Dict with open, high, low, close |
depth | Dict with buy and sell lists (5 levels each); each level has price, quantity, orders |
timestamp | Exchange timestamp of the tick |
tradable | Boolean; False for indices (NIFTY 50, SENSEX) |
Index ticks (for NIFTY, SENSEX, etc.) do not have depth or volume fields and always have tradable: False.
Reconnection configuration
KiteTicker handles reconnection automatically using exponential backoff. You can configure it:
ticker = KiteTicker(
API_KEY,
ACCESS_TOKEN,
reconnect=True,
reconnect_max_tries=50, # default is 50
reconnect_max_delay=60, # seconds; default is 60
connect_timeout=30, # seconds for initial connect
)
Setting reconnect=False disables automatic reconnection entirely; useful when you manage reconnection in your own supervisor process.
What can go wrong
- Empty ticks during pre-market and post-market hours. The exchange does not send ticks outside trading hours.
on_tickswill not be called even though the WebSocket connection remains open. This is expected behaviour. TokenExceptionon connect. Theaccess_tokenhas expired or is invalid. Regenerate the token. The WebSocket authenticates at connection time; it does not refresh mid-session.- Ticks arrive but LTP is missing. Some fields are absent in
MODE_LTPandMODE_QUOTE. Always use.get("field_name")rather than["field_name"]to avoidKeyError. - Queue buildup under high load. If your strategy logic is slower than the tick rate during volatile sessions,
tick_queuegrows unboundedly. Usequeue.Queue(maxsize=N)and handlequeue.Fullexceptions, or use a discard-oldest policy. - Connection drops at 6:00 AM IST. The WebSocket is forcibly closed when the
access_tokenexpires at 6:00 AM the next trading day. Plan for a daily restart. - Max 3,000 instruments. Subscribing more than 3,000 tokens on a single connection results in a server-side error. For larger watchlists, open multiple connections with separate
access_tokensessions.
Related guides
- How to write a basic Python script using kiteconnect
- How to place an order via the Kite Connect REST API
- How to generate the request_token and access_token
- How to authenticate Kite Connect with TOTP automation
- Kite Connect API overview
- Kite Connect ecosystem
- Zerodha overview
References
- Zerodha, Kite Connect WebSocket streaming documentation, kite.trade/docs/connect/v3/websocket/, accessed 2024.
- kiteconnect Python SDK,
KiteTickerclass, github.com/zerodha/pykiteconnect, accessed 2024. - Zerodha Support, Kite Connect market data and WebSocket, support.zerodha.com.
- SEBI, Guidelines on algorithmic trading, sebi.gov.in.
- Zerodha Z-Connect blog, Building with Kite Connect, zerodha.com/z-connect.