# 💰 Valuations ++ v6.5 — Scenario Tiers (filed guidance on the chart)
_Built 02-Aug-2026. The website's own scenario levels reach the chart. The scenario table now states its source; covered names draw the filed-guidance levels and the guided-vs-filed pace bar in-pane. The data travels as a Pine library (`umsibaba/PrimaegisScenarios/1`) because Pine cannot fetch a URL — no HTTP in v5 or v6, and `request.seed()` reads only TradingView-onboarded repos._

## 🏛️ The tier system — stated, never silently substituted

| Tier | Source | Cost | When |
|---|---|---|---|
| **T1** | `PrimaegisScenarios` library — bear/base/bull from filed-transcript growth × the company's own long-run exit band, delivery-calibrated haircuts. 192 NSE names, dated snapshot. | zero `request.*` | symbol covered |
| **T2** | Street target low/avg/high via `syminfo.target_price_*` built-ins | zero `request.*` | targets exist — **thin on NSE mid-caps** (screener-verified ~half of a 40-name sample, often 1 analyst), so the estimate count always shows |
| **T3** | The V++ engine, unchanged | as before | always |

The scenario-table header reads `SCENARIOS 📐 / T1 · filed guidance · 📸 2026-08-02` (or T2/T3). Request budget untouched: **37/40**.

## ✨ What draws on a covered name

- **🏛️ Filed row** in the scenario table — bear/base/bull at their **target FY** (cells self-label; tooltip says they do NOT belong to the 1/2/3-year grid), exit multiple, guided %/yr, composite score, `PS.disclaimer()`.
- **🎯 Street row** — target low/avg/high + estimate count (`6 est` on MTAR, matching the screener).
- **Three level lines** in the pane, house Levels-Style machinery, labels like `🏛️ BASE 6562.31 · FY27 · 87.2x (+14.6%)`, x-offsets +25/+31/+37 continuing the stagger.
- **Pace gauge** (own position input, default Bottom Center): 26-cell track spanning 0–130% of the guided rate so 100% lands at 77% of width; band colours; **spectrum fill over 105%** (over-delivery should look rare); 55% opacity while `provisional`; `pace()` na ⇒ nothing drawn. Caption carries guided → filed (nq) · band · 📸 build date.
- Validated on-chart 02-Aug: MTARTECH (T1, spectrum pace 80→129.9), KRISHANA (T3 stated, nothing fabricated).

## 🖥️ Display masters — the two-monitor workflow

New `🖥️ Display` group: **Valuation level lines + labels**, **All tables**, and **Band plots, zones & extras** as three independent master switches, plus a dedicated **Under/overvalued shaded zones** toggle. One pane fully dressed, the other stripped to the dashed level lines alone — the level lines are now independent of "Show Fair Value Bands". And because the level lines/labels are `line.new`/`label.new` drawings — which **never surface in the Style tab** — their appearance controls now live in `📏 Levels Style`: per-level colour pickers (Low/Fair/High/EV1Y + the three 🏛️ levels) and a **Pointer / Plain text / None** label-appearance selector. The zone fills keep their Style-tab entries (bottom of the list) and gain the input toggle.

## 🐛 CE10295 on first compile

v6.4 was already near the main-body ceiling; the additions tipped it. Fix per the IN Analytics pattern (expression weight, not line count): `f_scn_tier_rows()`, `f_fv_levels()` (existing block), `f_ps_levels()`, `f_pace_gauge()` — functions get their own scope budget; guards inside, vars localized, no history offsets so the conditional-call trap does not apply.

## 📚 The library itself

`scripts/pine_scenarios.py` generator fixes: switch cases must be single-line (`"SYM" => …` — the two-line form hits CE10001/CE10156, continuation may not sit at a multiple of 4), and `get()`/`pace()` now return the `switch` directly — the old `Scenario s = na` + bare switch discarded every branch and returned na for **everything**. Disclaimer emitted on one line (same continuation rule).

**Refresh flow**: `make valuation` → `python3 scripts/pine_scenarios.py` → paste-publish a new library version → bump the `import umsibaba/PrimaegisScenarios/N` line in V++ and republish. The import pin means a library republish alone does NOT move the chart.

**/2 (02-Aug afternoon): 197 levels + 71 paces.** Two structural fixes: (1) **pace decoupled from `publishable`** — the guided-vs-filed comparison never touches the earnings base, so names whose levels are withheld (low-confidence bridge, stale base) still carry their pace card; (2) **eps_history column-filter fix** — a "Mar 2018 3m" stub or legacy Dec fiscal years no longer disqualify a whole annual table (KPIT was rejected over one stub label), which freshened 8 bases and promoted 5 names to full levels (SANOFI, SHREDIGCEM, SPLPETRO, SUPREMEIND, IRISDOREME). Names still on a December year-end (CRISIL) or under 4 clean March years (ACC, Ambuja post-migration) stay out honestly. The scenario board at primaegis.com shows the same 197.

---

# 💰 Valuations ++ v6.4 — Evidence Scalers
_Built 01-Aug-2026, answering "won't track-record dampening miss turnarounds?" All four additions are realized-data; nothing price-derived ever touches the growth forecast._

## ✨ The guidance weight now sees the tape

| Scaler | Trigger | Effect |
|---|---|---|
| **Congruence** | Guided growth at/below the realized run-rate (ratio = realized ÷ guided) | Up to **2.2×** weight — a guide the tape already corroborates is trend extrapolation, not a cold promise. Guides far above the run-rate keep full backtested skepticism. |
| **EPS-inflection reinforcement** | Delivered earnings accelerating (Q-Δ > +10pp) / decelerating | ×1.25 / ×0.85 on the congruence case only |
| **Beat-record proxy credibility** | Guided-pair ledger empty AND ≥3 tracked quarters vs street | Beat multiplier stands in for "unknown" credibility, capped 1.15; the real ledger takes over as pairs form |
| **PE-ROC stationarity trust** | \|6M re-rating\| beyond ±30% (blended mode) | Cuts the PE method's **vote** up to −50% — price evidence reduces trust in stale multiple history; it never feeds the forecast. Other legs renormalise. |

Combined evidence scaler capped at 2.5×; the 0.45 guidance-weight cap still rules everything. Disclosure: the Fwd/source tooltip prints `evidence ×2.03: congr 1.52 · infl 1.25 · beat-proxy 1.07`; the weights tag adds `[PE trust 74%]`. **MTAR walk-through**: 8% → ~17% blend weight (guided +143% vs realized TTM +125%, accelerating, 75% beat record) — the band's forward EPS moves from −3% to ~+11% growth, and the verdict still reads its own evidence.

## 🐛 Fixes

- **Auto classifier unit bug**: `EARNINGS_PER_SHARE_BASIC_ONE_YEAR_GROWTH` returns PERCENT but the class thresholds are ratios — ">0.40" read as ">0.4%", so essentially every profitable grower typed Hyper Growth since the Auto port. Normalised; thresholds now mean what they say. Auto/Blended-mode weights will visibly change on mis-typed names.
- **Earnings Quality row was misread by design**: it showed FCF ÷ NI alone. MTAR: FCF/NI 0.09× *with CFO/NI ~2.0×* (screener-verified: FY26 CFO ₹192cr vs PAT ₹95cr) — a capacity build-out eating cash, NOT poor accrual quality. The row now shows both: `🟢 CFO 1.42x · FCF 0.09x`, colored by CFO/NI (the accrual-quality verdict), with FCF/NI as capex context. One new `request.financial` (36 of 40).

