בס״ד

MIS v2 — Logic Capture (Phase 0)

docs/MIS_V2_LOGIC_CAPTURE.md · last changed (pre-VM history) · rendered from GitHub master

MIS v2 — Logic Capture (Phase 0)

Purpose: capture the valuable logic in the current MIS before the clean rebuild, so v2 ports the logic, not the bloat. Sam's rule: "don't lose the logic / how it looked / the suggestions." This is the faithful inventory. It also separates logic to PORT from structural bugs to FIX (don't port the broken thresholds).
Source: MIS/src/Code.js (1356 lines, builders) + MIS/src/emailDailySnapshot.js (5161 lines, engine/render). Line refs are to those files.
Status: Phase 0 of the approved plan (.claude/plans/valiant-frolicking-trinket.md). Read this before Phase 1.


1. Reference_Rules — the tunable constants (PORT as-is; these are the dials)

Code.js:93-117. Eight rows, Parameter · Value · Notes:

Parameter Value Meaning
VIX_Low 14 Risk-On band ceiling
VIX_Normal 19.5 Neutral band ceiling
VIX_High 27 Risk-Off
VIX_Extreme 31 De-risk
Regime_Factor_Normal 1.0 Baseline sizing multiplier
Risk_Per_Trade 0.01 1% of equity per trade
Portfolio_Start 25000 Starting equity (drives sizing)
Compression_Ratio 0.9 Today-range ≤ 0.9×30D-vol ⇒ "Compression"

v2: keep this tab + these named-range lookups. Add the rules the dumps + thesis surfaced: max ~12 positions, trade windows 9:45-11 / 2:30-4, −20% hard stop, the EDGE statement, the Do-Not-Buy list pointer.


2. Data layer (PORT the derived math; SWAP the source)

Every price/vol field is GOOGLEFINANCE(...) — the 15-min-delay root cause. In v2 the source becomes Finnhub (cached, rate-limited), but the derived math below is correct and ports verbatim:
- 3D% J, 10D% K(label says 30D but window is TODAY()-45→ actually ~30-trading-day), 30D-avg L, Above/Below-30D MCode.js:309-313.
- 13W hi/lo + % from (N-Q, TODAY()-91), 52W hi/lo + % (R-U, TODAY()-365) — :315-322.
- Vol%(30D) V = STDEV(30d close)/AVG(30d close); Today-Range% W = (high-low)/price:324-325.
- Volume vs avg BH = today vol / 30D avg vol — :363-365.

Note: the column header "10D %" sits on a -14-day window and "30D %" on -45; fix the labels in v2 (logic ok, names lie). Confirm the intended windows = 10/22/65 trading days per project_mis_cashflow_thesis.


3. Momentum_Engine — the scoring chain (PORT the structure, RECALIBRATE the constants)

Code.js:220-379, 60 columns. The load-bearing derivations:

🔴 STRUCTURAL BUGS — do NOT port these constants; FIX in v2

  1. Composite caps ~45. AD maxes ≈ 76 (50+8+18); × 0.6 ≈ 45.6; AF (catalysts) is usually 0. So AG rarely exceeds ~46 → Perf_Grade can almost never reach A (≥75) or B (≥60) → everything reads C/D, most "Avoid." This is the core scoring defect behind the 10-day review's "grade deflation." v2: rescale Composite to a real 0-100, or redefine the grade/flag bands to the actual distribution.
  2. Flow Strength is 4 discrete values (76 / 48 / 36 / …) → the infamous "stuck at 76." v2: make Flow continuous (volume-vs-avg, RS, trend slope), not a ±8/±18 step function.
  3. Action Flag thresholds (42/28) are pinned to the broken Composite range — recalibrate after fixing #1.
  4. SACS double-counts AG (AZ = AG×0.5 + …) so SACS inherits the cap. Decide SACS's independent inputs in v2.

Port = the derivation graph + the intent of each signal. Fix = the magic constants that make the graph collapse to C/D.


4. Position sizing — Snapshot ATR cascade (PORT faithfully — this is sound)

