fix (ornith-35): watchlistRepository double-encoding bug — single JSON.stringify, 13/13 tests pass

This commit is contained in:
Investor Flow Build
2026-06-30 17:54:01 -04:00
parent 97607e0bd4
commit 1007ab4ed5
62 changed files with 11617 additions and 34 deletions
+242
View File
@@ -0,0 +1,242 @@
# Investor Flow — Domain Glossary
This file is the ubiquitous language for the Investor Flow project. It is a glossary, not a spec. Updated inline as terms are resolved during design (per the `domain-modeling` skill).
## Product
**Investor Flow** — A beginner-first, multi-tenant investment research terminal for retail investors with some stock experience, focused on conviction-based investing (not trading). Local-first: SPA + Bun/SQLite backend, Docker Compose deployment. Voice: convex in process, soft in presentation.
**Primary Rule — Education, not investment advice.** Investor Flow is an educational research terminal, not an investment adviser. It teaches *how a disciplined investor reasons* about a position; it never says "buy/sell/hold this." Every recommendation is a **consideration + a question**. RiskEngine `recommendedActions` are reworded (cut_to_cash → consider_reducing_position; trim_cluster → consider_rebalancing_cluster). SizingEngine outputs *math*, not instructions. Journal asks "what's your reasoning?" Alerts say "something changed," not "action needed." Every report closes with: *"Educational analysis, not investment advice. Verify the underlying data; you are responsible for your own decisions."* Legal posture: educational publisher. Formalized in ADR-0007. Every LLM prompt template and UI string reviewed against this rule ("Primary Rule lint"). When this conflicts with another principle, this wins.
**Analyst Voice** — The single house voice for every LLM Signal Summary, explainer, and alert. 70/25 blend of Mike Alfred (Alpine Fox LP — concentrated value conviction, ownership posture, plain-spoken directness) and Stanley Druckenmiller (macro-regime adaptation, asymmetric convexity). Rules: process over prediction; concentration posture; macro + company twin-lens; honest about uncertainty; P6 plain English; cite every claim to a cached source; confident when conviction exists, silent when it doesn't. Formalized in ADR-0005.
**P6 — Accessible-but-authored voice.** Core UX principle. Every user-facing string reads as plain English to a non-finance reader while staying professional. No orphan jargon (every term glossed in-screen); no baby talk; no unexplained acronyms. Complexity level adapts depth, not voice.
## Strategy & Sizing
**Strategy** — A named bundle of { Regime gate, Setup, Risk Policy }, reusable across symbols. A TradePlan is an instance of a Strategy applied to a symbol at a time.
**Regime** — A classification of market state (trending-up / trending-down / range-bound) over an index/timeframe, used to gate trading posture and sizing.
**Setup** — A parameterized, repeatable entry/exit checklist applied to a symbol situation.
**Risk Policy** — Sizing + stop-width + defined-risk rules applied when a setup fires.
**Screener** — A tool that evaluates a universe of symbols against one or more Strategies' entry conditions and outputs matches. (A screener run is a read-only backtest at "now".)
**Backtest** — Running a Strategy against cached historical OHLCV to compute performance. Cache-only; no live calls. Same engine as Screener.
**Position Sizing** — The function producing share quantity given a Strategy, risk%, stop, account, live portfolio, and regime. Multi-layered (Layers 0–4).
**Risk Per Trade** — Dollars an account is willing to lose if a plan's stop is hit, before any size is computed. Default 1% for beginners.
**Conviction Tier** — A_STAR / A / B / C — the user-graded quality of a setup; multiplies the base risk fraction (×3 / ×2 / ×1 / ×0.5). Locked at lower tiers until per-tier win-rate statistics justify unlocking.
**Sizing Unlock** — A workflow state: complexity-tier elevation earned by accumulating profitable trades at a sub-tier (20 profitable B → unlock A; 10 profitable A → unlock A_STAR). Tunable per-user.
**Macro Regime Gate** — When regime trending-down = ×0.5 size; ranging = no A_STAR; trending-up = normal + A_STAR unlocked. Default: auto-cap with one-tap override requiring a written reason.
**Correlation Cluster** — A group of holdings sharing a single macro/factor driver (e.g., all BTC miners). Aggregated exposure capped; beginners get hard caps, intermediates get warnings.
## Institutional & Insider
**Quarter** (institutional module) — The reported calendar quarter a 13F snapshot is *as of*. Buy-zone/sell-zone estimates reconstruct institutional transaction likelihood within that quarter from the snapshot diff + volume-weighted price action.
**Institutional Footprint** — Per-symbol combined ownership picture from all four SEC forms (13F, 13D, 13G, Form 4), with every owner row classified by holder type.
**Holder Class** — One of: `Passive Index`, `Activist`, `Active Conviction`, `Market-maker/Hedger`, `Insider`. Inferred from which SEC form(s) filed + CIK entity metadata (SIC codes).
**Net Active Conviction Δ** — Per-symbol QoQ share change summed across Active Conviction + Activist classes only. Excludes passive index and MM/hedger noise. The ranked signal on the dashboard.
**Holder Snapshot Diff** — Quarter-over-quarter Δ per institution per symbol, derived from consecutive 13F filings.
**Insider Transaction** — A single Form 4 transaction by an officer, director, or 10%+ holder. Classified: Informed Buy / Informed Sell / Routine.
**Informed Buy** — Open-market buy (code P) NOT under a Rule 10b5-1 plan. Highest-signal insider bull.
**Informed Sell** — Open-market sell (code S) NOT under 10b5-1. Negative signal; alert by default.
**Routine Insider Transaction** — Any Form 4 transaction under 10b5-1, OR an option exercise (M), grant (A), or vesting event. Pre-scheduled/compensation-driven; low signal; hidden by default for beginners.
**Buy-Zone Estimate** — Volume-weighted price band during a quarter in which an institution *likely* accumulated/reduced. An estimate, always tagged "estimated" in the UI.
**Insider Activity Stream** — Real-time per-symbol ledger of Form 4 filings, classified, with Informed events surfaced first and alertable. Own module (M5), separate from quarterly snapshot (M4).
## Sector Rotation
**Sector Rotation** — Movement of capital between market sectors. The module surfaces both realized (RS-rank reshuffle over N weeks) and incipient (early RS-slope turn + breadth thrust before price moves) rotation.
**Rotation Phase** — A label on detected rotation: Accumulation → Expansion → Distribution → Markdown, with a confidence score.
**Rotation Signal History** — Every incipient rotation signal is logged and later resolved as Real or False-alarm. Two-stage resolution (γ): price follow-through confirms first (within N=4 weeks, deterministic); institutional flow confirms later (quarter-end, durable). Enables "which signal types were reliable" learning.
## Ticker
**Ticker Kind** — `equity` | `crypto` | `etf` | `index`. Gates which modules apply (e.g., crypto excluded from SEC/13F/insider modules). BTC kept for price/sentiment only.
## Screener (two modules)
**Filter Screener (M15a)** — A TradingView/Finviz-style screener: user writes ad-hoc filter expressions (descriptive, technical, fundamental, events, ownership, sentiment) over a universe; outputs matching symbols with "why matched." Beginner-immediate. No Strategy required. Saved filter sets are per-user (Tier C). Not backtested. Universe: tiered (watchlist first, opt-in broader scan scoped by sector).
**Strategy Screener (M15b)** — A screener that evaluates a chosen Strategy bundle's entry conditions across a universe; outputs symbols where the Strategy fires, with conviction-strength (how many entry conditions true). Backtestable. Requires an authored Strategy (gated by Conviction Tier unlocks). Output: symbol + which conditions fired + one-tap into Symbol Overview workbench.
**UniverseEvaluator** — Shared deep module iterating a symbol universe and applying a pure predicate (a compiled filter expression OR a Strategy's entry conditions) against cached data. Powers both M15a (filter predicate) and M15b (Strategy predicate). One interface, two callers.
Screener output policy (both modules): symbol + "why matched" + one-tap "open in workbench" (drop symbol into Symbol Overview). The screener shortens time-to-conviction; it is never the final answer.
## Options Convexity Sleeve (M17)
**Options Convexity Sleeve (M17)** — A portfolio module applying a small defined-risk options overlay to a core holding — for income (covered calls), cheaper entry (cash-secured puts), downside insurance (protective puts/collars), or leveraged thesis (long LEAPS). Never standalone directional. (Research-grounded: Spitznagel/Universa tail-hedging, Pabrai cash-secured entry, Ackman rate-hedge overlay, Druckenmiller cheap-convexity, Buffett index-put seller.)
**Sleeve Risk Budget** — Per-thesis combined budget for stock + options risk (e.g. 1–5% of portfolio). SizingEngine enforces the combined ceiling so options can't quietly swell.
**Convexity Posture** — A user's options advancement state: `Off → Covered Income → Cash-Secured Entry → Insurance Sleeve → LEAPS Conviction`. Unlocks progressively by Sizing Unlock (mirrors Conviction Tier). Default `Off` (Alfred: "I don't think most people should use options tbh").
**Defined-Risk Only** — Hard module constraint: strategies with unbounded loss (naked short calls, naked short straddles, undefined-risk structures) are physically blocked. Beginner guardrail; never disabled for beginners.
**Tail Convexity** — A small portfolio sleeve (~1–3%/yr) of long-dated deep-OTM puts on broad indices OR a correlation cluster (Spitznagel/Universa model). Pays small premium most months, asymmetric payout in tail events — *insurance*, not speculation.
**IV Regime Gate (within M17)** — Modulates allowed overlays by IV Percentile: covered calls when IV high (juicy premium); protective puts / LEAPS when IV low (cheap insurance). Never buy convexity when it's expensive.
## Macro Module (M18)
**Macro Module (M18)** — Fourth pillar module: calendar of high-impact macro events (M18a), current-regime classifier (M18b), portfolio-impact commentary (M18c), and regime history (M18d). The Druckenmiller 25% lens given dedicated surface. Reads macro + connects to portfolio; never recommends a macro trade (the Alfred caution extends to macro-trading). Leaves action to Conviction Tier + Convexity Posture gates.
**Macro Regime** — A label classified by M18b (trending-up / trending-down / range-bound / structurally-shifting) from yield curve, inflation, rate path, liquidity, breadth. Consumed by the Macro Regime Gate (SizingEngine Layer 4). M18b is the classifier the gate depends on.
**Portfolio Impact Commentary** — LLM-generated (Druckenmiller lens), two-horizon: short-term reaction risk (per-event, per-correlation-cluster, with historical averages + sample size + disclaimer, never a forecast) and long-term structural read (regime-shift framing). Cites M18 regime + the user's actual holdings. Always on (matches Analyst Voice "always on" decision).
**Regime History** — Timeline of regime classifications over time; cross-references Rotation Signal History. Pedagogy for "did we detect the shift correctly" — beginner learns which classifier calls were early vs whipsawed.
## LLM Data Provenance (ADR-0006)
**ornith** — The default LLM provider for Investor Flow: a remote-hosted, operator-owned, OpenAI-compatible REST endpoint. Configured `is_local=true` in `llm_providers` so it serves both public and sensitive features (ADR-0006 Data-Classification Gate). Env vars `ORNITH_LLM_URL` + `ORNITH_LLM_API_KEY` injected via Docker Compose secrets. Formalized in ADR-0008. The provider itself is pluggable; `ornith` is the v1 default, not a hard dependency.
**LLM Data Provenance** — Three hard constraints enforcing no-training-on-user-data: (1) Production LLM Gateway defaults to a **local OpenAI-compatible endpoint**; non-local providers require explicit operator override + documented provenance review. (2) **Sensitive user data** (portfolio positions, trade plans, journal, SEC content, sentiment annotations, saved posts, anything tagged ownerId or Tier C) is **never routed through external LLM providers** by code-level data-classification gate, not a runtime toggle. (3) **Developer conduct**: never paste live user-data into external AI-assistant prompts during the build; use fixtures/synthetic data only.
**Local-first default** — The Gateway's `baseURL` defaults to a local endpoint (Ollama/vLLM on host or LAN); the only provider config loaded by default. "Local" = `localhost`, `127.0.0.1`, `::1`, or `LOCAL_LLM_SUBNETS` env override.
**Data-Classification Gate** — `LLMGateway.classifyPayload(payload): 'public_safe' | 'sensitive'` runs before any provider dispatch. Sensitive payloads routed to non-local providers throw `SensitiveDataBlockedError` and never leave the host. A code-level guarantee, tested via property tests over a fuzz corpus.
## Ticker-Data Dedupe (Architectural Pattern)
**Content-Addressed Caching** — All fetched market data is cached by a content-addressed key (e.g., `yfinance:quote:IREN`). Two users fetching the same symbol collapse to the same row; duplicates don't happen by construction. Tier A tables (price/candles/options/filings/13F) have no ownerId and are shared.
**Demand Set** — The set of symbols that currently have ≥1 user tracking them (watchlist ∪ open portfolio holdings). The adapter queue only schedules fetches for symbols in the demand set — zero wasted bandwidth on untracked symbols. Cost scales with the *breadth of the demand set*, not user count (a million users all tracking NVDA = still one NVDA fetch per staleness window).
**Refcount** — Per-symbol demand counter, bumped +1 when a user tracks the symbol, −1 when they untrack. Refcount → 0 halts live/sentiment refresh for that symbol; historical immutable data (backtest OHLCV, SEC filings) stays cached regardless because backtests/filings need it forever.
**Stale-While-Revalidate** — The SPA reads from cache instantly and the backend silently schedules a background refresh if the row is past its staleness window — the user never blocks on a live fetch. Duplicate concurrent cache-misses for the same key collapse to ONE fetch (multi-tenant dedupe per ADR-0004).
## P7 — Visualizations teach mechanics, never decorate outcomes
**P7** — Core UX principle (added alongside P6). Every visualization makes a mechanical relationship more *legible*, never more *exciting*. Visuals can teach or manipulate (Robinhood's confetti SEC fine is the cautionary tale). The four guardrails:
- **G1 — Teach the mechanic, don't decorate the outcome.** A chart showing *where Citadel accumulated within the quarterly price band* teaches; a "+15%!" bouncing number celebrates. Alfred-lean voice explains mechanics, never celebrates results.
- **G2 — Every chart has a one-line "what this tells you."** No naked visualization. Each chart/heatmap/payoff diagram carries a P6 plain-English caption written at design time. If we can't write the lesson, the viz is decoration, not a feature — drop it.
- **G3 — Color-blind / accessibility-safe by default.** Red/green for P/L is dangerous (8% of men). Use **shape + color + label** triads: institutional adds = up-triangles in blue, reduces = down-triangles in amber, text labels always present. Recharts/visx support custom shapes natively.
- **G4 — Annotated data viz over abstract 仪表盘.** The LLM-generated Signal Summary produces **annotated chart overlays** — summary text has chart positions tagged. One annotated story, not 5 detached widgets.
## Anti-gamification rules (locked)
Explicit "do not build" list — written down so the build doesn't accidentally Robinhood itself:
- No trade-animation confetti / win-streak badges / "you did it!" celebrations — Robinhood was SEC-fined for this.
- No 3D / decorative gauges — chart-porn, no mechanic taught.
- No real-time candle-minute flickering — encourages trader-brain, not investor-brain. Daily candle with a steady quote line is enough.
- No outcome-celebration visuals. Sizing/backtest viz shows mechanics (drawdown is more important than win rate), not trophies.
## Canonical visualizations (locked — the curated 10)
Each is curated at design time with its one-line lesson (G2). Not an open-ended viz library.
1. **Annotated Price Chart** — candles + Form 4 insider buy ▲ markers + institutional buy-zone shaded band + macro event markers + key levels overlaid. *Lesson: prices move WITH insiders/institutions/events, never alone.*
2. **Sector Rotation Heatmap** — sectors × weeks grid, color = RS rank, cells pulse on phase transitions. *Lesson: money rotates between sectors; early signs are subtle.*
3. **Rotation Phase Timeline** — horizontal stream of Accumulation→Expansion→Distribution→Markdown markers. *Lesson: rotation is a phase sequence, not an instant.*
4. **Options Payoff Diagram** — today + at-expiry + early curves, max loss/gain shaded, breakeven marker. *Lesson: an option position is a SHAPE not a bet; defined-risk is visibly bounded.*
5. **Institutional Footprint Stacked Bar** — per-symbol holder-% by Holder Class, color-coded (MM/hedger vs Active Conviction visually distinct). *Lesson: not all ownership is conviction.*
6. **QoQ Institutional Δ Chart** — per-filer bars over a price-range overlay at the band they likely transacted at. *Lesson: institutions move over a quarter, on a price band.*
7. **Correlation Cluster Treemap** — your holdings grouped by factor driver; cluster size = exposure $. *Lesson: 5 holdings != 5 bets; factor risk (the 2008 lesson).*
8. **Sizing Decision Tree** — account → risk-per-trade → tier multiplier → position size, animated as you change a Conviction Tier. *Lesson: sizing isn't a guess; it cascades from rules you earned.*
9. **Strategy Backtest Equity Curve + Drawdown overlay** — P/L line with drawdown under it; trade dots are entry+exit. *Lesson: worst pain matters more than win rate.*
10. **Annotated Institutional Event Card** — one chart with text callouts at each event point + the one-paragraph Analyst Voice summary alongside. *Lesson: many data streams → one coherent story. THE beginner viz.*
## M19 — Mobile Monitor (companion surface, not mobile-first)
**Mobile Monitor (M19)** — Separate thin client reading the same Bun backend + SQLite cache + adapter queue + LLM Gateway as the desktop workbench. For job A (passive monitoring: alerts, P/L glance, per-symbol story) NOT job B (active research: backtests, multi-panel cross-reference, screener, strategy authoring). Read-mostly; limited authoring (add to watchlist, ack alert, save post). Native is a later phase; v1 = Next responsive route, not React Native. Built second, after the desktop workbench.
**Two-job split** — Investor Flow serves two jobs at two home surfaces: (A) passive monitoring on the go = mobile phone, M19; (B) active research at a desk = desktop/laptop, M1–M18 workbench. One backend, two co-equal client surfaces. Going mobile-first would force job A's surface on job B (Robinhood's bet); the depth that justifies the product dies.into tabs. Build desktop workbench first; thin mobile companion second shares all backend work (refcounted shared cache means mobile is a second client, not a second product). ~30% more frontend, 0% more backend.
## Two-Axis Investment Model (Fundamental × Technical)
**Fundamental Thesis** — The written WHY of an investment: what to own + invalidation criteria. Tracked over time (`intact` / `weakening` / `broken`). Broken thesis = exit regardless of TA. Process-grounded: Alfred's BKKT entry was 8 months of fundamental thesis-building before deployment.
**Entry Confluence Rack** — The accumulating WHEN: a structured checklist of technical confluences. Each lit = +1; more lit = better entry quality. Generalizes the old journal's `confluenceCount` into a structured, named, trackable rack. A user authors the Rack per-Strategy by pulling from the Confluence Library.
**Two-Axis Posture** — Every investment has two independent axes: fundamental conviction (Conviction Tier) × technical entry (Confluence Rack). High conviction + bad entry = WAIT (never "buy like an idiot"). The SizingEngine enforces the posture matrix as a hard guardrail. Override requires one-tap + written reason (mirrors Macro Regime Gate).
**Entry Confluence Rack (4-factor default)**:
- **A. Trend alignment** — price > EMA200, EMA21 > EMA50, higher-highs/lows. +1 when all 3 hold.
- **B. Pullback maturity** — recent low near EMA21 or a key level + volume dryup on the dip. +1 when both.
- **C. Catalyst proximity** — earnings / 13D/A / insider informed-buy / rotation phase Accumulation→Expansion within ≤30 days. +1.
- **D. Risk-bound coherence** — Stop-loss set at a real level (under support / under EMA50) AND reward-to-risk ≥ 2:1. +1.
**Entry regime labels** (what the user sees, P6 plain English, P7 visual):
- 0–1 lit = **"Bad entry"** (WAIT — app shows which confluences are unlit + what would light them).
- 2 lit = **"Marginal entry"** (plan a small first deployment only).
- 3–4 lit = **"Good entry"** (DEPLOY per Conviction Tier capacity).
**Confluence Slot** — A single authored predicate `lit(symbol, cachedData) → bool`. Pulled from the Confluence Library. Rack = collection of slots. Default Rack = 4 slots (beginner); extendable to 6+ (advanced).
**Confluence Library** — Registry of named parameterizable slot templates: `trendAlignment`, `pullbackToEMA21`, `catalystProximity`, `riskBoundCoherence`, `sma200w` (200-week SMA proximity), `rsImproving`, `breadthThrust`, `insiderInformed30d`, `instNetActivePositive`, `ivPercentileLow`, etc. Long-horizon SMAs (e.g., 200-week) measure multi-year holder cost basis — strong *thesis support*, can also be authored as *entry slots* when price is within X% of the level.
**Redundancy Awareness** — When multiple lit slots measure the same underlying signal (e.g., 21-EMA > 50-EMA AND price > EMA200 AND price > 200-day SMA in a persistent uptrend), the app tags them "redundant — counts as one signal." Analyst Voice explains why; the user keeps/removes at will. Adding indicators doesn't necessarily improve entries; redundancy adds noise.
**Default Rack by complexity** — Beginner: 4-factor. Intermediate: +rotation-phase slot. Advanced: +full authorable Confluence Library (incl. 200-week SMA, VWAP, volume-profile POC, etc.).
**Deployment Schedule** — How capacity (Conviction-Tier-sized) is entered over time/space, gated by Confluence Rack accumulation. Replaces one-shot entry with corridor scale-in (Alfred's May 15-18 four-day deployment at a price corridor). Beginner-default: "deploy 40% at Rack≥3; deploy remaining 60% at Rack≥4 OR price revisits buy-zone / EMA21."
**Thesis Monitoring** (autonomous, 3 layers):
- **L1 — Per-holding**: every relevant event for that symbol cross-references the user's stated invalidation criteria; fires intact/weakening/broken per position.
- **L2 — Portfolio posture**: aggregated stock-level weakening ≥ threshold; correlation cluster over-exposure; regime change.
- **L3 — Macro context**: sector rotation phase flips; macro regime classification updates; market breadth thrust triggers.
Each independently alertable; surfaces on M1 (L1), M10 portfolio dashboard (L2), M18 macro module (L3); M19 mobile shows all three in priority order. Not a forecast engine — never predicts returns; only translates stated invalidation criteria into alerts when matching events arrive. L1 runs via CacheRepository reads + LLM Gateway over local-only provider per ADR-0006 (thesis content = sensitive user data).
## Risk Management (ADR-0007 territory)
**RiskEngine** (deep module) — Pure aggregator reading portfolio + theses (L1/L2/L3) + correlation clusters + macro regime → RiskPosture. Never touches network. Produces: totalRiskUsd/Pct, drawdownUsd/Pct, maxDrawdownTolerance status (healthy/warning/halted), clusterBreaches, regimeRisk (aligned/misaligned/hostile + recommendedCashPct), asymmetryScore, cashReservePct, recommendedActions (cut_to_cash/trim_cluster/halt_new_entries/close_thesis_broken/continue). Surfaces on M10 desktop + M19 mobile.
**M20 Risk Posture** — Single unified risk-picture surface. The "where you see your complete risk picture + what to cut" panel. Curated visualizations under P7 (drawdown gauge is NOT a decorative gauge — teaches the mechanic: drawdown-vs-tolerance-by-style-fit), recommendedActions with cited inputs. Prominent on M19 mobile.
### The 6 risk primitives (locked dictionary)
**Max Drawdown Tolerance** — Per-user $/% threshold stated at onboarding. Hitting it → halt_new_entries (24h cooldown + L1 thesis re-evaluation). The Soros circuit breaker as user policy.
**Total Risk Capacity** — Max sum of open-position risk if all stops hit (beginner default 5% of equity). SizingEngine enforces per-position; RiskEngine enforces aggregate.
**Correlation Cluster Cap** — Max % equity in one factor driver (beginner default 25%; 40% intermediate). SizingEngine Layer 3 enforces at entry; RiskEngine surfaces breach across whole book.
**Asymmetry Score** — Portfolio-weighted reward-to-risk across open positions (stated target & stop). <1.0 → warning ("your trades are sized wrong on average — losing over time even winning some"). Soros's principle in a number; pedagogically powerful but confronting.
**Regime Risk Posture** — Portfolio-wide cash recommendation by regime-vs-style fit (aligned/misaligned/hostile). Trending-up → ≤20% cash; structurally-shifting → ≥50% cash + halt fresh entries if no thesis resists the new regime. Druckenmiller's "cut risk when regime turns before losses prove it."
**Thesis-Broken Exit Rule** — L1/L2/L3 thesis monitor flag = broken → push-alert (mobile) + popup (desktop) + immediate exit recommendation with cited event. One-tap-override-with-written-reason; never silently held. The Alfred discipline.
### Default risk caps (by complexity)
- Beginner: total risk = 5% of equity; correlation cap = 25%; halt drawdown = -20%; cooldown = 24h.
- Intermediate: 10% / 40% / -30% / 12h.
- Advanced: authorable per user.
## Derisking (the asymmetric-management discipline)
**Derisking Strategy Library (6 strategies)** — Derisking is asymmetric: winning trades have flexibility (scale out, trail, insure); losing trades have only cut (stop or thesis-broken). The app asks "winning or losing?" before suggesting a derisk path. Default derisk for A_STAR conviction winner = choice between scale-out (SRxTrades-style selling) and protect-with-collar (Spitznagel-style insuring).
1. **Scale-out at targets** — trim 25%/target + breakeven-stop-after-first-trim + runners with trailing stop. SRxTrades mechanic.
2. **Stop-trail up** — trail with EMA21 (swing) or EMA50 (trend); exit fully below EMA50 close. Sunil mechanic.
3. **Thesis-based partial derisk** — trim by thesis-status: intact→hold full; weakening→trim 25-33%; broken→exit remaining. L1/L2/L3-driven. Alfred mechanic.
4. **Options-protected hold (collar)** — buy protective put below current price (locks downside, keeps upside) + covered call above (collar) to fund the put. The Spitznagel/Universa convex path: don't sell, insure. For convicted winners where you want downside bounded but thesis intact.
5. **Regime-cut derisk** — sell down to target cash posture (e.g. 50%); portfolio-wide not one-at-a-time. RiskEngine recommendedCashPct.
6. **Correlation-driven derisk** — trim the cluster not the winner; reduce biggest cluster-cap violator.
**Exit Strategy** — First-class field on `Strategy` (alongside Setup). Previously we specified entries but not exits. Now: Exit Strategy = the derisk + exit logic authored per-Strategy, sourced from the Derisking Strategy Library (6 primitives above, default per complexity).
**Two-Axis Derisking** — The app considers BOTH thesis-status AND price-momentum before suggesting. Winning + thesis intact → collar or scale-out; winning + thesis weakening → scale-out + tighter •••; losing → cut only (never average down or sell puts against a loser; those are trader-paths beginners lose on, not in our app). LLM Analyst Voice distinguishes: "Thesis still intact at A-STAR? The collar protects downside while keeping your winners. Thesis weakening? Scale out — don't insure a name you might not want."