Expired Options Data Using Dhan_TradeHull

Expired options data plays a crucial role in options research and strategy development. It is commonly used to study expiry behaviour, analyze option price decay, observe OI shifts near expiry, and build reliable backtesting datasets.

With Dhan_TradeHull, expired options data can now be fetched programmatically and stored in a structured format, making large-scale analysis simple and repeatable.

Downloading Expired ATM Options Data in Bulk

The example below demonstrates how expired ATM CALL option data can be fetched for multiple symbols and multiple monthly expiries.

For each expiry:

β€’ The last 30 days of data before expiry is fetched
β€’ Data is stored symbol-wise and expiry-wise
β€’ Files are saved automatically as CSV

from Dhan_Tradehull import Tradehull
import datetime
import os

client_id    = "YOUR_CLIENT_ID"
access_token = "YOUR_ACCESS_TOKEN"

tsl = Tradehull(client_id, access_token)

watchlist = ["NIFTY", "BANKNIFTY", "TCS", "INFY", "RELIANCE"]
expiries  = ["2024-01-25", "2024-02-29", "2024-03-28"]

for name in watchlist:
    for expiry in expiries:
        try:
            from_date = (
                datetime.datetime.strptime(expiry, "%Y-%m-%d")
                - datetime.timedelta(days=30)
            ).strftime("%Y-%m-%d")

            data = tsl.get_expired_option_data(
                tradingsymbol=name,
                exchange="NSE",
                interval=1,
                expiry_flag="MONTH",
                expiry_code=1,
                strike="ATM",
                option_type="CALL",
                from_date=from_date,
                to_date=expiry
            )

            path = f"Options data/{name}/ATM"
            os.makedirs(path, exist_ok=True)

            file_name = f"{name}_{expiry}.csv"
            data.to_csv(f"{path}/{file_name}", index=False)

            print(f"{name} {expiry} : Download completed")

        except Exception as e:
            print(f"{name} {expiry} : Error {e}")
            continue

Folder Structure Generated

The script automatically creates a clean and organized structure:

Options data/
 └── RELIANCE/
     └── ATM/
         β”œβ”€β”€ RELIANCE_2024-01-25.csv
         β”œβ”€β”€ RELIANCE_2024-02-29.csv
         └── RELIANCE_2024-03-28.csv

This makes it easy to load data later for analysis or backtesting.

1 Like

Hi Imran,
Thanks for making all those YT video, it has been a great learning.
Now coming to the issue with expired option data, I am running this code

watchlist = [β€œNIFTY”] #β€œBANKNIFTY”, β€œTCS”, β€œINFY”, β€œRELIANCE”]

expiries = [β€œ2026-01-06”]

CE_PE = [β€œCALL”, β€œPUT”]

for name in watchlist:

for expiry in expiries:

for option_type in CE_PE:

try:

from_date = (datetime.datetime.strptime(expiry, β€œ%Y-%m-%d”) - datetime.timedelta(days=15)).strftime(β€œ%Y-%m-%d”)

# pdb.set_trace()

print(from_date)

data = tsl.get_expired_option_data(

tradingsymbol=name,

exchange=β€œNSE”,

interval=1,

expiry_flag=β€œWEEK”,

expiry_code=1,

strike=β€œATM”,

option_type=option_type,

from_date=from_date,

to_date=expiry

            )

            path = f"/home/bug/Downloads/Python/Trading_Algo/BACK_TEST/Hist_Data/{name}/ATM" 

I am getting two files for call and put.
but the data is not consistent, like it has downloaded this file β€œNIFTY_2026-01-06_CALL.csvβ€œ
inside this file it has multiple strike, i filtered on strike 26150, cause on Jan 6 the market was around this strike.
I see inconsistency with times and data

please check these snaps.
am i doing something wrong, kindly help..
Thankyou …

Hello Imran Sir, after a long time i am back. sir 1min expiry data ka code kahan pe he? @Tradehull_Imran

Hi @Chandan_Thakur ,

The get_expired_option_data function is used to get expired option rolling data, so it is working as expected. Data for the particular strikes is not currently available.

Hi @Himansshu_Joshi ,

data = tsl.get_expired_option_data(tradingsymbol="RELIANCE",exchange="NSE",interval=1,expiry_flag="MONTH",expiry_code=1,strike="ATM",option_type="CALL",from_date="2024-10-10",to_date="2024-11-10")