---

# 💰 Valuations ++ v6.2 → v6.3 — AT A GLANCE (final, 01-Aug-2026)
_The finished shape of the release, consolidated. Detail in the entries below._

- **The guidance layer** — management guidance from 850+ NSE earnings-call transcripts (mainboard + Emerge SME) built into the indicator: what was guided, what was delivered, a credibility score per management. Ships as two private Pine libraries (`PrimaegisGuidance` **/6**, `PrimaegisGuidanceText` **/2**).
- **Guidance in the FAIR-VALUE BANDS** (default ON) — where usable guidance exists, the PE leg's forward EPS and the PS leg's revenue re-base on the evidence-weighted analyst⊕guidance blend (backtested identity weight × credibility × call-date freshness, cap 0.45). Basis disclosed on the band tooltip, the 🎯 Fair label, and the estimates EPS row. Toggle OFF / no guidance / TTM-anchor = exact v5.2 basis.
- **Scenario engine** — blend shifts the base case, disagreement widens the cone (capped +20pp), the bull leg extends toward credible aggressive guides.
- **Data-quality wave** — forward-gate calendar-drift fix (results recaps can no longer wear the guidance label), revision supersession ("raising from 50% to 80%" reads 80), score-gated acceptance of large-but-explicit arithmetic, call-date age policy. 641 names usable at full fidelity.
- **🔗 Bridge export for IN Analytics** — the composite fair value publishes as `🔗 Fair Value (bridge export)`. In IN Analytics: *Fundamental Factors → External fair value (point at Valuations++) → pick the 🔗 Fair Value (bridge export) plot of Valuations ++ → tick "Use external fair value"*. **Manual, per chart layout** — TradingView cannot auto-wire source inputs. Point at the 🔗 plot, not 🎯.
- **v6.3: Valuation Preset → `Auto (Blended)` (new default, published 01-Aug)** — no manual judgment: the company-type classifier and the industry map are blended by *classification confidence* (how decisively the company's own data types it away from its sector, scaled by history depth; Lender/Loss-making are definitional), then the empirical CV weights fade in continuously with sample depth — up to 65% say at deep history. Disclosed live: Profile cell reads `Hyper Growth⊕Aerospace α78`, weights tag reads `[CV 43%]`. Legacy presets (`Industry Default`, `Auto (Company Type)`, the four fixed profiles) are byte-identical for saved charts.

---

# 💰 Valuations ++ v6.2 (second wave) — Data-Quality Release (libraries /6 + Text/2)
_Shipped 01-Aug-2026, hours after the first v6.2 wave — the TradingView build keeps the single label **v6.2**, which covers both waves._ _Originally drafted as "v6.3"; consolidated per the published version. Started as "is 0.5 weight for last-FY guidance right?" and ended as a pollution cleanup: the forward gate had calendar drift._

## 🐛 The forward-gate leak

`\bFY2[6-9]\b` was a FUTURE marker — written when FY26 was the future. Once FY26 closed, every "During FY26, EBITDA margin stood at 9.52% as compared to…" results recap auto-passed the guidance gate on its year token; "as compared to / against / registering / ended" weren't past markers at all. **83 delivered numbers were wearing the guidance label.** Fixed: year tokens only count as forward evidence when STRICTLY ahead of the build date's FY (threaded through the extractors); the missing past markers added. Regression vs shipped: 665 names byte-identical, **22 recap-polluted names correctly dropped**, 18 re-sourced to cleaner forward passages, 3 gained. All validation anchors held (MTAR +143%, INOXWIND +119%, TVS +10%, J&K +20.6% — J&K's period self-corrected FY26→FY27 with the cleaner passage selection).

## ⚖️ Age policy rebuilt (the original question — both instincts were right)

The old Pine-side buckets keyed age off the GUIDED YEAR: last-FY 0.50, no-year 0.70. Measured reality: 195 of 234 "last-FY" names were *recent* calls whose FY26 tag came from recap context, and undated guidance in a fresh call is forward-looking by construction. New policy, computed at library build time from the CALL DATE and folded into `gd.weight`:
- **Freshness**: ≤200d → 1.00 · ≤400d → 0.75 · ≤730d → 0.40 · older → 0.
- **Period validity**: guided FY current/forward → ×1.0 · just-closed FY → ×0.75 (rates persist; timelines slip — was 0.50) · closed 2+ FYs → 0.
- **No fiscal year stated → no penalty** (was a flat 0.70); freshness alone governs.
- Pine keeps only the terminal kill (guided year closed 2+ FYs at chart time), so a stale library degrades safely. Priors on the right variables — calibrate against realisation pairs at the quarterly refresh.

Net: 641 names usable at full fidelity, 45 age-zeroed at build. Undated-fresh names (e.g. TVSMOTOR) gained ~43% effective weight; genuinely stale statements lost.

## 📎 For the quarterly refresh

Ordinary-sized numbers from weak passages (analyst-echo, hedged asides) still enter at low identity weight by the deliberate "rank, don't discard" design — consider score-weighting confidence once realisation pairs deepen (GPTHEALTH/BLS class).

---

# 💰 Valuations ++ v6.2 — Guidance in the Bands
_Published 01-Aug-2026 (update to the private invite-only script). The fair-value band itself now runs on the guidance blend — not just the scenario engine._

## ⚠️ Behavior change

| Change | Old | New | Why it matters |
|---|---|---|---|
| Band forward EPS (PE leg) | Analyst FY estimate (`eps_estimate_fy`), guidance never touched it | Where usable guidance exists: forward EPS re-based on the analyst⊕guidance blend via the same identity the YoY calc uses (`est = ttm + \|ttm\|·g`), same weight chain as scenarios (backtested identity weight × credibility × age, cap 0.45). At weight→0 the tilted figure equals the analyst estimate to the paisa. | Covered names' low/median/high fair levels move by the disclosed guidance delta. SMEs with guidance but no analyst coverage get a real forward EPS in the band instead of trailing. |
| Band sales driver (PS leg) | Trailing revenue per share, always | Forward revenue per share (analyst sales growth ⊕ guided growth) — ONLY when guidance is usable; uncovered names keep the trailing basis | PS-weighted covered names re-band on what management says the top line will do. |
| PB / EV legs | Evidence-anchored | Unchanged — no clean guided BVPS/EBITDA identity; lenders still get guidance in scenarios via the ROA bridge | The tilt never reaches a leg it can't ground in an accounting identity. |
| Band growth clamping | n/a | `g_compress()` softening only — NOT the industry corridor (that guards multi-year compounding; the band is a 1-year basis) | An accepted analyst number is never suddenly corridor-clipped just because guidance showed up. |

## ⚙️ New input

`Guidance in fair-value bands (v6.2)` — 🔭 Scenario Panel group, **default ON**. OFF, no-usable-guidance, or `Anchor bands to TTM EPS` (an explicit trailing choice outranks the tilt) all reproduce the v5.2 basis exactly.

## 🐛 Data-engine fixes shipped with v6.2 (library → /5)

- **Revision supersession (the MTAR bug):** "raising our guidance for FY'27 from 50% revenue growth to 80% plus" parsed as +50% — the SUPERSEDED number — because first-mention-wins stored the FROM figure. The extractor now rewrites from-X%-to-Y% idioms to the TO figure, gated on a revision-verb + guidance-noun cue so historical "NIM expanded from 5.6% to 9.4%" statements and "maintain a margin from 4.5% to 5%" ranges can't trigger it. MTAR FY27 now reads rev +80%.
- **Score-gated oversize acceptance:** the flat ±100% implausibility cap threw away explicit guidance whose arithmetic is simply large — MTAR's 80% revenue × 24% EBITDA margin off a 17.8% base IS +143%. The gate now accepts results up to ±250% when the bridge is one of the two fully-explicit identities (PAT guided directly; revenue × margin) AND every input's passage is strongly management-voiced (min score ≥ 6). Analyst-voiced numbers (TARSONS +135%, score 2) and weakly-attributed legs (ICEMAKE margin, score 0) stay gated; the unattributed path, which has no attribution, keeps the strict cap. Regression: exactly 2 of 1,353 names changed (MTARTECH +143% @ 0.08 weight, INOXWIND +119%), zero lost.

## 🔎 Disclosure (three places)

Band-column tooltip gains `Basis: …` (tilted @weight, EPS fwd %, Sales fwd % — or which fallback applied) · the 🎯 Fair level label carries the same on hover · estimates EPS-row tooltip gains a `Bands:` line. Internals: the analyst⊕guidance blend block was hoisted above FAIR VALUES so the bands can consume it; scenario semantics unchanged.

---

# 💰 Valuations ++ v6 — The Guidance Layer
_Published 31-Jul-2026 (invite-only, private). The first release where the panel knows what management PROMISED — not just what the price and the analysts did. Ships with two companion Pine libraries: `PrimaegisGuidance` v4 (data + accessors) and `PrimaegisGuidanceText` v1 (full statements), both private publications under umsibaba. Imports: `/4` + `Text/1`._

## ⚠️ Behavior changes (read before trusting old readings)

| Change | Old | New | Why it matters |
|---|---|---|---|
| Scenario base growth (PE leg) | Single analyst fwd-EPS number; hardcoded 10% when no coverage | Evidence-weighted blend of analyst consensus and management guidance. Weight = backtested per-identity figure (0.08–0.45) × credibility × age; guidance-only when no analyst exists | Covered names' base cases shift by the disclosed blend. SMEs with zero coverage now run on management's stated number instead of a placeholder constant. |
| Driver legs (PS/EV sales anchor, PB retention×ROE) | Realised-data anchors only — guidance never reached them | Guidance blended in at `min(cap, w_raw)` — never the guidance-only branch, since the realised anchor always exists | PS/PB/EV-primary covered names move. Names whose driver source already saturates the sector corridor show no change (J&K: base pinned at the 30% bank ceiling pre- and post-blend). |
| Scenario spread | Vol/sector derived | + up to 20pp widening when guided and analyst growth materially disagree | A 42.6pp guided-vs-street gap (J&K) now widens the cone to the 70% max instead of being averaged away. Disagreement IS the information. |
| Bull leg | Corridor-capped symmetric spread | Extends toward the guided rate (sanity cap +100%), proportional to weight — driver-aware | Backtested: a >45% guide doubles the odds of a >45% outcome (34% vs 16% base rate). AKIKO bull 1Y +1.4% → +56%, exact to the extension formula. |
| Reliability multiplier | beat_rate_mult alone | Geometric mean of beat_rate_mult and the credibility multiplier; credibility alone when there is no estimate coverage | Two reads on one question ("is this management reliable?") no longer double-count; uncovered names get a real signal instead of a hardcoded 1.0. |
| Guidance fiscal-year handling | n/a | "FY 25-'26" spans read as FY26; multi-year passages take the forward year; closed years age out of the blend (1.0 / 0.5 / 0.0) | Stale guidance decays instead of masquerading as current. |

## 🐛 Fixes (during the v6 rollout)

- **Library accessor off-by-one (v1/v2 of the data library):** `seek()` strips the leading key but accessors read 1-based slots — direction returned the management code, credibility returned the EPS figure, weight read past the record. The blend silently never fired; a misread credibility (0.205) crushed J&K's reliability multiplier to 0.49×. Caught from chart screenshots, not compile checks. Fixed in `/3`; accessors are now simulated against the generated blob before any publish.
- **pbcopy mojibake:** clipboard transfers under the C locale corrupted every emoji and unicode dash — and `cmp <(pbpaste) file` cannot detect it (symmetric mis-decoding). All staging now uses `LC_ALL=en_US.UTF-8` + independent osascript verification.
- **Pine compiler ceilings (library side):** reserved `text` export name; 40,960-char string-value cap; global-array ban in exported functions; const-string inlining vs the function-body cap; the 100,256 compiled-token cap (data ≈ 1 token/byte → ~95KB max per library); continuation lines indented by multiples of 4. Final ABI: 8 padded `part()` exports + parameter-based accessors, record chain in the consumer.

## ✨ New features

**🎯 Guidance row** (estimates table) — direction vs previous call · fiscal year · management credibility label · bridged EPS growth. Hover: management's full statement (564 highest-weight names via the Text library; compact digest fallback), the bridge, the scenario blend actually applied, disagreement warnings, and the source class. · **Inputs:** `Guidance Row (v6)` (default ON).

**Evidence tooltips everywhere** — credibility cell shows `n observations, median realisation` so a 2-observation label can't masquerade as a 5-observation one; EPS row shows guided-vs-consensus with the gap in pp; insights Fwd-Growth row and the scenario header disclose the exact blend (`blend 23% guidance / 77% analyst`) and any driver-leg blending.

**⚠/❗ conflict flags** — an upgrade from a "Hype man" management, or a downgrade from an "Overdelivers"/"Consistent" one, is flagged on the row. The combination a chart cannot otherwise show.

## ⚙️ Changed defaults

| Input | Old | New |
|---|---|---|
| `Label size` (📏 Levels Style) | Auto | `Normal` |
| `Line thickness` (📏 Levels Style) | 1 | `2` |
| `Blend management guidance into growth (v6)` | n/a | `ON` |
| `Max guidance weight vs analyst est` | n/a | `0.45` (backtest cap — median bridged error ~20pp) |
| `Widen scenario cone when guidance and street disagree` | n/a | `ON` |

## 🧪 Validation (performed 31-Jul-2026, on-chart)

| Symbol | Check | Result |
|---|---|---|
| TVSMOTOR | blend 13% = 0.19 × 1.0 cred × 0.7 undated-age; base +3.5% → +8.5% | ✅ exact |
| AKIKO | bull ext: 0.05 + 0.95 × (0.24/0.45) = +56% printed | ✅ exact |
| J&K BANK | blend 23% = 0.40 × 1.15 × 0.5 (FY26); cone 50→70% on 42.6pp gap; targets unchanged = corridor saturation, verified via scn tooltip | ✅ |
| CESC | no coverage — bit-identical to v5.x behaviour | ✅ control |

Known nits (queued for the quarterly `guidance-refresh`): scn_tip prints "cone +0%" where the spread math proves +20 (render truncation suspected); AKIKO base pinned at the corridor floor via stale `roe_used` on freshly-listed names.

## 📋 Data provenance & refresh

Guidance layer: 854 companies (684 NSE mainboard + 170 Emerge SME), built exclusively from earnings-call transcripts filed with NSE under SEBI LODR. 705 carry a bridged EPS growth; weights fitted on 713 closed-fiscal-year observations; credibility labels earned from guided-vs-delivered history across ≤4 consecutive calls. Refresh cadence: each results season via the `guidance-refresh` repo skill (sweep → extract → RE-FIT → regenerate → republish both libraries → bump imports).

---

# 💰 Valuations ++ v5.3 — Valuations ++ Dev
_A correctness release: no-analyst-coverage names stop being punished, the EV leg stops being stale, the fair-value bands stop collapsing into one line, and the level lines/labels are finally yours to style._

## ⚠️ Behavior changes (read before trusting old readings)

| Change | Old | New | Why it matters |
|---|---|---|---|
| Fair-value band sampling | Extreme multiples were **dropped** by hard cutoffs (PE < 500 etc.), so bands froze at the cutoff | Samples are winsorized **in**, clamped to an expandable envelope (rolling 1st/99th percentile ÷/× 1.25); only 10× sanity ceilings drop data (PE 5000, PS 1000, PB 500, EV 1000) | Low/Med/High bands, z-scores and CV weights move on high-multiple and crash-history names. Bands now widen with a genuine re-rating instead of freezing. Min/Max band mode shifts most. |
| EV/EBITDA history leg | Quarterly-stepped from reported FQ enterprise value | Marked **daily** as close × shares out + net debt | EV's variability was structurally understated, so the inverse-CV blend systematically overweighted the stalest leg. hist-EV bands, the EV fair-value leg and the composite bands all shift as the new history accumulates. |
| Displayed EV/EBITDA, its z-score and EV exit multiples | Reported FQ enterprise value | Same live-price construction as the history leg | The printed ratio jumps versus the old quarterly-step reading on any symbol with a stale FQ EV. |
| Beat/miss tracking with zero analyst coverage | Counted as a miss every quarter → ~30% growth haircut, −10 momentum points, red Track Record cells | Neutral: 1.0× growth multiplier, 0 beat bonus, ⚪ icons, neutral cell | Uncovered names (most NSE SMEs) had their scenario targets, momentum and composite score dragged down for having no data. Those readings rise. |
| Interest-coverage quality point | Reported-**zero** interest (debt-free, the best case) scored 0/2, while *missing* interest scored 2/2 | Zero interest scores 2.0; interest present with missing EBITDA is treated as missing (neutral) | Debt-free companies gain quality score; the inversion is gone. |
| Quality score with missing inputs | Missing ROE/D-E/Current-Ratio/FCF/OpMargin = 0/2 penalty, working capital = 1/2, interest = 2/2 bonus | Every missing factor reads neutral and is excluded; the score is renormalised over the factors actually present | Quality — and the composite score and scenario probabilities built on it — moves toward neutral for sparsely covered names instead of arbitrary. |
| Scenario growth drivers | PS, PB and EV legs all grew on EPS-derived growth | PS and EV grow on sales growth (EV grows EBITDA sales-linked); PB grows on sustainable growth = ROE × (1 − payout) | Scenario price targets shift for any symbol whose primary multiple is PS, PB or EV. Margin-expansion stories come down; high-retention compounders' PB targets move. PE-primary symbols are unchanged. |
| Quality ROE source | FY ROE | FQ ROE → FY ROE → computed NI(TTM) / total equity (FQ) | Quality moves wherever the fresh quarterly ROE differs from the annual figure. |

## 🐛 Fixes

- **Fair-value bands collapsed to a single line on any re-rated stock.** The new winsorizer was a one-way ratchet — it could only shrink the sample range, never extend it — so a 5-year window degenerated toward a constant and Low = Fair = High. Fixed with an expandable envelope; a simulated 18→55 PE re-rating goes from 0.0% band width back to the correct ~57%.
- **The band labels looked "missing".** They were never dropped from the code — all three sat at the same price and the same bar and rendered as one. The label x-offsets are now staggered so co-located levels can't stack.
- **A collapsed band leg hijacked the blend.** Because its variability read as ~zero, the inverse-CV weighting handed the degenerate leg near-total weight and dragged the composite with it. Fixed by the same envelope change.
- **Zero analyst coverage was scored as "missed every quarter".** Tracked quarters were counted from actuals alone while beats required an estimate, so the numerator and denominator disagreed. Both now require an actual *and* a standing estimate.
- **Debt-free companies were penalised for having no interest expense** — reported-zero interest scored worse than missing data.
- **The EV leg was the stalest input yet carried the most weight**, because a quarterly plateau looks less variable than a daily-marked series.
- **Missing quality inputs were scored inconsistently** — some as a zero penalty, one as a full bonus.
- **Track Record showed red for quarters that simply had no estimate** — those now show ⚪.
- **The legacy quality row failed debt-free names** on the same interest-coverage test.

## ✨ New features

**Anchor bands to TTM EPS** — puts the PE fair-value bands on a consistent trailing×trailing basis (trailing-PE percentiles × trailing EPS) instead of the default forward tilt, which biases bands high for growers. Falls back to the forward basis if TTM EPS is unusable. Graham number and reverse-DCF are unaffected. · **Inputs:** `Anchor bands to TTM EPS` (default OFF, 🎨 Valuation Bands) · **What you'll see:** the main-table PE fair-value tooltip names the basis in use.

**📏 Levels Style** — one uniform style, width and label size for all four level lines (Low, Fair, High, EV 1Y). · **Inputs:** `Label size` (default Auto — Fair normal, minors small), `Line style` (default Dashed), `Line thickness` (default 1, range 1–4) · **What you'll see:** the four dashed level lines redraw at the chosen style/width immediately; picking an explicit label size forces it on all four labels.

**Compact bands** — hides the minor overlays when the band area gets crowded: the MoS −10/−20/−30 ladder, the Norm-PE fair-value plot, the dotted Low/High lines and labels, and the EV 1Y line and label. Band plots, zone fills and the Fair line + label stay. · **Inputs:** `Compact bands` (default OFF, 🎨 Valuation Bands) · **What you'll see:** the overlay drops to the Fair line plus the shaded bands.

**Partial-history badge** — warns when the band percentiles were computed from fewer bars than the lookback asks for (the intraday 20k-bar cap can cut ~1260 samples to ~80 without any prior warning). · **What you'll see:** a ⚠️ with an "n/N samples" tooltip on the main-table Bands header, and a matching lowest-priority warning row in the scenario table.

**"No est. coverage" badge** — the Track Record cell now says so explicitly instead of showing a red 0% beat rate. · **What you'll see:** neutral background, " (no est. coverage)" text, and a tooltip explaining that ⚪ marks an uncovered quarter.

**Driver-aware scenario tooltips** — bear/base/bull tooltips now report the *effective* growth rate actually applied to the selected primary multiple, and name the driver behind it (EPS, sales, or ROE × retention).

**Fresher quality inputs** — quarterly ROE and total equity are now requested, so the quality ROE factor and the new BVPS growth driver no longer run on annual data.

## ⚙️ Changed defaults

| Input | Old | New | Effect |
|---|---|---|---|
| `Line thickness` (📏 Levels Style) | not an input — all four level lines hard-coded to width 2 | `1` | Thinner level lines. Set to 2 to restore the old weight. |
| `Line style` (📏 Levels Style) | not an input — hard-coded dashed | `Dashed` | No visual change at the default; now switchable to Dotted or Solid. |
| `Label size` (📏 Levels Style) | all four labels rendered at normal size | `Auto` | Fair stays normal; Low, High and EV 1Y labels shrink to small so the staggered row reads cleanly. |
| `Anchor bands to TTM EPS` | n/a (new) | `OFF` | The existing forward-EPS band basis is preserved exactly until you turn it on. |
| `Compact bands` | n/a (new) | `OFF` | All overlay lines keep drawing as before. |

Existing chart instances keep whatever values you already saved — the new defaults only apply when you add a fresh copy of the indicator or reset settings to defaults.

## 🧪 Test plan (before publishing)

1. **Bands must be three separate lines on a re-rated stock.** Pick a name whose multiple has trended one way across the 5-year lookback (confirm it on the chart's own PE history before using it as the test case). **Pass:** the Low, Fair and High dashed lines sit at visibly different prices, the zone fills have real height, and the main-table Low/Fair/High figures differ. **Fail:** any two of the three print the same number — that is the ratchet regression.
2. **Range-bound control.** Repeat on a symbol whose multiple has oscillated in a band. **Pass:** band width is essentially unchanged from the previous build (this case was never affected by the bug, so a large move here means something else shifted).
3. **Labels visible and staggered.** **Pass:** four distinct labels — Fair, Low, High, EV 1Y — at increasing horizontal offsets (+1, +7, +13, +19 bars), each showing its name, price and signed % versus price. **Fail:** fewer than four labels, or two overlapping.
4. **📏 Levels Style, one control at a time.** Set `Line thickness` 1 → 4: **pass** if all four lines visibly thicken. Set `Line style` Dashed → Dotted → Solid: **pass** if all four change together (the style is uniform by design — Fair should *not* stay solid while the others go dotted). Set `Label size` Auto → Large → Tiny: **pass** if all four labels resize, including Fair.
5. **Compact bands.** Tick it. **Pass:** the MoS ladder, Norm-PE plot, Low/High lines + labels and the EV 1Y line + label disappear while the shaded bands and the Fair line + label remain. Untick and confirm everything returns.
6. **Zero-coverage name reads neutral.** Load an NSE SME or any recently listed name with no analyst estimates. **Pass:** Track Record shows ⚪ icons and the "(no est. coverage)" text on a neutral background — not red; the scenario table shows no beat-history growth haircut and momentum carries no −10 beat penalty. **Fail:** a 0% beat rate on a red background.
7. **EV band behaviour after daily marking.** On a symbol with a visibly stale reported enterprise value, note the displayed EV/EBITDA and its z-score, then re-check after a day with a meaningful price move. **Pass:** the printed EV/EBITDA moves with price rather than sitting flat until the next quarterly report; the EV fair-value leg and its weight in the Bands tooltip are populated. **Pass (degradation):** on a symbol with no net-debt data the EV leg simply drops out of the blend rather than producing debt-blind bands.
8. **Partial-history badge fires where it should.** Load the indicator on an intraday timeframe where the 20k-bar cap bites. **Pass:** the ⚠️ appears on the Bands header with an "n/N samples" tooltip, and the scenario table carries the matching warning row (it should yield to stale/trough/poor-beat warnings when those apply).
9. **TTM anchor toggle.** On a high-growth name, note the PE fair-value figures, then tick `Anchor bands to TTM EPS`. **Pass:** the PE bands drop (trailing EPS < forward EPS) and the tooltip names the TTM basis; the Graham number and reverse-DCF values are unchanged.
10. **Scenario drivers on a non-PE-primary name.** Load a symbol whose primary method is PS, PB or EV. **Pass:** the bear/base/bull tooltips name sales growth (PS/EV) or ROE × retention (PB) as the driver and report an effective growth rate that differs from the EPS growth rate. On a PE-primary symbol, **pass** if the scenario targets are unchanged from the previous build.
11. **Debt-free name quality check.** Load a company with no debt. **Pass:** the interest-coverage factor contributes its full 2.0 and the quality score is at least as high as before.
12. **Compile and budget.** **Pass:** the script compiles and loads; request budget stays at 35 of 40.

## 📋 Publishing blurb (paste into TradingView release notes)

Fixed: fair-value bands could collapse into a single line on stocks whose multiple had re-rated — Low, Fair and High now separate correctly again.
Fixed: the three band labels are no longer stacked on top of each other; they're staggered and readable.
Fixed: stocks with no analyst coverage were being scored as if they had missed every quarter. They now read neutral — no growth haircut, no momentum penalty, ⚪ icons and a "no est. coverage" badge.
Fixed: debt-free companies were penalised on interest coverage. Zero debt now scores as the best case, not the worst.
Fixed: EV/EBITDA was quarterly-stepped while every other multiple re-marked daily, which quietly gave the stalest input the most weight. EV is now marked daily — expect band and z-score values to shift.
Improved: missing quality inputs now count as neutral and the score renormalises over what's actually available, instead of penalising sparse coverage.
Improved: PS and EV scenarios grow on sales, PB grows on ROE × retention. Targets shift for non-PE-primary names.
Improved: extreme historical multiples are now clamped into the sample instead of thrown away, so bands track genuine re-ratings.
New: 📏 Levels Style — set the line style, thickness and label size of the four level lines.
New: "Compact bands" to hide the minor overlay lines when the chart gets busy.
New: "Anchor bands to TTM EPS" (off by default) for a consistent trailing basis.
New: a ⚠️ "n/N samples" badge when the bands were built from less history than you asked for.

---

# Valuations + Pocket Pivot Screener v4 — 💰 Valuations Screener 💰
_Stops no-data stocks from ranking as "fairly valued", tightens what counts as a certified fair value, and spends the freed output slots on four columns that were computed but never shown._

## ⚠️ Behavior changes (read before trusting old readings)

| Change | Old | New | Why it matters |
|---|---|---|---|
| ③ Valuation Zone for names with no fundamental data | `0.0` — reads as "at fair value" | blank (na) | Zone-only screens and zone sorts now **exclude** these names instead of ranking them mid-pack, above genuinely overvalued stocks. |
| Data-quality certification | `Data Quality >= 3` (good) / `>= 2` (minimum) — a raw count of available metrics | Also requires covered weight ≥ 0.75 / ≥ 0.50 of the sector profile's intended weighting | A bank missing book value could pass "DQ ≥ 3" on a composite that was 100% P/E with 65% of the intended weight absent. Screens and alerts gated on these — value opportunity, deep value, 🔥 Strong Conviction, 🚀 Accumulation, 🔼 Value Trend Turn, 🔥 Pattern Conviction — are now stricter, and some previously flagged low-coverage names drop off. |
| Minimum history for fair-value bands | 6 valid fundamental samples (~2 weeks of listed history) | 60 (new input) | Composite fair value, the ① score, ② upside, ③ zone, Margin of Safety and every signal built on them stay na until 60 samples exist — recently listed names drop out of the valuation columns for roughly three months. The ⑤–⑨ percentile columns keep the lighter 6-sample floor. |
| Bottom-fishing pivot (type 2) | A gap-up finishing well above the 50MA still printed a pivot | Rejected when close is more than `Max % Extended Above Fast MA` above the 50MA | With the uptrend filter ON, everything downstream of the pivot can now flip false on those bars: tech score, 🚀 Accumulation, 💥 Value Breakout, 🔥 Strong Conviction, the conviction score's technical component, the "+ PP" pattern flags, 🔄 30% Fall Reversal, and the related alerts. |
| Pivot classification with "Require Price in Uptrend" OFF | Type 2 was unreachable — the filter sat inside the type-2 condition | 50MA-reclaim days now print type 2 | Classification only. Any-pivot screens (`>= 1`) see no change; with the filter ON, classification is bit-identical to the previous build. |
| 🟩 Pocket Pivot column values | 1 or 2 | 1 / 1.5 / 2 / 2.5 — the +0.5 marks a pivot whose volume was at least 2× the largest down-day volume it beat | Existing `>= 1` and `>= 2` filters keep working; an exact `= 2` filter now misses the strongest bottom-fish pivots. Use `>= 2`. |
| Band-cross alerts (📍 Dropped Below Low Band, 📍 Reclaimed Fair Value, 📍 Lost Fair Value) | Crossed the raw composite | Cross a 5-period EMA of the composite fair value and low band | Far fewer whipsaw alerts around estimate revisions; a single clean cross shifts by at most the EMA lag (~2 bars). The two val-score threshold alerts (📍 Became Under/Overvalued) are timing-identical. |
| Chart-mode visuals | Zone background tint, pocket-pivot triangle, accumulation diamond, always-on price line | Backgrounds and both shapes **removed**; the price line is behind a "Screener Build" toggle (ON by default = blank) | Hidden outputs still consume their slot toward the 64-output cap, so gating them was not enough — they had to go. Their information survives as columns (③ Valuation Zone, 🟩 Pocket Pivot, 🚀 Accumulation Signal). On a chart, untick "Screener Build" to get the price line back. |

## 🐛 Fixes

- **Stocks with no fundamental data printed as "at fair value" in the ③ Valuation Zone column** and ranked ahead of genuinely overvalued names in zone sorts. They now go blank and fall out of those screens.
- **"Good data" could certify a single-metric fair value.** The quality flags counted raw metric availability without checking whether those metrics carried any weight in the sector profile; they now also require 75% / 50% of the intended weight to be covered.
- **Fair value could be defined by two weeks of listed history** — the percentile bands accepted as few as 6 samples.
- **A gap-up straight through the 50MA counted as a bottom-fishing pivot,** with no extension backstop of the kind standard pivots already applied to the 10MA.
- **Unticking "Require Price in Uptrend" silently made the bottom-fishing pivot unreachable** rather than just relaxing the uptrend requirement.
- **A `ta.crossover` call sat inside a short-circuited `or` chain,** so it could be skipped on some bars — an inconsistent-execution and repaint hazard. It is now evaluated at global scope.

## ✨ New features

**Four promoted columns** — metrics that were computed since v3 but never output. · **What you'll see:** `Upside to High %` (distance to the top band), `Margin of Safety %`, `Coverage %` (the covered fraction of the sector profile's intended weight — the honest companion to Data Quality, and the same quantity the new quality guards threshold at 75/50), and `Vol / MaxDownVol` (the natural pocket-pivot ranking key — how forcefully the pivot beat the down-day volume it had to clear). All four are sortable screener columns.

**Minimum-samples control for the bands** · **Inputs:** `Min Samples for Fair-Value Bands` (default 60, range 6–500) · **What you'll see:** valuation columns stay blank on young listings until the history exists. Set it to 6 to restore the old behaviour exactly.

**Screener Build toggle** · **Inputs:** `Screener Build (blank the Price plot)` (default ON) · **What you'll see:** ON, the Price plot reads na so it doesn't duplicate the screener's native Price column. OFF, close is drawn against the fair-value bands for chart use.

**Pocket-pivot quality tiering** — the 🟩 column adds 0.5 when the pivot's volume was at least twice the largest down-day volume in the lookback window, so you can sort pivots by force. Degenerate windows (no valid down-day volume) stay at their base tier.

**Smoothed band-cross alerts** — the three band-transition alerts now cross 5-period EMAs of the fair value and low band, cutting the estimate-revision whipsaw.

**Guide update** — the usage guide gained a worked screen: `Margin of Safety % > 20 AND Coverage % >= 75`, and the note that pocket-pivot filters should use `>= 2` rather than `= 2`.

## ⚙️ Changed defaults

| Input | Old | New | Effect |
|---|---|---|---|
| `Min Samples for Fair-Value Bands` | not an input — hard-coded floor of 6 | `60` | Fair value, the ①/②/③ columns and every derived signal stay blank on names with under ~3 months of fundamental history. Set to 6 for the previous behaviour. |
| `Screener Build (blank the Price plot)` | n/a (new) | `ON` | The Price plot is blank by default. Untick for chart use. |
| `Require Price in Uptrend for Pocket Pivot` | `ON` | `ON` (value unchanged) | Same default, new meaning: it no longer gates the bottom-fishing pivot, which is now controlled solely by "Allow Bottom-Fishing Pivot". |

Existing chart instances keep whatever values you already saved — the new defaults only apply to a fresh copy of the indicator or a reset to defaults.

## 🧪 Test plan (before publishing)

1. **Output count — do this first.** The script errors outright above 64 outputs. Add the indicator to a chart and confirm it loads. **Pass:** it compiles and renders — the build is 42 plots + 21 alert conditions = 63/64, with one slot spare. **Fail:** any "too many outputs" error, which means an output was added somewhere without removing one.
2. **Compile check.** This script has never been run through the TradingView compiler. Run a `/pine-check` pass before publishing. **Pass:** zero compile errors.
3. **The four new columns exist and sort.** Open the Pine Screener column list. **Pass:** `Upside to High %`, `Margin of Safety %`, `Coverage %` and `Vol / MaxDownVol` all appear, populate with numbers on a well-covered large cap, and sort ascending/descending.
4. **No-data names drop out rather than ranking mid-pack.** Screen a list containing NSE SME or recently listed names, sort by ③ Valuation Zone. **Pass:** names without fundamental data show a blank ③ and blank ① score, and do not appear between the undervalued and overvalued groups. **Fail:** any row showing exactly 0.00 in ③.
5. **Coverage guard bites where it should.** Find a bank or NBFC where book value is missing. **Pass:** `Coverage %` reads below 75 and the name no longer flags 🔥 Strong Conviction or a value opportunity, even though Data Quality still reads 3+. Data Quality itself is unchanged — it remains an honest raw count.
6. **Screener Build toggle on a chart pane.** Add the indicator to a chart (it draws in its own pane) with the toggle ON. **Pass:** no price line, just the fair-value bands. Untick "Screener Build". **Pass:** the price line returns and can be compared against the bands. Also confirm the zone background tint and the two signal shapes are gone in both states — that is intended, not a regression.
7. **Minimum-samples behaviour.** Load a name listed within the last two months. **Pass:** ①, ②, ③ and Margin of Safety are blank. Set `Min Samples for Fair-Value Bands` to 6. **Pass:** the columns populate again, confirming the input is the only gate. Check the ⑤–⑨ percentile columns stayed populated throughout.
8. **Pivot classification truth table.** With `Require Price in Uptrend for Pocket Pivot` ON, compare the 🟩 column against the previous build on a handful of names. **Pass:** identical classification. Untick it. **Pass:** 50MA-reclaim days now print 2 or 2.5 instead of 1, and a screen on `🟩 >= 1` returns the same set in both states.
9. **Pivot quality tier.** Sort by 🟩 descending. **Pass:** values of 1.5 and 2.5 appear, and every one of them shows `Vol / MaxDownVol >= 2`.
10. **Extension guard on bottom-fish pivots.** Find a name that gapped up hard through its 50MA. **Pass:** no pivot is printed on that bar (with the uptrend filter ON), where the previous build printed a 2.
11. **Smoothed alerts.** Set an alert on 📍 Reclaimed Fair Value on a name with a recent estimate revision. **Pass:** the alert fires within a couple of bars of the raw cross and does not fire repeatedly on a single revision step. Confirm 📍 Became Undervalued / Overvalued fire at exactly the same bar as before.
12. **Worked screen end to end.** Run `Margin of Safety % > 20 AND Coverage % >= 75`. **Pass:** the result set is non-empty and every row has a populated ① score.

## 📋 Publishing blurb (paste into TradingView release notes)

Fixed: stocks with no fundamental data were printing "0.0" in the ③ Valuation Zone column — reading as "at fair value" and ranking above genuinely overvalued names. That column is now blank for them, so they drop out of zone screens.
Fixed: "good data" could certify a fair value built from a single metric. Quality now also requires that 75% (or 50% for the looser gate) of the sector profile's intended weight is actually covered. Some low-coverage names will fall off the conviction screens.
Fixed: fair-value bands could be defined by as little as two weeks of listed history. New "Min Samples for Fair-Value Bands" input, default 60 — set it to 6 for the old behaviour.
Fixed: a gap-up straight through the 50MA counted as a bottom-fishing pocket pivot. It now fails the same extension check standard pivots use.
Fixed: unticking "Require Price in Uptrend" made the bottom-fishing pivot unreachable instead of just relaxing the filter.
New columns: Upside to High %, Margin of Safety %, Coverage %, and Vol / MaxDownVol — all computed for a while, now sortable.
New: pocket pivots are tiered — add 0.5 when the pivot's volume was 2× the down-day volume it beat. Filter with >= 2, not = 2.
New: the three band-cross alerts now use a 5-bar EMA of the bands, which kills most of the estimate-revision whipsaw.
Chart users: the zone background tint and the two signal shapes have been removed to fund the new columns (TradingView charges an output slot even for hidden plots). Untick "Screener Build" to bring the price line back.

---

# EOD Screener — EOD Screener
_The bull-flag setup was mathematically incapable of firing and the BUY gate was tautological — both are fixed, plus five new diagnostic columns and a Weinstein-correct extension measure._

## ⚠️ Behavior changes (read before trusting old readings)

| Change | Old | New | Why it matters |
|---|---|---|---|
| Bull-flag setup (SetupCode 2) | **Never fired.** The breakout level included the current bar's own high, so close could never cross it | Level is taken from the prior bar, exactly like the Stage-2 ignition block | Every bull-flag breakout was being silently missed. Expect new BUY/ARM rows and "Setup triggered" alerts that never appeared before. The flag's range % now correctly excludes the breakout bar. |
| BUY gate | Included `TP1(R) >= Min R:R` — a comparison of two inputs, constant for the whole run | Removed; the gate is now "position size > 0 and stop is not a fallback" | At the shipped defaults (TP1 2.0, Min R:R 2.0) nothing changes. If Min R:R was ever set above TP1(R), the screener silently returned **zero BUYs** across the entire universe. It can now return BUYs. |
| Extension measure (`Ext_%`) | Measured against the 10-EMA, despite the input being labelled "above support MA" | Measured against the 30-period stage-timeframe MA — the Weinstein convention the label describes | Ext_% values are **larger** now, so at the same 12% default more names flag over-extended and drop out of BUY. If the BUY list thins too much, loosen `Max extension above support MA %`. The 10-EMA is untouched everywhere else (pullback setup, "Below Key MA" stop). |
| Relative-strength gate | `RS > RS-MA` **and** `RS > previous RS` | `RS > RS-MA` only | A single flat or soft RS day no longer demotes BUY to ARM. BUY lists widen on choppy-RS names. IPOs are now blocked only by the missing-RS-MA guard, which is visible in the new DataOK column. |
| Volume policy when volume history is missing | Breakout hard-failed; ignition and bull-flag triggers **auto-passed**; the double-bottom trigger had no volume condition at all | All hard-fail on missing volume; the double-bottom neckline break now requires the same surge multiple as the breakout it shares its crossover with | Expect **fewer** double-bottom signals — every surviving one is volume-confirmed. Symbols with under ~50 bars of volume history now fail closed instead of passing by default; DataOK tells you why. |
| Stage for short-history symbols (IPOs) | Reported as Stage 1 | Reported as na (unknown) | The Stage column no longer asserts a stage it cannot know. **Open item:** the "Entered Stage 2" alert will not fire on a na→2 transition, where the old 1→2 transition did. If first-Stage-2 alerts on young listings matter to you, this needs a decision. |
| "Require a triggered setup for BUY" set OFF | Silently killed the ignition path in the live-Stage-2 test and deadened the Stage-2 ignition alert | Both work | Only visible with the toggle OFF: BUY rows can now include ignition-driven names and the ignition alert fires. Default (ON) behaviour is identical to before. SetupCode and "Setup triggered" remain inert when OFF, by design. |

## 🐛 Fixes

- **The bull-flag breakout could never trigger.** The consolidation high was computed over a window that included the current bar, so a close could not exceed a range containing its own high. Every bull flag in the history of this script was missed.
- **The BUY decision line contained a tautology** comparing two inputs — harmless at defaults, but a silent zero-BUY failure for anyone who raised Min R:R above TP1(R).
- **IPOs and short-history symbols were labelled Stage 1** because a missing moving average fell through to the "not above the MA" branch.
- **The extension input said one thing and the code measured another** — "above support MA" against a 10-EMA.
- **Missing-volume handling was inconsistent across setups** — two triggers hard-failed, two auto-passed, one had no volume test at all.
- **Turning off "Require a triggered setup for BUY" broke more than it relaxed,** killing the ignition path and two alerts.
- **A structural stop wider than the max stop distance was silently converted to a percent stop** with no indication — now flagged by a column.
- **Three separate higher-timeframe data requests** where two suffice; the stage-timeframe trail is now returned by the same request as the stage data (numerically identical values, same timeframe, same no-lookahead setting).

## ✨ New features

**EOD confirm only** — this screener is designed for post-close runs; running it intraday means every trigger evaluates on a developing bar and can repaint. This toggle ANDs a confirmed-bar requirement into all six setup triggers (breakout, Fibonacci hold, ignition, bull flag, double bottom, pullback), and the BUY/ARM/setup/ignition/breakout alerts inherit it. · **Inputs:** `EOD confirm only` (default OFF — shipped behaviour unchanged) · **What you'll see:** with it ON, no trigger fires until the bar closes.

**MansRS_%** — Mansfield-style relative strength as a sortable number, `(RS / RS-MA − 1) × 100`, alongside the existing binary RS_out column. · **What you'll see:** rank the BUY list by relative strength instead of just filtering on it.

**StageWeeks** — how long the symbol has been in Stage 2, counted in stage-timeframe bars, computed inside the stage-timeframe context. The single highest-value Weinstein addition: it separates fresh Stage-2 breakouts from late-stage ones. · **What you'll see:** a number on Stage-2 rows only. Reads na for a symbol that has been Stage 2 across its entire loaded history.

**SlClamped** — 0/1 flag next to Stop_%, marking rows where the structural or method stop was wider than the max stop distance and was silently replaced by the percent stop. · **What you'll see:** a 1 tells you the stop on that row is not the one your stop method chose.

**DataOK** — 0/1 flag confirming that the stage MA, RS MA and volume ratio all had real data. Pairs with the na-stage fix: the new hard-fail volume policy makes short-history rows fail closed, and this column says why. · **What you'll see:** a 0 means the gates ran on missing data — treat the whole row as unreliable.

**Turnover** — average rupees traded per bar (`close × average volume`), beside Vol_x. Slippage is the dominant unmodeled risk with full-capital sizing and 1–3% stops. · **What you'll see:** a liquidity figure you can set a floor on before sizing a position.

## ⚙️ Changed defaults

| Input | Old | New | Effect |
|---|---|---|---|
| `Max extension above support MA %` | `12.0`, measured against the 10-EMA | `12.0`, measured against the 30-period stage-timeframe MA | Value unchanged, meaning corrected. Ext_% readings are larger, so the same 12% rejects more names. **This is the retune knob** if the BUY list thins too much. |
| `EOD confirm only` | n/a (new) | `OFF` | Shipped behaviour is unchanged; turn it on if you ever run the screener intraday. |

Everything else — capital, risk %, stop method, TP1, Min R:R, setup lengths, surge multiple, RS settings — keeps its previous default. Existing chart instances keep whatever values you already saved; the new input only appears with its default on a fresh copy or a reset to defaults.

## 🧪 Test plan (before publishing)

1. **Bull flags actually appear.** Screen a broad NSE list on the daily and sort by SetupCode. **Pass:** at least some rows show SetupCode 2 — this value was unreachable in every previous build, so **zero 2s across a large universe is a fail**. Spot-check one on a chart: a pole of at least 18%, a consolidation range under 10%, and a close above the prior bars' consolidation high.
2. **Bull-flag alert path.** Set a "Setup triggered" alert on a name currently in a flag. **Pass:** it fires on the breakout bar with a SetupCode of 2.
3. **BUY gate is no longer tautological.** Set `Min R:R (TP1)` to 3.0 while leaving `TP1 (R)` at 2.0. **Pass:** the screener still returns BUY rows. **Fail:** zero BUYs universe-wide, which was the old behaviour.
4. **Extension retune check — do this before publishing.** Record the BUY count at `Max extension above support MA %` = 12.0, then compare against the previous build's BUY count on the same list and date. **Pass:** the list is thinner but not empty, and the dropped names are visibly extended above their 30-period stage MA. If it is too thin, raise the input (try 15–18) and note the value you settled on in the published description.
5. **New columns present and populated.** Open the screener column list. **Pass:** `StageWeeks`, `MansRS_%`, `Turnover`, `SlClamped` and `DataOK` all appear and sort. Spot-check: StageWeeks is blank on non-Stage-2 rows; MansRS_% is positive on names beating the benchmark; Turnover scales with price × volume.
6. **DataOK does its job.** Screen a list containing a recent IPO. **Pass:** DataOK reads 0 on it and no BUY/ARM is issued; the Stage column is blank rather than showing 1.
7. **"Entered Stage 2" gap — decide before publishing.** On a young listing that has just crossed into Stage 2, check whether the alert fires. **Expected:** it does not, because the transition is na→2. Decide whether to accept this or add a follow-up fix, and document whichever you choose.
8. **Double-bottom triggers thinned but confirmed.** Compare double-bottom (SetupCode 3) counts against the previous build. **Pass:** fewer rows, and every surviving one shows Vol_x at or above the breakout surge multiple (1.5 default).
9. **SlClamped catches the wide-stop case.** Find a double-bottom row whose structural stop sits below the neckline low by more than the max stop distance. **Pass:** SlClamped reads 1 and Stop_% equals `Max stop distance %`.
10. **useSetups OFF path.** Untick `Require a triggered setup for BUY`. **Pass:** BUY rows now include ignition-driven names and a "Stage-2 ignition" alert fires; SetupCode stays 0. Re-tick it. **Pass:** results are identical to the previous build.
11. **EOD confirm toggle.** During market hours, tick `EOD confirm only`. **Pass:** no setup trigger fires on the developing bar; after the close, the same names trigger as with the toggle off.
12. **RS gate widening.** Compare BUY counts with `Require RS outperformance for BUY` ON against the previous build. **Pass:** more names pass, and the ones that newly qualify have a positive MansRS_% but had a flat or down RS on the most recent bar.
13. **Budget and compile.** **Pass:** the script compiles and loads with 27 plots + 8 alert conditions = 35/64 outputs and 2 higher-timeframe requests (was 3). Confirm the 20-EMA trail values are unchanged from the previous build — the request merge should be numerically identical.

## 📋 Publishing blurb (paste into TradingView release notes)

Fixed: the bull-flag setup (SetupCode 2) could never fire — the breakout level was computed over a window that included the current bar's own high. Every bull flag was being missed. Expect new setups to show up.
Fixed: the BUY gate contained a comparison between two inputs. Harmless at defaults, but if you raised Min R:R above TP1(R) the screener silently returned zero BUYs.
Fixed: IPOs and short-history symbols were reported as Stage 1. The Stage column now reads blank when there isn't enough history to know.
Fixed: the "Max extension above support MA %" input measured against the 10-EMA, not the support MA. It now measures against the 30-period stage-timeframe MA as labelled — extension readings are larger, so the same 12% setting rejects more names. Loosen it if your BUY list gets too thin.
Fixed: missing-volume handling was inconsistent — two setups auto-passed and the double-bottom had no volume test at all. All setups now fail closed on missing volume, and double-bottom neckline breaks need the same volume surge as any other breakout. Expect fewer double-bottom signals, all of them confirmed.
Fixed: turning off "Require a triggered setup for BUY" used to kill the Stage-2 ignition path and two alerts.
Improved: the RS gate no longer demotes a stock for one flat day — it just needs RS above its own moving average.
New columns: StageWeeks (how fresh the Stage 2 is), MansRS_% (sortable Mansfield relative strength), Turnover (liquidity), SlClamped (your stop got clamped to the max), DataOK (this row's gates ran on missing data).
New: "EOD confirm only" toggle, off by default — turn it on if you ever run this intraday, so nothing evaluates on a developing bar.
Under the hood: three higher-timeframe data requests merged into two, with identical values.
