Overview
The Price Bands API retrieves price band data from NSE archives in two modes: incremental changes (daily price band updates) and complete security lists (full market price bands). Both endpoints use CSV files with automatic date-based discovery to find the latest available data.
Source Files:
fetch_incremental_price_bands.py
fetch_complete_price_bands.py
Endpoint Details
Incremental Price Bands
https://nsearchives.nseindia.com/content/equities/eq_band_changes_{date}.csv
ddmmyyyy (e.g., 15012024 for January 15, 2024)
Complete Price Bands
https://nsearchives.nseindia.com/content/equities/sec_list_{date}.csv
ddmmyyyy (e.g., 15012024 for January 15, 2024)
{
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Accept": "*/*"
}
Example Requests
Incremental Price Bands
curl -X GET "https://nsearchives.nseindia.com/content/equities/eq_band_changes_15012024.csv" \
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" \
-H "Accept: */*"
Complete Security List
curl -X GET "https://nsearchives.nseindia.com/content/equities/sec_list_15012024.csv" \
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" \
-H "Accept: */*"
Both endpoints return CSV files that are parsed and converted to JSON.
Incremental Price Bands CSV Structure
SYMBOL,SERIES,CHANGE_DATE,OLD_PRICE_BAND,NEW_PRICE_BAND,REMARKS
EXAMPLE,EQ,15-JAN-2024,20,10,Price band revised
ANOTHER,EQ,15-JAN-2024,10,5,ASM Stage 1
Complete Security List CSV Structure
SYMBOL,NAME_OF_COMPANY,SERIES,DATE_OF_LISTING,PAID_UP_VALUE,MARKET_LOT,ISIN_NUMBER,FACE_VALUE
RELIANCE,Reliance Industries Ltd.,EQ,29-NOV-1977,10,1,INE002A01018,10
TCS,Tata Consultancy Services Ltd.,EQ,25-AUG-2004,1,1,INE467B01029,1
Processed Response
Incremental Price Bands JSON
Series (typically “EQ” for equities)
Date of price band change
Previous price band percentage
New price band percentage
Reason for change (e.g., “ASM Stage 1”, “Price band revised”)
Complete Security List JSON
Example JSON Outputs
incremental_price_bands.json
[
{
"SYMBOL": "EXAMPLE",
"SERIES": "EQ",
"CHANGE_DATE": "15-JAN-2024",
"OLD_PRICE_BAND": "20",
"NEW_PRICE_BAND": "10",
"REMARKS": "Price band revised"
},
{
"SYMBOL": "ANOTHER",
"SERIES": "EQ",
"CHANGE_DATE": "15-JAN-2024",
"OLD_PRICE_BAND": "10",
"NEW_PRICE_BAND": "5",
"REMARKS": "ASM Stage 1"
}
]
complete_price_bands.json
[
{
"SYMBOL": "RELIANCE",
"NAME_OF_COMPANY": "Reliance Industries Ltd.",
"SERIES": "EQ",
"DATE_OF_LISTING": "29-NOV-1977",
"PAID_UP_VALUE": "10",
"MARKET_LOT": "1",
"ISIN_NUMBER": "INE002A01018",
"FACE_VALUE": "10"
},
{
"SYMBOL": "TCS",
"NAME_OF_COMPANY": "Tata Consultancy Services Ltd.",
"SERIES": "EQ",
"DATE_OF_LISTING": "25-AUG-2004",
"PAID_UP_VALUE": "1",
"MARKET_LOT": "1",
"ISIN_NUMBER": "INE467B01029",
"FACE_VALUE": "1"
}
]
Implementation Details
Date Discovery Strategy
Both scripts use backwards date discovery (up to 7 days) to find the latest available file:
import requests
import pandas as pd
import json
from datetime import datetime, timedelta
import io
def fetch_nse_price_bands():
base_url = "https://nsearchives.nseindia.com/content/equities/eq_band_changes_{date}.csv"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Accept": "*/*"
}
today = datetime.now()
clean_data = []
# Check last 8 days (today + 7 days back)
for i in range(8):
check_date = today - timedelta(days=i)
date_str = check_date.strftime("%d%m%Y") # Format: ddmmyyyy
url = base_url.format(date=date_str)
print(f"Checking for price band changes on {date_str}...")
try:
response = requests.get(url, headers=headers, timeout=10)
if response.status_code == 200:
print(f" Found data for {date_str}!")
# Parse CSV using pandas
csv_content = response.content.decode('utf-8')
df = pd.read_csv(io.StringIO(csv_content))
# Convert to list of dictionaries
raw_data = df.to_dict(orient='records')
# Clean whitespace from keys and values
for record in raw_data:
cleaned_record = {}
for k, v in record.items():
key = k.strip() if isinstance(k, str) else k
value = v.strip() if isinstance(v, str) else v
cleaned_record[key] = value
clean_data.append(cleaned_record)
break # Stop after finding latest file
elif response.status_code == 404:
print(f" No file found for {date_str} (404).")
else:
print(f" Unexpected status {response.status_code} for {date_str}.")
except Exception as e:
print(f" Error checking {date_str}: {e}")
if clean_data:
output_file = "incremental_price_bands.json"
with open(output_file, "w") as f:
json.dump(clean_data, f, indent=4)
print(f"Successfully saved {len(clean_data)} price band changes to {output_file}")
else:
print("Could not find any price band files in the last 7 days.")
CSV Parsing with Pandas
import pandas as pd
import io
# Decode CSV content
csv_content = response.content.decode('utf-8')
# Use pandas for robust parsing
df = pd.read_csv(io.StringIO(csv_content))
# Convert to list of dictionaries
raw_data = df.to_dict(orient='records')
# Clean whitespace
for record in raw_data:
cleaned_record = {}
for k, v in record.items():
key = k.strip() if isinstance(k, str) else k
value = v.strip() if isinstance(v, str) else v
cleaned_record[key] = value
clean_data.append(cleaned_record)
Configuration
Incremental Price Bands
Days to search backwards for latest file
incremental_price_bands.json
Complete Price Bands
Days to search backwards for latest file
complete_price_bands.json
Use Cases
Incremental Price Bands
- Surveillance Alerts: Track stocks moving to stricter price bands
- ASM/GSM Monitoring: Identify stocks entering surveillance
- Risk Management: Flag portfolio stocks with band changes
- Daily Updates: Monitor price band revisions
Complete Security List
- Master Data: Build comprehensive security master file
- ISIN Mapping: Cross-reference symbols with ISINs
- Listing Data: Track listing dates and face values
- Market Lot Info: Determine minimum trading quantities
- Data Validation: Verify security details against official NSE data
Price Band Categories
Standard stocks (normal volatility)
Moderate surveillance or small caps
High surveillance (ASM/GSM Stage 1-2)
Strictest surveillance (ASM/GSM Stage 3+)
Newly listed stocks (first day) - no upper circuit
Incremental Price Bands
- Typical Changes: 5-20 stocks per day
- File Availability: 95%+ (weekdays)
- Fetch Time: 2-5 seconds
- Lookback Success: 99%+ (finds file within 7 days)
Complete Security List
- Total Securities: ~2,800-3,000
- File Size: ~200-300 KB (CSV)
- JSON Size: ~500-700 KB
- Fetch Time: 3-7 seconds
- Lookback Success: 99%+ (finds file within 7 days)
Error Handling
File Not Found
if response.status_code == 404:
print(f" No file found for {date_str} (404).")
# Continue to next date
CSV Parsing Error
try:
df = pd.read_csv(io.StringIO(csv_content))
raw_data = df.to_dict(orient='records')
except Exception as parse_error:
print(f" Error parsing CSV for {date_str}: {parse_error}")
continue # Try next date
No Data Found
if not clean_data:
print("Could not find any price band files in the last 7 days.")
# No output file created
Analysis Examples
Stocks with Tighter Bands
# Incremental: Find stocks moving to stricter bands
tighter_bands = [
change for change in incremental_data
if int(change["NEW_PRICE_BAND"]) < int(change["OLD_PRICE_BAND"])
]
ASM Additions
# Incremental: Find new ASM stocks
asm_additions = [
change for change in incremental_data
if "ASM" in change.get("REMARKS", "")
]
Complete List Filtering
# Complete: Filter by series
eq_series = [
stock for stock in complete_data
if stock["SERIES"] == "EQ"
]
# Complete: Filter by face value
low_fv = [
stock for stock in complete_data
if float(stock["FACE_VALUE"]) <= 2
]
File Availability
Weekdays
- Files typically published after market close (3:30 PM IST)
- Available by 6:00 PM IST same day
Weekends/Holidays
- No new files published
- Use lookback strategy to find last trading day’s file
Special Cases
- Market holidays: No files
- Technical issues: File may be delayed or missing
- Lookback of 7 days ensures high success rate
Integration with Other APIs
# Cross-reference with master ISIN map
with open("master_isin_map.json", "r") as f:
master_map = json.load(f)
with open("incremental_price_bands.json", "r") as f:
price_bands = json.load(f)
# Find symbols with price band changes
changed_symbols = {pb["SYMBOL"] for pb in price_bands}
# Get full details from master map
affected_stocks = [
stock for stock in master_map
if stock["Symbol"] in changed_symbols
]
Notes
- NSE updates incremental file only when there are changes (may not exist daily)
- Complete security list is published daily (more reliable)
- CSV encoding is UTF-8
- Column names may have leading/trailing whitespace - script cleans this
- Date format in CSV data is DD-MMM-YYYY (e.g., “15-JAN-2024”)
- URL date format is DDMMYYYY (e.g., “15012024”)
- Pandas is required for robust CSV parsing
- Files are archived and may not be available beyond 1-2 months
- For historical data, use incremental files to track changes over time
- Complete list provides snapshot of current price bands for all securities