Code.js:440-488:
- ATR14_proxy H = STDEV(21d close) × 1.5 (fallback price × 0.03).
- Stops = price − {1.0, 1.3, 2.0} × ATR (I/J/K).
- % Risk @1.3× L = (price − stop1.3) / price.
- Shares @1.3× M = FLOOR( Portfolio_Start × 0.01 / |price − stop1.3| ) ← 1% risk sizing.
- Dollar risk N = shares × |price − stop1.3|.

This is the clean per-trade risk math. v2 keeps it; the FSE pulls Stop/Target/Shares from here (single source).


5. Daily_Snapshot — regime truth (PORT)

Code.js:423-435: Regime = VIX vs Reference_Rules bands (LOW/NORMAL/HIGH). VIX = INDEXCBOE:VIX. 10Y = INDEXCBOE:TNX / 10. Treasury regime = ≥4.5 Risk-Off / ≥3.8 Neutral / else Risk-On. Portfolio_Start mirrored to A9 for sizing.


6. LiveGuard resolver — THE PROTO-FSE (PORT the gate order + severity → becomes FINAL_STATE_ENGINE)

emailDailySnapshot.js:1353-1424. This is the decision tree that v2's FINAL_STATE_ENGINE formalizes as the single classifier:

v2 FSE = this resolver, made the ONLY authority, emitting FinalState ∈ {ADD, STARTER, WATCH, BLOCKED, REJECTED, EARNINGS_RISK} + PrimaryRejectCode + Stop/Target/RR/Shares (from §4). No other surface (HOLDINGS/OPEN-RISK email section, etc.) may classify independently — that's the "OK at −24% vs EXIT" contradiction the 10-day review caught.


7. Render section order (PORT the useful sections, drop the redundancy)

From the email engine (misBuildDailyBrief_:1700-1896, misBuildHtmlBrief_:4828-5161): Bottom Line · Holdings · Macro Pulse · Game Plan (regime/VIX/bias/SACS dist) · Recommendation Follow-up (self-grading — KEEP, high value) · Regime/Vol · Forward Look (compression setups, earnings-this-week) · Tape Breadth · Sector Pressure · Outliers · Trade Actions (ADD/STARTER/WATCH + brackets) · News/Catalyst · Position Reviews (RIDE/REDUCE/EXIT) · Live Guard · Mag 7 · 30-day charts · Data Health · Legend.

v2: morning carries holdings+macro; afternoons show only what changed (the FINAL_STATE_HISTORY delta). Lead with the FORWARD_NOTE, not "SPY up 0.70%."


8. Old → new tab map


9. Bugs to FIX in v2 (carried from the 10-day review — do NOT reproduce)

  1. "OK" verdict on a −24% position while FSE says EXIT → single classifier (§6).
  2. CALENDAR OVERLAY "no events in 21 days" (stale/empty) → real macro calendar feed.
  3. "live" label over 6-12-day-stale broker data → label honestly / Finnhub quotes.
  4. Bitcoin change frozen +0.00%; ETH/Brent garbage; ETF proxies mislabeled as spot → fix or label as proxy.
  5. Tape Breadth frozen across the day → recompute intraday.
  6. Universe count disagrees with itself (182/181/189) → one source.
  7. Composite/grade collapse to C/D (§3) → rescale.
  8. Morning brief misfired at 2:28 PM → trigger hygiene.

10. SWEEP ADDENDUM — everything else (full-history sweep, 2026-05-26)

Three parallel sweeps (MIS nested repo · workspace docs+memory+.remember · GitHub issues+outputs). The net-new beyond §1-9. Harvest the LOGIC/IDEAS from the old sheets; the NEW v2 sheet (1N2v-MDDi…) is the target — do NOT reuse old sheet IDs (1HEmRev/1cosuFr/1F31z are legacy; v2 1F31z is Excel-roundtrip-corrupted, discard).

10a. The CANONICAL FSE resolver (UPGRADES §6 — use THIS, not LiveGuard-only)

