market-breadth
Market-wide breadth for Indian equities: how many NSE/BSE stocks are actually joining the index's move. From a folder of stock CSVs (NIFTY 50/500, midcap or smallcap constituents), a yfinance symbol l
SKILL.mdskills/market-breadth/SKILL.md
GitHubMarket Breadth (India)
The index tells you where a few large weights went. Breadth tells you what the typical stock did. A NIFTY high made by five heavyweights while most stocks slide is a weaker market than the chart shows.
1. Run it
python3 scripts/breadth.py status --csv-dir nifty500/ --benchmark-csv "NIFTY 50.csv" --members ind_nifty500list.csv
python3 scripts/breadth.py status --csv-dir nifty500/ --universe-file ind_nifty50list.csv --benchmark-csv nifty.csv
python3 scripts/breadth.py status --ad-csv nse_adv_dec.csv # exchange counts, no stock files
python3 scripts/breadth.py status --universe-file ind_nifty500list.csv --save-dir nifty500/ # yfinance
python3 scripts/breadth.py history --csv-dir nifty500/ --sessions 60 --out breadth.csv --json
Stock CSVs are daily OHLCV, one per stock, file stem = symbol (RELIANCE.csv, .NS is stripped),
from ../technical-analysis/scripts/ta.py fetch, a broker export, or --save-dir (caches the Yahoo
download: ~500 requests for NIFTY 500). Rows with blank or null prices are skipped. --pattern
filters the folder; --universe-file restricts it to a constituent list, so one NIFTY 500 folder
gives NIFTY 50, NIFTY 500 and midcap breadth. --members (symbol,sector, or the Industry column of a
niftyindices list) adds sector participation. Also: --as-of DATE (replay), --hl-window 252,
--div-window 20, --div-min-pct 1.0, --benchmark NAME (yfinance; NIFTY by default when fetching).
2. Getting the data
- Constituents: niftyindices.com, each index page, "Index Constituent" CSV (for example
ind_nifty500list.csv, with Company Name, Industry and Symbol columns). Pass it straight to--universe-fileor--members. - Exchange-wide A/D (
--ad-csv): NSE and BSE show daily advances, declines and unchanged counts, and 52-week high/low lists, on their market-data pages. nseindia.com blocks scripts, so copy the numbers by hand or find them with WebSearch in market-wrap reports, citing the source. Columns:Date,Advances,Declines[,Unchanged,New 52W Highs,New 52W Lows,NIFTY 50]. Any case or spacing works, and the index column feeds the divergence check. This mode gives A/D, McClellan, thrust and highs/lows but no DMA participation (that needs per-stock prices).
3. What it measures
| Metric | Definition in breadth.py |
|---|---|
| % above 20/50/200 DMA | Stocks with close > N-day SMA ÷ stocks with ≥ N bars. Change over 5 and 20 sessions in points |
| Uptrend ratio | % of stocks with close > 50 DMA > 200 DMA (stocks with ≥ 200 bars) |
| Advance / decline | Close vs that stock's previous close; equal = unchanged. A/D line = running sum of A − D (read its slope, not its level) |
| Divergence | Over --div-window sessions: index up ≥ 1% while the A/D line falls = bearish; index down ≥ 1% while it rises = bullish |
| New 52w highs/lows | Today's high above every high of the prior 251 sessions (lows mirrored). Only stocks with 252 bars count |
| McClellan | RANA = 1000 × (A − D)/(A + D). Oscillator = EMA19(RANA) − EMA39(RANA) (smoothing 0.10/0.05, SMA-seeded). Summation = running sum of the oscillator from the first value |
| Breadth thrust | 10-session EMA of A/(A + D) closes above 0.615 having been below 0.40 within the previous 10 sessions (Zweig's thresholds). "Armed" = below 0.40 recently, window still open |
| Sector participation | A sector participates when ≥ 50% of its members are above their 50 DMA |
| Circuit suspects | Zero-range bar (high = low) with a move ≥ 1.9%: probably locked at a price band |
Ratio adjustment lets a 50-stock list and exchange-wide counts share one McClellan scale. The summation level depends on where the data starts, so read its direction and zero crossings.
4. Health score (0–100)
| Component | Weight | Scaling |
|---|---|---|
| Participation | 25 | 0.2 × %>20 DMA + 0.4 × %>50 DMA + 0.4 × %>200 DMA |
| Uptrend ratio | 15 | 10% → 0, 60% → 100 |
| Participation trend | 10 | 20-session change in %>50 DMA: −25 pts → 0, +25 → 100 |
| A/D line | 15 | 20-session (A − D)/(A + D): −0.25 → 0, +0.25 → 100 |
| McClellan | 10 | oscillator −100 → 0, +100 → 100 |
| Highs vs lows | 15 | 10-session new highs ÷ (highs + lows); none of either = 50 |
| Sectors | 10 | % of sectors participating |
Missing components (no members, short history, --ad-csv) are dropped and the rest re-weighted.
"Coverage" shows how much weight was scored, and under 50% the read is A/D-only. Labels: 75+ Broad
participation, 60–74 Healthy, 40–59 Mixed, 25–39 Narrow / weak, below 25 Very weak. The scalings
are judgement calls, not fitted values, so compare a universe with its own history (history).
5. Reading breadth in India
- Index vs broad market. The top six names (HDFC Bank, ICICI Bank, Reliance, Infosys, Bharti Airtel, L&T) are about 40% of NIFTY 50, so heavyweight-led rallies are common (2018: smallcaps fell hard while NIFTY made highs). Run one folder three ways: NIFTY 50, NIFTY 500, midcap/smallcap lists. NIFTY near highs with NIFTY 500 %>50 DMA under 40% and falling, or a bearish A/D divergence, is a narrowing market; the script flags an index above its 50 DMA with under 40% of stocks above theirs.
- Survivorship bias. Today's constituent list omits stocks dropped after falling and includes
ones added after rallying, so past breadth looks stronger than it was. Treat long
historyas rough. - Circuit-locked stocks. A stock frozen at its 5/10/20% band counts as an advance or decline but nobody could trade it. Clusters of lower circuits in SME, ASM/GSM or small names exaggerate declines, so check the circuit-suspect line before reading a washout.
- F&O ban names (open interest above 95% of the market-wide limit) still trade in cash and stay in the counts. Their sharp moves are stock events, not breadth.
- How many stocks. Each stock is 100/N points: 2 points in NIFTY 50, 0.2 in NIFTY 500. Use 100+
for stable percentages and 200–500 for McClellan and thrust, or use
--ad-csvexchange counts. Ten stocks give a sketch, not a signal.
6. How other skills use this
market-regimesets the exposure ceiling; breadth adjusts within it. Confirmed uptrend with a score under 40 or a bearish divergence: act one notch lower (fewer, smaller new positions). In a Correction or Rally attempt, count a thrust as supporting evidence for a follow-through day. Score 60+ with %>50 DMA rising backs the uptrend.market-pulse: the "Breadth" line quotes exchange A/D for the day, NIFTY 500 %>50/200 DMA, the score and label, and any divergence or thrust. Don't infer breadth from index points.india-market-analyst: put the breadth label next to the regime in the context line. In a narrow market, prefer leaders in participating sectors and cut size in small caps.breakout-planner: in a narrow tape (under 40% above the 50 DMA) demand stronger relative strength.sector-rotationhas per-sector member breadth (itsbreadthsub-command); this is the market view.
Caveats
- Stale or suspended stocks (no bar on the last date) are excluded and listed. Use split-adjusted daily bars after 15:30 IST: a raw split looks like a crash, a partial day distorts A/D.
- Thresholds (0.40/0.615 thrust, 19/39 McClellan, 52-week window) are US-born conventions applied to
Indian data. Replay past turns with
--as-of(Mar 2020, mid-2022, early 2025) before you rely on them.
Output
Breadth: [universe, N stocks / exchange A/D] to [date] | score s/100 [label] (coverage c%)
%>20/50/200 DMA a/b/c (20-session change) | uptrend u% | A/D adv/dec, 20s net, divergence [flag]
NH/NL today and 10s | McClellan osc, summation trend | thrust [state] | sectors k/m participating
Read: [one line] | Regime fit: [how it shifts the market-regime exposure ceiling]
Educational analysis, not investment advice. Data: [sources + timestamps].