I am trying to fetch the nifty oi and spot price using the below script but it is not working
#!/usr/bin/env python3
-- coding: utf-8 --
“”"
NIFTY 50 OPTION CHAIN — ADVANCED TERMINAL DASHBOARD
Upstox Market Data Feed V3
Author: Code2DevOps
“”"
import marketdata_pb2
import json, time, uuid, threading, os
import requests, websocket
from collections import defaultdict
from datetime import datetime
from rich.console import Console
from rich.table import Table
from rich.live import Live
from marketdata_pb2 import FeedResponse
MARKET_STATUS_MAP = {
0: “PRE_OPEN_START”,
1: “PRE_OPEN_END”,
2: “NORMAL_OPEN”,
3: “NORMAL_CLOSE”,
4: “CLOSING_START”,
5: “CLOSING_END”,
}
=====================================================
CONFIG
=====================================================
ACCESS_TOKEN = “eyJ0eXAiOiJKV1QiLCJrZXlfaWQiOiJza192MS4wIiwiYWxnIjoiSFMyNTYifQ.eyJzdWIiOiI0U0NNVjMiLCJqdGkiOiI2OTQ0YjhiNjI4ZmNiYTM2NTg4ZDhkZWMiLCJpc011bHRpQ2xpZW50IjpmYWxzZSwiaXNQbHVzUGxhbiI6dHJ1ZSwiaWF0IjoxNzY2MTExNDE0LCJpc3MiOiJ1ZGFwaS1nYXRld2F5LXNlcnZpY2UiLCJleHAiOjE3NjYxODE2MDB9.Y8HVYGsQeC6ZpLheI_0GRuHGG8RXHzuii9LvMFnrV6s”
AUTHORIZE_URL = “https://api.upstox.com/v3/feed/market-data-feed/authorize”
HEADERS = {
“Authorization”: f"Bearer {ACCESS_TOKEN}",
“Accept”: “application/json”
}
NIFTY_SPOT_KEY = “NSE_INDEX|NIFTY 50”
INDIA_VIX_KEY = “NSE_INDEX|INDIA VIX”
console = Console()
=====================================================
STATE
=====================================================
state = {
“market_status”: “UNKNOWN”,
“spot”: None,
“vix”: None,
"call_oi": 0,
"put_oi": 0,
"prev_call_oi": 0,
"prev_put_oi": 0,
"strike_data": defaultdict(lambda: {
"CE": {"oi": 0, "delta": None, "gamma": None},
"PE": {"oi": 0, "delta": None, "gamma": None},
}),
"last_update": None
}
=====================================================
HELPERS (CRITICAL)
=====================================================
def safe_ltp(ltpc):
if not isinstance(ltpc, dict):
return None
return ltpc.get(“ltp”) or ltpc.get(“cp”)
def find_ltpc(obj):
“”“Recursively find ltpc anywhere in Upstox V3 feed”“”
if isinstance(obj, dict):
if “ltpc” in obj:
return obj[“ltpc”]
for v in obj.values():
found = find_ltpc(v)
if found:
return found
elif isinstance(obj, list):
for i in obj:
found = find_ltpc(i)
if found:
return found
return None
def decode_protobuf(binary):
feed = FeedResponse()
feed.ParseFromString(binary)
return feed # RETURN RAW PROTO OBJECT
=====================================================
ANALYTICS
=====================================================
def detect_regime(pcr, oi_change):
if state[“market_status”] != “NORMAL_OPEN”:
return “CLOSED”
if 0.9 <= pcr <= 1.1 and abs(oi_change) < 1_000_000:
return “SIDEWAYS”
return “TRENDING”
def gamma_wall():
best = None
score = 0
for strike, d in state[“strike_data”].items():
for side in (“CE”, “PE”):
g = d[side][“gamma”]
oi = d[side][“oi”]
if g and abs(g * oi) > score:
score = abs(g * oi)
best = strike
return best
def build_nifty_option_keys(spot):
“”"
Build CURRENT weekly ATM ±5 strikes
“”"
expiry = “23DEC” #
MUST be current weekly expiry
atm = round(spot / 50) * 50
keys = []
for strike in range(atm - 250, atm + 251, 50):
keys.append(f"NSE_FO|NIFTY{expiry}{strike}CE")
keys.append(f"NSE_FO|NIFTY{expiry}{strike}PE")
return keys
=====================================================
WEBSOCKET HANDLERS
=====================================================
def on_open(ws):
console.print(“[green]
WebSocket connected (V3)[/green]”)
# -------------------------------
# 1️⃣ Subscribe INDEX feeds
# -------------------------------
ws.send(
json.dumps({
"guid": str(uuid.uuid4()),
"method": "sub",
"data": {
"mode": "full",
"instrumentKeys": [
NIFTY_SPOT_KEY,
INDIA_VIX_KEY
]
}
}).encode(),
websocket.ABNF.OPCODE_BINARY
)
# -------------------------------
# 2️⃣ Subscribe OPTIONS immediately
# -------------------------------
expiry = "23DEC" # 🔴 MUST be current weekly expiry
atm = 26000 # initial fallback ATM
option_keys = []
for strike in range(atm - 250, atm + 251, 50):
option_keys.append(f"NSE_FO|NIFTY{expiry}{strike}CE")
option_keys.append(f"NSE_FO|NIFTY{expiry}{strike}PE")
console.print(f"[cyan]Subscribing {len(option_keys)} option contracts[/cyan]")
ws.send(
json.dumps({
"guid": str(uuid.uuid4()),
"method": "sub",
"data": {
"mode": "full",
"instrumentKeys": option_keys
}
}).encode(),
websocket.ABNF.OPCODE_BINARY
)
def on_message(ws, message):
feed = FeedResponse()
feed.ParseFromString(message)
msg_type = feed.type
# ENUM VALUES (PROTO)
INITIAL_FEED = 0
LIVE_FEED = 1
MARKET_INFO = 2
# -----------------------------------------
# IGNORE EMPTY SNAPSHOT
# -----------------------------------------
if msg_type == INITIAL_FEED:
return
# -----------------------------------------
# MARKET STATUS
# -----------------------------------------
if msg_type == MARKET_INFO:
try:
raw = dict(feed.marketInfo.segmentStatus).get("NSE_FO")
state["market_status"] = MARKET_STATUS_MAP.get(raw, "UNKNOWN")
except Exception:
state["market_status"] = "UNKNOWN"
return
# -----------------------------------------
# ONLY PROCESS LIVE FEED
# -----------------------------------------
if msg_type != LIVE_FEED:
return
# ---- continue with your existing logic ----
=====================================================
DASHBOARD
=====================================================
def render_dashboard():
pcr = round(state[“put_oi”] / state[“call_oi”], 2) if state[“call_oi”] else 0
oi_change = (state[“call_oi”] - state[“prev_call_oi”]) + (state[“put_oi”] - state[“prev_put_oi”])
regime = detect_regime(pcr, oi_change)
atm = round(state["spot"] / 50) * 50 if state["spot"] else None
wall = gamma_wall()
table = Table(title="📊 NIFTY OPTION CHAIN — ADVANCED")
table.add_column("Metric")
table.add_column("Value", justify="right")
table.add_row("Market Status", state["market_status"])
table.add_row("Spot", str(state["spot"]))
table.add_row("ATM", str(atm))
table.add_row("PCR", str(pcr))
table.add_row("OI Change", f"{oi_change:+,}")
table.add_row("Regime", regime)
table.add_row("India VIX", str(state["vix"]))
table.add_row("Gamma Wall", str(wall))
table.add_row("Last Update", state["last_update"] or "")
ladder = Table(title="Strike Ladder (±5 ATM)")
ladder.add_column("CE OI")
ladder.add_column("Strike")
ladder.add_column("PE OI")
if atm:
for s in range(atm - 250, atm + 251, 50):
d = state["strike_data"].get(s, {})
ladder.add_row(
str(d.get("CE", {}).get("oi", "")),
str(s),
str(d.get("PE", {}).get("oi", ""))
)
return table, ladder
=====================================================
MAIN
=====================================================
def main():
console.print(“[cyan]Authorizing market feed (V3)…[/cyan]”)
data = requests.get(AUTHORIZE_URL, headers=HEADERS).json()
if data.get("status") != "success":
console.print("[red]Authorize failed[/red]", data)
return
ws_url = data["data"]["authorized_redirect_uri"]
console.print("[green]✔ Authorized[/green]")
ws = websocket.WebSocketApp(
ws_url,
on_open=on_open,
on_message=on_message,
on_error=lambda ws, e: console.print(f"[red]WS error:[/red] {e}")
)
threading.Thread(target=ws.run_forever, daemon=True).start()
with Live(console=console, refresh_per_second=1) as live:
while True:
grid = Table.grid(expand=True)
table, ladder = render_dashboard()
grid.add_row(table)
grid.add_row(ladder)
live.update(grid)
time.sleep(1)
if name == “main”:
main()