Option chain of a security is a single table which shows premium price, open interest, volume traded etc for both put and call options and for every strike price
pip install requests bs4 pandas
We import the required modules
import requests
from bs4 import BeautifulSoup
import numpy as np
import pandas as pd
URL for option chain
url = "https://www1.nseindia.com/live_market/dynaContent/live_watch/option_chain/optionKeys.jsp"
Below headers are required for NSE to respond. Without these headers the request will just time out.
headers = {
"Host": "www1.nseindia.com",
"Referer": "https://www1.nseindia.com/live_market/dynaContent/live_watch/option_chain/optionKeys.jsp",
"X-Requested-With": "XMLHttpRequest",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36",
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
}
r = requests.get(url, headers=headers)
Open chrome and go to https://www1.nseindia.com/live_market/dynaContent/live_watch/option_chain/optionKeys.jsp . Press Ctrl+U to view the source. You can see that the table tag has an id - octable
. We can extract the table using this id as below-
bs = BeautifulSoup(r.text)
table = bs.find("table", {"id": "octable"})
# Get all rows
table_rows = table.find_all('tr')
Extract the text in each cell
l = []
for tr in table_rows:
td = tr.find_all('td')
if td:
row = [tr.text for tr in td]
l.append(row)
Lets write a function which tries to convert the cell to numpy.float64
and if it fails because of -
in many cells, it will return numpy.nan
def np_float(x):
try:
y = x.lstrip().rstrip().replace(',','')
return np.float64(y)
except:
return np.nan
Loop thru each cell to convert to a array of numpy.float64
arr = []
for r in l:
row = [np_float(x) for x in r]
arr.append(row)
Convert the array to a dataframe and provide column headers manually
df = pd.DataFrame(arr[:-1]) # Leave last row of summary
df.columns = ["CE Chart", "CE OI", "CE Change in OI", "CE Volume", "CE IV", "CE LTP", "CE Net Change", "CE Bid Qty", "CE Bid Price", "CE Ask Price", "CE Ask Quantity",
"Strike Price",
"PE Bid Qty", "PE Bid Price", "PE Ask Price", "PE Ask Qty", "PE Net Change", "PE LTP", "PE IV", "PE Volume", "PE Change in OI", "PE OI", "PE Chart"]
Here’s how the output looks like
print(df.head())
CE Chart CE OI CE Change in OI CE Volume CE IV CE LTP CE Net Change \
0 NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN
CE Bid Qty CE Bid Price CE Ask Price ... PE Bid Price PE Ask Price \
0 7350.0 3110.30 3844.05 ... 0.25 0.4
1 7350.0 3065.20 3786.65 ... 0.10 0.5
2 7350.0 3019.80 3732.70 ... 0.20 0.5
3 7350.0 2975.00 3674.90 ... 0.10 0.6
4 7350.0 2929.55 3618.65 ... 0.30 0.4
PE Ask Qty PE Net Change PE LTP PE IV PE Volume PE Change in OI \
0 1725.0 -0.35 0.30 98.28 4032.0 300.0
1 3000.0 NaN NaN NaN NaN NaN
2 3000.0 -198.35 0.25 93.68 1680.0 NaN
3 600.0 NaN NaN NaN NaN NaN
4 1800.0 -0.15 0.35 93.10 1175.0 3225.0
PE OI PE Chart
0 450.0 NaN
1 NaN NaN
2 NaN NaN
3 NaN NaN
4 5550.0 NaN
[5 rows x 23 columns]
If you want to see the option chain for a security other than the default NIFTY, below is the URL format-
https://www1.nseindia.com/live_market/dynaContent/live_watch/option_chain/optionKeys.jsp?segmentLink=17&instrument=OPTSTK
&symbol=SBIN
&date=30JUL2020
Observe the parameters at the end. Now let’s start putting everything together in function
import requests
from bs4 import BeautifulSoup
import numpy as np
import pandas as pd
from urllib.parse import urlencode
def np_float(x):
try:
y = x.lstrip().rstrip().replace(',','')
return np.float64(y)
except:
return np.nan
def option_chain(symbol, instrument, date_="-"):
base_url = "https://www1.nseindia.com/live_market/dynaContent/live_watch/option_chain/optionKeys.jsp?"
parameters = {
"segmentLink": 17,
"instrument": instrument,
"symbol": symbol,
"date": date_
}
url = base_url + urlencode(parameters)
headers = {
"Host": "www1.nseindia.com",
"Referer": "https://www1.nseindia.com/live_market/dynaContent/live_watch/option_chain/optionKeys.jsp",
"X-Requested-With": "XMLHttpRequest",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36",
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
}
r = requests.get(url, headers=headers)
bs = BeautifulSoup(r.text)
table = bs.find("table", {"id": "octable"})
# Get all rows
table_rows = table.find_all('tr')
l = []
for tr in table_rows:
td = tr.find_all('td')
if td:
row = [tr.text for tr in td]
l.append(row)
arr = []
for r in l:
row = [np_float(x) for x in r]
arr.append(row)
df = pd.DataFrame(arr[:-1])
df.columns = ["CE Chart", "CE OI", "CE Change in OI", "CE Volume", "CE IV", "CE LTP", "CE Net Change", "CE Bid Qty", "CE Bid Price", "CE Ask Price", "CE Ask Quantity",
"Strike Price",
"PE Bid Qty", "PE Bid Price", "PE Ask Price", "PE Ask Qty", "PE Net Change", "PE LTP", "PE IV", "PE Volume", "PE Change in OI", "PE OI", "PE Chart"]
return df
Let us now try to use this to get BANKNIFTY option chain
print(option_chain("BANKNIFTY", "OPTIDX"))
CE Chart CE OI CE Change in OI CE Volume CE IV CE LTP \
0 NaN 20.0 20.0 6.0 NaN 8071.25
1 NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN
.. ... ... ... ... ... ...
112 NaN 78820.0 14980.0 18094.0 41.29 3.25
113 NaN 10100.0 5000.0 1787.0 41.39 2.65
114 NaN 3120.0 3120.0 333.0 42.27 2.55
115 NaN NaN NaN NaN NaN NaN
116 NaN 36660.0 36660.0 3100.0 45.81 3.35
CE Net Change CE Bid Qty CE Bid Price CE Ask Price ... PE Bid Price \
0 4390.85 40.0 8069.40 8207.15 ... 1.30
1 NaN 2400.0 7548.45 8812.25 ... 0.35
2 NaN 40.0 7794.35 8094.75 ... 1.30
3 NaN 2400.0 7369.30 8590.55 ... NaN
4 NaN 2400.0 7275.05 8489.00 ... NaN
.. ... ... ... ... ... ...
112 -3.90 820.0 3.25 3.30 ... 2990.65
113 -3.10 160.0 2.65 3.20 ... 2973.75
114 -24.50 40.0 2.35 3.90 ... 3069.30
115 NaN 1200.0 2.55 4.00 ... 3176.25
116 -16.85 800.0 2.55 3.30 ... 3375.45
PE Ask Price PE Ask Qty PE Net Change PE LTP PE IV PE Volume \
0 1.55 480.0 -1.00 1.30 119.58 330.0
1 2.95 200.0 NaN NaN NaN NaN
2 1.65 140.0 0.25 1.65 118.69 32.0
3 NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN
.. ... ... ... ... ... ...
112 3134.20 200.0 NaN NaN NaN NaN
113 3463.30 500.0 NaN NaN NaN NaN
114 3484.20 500.0 NaN NaN NaN NaN
115 3597.65 500.0 NaN NaN NaN NaN
116 3548.25 40.0 NaN NaN NaN NaN
PE Change in OI PE OI PE Chart
0 3900.0 4580.0 NaN
1 NaN NaN NaN
2 240.0 360.0 NaN
3 NaN NaN NaN
4 NaN NaN NaN
.. ... ... ...
112 NaN NaN NaN
113 NaN NaN NaN
114 NaN NaN NaN
115 NaN NaN NaN
116 NaN NaN NaN
[117 rows x 23 columns]
SBIN option chain (Please change the expiry date to the latest future expiry dates, it does not seem to work on past expiry dates)
print(option_chain("SBIN", "OPTSTK", "30JUL2020").tail())
CE Chart CE OI CE Change in OI CE Volume CE IV CE LTP \
52 NaN 5751000.0 732000.0 3355.0 63.13 0.65
53 NaN 1308000.0 540000.0 1138.0 64.01 0.45
54 NaN 405000.0 84000.0 159.0 69.34 0.35
55 NaN 1371000.0 66000.0 116.0 73.94 0.30
56 NaN 999000.0 180000.0 231.0 77.81 0.25
CE Net Change CE Bid Qty CE Bid Price CE Ask Price ... PE Bid Price \
52 -0.15 195000.0 0.65 0.70 ... 54.25
53 -0.05 30000.0 0.40 0.45 ... 63.30
54 -0.05 9000.0 0.30 0.35 ... 73.20
55 NaN 111000.0 0.25 0.30 ... 82.60
56 NaN 33000.0 0.25 0.30 ... 92.80
PE Ask Price PE Ask Qty PE Net Change PE LTP PE IV PE Volume \
52 55.20 3000.0 2.95 53.5 51.18 12.0
53 66.10 30000.0 NaN 62.3 NaN NaN
54 75.80 30000.0 NaN 72.5 NaN NaN
55 85.75 30000.0 NaN 92.5 NaN NaN
56 95.80 33000.0 NaN 93.7 NaN NaN
PE Change in OI PE OI PE Chart
52 24000.0 273000.0 NaN
53 NaN 42000.0 NaN
54 NaN 18000.0 NaN
55 NaN 45000.0 NaN
56 NaN 210000.0 NaN
[5 rows x 23 columns]