Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Anny26022/chartsmaze_clone/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The Surveillance Lists API retrieves NSE’s Additional Surveillance Measure (ASM) and GSM (Graded Surveillance Measure) lists. This endpoint uses a triple-fallback strategy: Google Sheets Gviz API (primary), Dhan Next.js API (secondary), and web scraping (tertiary) to ensure maximum reliability.
Source File: fetch_surveillance_lists.py
Endpoint Details
Primary Source: Google Sheets Gviz API
https://docs.google.com/spreadsheets/d/{SHEET_ID}/gviz/tq?tqx=out:json&gid={GID}
Secondary Source: Dhan Next.js API
https://dhan.co/_next/data/{BUILD_ID}/{PAGE_KEY}.json
Tertiary Source: Web Scraping
https://dhan.co/{PAGE_URL}/
GET (parse __NEXT_DATA__ script tag)
Configuration
ASM List
https://dhan.co/nse-asm-list/
GSM List
https://dhan.co/nse-gsm-list/
{
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
}
Example Requests
Primary: Google Sheets Gviz
curl -X GET "https://docs.google.com/spreadsheets/d/1zqhM3geRNW_ZzEx62y0W5U2ZlaXxG-NDn0V8sJk5TQ4/gviz/tq?tqx=out:json&gid=290894275" \
-H "User-Agent: Mozilla/5.0"
Secondary: Next.js API
# First get build ID
curl -X GET https://dhan.co/all-indices/ | grep buildId
# Then fetch data
curl -X GET "https://dhan.co/_next/data/{BUILD_ID}/nse-asm-list.json" \
-H "User-Agent: Mozilla/5.0"
Tertiary: Web Scraping
curl -X GET https://dhan.co/nse-asm-list/ \
-H "User-Agent: Mozilla/5.0"
Response Structure
List Object Fields
Surveillance stage (for ASM: “Stage 1”, “Stage 2”, etc.; for GSM: similar staging)
Example Response (Google Sheets Gviz)
{
"table": {
"rows": [
{
"c": [
null,
{"v": "YESBANK"},
{"v": "Yes Bank Ltd."},
{"v": "INE528G01035"},
{"v": "Stage 1"}
]
}
]
}
}
Processed Output
[
{
"Symbol": "YESBANK",
"Name": "Yes Bank Ltd.",
"ISIN": "INE528G01035",
"Stage": "Stage 1"
},
{
"Symbol": "SUZLON",
"Name": "Suzlon Energy Ltd.",
"ISIN": "INE040H01021",
"Stage": "Stage 2"
}
]
Implementation Details
Triple-Fallback Strategy
import requests
import json
import re
from bs4 import BeautifulSoup
def fetch_surveillance_lists():
spreadsheet_base_url = "https://docs.google.com/spreadsheets/d/1zqhM3geRNW_ZzEx62y0W5U2ZlaXxG-NDn0V8sJk5TQ4/gviz/tq?tqx=out:json&gid="
lists_config = {
"nse_asm_list.json": {
"gid": "290894275",
"web_url": "https://dhan.co/nse-asm-list/",
"data_key": "nse-asm-list"
},
"nse_gsm_list.json": {
"gid": "1525483995",
"web_url": "https://dhan.co/nse-gsm-list/",
"data_key": "nse-gsm-list"
}
}
headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"}
build_id = get_build_id() # Fetch dynamic build ID
for filename, config in lists_config.items():
gid = config['gid']
cleaned_list = []
success = False
# Attempt 1: Google Sheets Gviz API
try:
url = f"{spreadsheet_base_url}{gid}"
response = requests.get(url, headers=headers, timeout=10)
text = response.text
match = re.search(r'setResponse\((.*)\);', text)
if match:
data = json.loads(match.group(1))
rows = data.get('table', {}).get('rows', [])
for row in rows:
c = row.get('c', [])
if len(c) >= 5:
symbol = c[1].get('v') if c[1] else None
name = c[2].get('v') if c[2] else None
isin = c[3].get('v') if c[3] else None
stage = c[4].get('v') if c[4] else None
if symbol and symbol != "Symbol":
cleaned_list.append({
"Symbol": str(symbol),
"Name": str(name),
"ISIN": str(isin),
"Stage": str(stage)
})
success = True
except Exception as e:
print(f"Gviz failed: {e}")
# Attempt 2: Next.js API (if Gviz failed)
if not success and build_id:
try:
url = f"https://dhan.co/_next/data/{build_id}/{config['data_key']}.json"
response = requests.get(url, headers=headers)
# Parse pageProps for list data
success = True # If data found
except:
pass
# Attempt 3: Web scraping (if both failed)
if not success:
try:
response = requests.get(config['web_url'], headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
script = soup.find('script', id='__NEXT_DATA__')
if script:
data_json = json.loads(script.string)
# Extract list from props
success = True
except:
pass
if success:
with open(filename, "w") as f:
json.dump(cleaned_list, f, indent=4)
def get_build_id():
"""Dynamically fetch Next.js build ID"""
url = "https://dhan.co/all-indices/"
headers = {"User-Agent": "Mozilla/5.0"}
try:
response = requests.get(url, headers=headers, timeout=10)
match = re.search(r'"buildId":"([^"]+)"', response.text)
return match.group(1) if match else None
except:
return None
Output Files
nse_asm_list.json
[
{
"Symbol": "YESBANK",
"Name": "Yes Bank Ltd.",
"ISIN": "INE528G01035",
"Stage": "Stage 1"
},
{
"Symbol": "SUZLON",
"Name": "Suzlon Energy Ltd.",
"ISIN": "INE040H01021",
"Stage": "Stage 2"
}
]
nse_gsm_list.json
[
{
"Symbol": "EXAMPLE",
"Name": "Example Company Ltd.",
"ISIN": "INE123A01012",
"Stage": "Stage 1"
}
]
Surveillance Stages
ASM (Additional Surveillance Measure)
- Stage 1: Initial surveillance - price volatility, volume spikes
- Stage 2: Enhanced surveillance - continued concerns
- Stage 3: Strictest surveillance - severe concerns
- Long Term: Long-term ASM list
- Short Term: Short-term ASM list
GSM (Graded Surveillance Measure)
- Stage 1: Initial graded surveillance
- Stage 2: Enhanced graded surveillance
- Stage 3+: Higher surveillance stages
Use Cases
- Risk Screening: Filter out high-risk surveillance stocks
- Compliance Checking: Ensure portfolio doesn’t include restricted stocks
- Intraday Trading: ASM stocks have stricter intraday limits
- Position Limits: GSM stocks have position size restrictions
- Circuit Limits: Surveillance stocks often have tighter circuit filters
- ASM List Size: 50-150 stocks (varies)
- GSM List Size: 20-80 stocks (varies)
- Fetch Time: 2-5 seconds per list
- Success Rate: >99% (triple fallback)
- Update Frequency: NSE updates weekly/as needed
Trading Restrictions
Stocks in surveillance lists face:
- Reduced Circuit Limits: 5% or 2% instead of 10%/20%
- Trade-for-Trade (T2T): No intraday allowed
- 100% Margin: Full upfront payment required
- Position Limits: Maximum holding restrictions
- Auction Settlement: Delivery obligations strictly enforced
Error Handling
Primary Source Failure
try:
# Google Sheets Gviz
response = requests.get(gviz_url, timeout=10)
# Process...
except Exception as e:
print(f"Gviz failed: {e}")
# Fall back to secondary source
All Sources Failed
if not success:
print(f"Critical failure: Could not fetch {filename} from any source.")
# No file written
Data Validation
# Skip header rows
if symbol == "Symbol" or not symbol:
continue
# Ensure all fields are strings
cleaned_list.append({
"Symbol": str(symbol),
"Name": str(name),
"ISIN": str(isin),
"Stage": str(stage)
})
Integration Example
# Load surveillance lists
with open("nse_asm_list.json", "r") as f:
asm_list = json.load(f)
with open("nse_gsm_list.json", "r") as f:
gsm_list = json.load(f)
# Create lookup sets
asm_symbols = {stock["Symbol"] for stock in asm_list}
gsm_symbols = {stock["Symbol"] for stock in gsm_list}
# Filter master list
safe_stocks = [
stock for stock in master_list
if stock["Symbol"] not in asm_symbols and stock["Symbol"] not in gsm_symbols
]
Notes
- Surveillance lists change frequently - run daily for accuracy
- Google Sheets is the most reliable source (99%+ uptime)
- Build ID changes with Next.js deployments - extracted dynamically
- Web scraping is slowest but most resilient fallback
- Stage progression: stocks can move up/down or be removed
- Exit from surveillance: stocks meeting criteria for 6+ months may be removed
- ASM is more common than GSM
- Both lists are maintained by NSE and updated on exchange website