Overview
The Circuit Stocks API retrieves lists of stocks that have hit upper or lower circuit limits during the trading day. It uses a triple-fallback strategy: Dhan ScanX Analytics API (primary), Next.js API (secondary), and web scraping (tertiary) for maximum reliability.
Source File: fetch_circuit_stocks.py
Endpoint Details
Primary Source: ScanX Analytics API
https://ow-scanx-analytics.dhan.co/customscan/fetchdt
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}/
Configuration
Upper Circuit
LiveData.UpperCircuitBreak
"1" (stocks at upper circuit)
https://dhan.co/stocks/market/shares-with-upper-circuit/
upper_circuit_stocks.json
Lower Circuit
LiveData.LowerCircuitBreak
"1" (stocks at lower circuit)
https://dhan.co/stocks/market/lower-circuit-stocks/
lower_circuit_stocks.json
{
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
"Content-Type": "application/json"
}
Request Payload (Primary API)
Maximum results to return
Filter parameters including circuit flag
Example Payload (Upper Circuit)
{
"data": {
"sort": "Mcap",
"sorder": "desc",
"count": 500,
"fields": [
"Sym", "DispSym", "Ltp", "PPerchange", "Mcap", "Volume",
"High5yr", "Low1Yr", "High1Yr", "Pe", "Pb", "DivYeild"
],
"params": [
{"field": "LiveData.UpperCircuitBreak", "op": "", "val": "1"},
{"field": "OgInst", "op": "", "val": "ES"},
{"field": "Seg", "op": "", "val": "E"}
],
"pgno": 1
}
}
Example Payload (Lower Circuit)
{
"data": {
"sort": "Mcap",
"sorder": "desc",
"count": 500,
"fields": [
"Sym", "DispSym", "Ltp", "PPerchange", "Mcap", "Volume",
"High5yr", "Low1Yr", "High1Yr", "Pe", "Pb", "DivYeild"
],
"params": [
{"field": "LiveData.LowerCircuitBreak", "op": "", "val": "1"},
{"field": "OgInst", "op": "", "val": "ES"},
{"field": "Seg", "op": "", "val": "E"}
],
"pgno": 1
}
}
Example Request
curl -X POST https://ow-scanx-analytics.dhan.co/customscan/fetchdt \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0" \
-d '{
"data": {
"sort": "Mcap",
"sorder": "desc",
"count": 500,
"fields": ["Sym", "DispSym", "Ltp", "PPerchange", "Mcap", "Volume"],
"params": [
{"field": "LiveData.UpperCircuitBreak", "op": "", "val": "1"},
{"field": "OgInst", "op": "", "val": "ES"},
{"field": "Seg", "op": "", "val": "E"}
],
"pgno": 1
}
}'
Response Structure
Array of stock objects at circuit limits
Stock Object Fields
Percentage change from previous close
Example Response
{
"data": [
{
"Sym": "EXAMPLE",
"DispSym": "Example Company Ltd.",
"Ltp": 550.0,
"PPerchange": 20.0,
"Mcap": 25000.0,
"Volume": 1500000,
"High5yr": 600.0,
"High1Yr": 580.0,
"Low1Yr": 350.0,
"Pe": 25.5,
"Pb": 3.2,
"DivYeild": 1.5
}
]
}
Implementation Details
Triple-Fallback Strategy
import requests
import json
import re
from bs4 import BeautifulSoup
api_url = "https://ow-scanx-analytics.dhan.co/customscan/fetchdt"
scans_config = {
"upper_circuit_stocks.json": {
"val": "1",
"field": "LiveData.UpperCircuitBreak",
"web_key": "stocks/market/shares-with-upper-circuit",
"web_url": "https://dhan.co/stocks/market/shares-with-upper-circuit/"
},
"lower_circuit_stocks.json": {
"val": "1",
"field": "LiveData.LowerCircuitBreak",
"web_key": "stocks/market/lower-circuit-stocks",
"web_url": "https://dhan.co/stocks/market/lower-circuit-stocks/"
}
}
build_id = get_build_id()
for filename, config in scans_config.items():
cleaned_list = []
success = False
# Attempt 1: ScanX Analytics API
try:
payload = {
"data": {
"sort": "Mcap", "sorder": "desc", "count": 500,
"fields": ["Sym", "DispSym", "Ltp", "PPerchange", "Mcap", "Volume",
"High5yr", "Low1Yr", "High1Yr", "Pe", "Pb", "DivYeild"],
"params": [
{"field": config['field'], "op": "", "val": config['val']},
{"field": "OgInst", "op": "", "val": "ES"},
{"field": "Seg", "op": "", "val": "E"}
],
"pgno": 1
}
}
response = requests.post(api_url, json=payload, headers=headers, timeout=10)
if response.status_code == 200:
stocks = response.json().get('data', [])
for item in stocks:
cleaned_list.append({
"Symbol": item.get('Sym'),
"Name": item.get('DispSym'),
"LTP": item.get('Ltp'),
"ChangePercent": item.get('PPerchange'),
"MarketCap": item.get('Mcap'),
"Volume": item.get('Volume'),
"High5Yr": item.get('High5yr'),
"High1Yr": item.get('High1Yr'),
"Low1Yr": item.get('Low1Yr'),
"PE": item.get('Pe'),
"PB": item.get('Pb'),
"DivYield": item.get('DivYeild')
})
success = True
except Exception as e:
print(f"ScanX API Failed: {e}")
# Attempt 2: Next.js API (if primary failed)
# Attempt 3: Web scraping (if both failed)
if success:
with open(filename, "w") as f:
json.dump(cleaned_list, f, indent=4)
Output Structure
upper_circuit_stocks.json
[
{
"Symbol": "EXAMPLE",
"Name": "Example Company Ltd.",
"LTP": 550.0,
"ChangePercent": 20.0,
"MarketCap": 25000.0,
"Volume": 1500000,
"High5Yr": 600.0,
"High1Yr": 580.0,
"Low1Yr": 350.0,
"PE": 25.5,
"PB": 3.2,
"DivYield": 1.5
}
]
lower_circuit_stocks.json
[
{
"Symbol": "DOWNSTOCK",
"Name": "Downtrend Company Ltd.",
"LTP": 80.0,
"ChangePercent": -20.0,
"MarketCap": 5000.0,
"Volume": 2000000,
"High5Yr": 250.0,
"High1Yr": 150.0,
"Low1Yr": 75.0,
"PE": 8.5,
"PB": 0.9,
"DivYield": 0.0
}
]
Circuit Limit Rules
Standard Stocks
- Upper Circuit: +20% from previous close
- Lower Circuit: -20% from previous close
Surveillance/Special Stocks
- Upper/Lower: ±10%, ±5%, or ±2% (varies by category)
Newly Listed Stocks
- First Day: No upper circuit (but lower circuit applies)
- Subsequent Days: Standard limits apply
Use Cases
- Momentum Trading: Identify stocks with extreme buying/selling pressure
- Breakout Detection: Upper circuit stocks showing strong breakouts
- Panic Selling: Lower circuit stocks in distress
- Volume Analysis: Circuit stocks with high volume indicate conviction
- Risk Management: Avoid entering positions in circuit-locked stocks
- News Correlation: Cross-reference with news API for circuit triggers
- Upper Circuit Count: 10-50 stocks (typical trading day)
- Lower Circuit Count: 5-30 stocks (typical trading day)
- Fetch Time: 2-5 seconds per list
- Success Rate: >99% (triple fallback)
- Update Frequency: Real-time during market hours
Circuit Analysis
Strong Momentum (Upper Circuit)
# High volume + upper circuit = strong momentum
strong_momentum = [
stock for stock in upper_circuit
if stock["Volume"] > 1000000 and stock["ChangePercent"] >= 20
]
Near 52-Week High
# Upper circuit near 1-year high = breakout
breakout_candidates = [
stock for stock in upper_circuit
if stock["LTP"] >= stock["High1Yr"] * 0.95
]
Oversold Bounce (Lower Circuit)
# Lower circuit with low P/B = potential value
value_plays = [
stock for stock in lower_circuit
if stock["PB"] < 1.0 and stock["PE"] > 0
]
Trading Considerations
Upper Circuit
- Buying: Difficult or impossible (no sellers)
- Selling: Easy (strong demand)
- Next Day: Often opens gap up and continues higher
- Risk: FOMO-driven, potential reversal
Lower Circuit
- Selling: Difficult or impossible (no buyers)
- Buying: Risky (catching falling knife)
- Next Day: Often opens gap down and continues lower
- Risk: Further decline, liquidity issues
Integration Example
# Load circuit stocks
with open("upper_circuit_stocks.json", "r") as f:
upper_circuit = json.load(f)
with open("lower_circuit_stocks.json", "r") as f:
lower_circuit = json.load(f)
# Combine for analysis
circuit_symbols = set(
[s["Symbol"] for s in upper_circuit] +
[s["Symbol"] for s in lower_circuit]
)
# Filter watchlist
watchlist_safe = [
stock for stock in watchlist
if stock["Symbol"] not in circuit_symbols
]
Error Handling
try:
response = requests.post(api_url, json=payload, headers=headers, timeout=10)
if response.status_code == 200:
stocks = response.json().get('data', [])
# Process stocks
else:
print(f"HTTP Error: {response.status_code}")
except Exception as e:
print(f"ScanX API Failed: {e}")
# Fall back to Next.js API or web scraping
Notes
- Circuit data is only relevant during market hours (9:15 AM - 3:30 PM IST)
- Post-market, circuit flags reset for next trading day
- Some stocks may hit circuit multiple days in a row
- Circuit limits are based on previous day’s closing price
- Stocks can lock at circuit with zero trades (all buyers/sellers)
- Run during market hours for real-time circuit monitoring
- Small caps more likely to hit circuits than large caps
- Corporate actions (bonus, split) affect circuit calculation on ex-date