Anyone fetched real-time option-chain

has any one try to fetch ticker options data or real-time option-chain from the Dhan API?

Hey @Lauren_Menezes ,

Yes , you can fetch ticker option data and real-time option chain using the Dhan APIs, and both work correctly.
For ticker option data Live Market Feed - DhanHQ Ver 2.0 / API Document
And for option chain data Option Chain - DhanHQ Ver 2.0 / API Document .

I have gone through this link and tried in my code but it is just fetching the strike and sometimes the expiry

Code: [import os
import logging
import asyncio
import threading
from typing import Dict, List, Any, Optional
from datetime import datetime
from dhanhq import dhanhq, marketfeed
from dotenv import load_dotenv

Load environment variables

load_dotenv()

logger = logging.getLogger(“DhanBridge”)
logging.basicConfig(level=logging.INFO)

class DhanBridge:
def init(self):
self.client_id = os.getenv(“DHAN_CLIENT_ID”)
self.access_token = os.getenv(“DHAN_ACCESS_TOKEN”)
self.dhan = None
self.feed = None
self.subscribed_instruments = set()
self.market_data = {} # Store latest ticks: {security_id: {ltp: …, …}}
self.on_tick_callback = None

    if self.client_id and self.access_token:
        try:
            self.dhan = dhanhq(self.client_id, self.access_token)
            logger.info("Dhan API Client Initialized")
        except Exception as e:
            logger.error(f"Failed to initialize Dhan API: {e}")
    else:
        logger.warning("Dhan credentials not found in .env")

def get_option_chain(self, symbol: str, expiry: str) -> Dict[str, Any]:
    """
    Fetch option chain for a symbol and expiry.
    """
    if not self.dhan:
        return {"error": "Dhan API not initialized"}

    # Map common symbols to Security IDs (NSE)
    # NIFTY: 13, BANKNIFTY: 23
    security_id = "13" if symbol.upper() == "NIFTY" else "23" if symbol.upper() == "BANKNIFTY" else None
    
    if not security_id:
         return {"error": f"Symbol {symbol} not supported for automatic ID lookup. Only NIFTY/BANKNIFTY supported currently."}

    try:
        response = self.dhan.option_chain(
            under_security_id=security_id,
            under_exchange_segment="IDX_I",
            expiry=expiry
        )
        return response
    except Exception as e:
        logger.error(f"Error fetching option chain: {e}")
        return {"error": str(e)}

async def start_websocket(self, instruments: List[tuple], callback):
    """
    Start WebSocket and subscribe to instruments.
    instruments: List of (exchange_segment, security_id)
    """
    if not self.client_id or not self.access_token:
        logger.error("Cannot start WebSocket without credentials")
        return

    self.on_tick_callback = callback
    
    try:
        # If feed already exists, just subscribe
        if self.feed:
            self.subscribe(instruments)
            return

        logger.info(f"Starting WebSocket with {len(instruments)} instruments")
        
        self.feed = marketfeed.DhanFeed(
            self.client_id,
            self.access_token,
            instruments,
            version="v2"
        )
        
        self.feed.on_connect = self._on_connect
        self.feed.on_message = self._on_message
        self.feed.on_error = self._on_error
        self.feed.on_close = self._on_close
        
        # Run in a separate thread
        t = threading.Thread(target=self.feed.run_forever)
        t.daemon = True
        t.start()
        
        logger.info("WebSocket thread started")
        
    except Exception as e:
        logger.error(f"Error starting WebSocket: {e}")

def _on_connect(self, instance):
    logger.info("Connected to Dhan WebSocket")

def _on_message(self, instance, message):
    # logger.info(f"Tick received: {message}") # Debug logging
    if 'LTP' in message:
        security_id = message.get('security_id')
        self.market_data[security_id] = message
        
        if self.on_tick_callback:
            self.on_tick_callback(message)

def _on_error(self, instance, error):
    logger.error(f"WebSocket Error: {error}")

def _on_close(self, instance):
    logger.info("WebSocket Connection Closed")

def subscribe(self, subscription_list: List[tuple]):
    if self.feed:
        try:
            self.feed.subscribe_symbols(subscription_list)
            logger.info(f"Subscribed to {len(subscription_list)} symbols")
        except Exception as e:
            logger.error(f"Error subscribing: {e}")

dhan_bridge = DhanBridge() ]

Console : [ ng:
on_event is deprecated, use lifespan event handlers instead.

    Read more about it in the
    [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/).    

@app.on_event(“startup”)
INFO: Will watch for changes in these directories: [‘C:\Users\inkstall\OneDrive\Desktop\Option\dhan_options_app\backend’]
INFO: Uvicorn running on (Press CTRL+C to quit)
INFO: Started reloader process [33680] using WatchFiles
INFO:DhanBridge:Dhan API Client Initialized
INFO: Started server process [22704]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO:watchfiles.main:5 changes detected
INFO: 127.0.0.1:52929 - “WebSocket /socket.io/?EIO=4&transport=websocket” [accepted]
INFO: connection open
INFO:Main:Fetching option chain for NIFTY expiry 2025-11-25
INFO: 127.0.0.1:55342 - “GET /api/option-chain/NIFTY/2025-11-25 HTTP/1.1” 200 OK
INFO:Main:Fetching option chain for NIFTY expiry 2025-11-25
INFO: 127.0.0.1:55342 - “GET /api/option-chain/NIFTY/2025-11-25 HTTP/1.1” 200 OK
INFO:Main:Fetching option chain for BANKNIFTY expiry 2025-11-25
INFO: 127.0.0.1:51036 - “GET /api/option-chain/BANKNIFTY/2025-11-25 HTTP/1.1” 200 OK
INFO:Main:Fetching option chain for NIFTY expiry 2025-11-25
INFO: 127.0.0.1:51036 - “GET /api/option-chain/NIFTY/2025-11-25 HTTP/1.1” 200 OK ]

Please Give me the solution for this asap as I have deadlines to be submited .