Get Expired Option Data

  • tsl.get_expired_option_data(tradingsymbol: str,exchange: str,interval: int,expiry_flag: str,expiry_code: int,strike: str = β€œATM”,option_type: str = β€œCALL”,required_data: list = None,from_date: str = β€œβ€,to_date: str = β€œβ€)
  • Arguments:
    • tradingsymbol (str): The symbol for which historical expired option data is required
      (e.g., "NIFTY", "BANKNIFTY", "RELIANCE").
    • exchange (str): Exchange of the underlying
      Allowed: "NSE", "BSE"
    • interval (int): Candle interval in minutes
      Allowed: 1, 5, 15, 25, 60.
    • expiry_flag (str): The expiry type
      • "MONTH" for monthly contracts
      • "WEEK" for weekly contracts
    • expiry_code (int): Expiry sequence number
      • 1 Ò†’ Near expiry
      • 2 Ò†’ Next expiry
      • 3 Ò†’ Far expiry
    • strike (str): Strike selection mode
      Examples: "ATM", "ATM+3", "ATM-3".
    • option_type (str): "CALL" or "PUT".
    • required_data (list, optional): Which fields to fetch
      Default: ["open","high","low","close","volume","iv","oi","spot","strike"]
    • from_date (str): Start date in YYYY-MM-DD format.
    • to_date (str): End date in YYYY-MM-DD format.

Refer this link for more details -

sir data blank aaya he,

from Dhan_Tradehull import Tradehull

import time

import datetime

import pdb

import os

client_id = β€œ1100578034”

tsl = ___
folder = β€œD:/Options data 5 mins”

watchlist = [β€œNIFTY”]

expiries = [β€œ2025-04-03”,β€œ2025-04-09”,β€œ2025-04-17”,β€œ2025-04-24”,β€œ2025-05-01”,β€œ2025-05-08”,β€œ2025-05-15”,β€œ2025-05-22”,β€œ2025-05-29”,

β€œ2025-06-05”,β€œ2025-06-12”,β€œ2025-06-19”,β€œ2025-06-26”,β€œ2025-07-03”,β€œ2025-07-10”,β€œ2025-07-17”,β€œ2025-07-24”,β€œ2025-07-31”,β€œ2025-08-07”,β€œ2025-08-14”,β€œ2025-08-21”,β€œ2025-08-28”,

β€œ2025-09-02”,β€œ2025-09-09”,β€œ2025-09-16”,β€œ2025-09-23”,β€œ2025-09-30”,β€œ2025-10-07”,β€œ2025-10-14”,β€œ2025-10-21”,β€œ2025-10-28”,

β€œ2025-11-04”,β€œ2025-11-11”,β€œ2025-11-18”,β€œ2025-11-25”,β€œ2025-12-02”,β€œ2025-12-09”,β€œ2025-12-16”,β€œ2025-12-23”,β€œ2025-12-30”,

β€œ2026-01-06”,β€œ2026-01-13”,β€œ2026-01-20”,β€œ2026-01-27”,β€œ2026-02-03”,β€œ2026-02-10”,β€œ2026-02-17”,β€œ2026-02-24”,

β€œ2026-03-03”,β€œ2026-03-10”,β€œ2026-03-17”,β€œ2026-03-24”,β€œ2026-03-31”,β€œ2026-04-02”,β€œ2026-04-09”]

atm_range = [β€˜ATM-10’, β€˜ATM-9’, β€˜ATM-8’, β€˜ATM-7’, β€˜ATM-6’, β€˜ATM-5’, β€˜ATM-4’, β€˜ATM-3’, β€˜ATM-2’, β€˜ATM-1’, β€˜ATM’, β€˜ATM+1’, β€˜ATM+2’, β€˜ATM+3’, β€˜ATM+4’, β€˜ATM+5’, β€˜ATM+6’, β€˜ATM+7’, β€˜ATM+8’, β€˜ATM+9’, β€˜ATM+10’]

for name in watchlist:

for expiry in expiries:

    for rangex in atm_range: 

        for right in \["CALL", "PUT"\]:

            try:

                from_date = datetime.datetime.strptime(expiry, "%Y-%m-%d") - datetime.timedelta(days=30)

                from_date = from_date.strftime("%Y-%m-%d")        

                data      = tsl.get_expired_option_data(tradingsymbol=name,exchange="NSE",interval=5,expiry_flag="WEEK",expiry_code=1,strike=rangex,option_type=right,from_date=from_date,to_date=expiry)

                file_name = f"{name}\_{expiry}\_{right}.csv"

                path      = f"{folder}/ATM Wise data/{name}/{expiry}/{rangex}"

                os.makedirs(path, exist_ok=True)

                data.to_csv(f"{path}/{file_name}", index=False)

                print(f"{name} {rangex} {expiry} {file_name}: Download completed")

                time.sleep(0.1)



            except Exception as e:

                print(f"{name} {expiry} : Error {e}")

                continue

Hi @Himansshu_Joshi ,

Here’s how can fetch the expired options data -

Refer the below link to get the code file on how to get the expired options data -

If you still face any issues, add pdb.set_trace() above that line and share a screenshot showing all the available parameters.

 data      = tsl.get_expired_option_data(tradingsymbol=name,exchange="NSE",interval=5,expiry_flag="WEEK",expiry_code=1,strike=rangex,option_type=right,from_date=from_date,to_date=expiry)