Per MIS_FSE_ARCHITECTURE.md: FSE assigns 3 states — ScannerState (technical), RiskState (gates), FinalState (what Sam may do). Resolver = first gate that fires wins:
1. formula error / stale → REJECTED/DATA_STALE · 2. Live Guard → BLOCKED · 3. held position past loss threshold → REDUCE/EXIT · 4. concentration violation → PORTFOLIO_OVERLAP · 5. ATR stop too wide → SETUP_DISTANCE_FAIL · 6. $risk > max → PORTFOLIO_RISK_FAIL · 7. Grade < B → WATCH · 8. SACS < 60 → can't be Lean In; 40-59 = STARTER only if all gates pass · 9. extended > 1.5× ATR intraday → CONDITIONAL/EXTENDED · 10. no stop/trigger → WATCH · 11. passes all → STARTER, or ADD only if live trigger confirmed.
Reject codes: DATA_STALE·LIVE_GUARD_BLOCK·NEWS_BLOCK·SHOCK_DOWN·EARNINGS_RISK·SETUP_DISTANCE_FAIL·PORTFOLIO_RISK_FAIL·GRADE_FAIL·SACS_FAIL·FLOW_FAIL·SECTOR_FAIL·NO_TRIGGER·EXTENDED·PORTFOLIO_OVERLAP·MISSING_STOP/TARGET/SIZE·FORMULA_ERROR.
Email top line = 6 permission tiers (NOT binary): 1 No new trades · 2 Watch only · 3 Starter only (delayed/limit) · 4 Selective adds · 5 Reduce risk · 6 Exit mode.

10b. SACS — the CORRECT weighted formula (FIX the grade collapse)

The v1 code SACS in §3 (AG×0.5 + AT×25) inherits the Composite cap. The canonical weighted SACS (MIS_FSE_ADDENDUM) is what to build: SACS = Composite×0.3 + Flow×0.3 + min(100, RR_13W×20)×0.2 + Grade_score×0.2, normalized 0-100. Grade bands (real distribution): A≥40 · B≥25 · C≥10 · D<10 (NOT the ≥75/≥60 that collapses everything to C/D). Lean In = SACS≥60; STARTER = 40-59 + all gates. Also: VolPenalty = 15 (locked; was 40, caused ±40-pt swings) and R:R must vary by setup (currently hardcoded 2.0 → placeholder; gate needs ≥2.5).

10c. Methods Sam HAD but UNDER-USES / ABANDONED — REVIVE these (his explicit ask)

10d. Build discipline (from the FSE architecture — non-negotiable)

Anti-80% rule: do NOT advance to the next module until the current acceptance test passes. One ticker end-to-end before scaling. Session Stop Rule: stop when the test passes / a blocker is found / safety uncertain / scope tempts to broaden. 15-point acceptance test gates "decision-grade": Flow distributed (not clustered) · SACS weighted · Snapshot full gate fields · execution surface can't show BUY on a rejected name · blocked names appear once · Grade-C never under High Conviction · Diagnostics can block · FSE one row/ticker/run · email reads FinalState from FSE only · delta from FINAL_STATE_HISTORY · answers the 10-sec questions · ADD requires live price · test basket (INTC·AMD·NVDL·MRVL·JBLU·SOXX·BLK·SCHG) resolves correctly.

10e. Holdings seed + secrets

10f. Locked behavioral rules to bake in (memory)

No-Monday-morning-QB (surface the warning BEFORE the trade, inline) · direction (↑/↓ + today's % @ price) on every signal · tab-duplicity defense (Include must be literal "Y"; IFERROR(primary, IFERROR(secondary, warned-default)), never silent 0) · check-the-sheet before reaching for an external API.


Phase 0 capture + full-history sweep · 2026-05-26 · Claude Code. The complete "everything MIS" reference. Next: the deep 2-ticker FSE build on this foundation (Anti-80% rule).

Source trail · docs/MIS_V2_LOGIC_CAPTURE.md @ master · rendered 2026-07-02 7:23 PM EDT by scripts/build-docs.py · the .md in the repo is the truth; this page is the phone-readable view