Download 15 years of Nifty Index Options Data using NSEpy Package

Gurdeep101 30 Jun, 2021 • 7 min read
This article was published as a part of the Data Science Blogathon
 

In my previous article on fat tails in the NSE Nifty, we saw that fat-tailed events are more frequent than expected under a standard normal distribution. We also saw the impact on our returns if we are able to protect ourselves against the downside of negative black swans or capture the upside from positive black swans — reproduced below for reference (link here).

Download Nifty Options Data NSEpy

While there are many ways to achieve these objectives, the ones that interest me the most are equity options. Backtesting your options strategy is always a good idea before you start executing it. So I downloaded 15 years of index options data of the NSE Nifty. This is based on the very helpful nsepy package.

During the course of this article, I will also touch upon how to work with data objects and go back or move forward in time as well as optionally structure nested for loops

 

Segue into Options 101

Here’s a longish video on the basics of equity options that you should review before reading further if you have no idea about what options are. Below is a 2 minute Maggi noodle version

Options are like term insurance

  • You get a payout if something happens; for example, death in case of term insurance
  • You get nothing if the expected event does not happen; you survive
  • You need to pay a premium
  • The arrangement is valid for a predefined period
  • The payout is contingent upon you paying the premium and the event (death) happening within the contract period; or if the index falls below or closes above a defined value

However, unlike term insurance —

  • Options work both ways; i.e. depending on how the contract is made options payoff if the closing value is above or below the contract price
  • Unlike your life insurance, these options contracts can also be bought and sold in the markets; changes in their value depend on multiple factors such as time to expiry, market conditions, prevailing interest rates, the difference between the option contract value, and current market price.

Let’s look at examples of both

  • Term Insurance — You get paid 20 lakh (2 Mn) rupees if you die anytime during the next 15 years provided you pay a premium of Rs. 20,000 on time.
  • Option contract — You get paid the market price of the Nifty (in reality the difference between the closing price and contract price) if it closes above 15,000 on the expiry provided you have paid the premium (usually a one time cost)

Note: This is an extremely simplistic view. Please read and watch some videos to understand this further. And don’t trade in options till you don’t understand the risks. It is better for you to donate to a charity.

Let’s download the data for a single option contract so that we get an idea of which inputs are needed

# lets try to download for a single option first; manually specify dates
sample_opt1 = get_history(symbol = 'NIFTY',
                        start = date(2004,11,1), end = date(2005,1,27),
                        index = True,
                        option_type = 'PE',
                        strike_price = 2000,
                        expiry_date = date(2005,1,27))
print(sample_opt1.shape)
sample_opt1.head(n=3)
Download Nifty Options Data sample sata NSEpy

Sample data for a single option

For each options contract, we need to enter 5 variables- the start and end dates, option type, strike (contract) price, and its expiry date. The NSE site allows us to only download options data for 1 contract at a time. See the screenshot below.

Since our objective is to look at the impact of black swan events we need to get deep out of the money options for strategy. This means that for each month we need over 20 option prices for 90 months (15 years). We need to loop else we get loopy 🙂

 

Choosing the best option among the options

For each strike price, we have two types of options. Recall that an option is a contract that allows us to buy the underlying item (NSE Nifty for us) at a pre-agreed price on a future date irrespective of the market price on the expiry date. Call options are a right to buy the underlying and used when the market price increases while Put options are the right to sell and used to protect oneself when the market falls.

The NSE has weekly, monthly and yearly options listed on its website for strike prices that are sufficiently above and below the current market levels (aka at-the-money option price). See screenshot from the NSE site below

NSE option prices by maturity NSEpy

NSE option prices by maturity

Of all these options, monthly options are the most liquid for the current month and next month. Liquidity shifts to the next month as the current month nears expiry. Weekly options were started a few years ago but they lack sufficient liquidity beyond the current week and next week.In summary, we need to download data for monthly options with a start date 3 months prior to expiry for strike prices ~1000 points above and below the highest and lowest prices for the month for 90 months.

 

Sorting out dates

Monthly options are settled on the last Thursday of each month. The current date is defined as a “ object. We use the relativedelta from dateutils library to get the download start date by going back 2 months (see months = -2)

# current date - 3 months prior to the 1st option contract expiry
current_date = date(2005, 1,1); print(current_date); print(type(current_date))
type(current_date)
Sorting out dates download nifty options data NSEpy
# price download start date
start_date = current_date + relativedelta(months = -2); print(start_date); print(type(start_date))
start_month = current_date.month; print('Start Month:', start_month)
start_yr = start_date.year; print('Start Year: ', start_yr)
NSEpy start year data

NSE options expire on the last Thursday of the month for daily options and every Thursday for weekly options. For the last week of the month the monthly option doubles as the weekly option. We use the `get_expiry` function from the NSEPy library to get the list of data for all Thursdays for the month and put it inside a max function to get the date of the last Thursday or the monthly expiry.

# get expiry date
end_month = current_date.month; print('End Month:', end_month)
end_yr = current_date.year; print('End Year: ', end_yr)

# Use the get expiry function to get a list of expiry dates - sample below
# get_expiry_date returns a list of weekly expiries; use max to get the month end expiry date

