TASK: H-4 — give each option contract its real delta, projected from the
      chain's own IV, so the stop geometry stops assuming a flat 0.5 on
      strikes where it is wrong. The gate that consumes it is already
      built. ONE change: project the delta; do NOT touch the gate, the
      selector's ranking, or any threshold.
      SEQUENCING: this changes ENTRY geometry (stop placement). It runs on
      its OWN session — never the same day as H-1 or H-5 — so its effect
      is attributable. Land after H-1 and H-5 each have a clean session.

## Established context (verified in code 2026-09-06)

- option_trade_quality.py:_delta (353-382) ALREADY has the consuming
  branch: if the contract mapping carries a usable `delta` in (0,1] it is
  used (DELTA_FROM_CONTRACT), with abs() for puts and reject-not-clamp on
  0.0/out-of-range; only the fallback to ATM_OPTION_DELTA=0.5
  (DELTA_FROM_RATIFIED) fires today, because "neither selector projects a
  delta, so nothing puts one on the contract mapping" (A-72/A-73). The
  docstring states reading the real value STRICTLY TIGHTENS the gate.
- IV is carried end to end: option_chain.py:253 reads impliedVolatility;
  it flows as ce_iv/pe_iv into the selector output
  (option_selector.py:154/194 "iv": _safe_float(...)). The stored trade
  plans show real IV (e.g. 10.35). So a Black-Scholes delta is computable
  from data already present.
- Decision (Nitin, 2026-09-06): route = PROJECT THE REAL DELTA. Do NOT
  change the selector to force ATM; keep the liquidity ranking. The fix is
  a projected delta on the contract, consumed by the existing branch.
- Why it matters (weekly analysis): 16 of 21 selections were 40–75 pts
  OTM/ITM; delta_source='ratified_default' on 53/53. P11/P13 (ITM 0-DTE
  puts, true δ≈0.75–0.80) had effective stops ~35% tighter than intended
  and died in 46–62 s for −₹773.50.

## IMPORTANT FINDING — this fix TIGHTENS, never loosens

Per the gate's own docstring: a true delta only ever raises the noise
estimate for a contract whose real delta exceeds 0.5, refusing a geometry
that 0.5 wrongly passed. A contract with true delta below 0.5 gets a
looser noise estimate — verify this direction is correct and intended
(an OTM strike with δ<0.5 moves LESS per index point, so its premium
noise is genuinely smaller; the gate passing it is correct, not a
loosening bug). State this two-sidedness explicitly in the report.

## Verify the premises

1. The IV units and validity: is impliedVolatility a percentage (10.35 =
   10.35%) or a fraction? Black-Scholes needs the fraction. Confirm from
   option_chain.py and a stored plan; a wrong scale makes every delta
   wrong. If IV is 0/absent on a row (the `or 0` fallback), the projection
   MUST decline and leave the contract deltaless so the gate keeps its
   0.5 fallback — never project from IV=0.
2. Time to expiry: the exact expiry timestamp the plan already resolves
   (the expiry floor work put expiry on the chain), the risk-free rate
   convention if any exists in the repo (else state the r you use and
   why it barely matters at these tenors), and that TTE is computed in
   YEARS with the session clock the rest of v2 uses (no naive-local bug —
   the H-1 report just fixed one of those).
3. WHERE to project so it lands on the contract mapping _delta reads:
   the selector output dict, or the entry-plan step that builds the
   contract the quality gate sees. Trace the one path from selected
   contract → option_trade_quality input and put the delta at the point
   that mapping is built. Confirm _delta reads THAT mapping.
4. Every consumer of delta_source / the delta value: evidence rows,
   admission, the quality verdict, any renderer. The value changing from
   0.5 to real on most rows must not break a reader that assumed the
   constant (e.g. a test asserting delta_source=='ratified_default').
   List them; update tests that pinned the constant, in this change.
5. BANKNIFTY/SENSEX/BANKEX and replay: the docstring says these emit 0.0
   for an unavailable Greek. Projection must decline cleanly there too
   (premise 1's IV=0 guard covers it — confirm) so those paths keep the
   ratified fallback exactly as today.

## Do NOT change

The quality gate's logic or its consuming branch (it is READY — only feed
it) · ATM_OPTION_DELTA (0.5 stays the fallback) · the selector's
liquidity ranking / three-strike window (Nitin's decision: keep it) ·
option_stop_atr_mult (1.25) · the stop model · any threshold or filter ·
the trail. This task ADDS a projected delta onto the contract mapping and
NOTHING else.

## Implementation

1. A small, pure, tested Black-Scholes delta function: inputs spot,
   strike, TTE (years), IV (fraction), option kind (CE/PE), r; output the
   signed delta (the gate takes abs()). No external dependency —
   Newton/erf from math. Reject-not-project on IV≤0, TTE≤0, or any
   non-finite input (return None; the caller then omits delta and the
   0.5 fallback stands).
2. Project it at the one site premise 3 identifies, onto the contract
   mapping the quality gate reads, keyed `delta`. delta_source then
   reads DELTA_FROM_CONTRACT on rows where projection succeeded and
   DELTA_FROM_RATIFIED where it declined — both honest.
3. Nothing else. No selector change, no gate change, no config key.

## Tests

- The BS function against known textbook values (ATM ~0.5, deep ITM →1,
  deep OTM →0, a put's magnitude) on a fixture table; declines on
  IV=0/TTE=0/NaN.
- Projection lands on the mapping; _delta returns DELTA_FROM_CONTRACT with
  the projected value; IV=0 row still returns DELTA_FROM_RATIFIED 0.5.
- Two-sidedness: an ITM contract (δ>0.5) now yields a HIGHER noise and can
  flip a borderline geometry from pass to refuse; an OTM (δ<0.5) yields
  lower noise — both asserted on fixtures.
- Premise-4 readers: every pinned-constant test updated, none weakened.
- SENSEX/replay path: unchanged, still 0.5.
Then the FULL suite:

    bash backend/scripts/ci/run_all.sh

All 13 gates green.

## Verification report

A. Files changed  B. The BS function and its textbook-value proof
C. Premise-1 IV scale verdict (pct vs fraction) and the IV=0 guard
D. Premise-3 projection site (the traced path)  E. Two-sidedness proof
(a pass→refuse flip and a correct OTM pass)  F. delta_source distribution
on a fixture chain (how many real vs fallback)  G. Premise-4 reader/test
inventory  H. 13 gates  I. Premises that did not match  J. Unknowns
(esp. how often real IV is actually present on Angel One NIFTY rows —
if it is usually 0, this fix is inert in production and that is a
finding, not a failure)

CRITICAL: Feed the gate, do not touch it. If premise 1 finds IV is
usually 0/absent on production NIFTY chains, STOP after reporting — the
fix would be inert and the real problem is the missing Greek upstream,
which is a different task and Nitin's call.
