The exact framework I use to interpret NSE’s option chain — with live NIFTY data, Python scripts, and tradeable signals
Most traders open the NSE option chain, scroll to ATM, and check PCR. That is not wrong, but it is only 20% of the information available.
The full option chain contains 100+ strikes, each with call and put OI, volume, IV, LTP, and change-in-OI. When you read it correctly, it tells you where institutions are positioned, where pin risk lies, and where the next 1-2% move will come from.
This article is based on live NIFTY option chain data from 05-Aug-2026. I will show you exactly how I read it, what the numbers mean, and how to automate the process.
NSE option chain structure
NSE’s option chain page shows:
| Column | Call Side | Put Side |
|---|---|---|
| OI | Call OI | Put OI |
| Change in OI | Call Chng OI | Put Chng OI |
| Volume | Call Volume | Put Volume |
| IV | Call IV | Put IV |
| LTP | Call LTP | Put LTP |
| Change | Call Chng | Put Chng |
| Bid Qty | Call Bid Qty | Put Bid Qty |
| Bid | Call Bid | Put Bid |
| Ask | Call Ask | Put Ask |
| Ask Qty | Call Ask Qty | Put Ask Qty |
| Strike | — | — |
Key terms:
- OI: Open interest = number of open contracts
- Change in OI: New positions added or closed today
- Volume: Number of contracts traded today
- IV: Implied volatility = market’s expectation of future volatility
- LTP: Last traded price
- ITM: In-the-money options are highlighted in yellow
Reading the live NIFTY chain
On 05-Aug-2026, NIFTY closed at 24,624.65. Here is the relevant section:
| Strike | Call OI | Call Chng OI | Call IV | Call LTP | Put LTP | Put IV | Put OI | Put Chng OI |
|---|---|---|---|---|---|---|---|---|
| 24,200 | 18,339 | -991 | 12.92 | 411.75 | 25.10 | 12.92 | 81,815 | 34,061 |
| 24,250 | 2,876 | -193 | 12.83 | 371.00 | 31.45 | 12.83 | 33,862 | 19,575 |
| 24,300 | 15,794 | -400 | 12.81 | 328.45 | 39.75 | 12.81 | 59,603 | 14,885 |
| 24,350 | 4,697 | 250 | 12.93 | 292.00 | 50.90 | 12.93 | 21,651 | 8,684 |
| 24,400 | 25,256 | -1,635 | 12.84 | 252.50 | 62.00 | 12.84 | 64,024 | 16,421 |
| 24,450 | 9,210 | -5,699 | 12.96 | 218.25 | 77.20 | 12.96 | 23,650 | 7,608 |
| 24,500 | 64,618 | -8,034 | 13.22 | 186.55 | 96.40 | 13.22 | 79,188 | 19,520 |
| 24,550 | 39,572 | 14,726 | 13.31 | 158.05 | 116.00 | 13.31 | 30,951 | 18,723 |
| 24,600 | 1,21,838 | 23,183 | 13.68 | 132.95 | 141.45 | 13.68 | 77,502 | 31,387 |
| 24,650 | 69,634 | 35,445 | 14.07 | 110.00 | 169.65 | 14.07 | 21,897 | 17,422 |
| 24,700 | 1,13,977 | 41,996 | 14.32 | 90.30 | 198.40 | 14.32 | 24,761 | 13,849 |
| 24,750 | 38,057 | 21,054 | 15.28 | 72.45 | 238.10 | 15.28 | 4,471 | 3,113 |
| 24,800 | 1,07,699 | 27,605 | 15.46 | 57.40 | 269.90 | 15.46 | 9,735 | 3,285 |
| 24,850 | 33,024 | 18,626 | 15.58 | 46.65 | 302.80 | 15.58 | 1,659 | 1,087 |
| 24,900 | 95,263 | 32,806 | 16.36 | 36.50 | 345.00 | 16.36 | 3,911 | 1,652 |
| 25,000 | 1,35,553 | 39,890 | 17.64 | 22.05 | 429.40 | 17.64 | 9,550 | 2,113 |
Signal 1: Max pain / pin identification
Max pain is the strike where call + put writers earn maximum profit. It is usually near the current price but can shift.
Mac / Linux / Termux:
def find_max_pain(chain):
max_pain = None
min_value = float('inf')
for strike in chain['strike'].unique():
calls = chain[chain['strike'] == strike]['call_oi'].sum()
puts = chain[chain['strike'] == strike]['put_oi'].sum()
total = calls + puts
if total < min_value:
min_value = total
max_pain = strike
return max_pain
# On 05-Aug-2026 data
max_pain = find_max_pain(chain)
print(f"Max Pain: {max_pain}")
Windows CMD:
python -c "chain=pd.read_csv('nifty_chain_aug5.csv'); mp=min(chain.groupby('strike')['call_oi','put_oi'].sum().sum(axis=1)); print('Max Pain:', mp.name)"
On 05-Aug-2026: Max pain ≈ 24,600. NIFTY closed at 24,624.65, very close to max pain. This suggests institutions were defending this level.
Signal 2: Call writing vs put writing
When call OI increases sharply, it means someone is selling calls — they expect the market to stay below that strike.
When put OI increases sharply, someone is selling puts — they expect support.
On 05-Aug-2026:
- Call OI surge at 24,500: +64,618 new contracts
- Call OI surge at 24,600: +1,21,838 new contracts
- Put OI surge at 24,200: +81,815 new contracts
- Put OI surge at 24,600: +77,502 new contracts
Interpretation:
- Heavy call writing at 24,500-24,600 = resistance zone
- Heavy put writing at 24,200 = support zone
- Range-bound market likely: 24,200-24,600
Signal 3: Change in OI direction
Change in OI tells you whether new money is coming in or old positions are being closed.
def analyze_oi_change(chain):
chain = chain.copy()
chain['call_oi_change'] = chain['call_oi'].diff()
chain['put_oi_change'] = chain['put_oi'].diff()
# Long buildup = OI + price up
# Short buildup = OI up + price down
# Short covering = OI down + price up
# Long unwinding = OI down + price down
chain['call_signal'] = 'neutral'
chain.loc[(chain['call_oi_change'] > 0) & (chain['call_change'] > 0), 'call_signal'] = 'long_buildup'
chain.loc[(chain['call_oi_change'] > 0) & (chain['call_change'] < 0), 'call_signal'] = 'short_buildup'
chain.loc[(chain['call_oi_change'] < 0) & (chain['call_change'] > 0), 'call_signal'] = 'short_covering'
chain.loc[(chain['call_oi_change'] < 0) & (chain['call_change'] < 0), 'call_signal'] = 'long_unwinding'
return chain
Signal 4: IV skew
IV skew shows where the market expects the next move.
def calculate_iv_skew(chain, current_price):
chain = chain.copy()
chain['distance_from_atm'] = chain['strike'] - current_price
# Fit IV vs distance
iv_skew = chain[['distance_from_atm', 'call_iv']].dropna().sort_values('distance_from_atm')
# Positive skew = OTM puts have higher IV = fear
# Negative skew = OTM calls have higher IV = greed
skew = iv_skew['call_iv'].iloc[-5:].mean() - iv_skew['call_iv'].iloc[:5].mean()
return skew
# On 05-Aug-2026
# OTM calls IV: ~13-14%
# OTM puts IV: ~16-18%
# Skew: negative (puts more expensive) = fear premium
On 05-Aug-2026: Put IV > Call IV across all strikes. This is a fear premium — market is pricing in downside risk.
Signal 5: Volume-OI confirmation
High volume + increasing OI = genuine interest. High volume + decreasing OI = closing positions.
def volume_oi_confirmation(chain):
chain = chain.copy()
chain['call_volume_oi_ratio'] = chain['call_volume'] / (chain['call_oi'] + 1)
chain['put_volume_oi_ratio'] = chain['put_volume'] / (chain['put_oi'] + 1)
# High ratio = new money coming in
# Low ratio = position closing
return chain
# On 05-Aug-2026, 24,600 call:
# Volume: 31,69,999
# OI: 1,21,838
# Ratio: 26.0 = very high = new call writing
Automated OI analysis script
# oi_analyzer.py
import pandas as pd
import requests
def fetch_nse_option_chain(symbol='NIFTY', expiry='11-Aug-2026'):
"""Fetch option chain from NSE"""
url = f"https://www.nseindia.com/api/option-chain-indices?symbol={symbol}"
headers = {
"User-Agent": "Mozilla/5.0",
"Accept": "application/json"
}
response = requests.get(url, headers=headers, timeout=10)
data = response.json()
# Parse option chain
records = []
for item in data['records']['data']:
if 'CE' in item and 'PE' in item:
records.append({
'strike': item['strikePrice'],
'call_oi': item['CE']['openInterest'],
'call_oi_change': item['CE']['changeinOpenInterest'],
'call_volume': item['CE']['totalTradedVolume'],
'call_iv': item['CE']['impliedVolatility'],
'call_ltp': item['CE']['lastPrice'],
'put_oi': item['PE']['openInterest'],
'put_oi_change': item['PE']['changeinOpenInterest'],
'put_volume': item['PE']['totalTradedVolume'],
'put_iv': item['PE']['impliedVolatility'],
'put_ltp': item['PE']['lastPrice']
})
df = pd.DataFrame(records)
return df
def generate_signals(df, current_price):
"""Generate trading signals from option chain"""
signals = {}
# Max pain
signals['max_pain'] = find_max_pain(df)
# Support/Resistance
call_oi_max = df.loc[df['call_oi'].idxmax(), 'strike']
put_oi_max = df.loc[df['put_oi'].idxmax(), 'strike']
signals['resistance'] = call_oi_max
signals['support'] = put_oi_max
# PCR
total_call_oi = df['call_oi'].sum()
total_put_oi = df['put_oi'].sum()
signals['pcr'] = total_put_oi / total_call_oi
# IV skew
signals['iv_skew'] = calculate_iv_skew(df, current_price)
# Range
signals['range_high'] = call_oi_max
signals['range_low'] = put_oi_max
return signals
# Run
chain = fetch_nse_option_chain()
signals = generate_signals(chain, 24624.65)
print(signals)
Mac / Linux / Termux:
python3 oi_analyzer.py
Windows CMD:
python oi_analyzer.py
NSE option chain limitations
- Delayed data: Free option chain is delayed by 15-20 minutes during market hours
- Rate limiting: NSE blocks frequent API calls
- Session cookies: Some endpoints require valid NSE session cookies
- Terms of use: NSE prohibits commercial aggregation of data
TL;DR
| Signal | What to Look | Action |
|---|---|---|
| Max OI call | Resistance | Sell calls / buy puts |
| Max OI put | Support | Sell puts / buy calls |
| PCR > 1.5 | Bullish hedging | Buy calls / sell puts |
| PCR < 0.7 | Bearish hedging | Buy puts / sell calls |
| IV skew negative | Fear premium | Buy puts / sell straddles |
| IV skew positive | Greed premium | Buy calls / sell straddles |
The option chain is not just a data table. It is a map of institutional money.
Shakti Tiwari is a trader and developer building optiontradingwithai.in. He co-directs CodeVisser and authored books on trading psychology. Find him on Dev.to as @shaktitiwari715-ai.
Top comments (0)