expiry_date = max(get_expiry_date(year = end_yr, month = end_month))
print('Expiry_date:', expiry_date, 'Type: ', type(expiry_date))
type(expiry_date)
download nifty options data expiry

 

Let’s Loop

With a clear handle on start and end dates, we proceed to embed them into a loop to allow us to call the `get_expiry` function for each month over 15 years. We’ll use nested for-loops for this.

In order to identify the range of option strike prices we get the Nifty closing value for each month; define a range of strike prices that are 1000 points above the highest price for the month and 1000 points below the lowest closing for that month. For each option, we get daily prices that are 3 months prior to the expiry date.

Before we code, let’s do a recap and understand what exactly it is that we want to loop over. We want monthly option data for 15 years so 180 months. For each month assume that the average range between high and low values is 300 points. With over 1000 points above the high point and 1000 points below the option point, we have 23 option strike prices at each month and 2 types of options — Puts and Calls; which takes us to 46 discrete options per month. 46 options times 180 months gives us 8280 strike prices.

The nested loops are run as follows:

For each year in the range → For each month in the year → For each strike

# define and month year range to loop over
month_list = np.arange(1, 13, step = 1); print(month_list)
# break the year list into 2 parts - 2005 to 2012 and 2013 to 2020
yr_list = np.arange(2005, 2012, step = 1 ); print(yr_list)
# create empty dataframe to store results
nifty_data = pd.DataFrame() # to use in the loop
option_data = pd.DataFrame() # to store output
counter = 0
# break the loop into 2 parts to avoid querying errors
for yr in yr_list:
    # loop through all the months and years
    print('Year: ', yr)
    for mnth in month_list:
        current_dt = date(yr, mnth, 1)
        start_dt = current_dt + relativedelta(months = -2)
        end_dt = max(get_expiry_date(year = yr, month = mnth))
        
        # print('current: ', current_dt)
        # print('start: ', start_dt)
        # print('end: ', end_dt)
        
        # get nifty futures data
        nifty_fut = get_history(symbol = 'NIFTY',
                               start = start_dt, end = end_dt,
                               index = True,
                               expiry_date = end_dt)
        nifty_data = nifty_data.append(nifty_fut)
        
        # calculate high and low values for each month; round off to get strike prices
        high = nifty_fut['Close'].max()
        high = int(round(high/100)*100) + 1000# ; print('High:', high)
        
        low = nifty_fut['Close'].min()
        low = int(round(low/100)*100) + 1000# ; print('Low :', low)
        
        for strike in range(low, high, 100): # start, stop, step
            """
            get daily closing nifty index option prices for 3 months 
            over the entire range 
            """
            #time.sleep(random.randint(10,25)) # pause for random interval so as to not overwhelm the site
            nifty_opt = get_history(symbol = 'NIFTY',
                                   start = start_dt, end = end_dt,
                                   index = True, option_type = 'PE',
                                   strike_price = strike,
                                   expiry_date = end_dt)
            
            option_data = option_data.append(nifty_opt)
            
            #time.sleep(random.randint(20,50)) # pause for random interval so as to not overwhelm the site
            nifty_opt = get_history(symbol = 'NIFTY',
                                   start = start_dt, end = end_dt,
                                   index = True, option_type = 'CE',
                                   strike_price = strike,
                                   expiry_date = end_dt)
            
            option_data = option_data.append(nifty_opt)
            
        counter+=1
        print('Months: ', counter)

And voila! We have 15 years of option data for a range of strike prices that can be stored to csv; let’s verify before we store

# visually verify
print(option_data.shape)
option_data.tail()
output

All the above code is on this GitHub page.

Connect with me on LinkedIn, Twitter, or Medium to stay updated. That’s all folks!

Note: All content is for research purposes and not investment recommendations. I recommend that you do not try the same without consulting a registered financial advisor and only then make investment decisions.

The media shown in this article are not owned by Analytics Vidhya and are used at the Author’s discretion.
Gurdeep101 30 Jun 2021

Frequently Asked Questions

Lorem ipsum dolor sit amet, consectetur adipiscing elit,

Responses From Readers

Clear

Raghavan
Raghavan 25 Jul, 2021

Hi, Thanks for sharing this. start_date = current_date + relativedelta(months = -2); print(start_date); print(type(start_date)) this line throws the following error NameError: name 'relativedelta' is not defined

Venkatesh Varadhan
Venkatesh Varadhan 18 Dec, 2021

Hi, I very much appreciate your efforts to write this article. Last week i was actually speaking to my friend about downloading historical options data (15mins data infact, not the daily OHLC). It is interesting that I came across this article today. I have not searched for this online, may be the Google/ bixby has overheared my discussion and its AI ML has suggested me this article that too in the home page of browser :). I used to crib about AI ML listening our conversations and pushing marketing info to us. This time it has helped me .. thanks Sir, I will be downloading options data now . Incase if there is a method to download 15 mins OHLC of all 15 years data, please let me know

Raja sudhan
Raja sudhan 31 Oct, 2022

Any source for minute level data pre 2021 ?