0–100 composite score. Max raw ≈ 113 pts → capped at 100 after miss penalty. Cache key: v21
| Sub-component | Condition | Points | Formula |
|---|---|---|---|
| Sales YoY | Sales growth > 0% YoY | 0 – 10 | min(salesYoy, 30) / 30 × 10 |
| 30%+ YoY → full 10 pts | 15% → 5 pts | ≤ 0 → 0 | |||
| Sales QoQ | Sales growth > 0% QoQ | 0 – 5 | min(salesQoq, 20) / 20 × 5 |
| 20%+ QoQ → full 5 pts | Banks: Revenue used when Sales = 0 |
| Sub-component | Condition | Points | Notes |
|---|---|---|---|
| NP YoY (normal) | Prev year base > 0 && NP YoY > 0 | 0 – 8 | min(npYoy, 60) / 60 × 8 |
| NP YoY (turnaround) | Prev year base ≤ 0 && current NP > 0 | 3 | Fixed credit — growth % not used (avoids 2600% inflation) |
| NP QoQ (normal) | Prev quarter base > 0 && NP QoQ > 0 | 0 – 4 | min(npQoq, 30) / 30 × 4 |
| NP QoQ (turnaround) | Prev quarter base ≤ 0 && current NP > 0 | 2 | Fixed credit |
| Sub-component | Condition | Points | Formula / Notes |
|---|---|---|---|
| EBITDA YoY | Prev year OP > 0 && YoY growth > 0 | 0 – 6 | min(ebitdaYoy%, 50) / 50 × 6 |
| EBITDA YoY (turnaround) | Prev year OP ≤ 0 && current OP > 0 | 2 | Fixed credit |
| EBITDA QoQ | Prev quarter OP > 0 && QoQ growth > 0 | 0 – 2 | min(ebitdaQoq%, 20) / 20 × 2 |
| EBITDA QoQ (turnaround) | Prev quarter OP ≤ 0 && current OP > 0 | 1 | Banks: OP = Revenue − Interest (NII proxy) |
| Avg CFOOP (3 yrs) | Points | Meaning |
|---|---|---|
| ≥ 120% | 10 | Excellent — cash far exceeds reported profit |
| ≥ 100% | 8 | Strong — all profit backed by cash |
| ≥ 80% | 6 | Good |
| ≥ 50% | 4 | Acceptable |
| < 50% or missing | 0 | Poor or no data |
| Ratio = avgGrowth / PE | Points | Notes |
|---|---|---|
| ≥ 2.5 | 15 | Deeply undervalued relative to growth |
| ≥ 1.8 | 12 | |
| ≥ 1.2 | 9 | |
| ≥ 0.75 | 7 | |
| ≥ 0.5 | 4 | |
| ≥ 0.25 | 1 | |
| ≥ 0.0 | 0 | |
| < 0 (negative avg growth) | −3 | NP YoY capped at 100% before averaging |
avgGrowth = (min(NP YoY, 100%) + Sales YoY) / 2
| Condition | Points | Metrics checked |
|---|---|---|
| ≥ 4 of 5 metrics positive | 10 | NP YoY, NP QoQ, Sales YoY, Sales QoQ, EBITDA YoY |
| < 4 positive | 0 |
| Beat rate | Points | Example |
|---|---|---|
| 8 / 8 | 20 | 100% beat rate |
| 6 / 8 | 15 | 75% |
| 5 / 8 | 13 | 62.5% |
| 4 / 8 | 10 | 50% |
| 2 / 8 | 5 | 25% |
| 0 / 8 | 0 | Beat = NP YoY > 15%; formula: beatQty / totalQ × 20 |
★ New Quality Signals Edit thresholds in ConcallScan.aspx.cs lines ~431–478
| ROCE % | Points | Signal |
|---|---|---|
| ≥ 25% | 10 | Exceptional capital allocator / moat |
| ≥ 20% | 8 | Strong compounder |
| ≥ 15% | 5 | Good |
| ≥ 10% | 2 | Acceptable |
| < 10% | 0 | Weak or no data |
| D/E ratio | Points | Signal |
|---|---|---|
| = 0 (debt-free) | +5 | Zero financial risk |
| ≤ 0.5 | +3 | Conservatively financed |
| ≤ 1.0 | 0 | Neutral |
| ≤ 2.0 | −3 | Elevated leverage |
| > 2.0 | −8 | High risk — debt servicing may eat profits |
| Condition | Points | Source field |
|---|---|---|
| FII increasing (quarter-on-quarter) | +2 | Instrument.FiiIncreasing |
| Promotor ≥ 50% AND Promotor increasing | +2 | Instrument.PromotorHolding / PromotorIncreasing |
| Neither FII nor DII decreasing | +1 | No smart-money exits this quarter |
| Pledged % | Penalty | Meaning |
|---|---|---|
| ≤ 10% | 0 | Acceptable |
| > 10% | −2 | Minor concern |
| > 30% | −5 | Significant stress |
| > 50% | −10 | Major red flag — lender sell-off risk |
| FCF > 0 in last 3 fiscal years | Points | Signal |
|---|---|---|
| 3 of 3 years positive | 3 | Consistently self-funding |
| 2 of 3 years positive | 2 | Usually positive |
| 1 or 0 of 3 years positive | 0 | Capital-hungry or FCF negative |
| Condition | Effect | Notes |
|---|---|---|
| Miss streak ≥ 2 consecutive quarters | −20 pts | Applied to strengthRaw before cap; floor = 0 |
| Negative avgGrowth (G2PE) | −3 pts | avgGrowth < 0 |
| D/E > 2.0 | −8 pts | Via debtScore |
| Pledge > 50% | −10 pts | Via pledgePenalty |
Stock Screener · Composite Score ScreenerRow.cs · max 20 pts
| Layer | Signal | Points | Source |
|---|---|---|---|
| Institutional | MF Accumulating (positive avg change ≥ 2 of last 3 periods) | +2 | MFHoldingHistory · last 4 months |
| FII Increasing (quarter-on-quarter) | +1 | ShareholdingPattern.FiiIncreasing | |
| DII Increasing | +1 | ShareholdingPattern.DiiIncreasing | |
| Promoter not decreasing | +1 | !PromotorDecreasing | |
| Earnings | Strength ≥ 70 | +3 | StrengthScore.Compute() — see above |
| Strength 50–69 | +2 | ||
| Strength 25–49 | +1 | ||
| Growth ★ | Avg YoY sales growth ≥ 20% across recent quarters | +2 | salesGrowthAvg in ScreenerRow |
| Avg YoY sales growth 12–19% | +1 | avg of YOYSalesGrowthPercentage across resultList | |
| Accelerating — latest 2 qtrs avg > prior 2 qtrs avg by +2 pp | +1 | needs ≥ 4 quarterly results | |
| Guidance | Bullish concall sentiment | +2 | ConcallProjection.Sentiment |
| Strong guidance metrics ≥ 2 | +2 | Improving + Strong direction/strength | |
| Avg concall confidence ≥ 0.8 | +1 | AvgConf across Metrics | |
| Technical | Price above SMA 61 | +1 | Instrument.SMA61 |
| Price above SMA 200 | +1 | Instrument.SMA200 | |
| RSI 50–75 (healthy momentum) | +1 | Instrument.RSI12 |
The Trend column in the screener table and the Fast Mover only layer filter both derive from
GrowthMomentum — a string computed in ScreenerRow.cs using the same
resultList already fetched for earnings quality. No extra DB query.
| Badge | Condition | Score contribution |
|---|---|---|
| ⚡ Fast | salesGrowthAvg ≥ 15% OR (salesGrowthAvg ≥ 10% AND accelerating) | Qualifies for "Fast Mover only" layer filter |
| ▲ Growing | salesGrowthAvg ≥ 8% | — |
| → Stable | salesGrowthAvg ≥ 0% | — |
| ▼ Slowing | salesGrowthAvg < 0% | — |
| — | No quarterly results with sales > 0 | No data |
salesGrowthAvg: average of YOYSalesGrowthPercentage across all Result records where Sales > 0 and growth ≠ 0 (up to 8 quarters).
Accelerating: true when (avg of 2 most-recent quarters' YoY growth) > (avg of next 2 prior quarters) + 2 pp. Requires ≥ 4 data points.
npGrowthAvg: also computed (avg of NetProfitChangePctYOY) and returned in JSON but not shown as a separate column — used by the PEG/Valuation columns below.
Summary pill: "⚡ fast mover" pill in the results bar shows the count of Fast-tier stocks in the current result set.
The Sector field on both pages is a server-rendered <select> (BindSectorDropdown() in each code-behind, populated from Sector.GetAll(SectorIndustryType.Sector)) — not free text. The selected option's value is the sector's numeric ID, sent to data.aspx as sectorId and matched exactly against Instrument.SectorIndustryLink (no substring matching, no name lookup needed).
| Field | Source | Notes |
|---|---|---|
| Pe | Instrument.PE (broker/fundamentals feed) | When the feed value is 0, falls back to LTP / trailing-4Q EPS — EPS summed from quarterly Result.EPSInRs, filtered to ResultPeriod.Quarter and re-sorted to the newest 4 |
| PeEstimated | bool | True when the fallback above was used instead of the feed value — the table shows a * next to PE with an explanatory tooltip |
| Peg | Pe / NpGrowthAvg | 0 (shown as —) when Pe ≤ 0 or NpGrowthAvg ≤ 0 |
| Valuation | derived from Peg | Cheap ≤ 1 · Fair ≤ 1.5 · Expensive > 1.5 · N/A when Peg ≤ 0 |
Wealth Shortlist · Verdict Tiers WealthShortlist.aspx · ScreenerRow.Verdict()
| Verdict | Condition | Notes |
|---|---|---|
| ★ Strong | Score ≥ 12 AND NpGrowthAvg > 0 AND De ≤ 1.5 AND Valuation ≠ Expensive | All four conditions must hold |
| Watch | Score ≥ 8 | Doesn't clear the Strong bar |
| weak (filtered out) | Score < 8 | Excluded entirely under the page's default Min Score filter (8+) |
Differences from the Stock Screener defaults: Min Score starts at 8+ (vs. Screener's "Any"), and the Universe toggle defaults to All equities (fnoOnly=false) rather than F&O-only, since F&O eligibility is a liquidity/derivatives signal, not a quality one.
Column Reference how each display column is computed
OPM% has a different meaning depending on the company type. The column always shows the closest structural equivalent to "how much of each revenue rupee survives after the core cost of doing business."
| Company type | Formula shown | Why |
|---|---|---|
| Non-financial FMCG, IT, Pharma, Auto… |
OPMPercentage from DB(stored by the result scraper) |
Traditional operating margin: Sales − Raw Material − Employee − Other Expenses = OP; OPM% = OP / Sales × 100 |
| Bank / NBFC ICICIBANK, HDFCBANK… |
(Revenue − Interest) / Revenue × 100NII Margin, computed on-the-fly |
Banks have no "Sales". Their product is money; cost of product = interest paid on deposits. Net Interest Income (NII) is structurally identical to Gross Profit for a manufacturer. |
| Insurance ICICIPRULI, SBILIFE… |
OPMPercentage from DB(may be negative in high-claims quarters) |
Insurance OPM is volatile — large claims in one quarter can flip the margin negative. Negative values are shown in red; zero is shown as —. |
Why not use stored FinancingMarginPercentage for banks?
The scraper stores FinancingProfit = Revenue − Interest − Operating Expenses (and sometimes provisions).
For banks with high provisions or opex, this figure can turn negative even when the bank is
highly profitable (e.g. ICICIBANK FY26 Q4: stored FinancingMarginPercentage = −29%,
actual NP = ₹15,681 Cr). The on-the-fly NII% is always positive for a solvent bank
and is directly comparable across all banks.
Code reference:
ConcallScan.aspx.cs → CalcOpm(Result r)
— priority: OPMPercentage (if non-zero) → FinancingMarginPercentage (if > 0) → (Revenue − Interest) / Revenue × 100 (if Sales = 0 and Revenue > 0).