diff --git a/prod/docs/BEADS_PASS_TRACKER_EVALUATION.md b/prod/docs/BEADS_PASS_TRACKER_EVALUATION.md new file mode 100644 index 00000000..c4c37080 --- /dev/null +++ b/prod/docs/BEADS_PASS_TRACKER_EVALUATION.md @@ -0,0 +1,105 @@ +# BEADS as PASS Tracker — Evaluation & Recommendation + +**Author:** pi_nvnemo (UV Overseer) +**Date:** 2026-07-08 +**Context:** UV_OVERSEER_CHARTER__PI.md §6 task — evaluate beads vs bus+doc for PASS board + +--- + +## Current State + +| Tracker | Status | +|---------|--------| +| **h5i bus** | Active — dispatch, ACK, status updates | +| **Status doc** | Not yet created (charter says "track PASSes on the bus + a short status doc") | +| **beads** | Installed, `.beads/` exists at repo root (prefix `dp`), 1 existing PRODGREEN issue | + +--- + +## What Beads Gives Us Over Bus+Doc + +| Capability | h5i Bus + Doc | Beads | +|------------|---------------|-------| +| **Dependency graph** | Manual (doc) | Native (`br dep add`, `br graph`) | +| **Task hierarchy** | Flat (doc sections) | Epic → child beads (parent/child) | +| **State machine** | Manual (doc) | Enforced (open → in_progress → closed) | +| **Acceptance criteria** | Doc prose | Structured fields (`acceptance_criteria`, `test_command`) | +| **Audit trail** | Bus history + doc edits | Immutable JSONL + SQL + `br audit` | +| **Handoff protocol** | Informal | Formal (`br audit --message`, `br ready`) | +| **Multi-agent isolation** | Bus channels | Separate workspace per refactor stream | +| **Low-skill agent onboarding** | Ad-hoc | Bounded task template + dependency chain | +| **Query/Filter** | grep/awk | `br ready`, `br list`, `br status`, SQL | +| **Backup/Sync** | Git + manual | `br sync`, `br backup` | + +**Verdict:** Beads adds **structured task management** that the bus+doc lacks — critical for multi-PASS dependency chains (PASS-P → PASS-A → PASS-S → PASS-B/X). + +--- + +## PASS → Bead Mapping + +| PASS | Bead Type | Suggested ID | Parent | +|------|-----------|--------------|--------| +| **PASS-P** (Pulse Landing) | Epic | `UV_PASS-P` | — | +| ├─ Copy `prod/uv_pulse_host/` | Task | `UV_PASS-P.1` | `UV_PASS-P` | +| ├─ Add `.gitignore` (exclude `target/`) | Task | `UV_PASS-P.2` | `UV_PASS-P` | +| ├─ Cert conveyor commit | Task | `UV_PASS-P.3` | `UV_PASS-P` | +| ├─ Soak DARK + TUI heartbeat | Task | `UV_PASS-P.4` | `UV_PASS-P` | +| **PASS-A** (Account Region) | Epic | `UV_PASS-A` | — | +| ├─ Phase 0: Contracts + in-mem | Task | `UV_PASS-A.1` | `UV_PASS-A` | +| ├─ Phase 1: Real shm + hardened reader | Task | `UV_PASS-A.2` | `UV_PASS-A` | +| ├─ Phase 2: ASEx publish | Task | `UV_PASS-A.3` | `UV_PASS-A` | +| ├─ Phase 3: Capital provider | Task | `UV_PASS-A.4` | `UV_PASS-A` | +| **PASS-S** (Sizing Seam) | Epic | `UV_PASS-S` | — | +| **PASS-B** (Host Brain) | Epic | `UV_PASS-B` | — | +| **PASS-X** (Tick Exits) | Epic | `UV_PASS-X` | — | + +**Dependency Chain:** +``` +UV_PASS-P → UV_PASS-A → UV_PASS-S → UV_PASS-B → UV_PASS-X +``` + +--- + +## Smallest Viable Setup + +```bash +# 1. Create dedicated UV workspace (isolate from PRODGREEN) +mkdir -p /mnt/dolphinng5_predict/uv/.beads +export BEADS_DIR=/mnt/dolphinng5_predict/uv/.beads + +# 2. Initialize +br where # confirms workspace + +# 3. Create PASS-P epic + children +br create --title "PASS-P: Pulse Landing" --type epic --id UV_PASS-P +br create --title "Copy prod/uv_pulse_host/ from /mnt/vp-PASS9" --parent UV_PASS-P --type task --acceptance "Directory copied, target/ excluded" --test "ls prod/uv_pulse_host/ && ! ls prod/uv_pulse_host/target/" --id UV_PASS-P.1 +br create --title "Add .gitignore excluding target/" --parent UV_PASS-P --type task --acceptance "target/ ignored by git" --test "git check-ignore prod/uv_pulse_host/target/" --id UV_PASS-P.2 +br create --title "Cert conveyor commit + integrator review" --parent UV_PASS-P --type task --acceptance "Commit on main, integrator signed" --test "git log --oneline -1 prod/uv_pulse_host/" --id UV_PASS-P.3 +br create --title "Soak DARK + TUI heartbeat + STALE" --parent UV_PASS-P --type task --acceptance "TUI renders live rate/AGE/STALE, RSS flat ≥4h" --test "TUI smoke test + log review" --id UV_PASS-P.4 + +# 4. Link to bus for dispatch notifications +# (beads = source of truth; bus = real-time signal) +``` + +--- + +## Recommendation + +**ADOPT BEADS for PASS tracking** with the following protocol: + +1. **Beads = Source of Truth** — all PASS state, dependencies, acceptance criteria, audit trail +2. **h5i Bus = Real-time Signal** — dispatch, ACK, status pings, escalation (what we already do) +3. **Status Doc = Snapshot** — auto-generated from beads weekly or on demand (`br status > PASS_BOARD.md`) + +**Migration Path:** +- Week 1: Create UV workspace, populate PASS-P + PASS-A epics/children +- Week 1: Run dual-track (beads + bus) — validate no drift +- Week 2: Deprecate manual status doc; auto-generate from `br status` + +**Why not bus+doc alone?** The PASS chain has 5 epics with 15+ children, strict dependencies, and must survive agent rotation. Beads enforces what the charter demands: "keep a live board; chase stalls; escalate blocked specs." + +--- + +## Next Action + +If approved: I'll initialize `/mnt/dolphinng5_predict/uv/.beads`, populate PASS-P epic + children, and link dispatch messages to bead IDs. diff --git a/prod/docs/NEW_PINK_FORENSICS_DUAL_LEV_2026_SEARCH_RESULTS_SPEC.md b/prod/docs/NEW_PINK_FORENSICS_DUAL_LEV_2026_SEARCH_RESULTS_SPEC.md new file mode 100644 index 00000000..50bfe098 --- /dev/null +++ b/prod/docs/NEW_PINK_FORENSICS_DUAL_LEV_2026_SEARCH_RESULTS_SPEC.md @@ -0,0 +1,659 @@ +# PINK Forensics — Dual Leverage Architecture (2026 Search Results) + +**Date:** 2026-07-06 +**Agent:** pi_nvnemo +**Trigger:** Operator request — locate the authoritative dual-leverage spec + +--- + +## Executive Summary + +The DOLPHIN system implements a **strict dual-leverage architecture** separating two distinct leverage concepts that must NEVER be conflated: + +| Layer | Name | Range | Purpose | Set By | +|-------|------|-------|---------|--------| +| **Internal** | **Conviction Leverage** (our_leverage) | 0.5 – 9.0 (fractional) | Sizes QUANTITY: `notional = capital × 0.20 × conviction`, `qty = notional / entry_price` | Strategy / sizer (`esf_alpha_orchestrator`, `AlphaBetSizer`) | +| **Venue** | **Exchange Leverage** (xlev) | 1 – 3 (integer) | Controls MARGIN: `margin = notional / exchange_lev` sent to BingX API | Venue boundary mapper (`prod/bingx/leverage.py`) | + +**PnL is ALWAYS leverage-free**: `qty × Δprice` (side-signed). Exchange leverage only affects collateral lockup. + +--- + +## Authoritative Source Files (Bit-Identity Required) + +### 1. `prod/bingx/leverage.py` — **THE SINGLE SOURCE OF TRUTH** (83 lines, no callers) + +```python +CONVICTION_MIN = 0.5 +CONVICTION_MAX = 9.0 +EXCHANGE_LEV_MIN = 1 +EXCHANGE_LEV_MAX = 3 +LEVERAGE_MAPPING_RULE = "round_half_even_linear_0.5_to_9.0_to_1_to_exchange_cap" + +def map_internal_conviction_to_exchange_leverage_target(internal, *, exchange_min, exchange_max) -> float: + # clamp internal to [0.5, 9.0] + # linear: exchange_min + (internal - 0.5)/(9.0 - 0.5) * (exchange_max - exchange_min) + # returns FLOAT target (pre-round) + +def normalize_bingx_leverage_value(leverage, *, exchange_min, exchange_max) -> int: + # ROUND_HALF_EVEN (banker's: 1.5→2, 2.5→2, 3.5→4) + clamp to [exchange_min, exchange_max] + +def map_internal_conviction_to_exchange_leverage(internal, *, exchange_min, exchange_max) -> int: + # = normalize_bingx_leverage_value(map_..._target(internal), ...) + # FINAL integer sent to BingX API +``` + +### 2. `prod/clean_arch/runtime/pink_direct.py:_hz_publish()` (line ~909) + +```python +def _hz_publish(self, slot_dict: dict, acc: dict) -> None: + """Fire-and-forget Hz write after any kernel state change. + + Computes system leverage (our_leverage = notional/capital) for the Hz + snapshot — PINK/BLUE dual-leverage invariant: system leverage reflects real + margin utilisation; exchange leverage (1-3x cap) is set at BingX API level. + """ + size = float(slot_dict.get("size") or 0.0) + ep = float(slot_dict.get("entry_price") or 0.0) + capital = float(acc.get("capital") or 0.0) + our_leverage = (size * ep / capital) if capital > 1e-10 else 0.0 + self.hz_state_writer.write_engine_snapshot( + slot_dict, acc, + posture=self._last_posture, + our_leverage=our_leverage, # <-- CONVICTION leverage published to Hz + scan_number=self._last_scan_number, + vel_div=self._last_vel_div, + vol_ok=self._last_vol_ok, + ) +``` + +--- + +## Spec Documents (Chronological) + +### A. `prod/docs/FRACTIONAL_LEVERAGE_TO_BINGX_FIX.md` (2025-04-24) +**Origin story** — CRITICAL bug: exchange leverage was hardcoded to 1x, ignoring per-trade fractional leverage. +- "The system correctly separates leverage into two roles" +- Fractional leverage → affects quantity (how many contracts) +- Exchange leverage → affects margin (how much collateral) +- Fix: CEIL rounding for exchange leverage (`ceil(fractional_lev)` clamped to [1,9]) + +### B. `prod/docs/PINK_ACCOUNTING_EXEC_FIX.md` (2026-06-11) +**Forensic incident** — FET short settled at +$164 but kernel booked −$5,990.90. +**HARD INVARIANT (§0):** +> **Dual leverage**: `slot.size` = exchange quantity; `slot.leverage` = exchange leverage (1–3x cap, set at BingX API); *our*-leverage (conviction) = `size × entry_price / capital`, computed **only** at `pink_direct._hz_publish` (line ~911). PnL is therefore **leverage-free**: `qty × Δprice`, side-signed. Do not touch the conviction→exchange mapping (`round_half_even_linear_0.5_to_9.0_to_1_to_exchange_cap`) or `target_size` computation. + +### C. `prod/docs/VIOLET_SUB_SPEC__L3_EXCHANGE_LEVERAGE.md` (2026-06-15) +**VIOLET L3 wrapper spec** — "WRAP, DON'T REIMPLEMENT" +- V-TYPES boundary: `ConvictionLeverage` (Annotated float) → `ExchangeLeverage` (Annotated int ≥1) +- `VioletExchangeLeverage` class wraps `prod/bingx/leverage.py` functions exactly +- Gate: MC bit-identity @ N≥1e6 vs real `leverage.py` output +- Zero shared-file edits; bit-identity is the contract + +### D. `prod/docs/VIOLET_V3_FINDINGS.md` §2 (2026-06-15) +> **DUAL-LEVERAGE:** conviction leverage sizes the QUANTITY (internal); exchange leverage mapped at venue boundary via `prod/bingx/leverage.py` `map_internal_conviction_to_exchange_leverage_target` (round_half_even linear 0.5–9.0 → 1..cap; PINK/VIOLET use max-3× **linear** translator). + +### E. `prod/docs/PRODGREEN_TUI_AND_LEVERAGE_OBSERVABILITY_SPEC.md` (2026) +**TUI display labels:** +- `cm:` for conviction multiplier +- `xlev:` for exchange leverage +- `lev:` legacy (visually secondary) + +--- + +## Key Terms / Vocabulary + +| Term | Meaning | Where Defined | +|------|---------|---------------| +| `conviction leverage` / `our_leverage` | Internal fractional [0.5, 9.0], sizes quantity | `pink_direct.py:_hz_publish` | +| `exchange leverage` / `xlev` | Integer [1,3] sent to BingX API | `leverage.py`, `pink_direct.py` | +| `dual-leverage doctrine` | The separation principle | `PINK_ACCOUNTING_EXEC_FIX.md` §0 | +| `round_half_even` | Banker's rounding (x.5 → even) | `leverage.py`, `VIOLET_SUB_SPEC__L3` | +| `map_internal_conviction_to_exchange_leverage` | The mapper function | `leverage.py` | +| `target_exchange_leverage` | Float pre-round value | `VIOLET_SUB_SPEC__L3` | +| `exchange_leverage` | Final int sent to venue | `VIOLET_SUB_SPEC__L3` | +| `notional` | `capital × 0.20 × conviction` | `esf_alpha_orchestrator.py` | +| `base_fraction` | 0.20 (constant in BLUE) | `VIOLET_V3_FINDINGS.md` §2 | + +--- + +## Execution Flow (PINK → BingX) + +``` +1. BLUE/VIOLET sizer computes conviction ∈ [0.5, 9.0] +2. notional = capital × 0.20 × conviction +3. quantity = notional / entry_price +4. At venue boundary (pink_direct / execution.py): + target = map_internal_conviction_to_exchange_leverage_target(conviction) # float + xlev = normalize_bingx_leverage_value(target) # int [1,3] +5. BingX API: POST /leverage {"symbol": "...", "side": "BOTH", "leverage": xlev} +6. Margin locked = notional / xlev +7. PnL calculation: qty × (exit_price - entry_price) [NO leverage factor] +8. Hz snapshot publishes: our_leverage = (size × entry_price) / capital +``` + +--- + +## VIOLET Integration Points + +| Component | Role | File | +|-----------|------|------| +| `VioletExchangeLeverage` | V-TYPES wrapper, bit-identity gated | `prod/clean_arch/violet/exchange_leverage.py` | +| `TradeabilityProjection` | L1→L3 projector (conviction → xlev + margin) | `prod/clean_arch/violet/tradeability.py` (Task 6) | +| `ShadowDecision` | L1 output carrying `conviction_leverage` | `decision_engine.py` | + +--- + +## Mutation Litmus (What Breaks If Conflated) + +| Mutation | Expected Test Failure | +|----------|----------------------| +| Use `exchange_leverage` in PnL calc | `test_pink_ditav2_accounting_invariants.py` — realized PnL 3× inflated | +| Use `conviction` as BingX leverage | Margin rejection or over-leverage (BingX max 3× for PINK) | +| Round-half-up instead of half-even | `VIOLET_SUB_SPEC__L3` gate: 2.5→3 instead of 2, bit-identity fails | +| Drop the clamp to [1,3] | BingX API rejects leverage >3 for PINK symbols | + +--- + +## Related Files to Audit (Per Search) + +- `prod/clean_arch/runtime/pink_direct.py` — `_hz_publish`, `_exec_submit`, intent leverage flow +- `prod/bingx/execution.py` — `_ensure_leverage`, `_normalize_bingx_leverage_value` (legacy CEIL, not ROUND_HALF_EVEN) +- `prod/clean_arch/violet/exchange_leverage.py` — VIOLET L3 wrapper +- `prod/clean_arch/violet/tradeability.py` — L3 projector (if built) +- `esf_alpha_orchestrator.py` — 5-factor conviction composition (base × DC × ACB × OB × EsoF) +- `alpha_wrappers.py` — VIOLET V-TYPES for `ConvictionLeverage` +- `prod/tests/test_pink_ditav2_accounting_invariants.py` — Accounting tests +- `prod/tests/test_violet_exchange_leverage.py` — VIOLET L3 gate tests + +--- + +## Operator Directives (Binding) + +1. **NEVER reimplement `leverage.py` logic** — wrap it (VIOLET L3 spec, non-negotiable) +2. **PnL is leverage-free** — `qty × Δprice` only (PINK_ACCOUNTING_EXEC_FIX.md HARD INVARIANT) +3. **Bit-identity gate** — VIOLET output must `==` `prod/bingx/leverage.py` output exactly (MC N≥1e6) +4. **ROUND_HALF_EVEN** — not round-half-up, not CEIL, not floor (banker's rounding) +5. **Conviction sizes qty; exchange lev sizes margin** — the two paths are orthogonal after notional + +--- + +## Search Provenance + +Found via: `grep -r "dual.leverage\|our.*leverage.*exchange\|conviction.*multiplier\|map_internal_conviction_to_exchange" /mnt/dolphinng5_predict/prod/docs --include="*.md"` + +Key hits: `PINK_ACCOUNTING_EXEC_FIX.md`, `VIOLET_SUB_SPEC__L3_EXCHANGE_LEVERAGE.md`, `FRACTIONAL_LEVERAGE_TO_BINGX_FIX.md`, `VIOLET_V3_FINDINGS.md`, `PRODGREEN_TUI_AND_LEVERAGE_OBSERVABILITY_SPEC.md`, `INDEX_REVIEW_alpha_engine.md`, `UV_TASK_T19_UV_CLOCK_HOST.md` + +--- + +## Next Search Vectors (Operator Guidance) + +- Search `esf_alpha_orchestrator.py` for 5-factor conviction composition +- Search `alpha_wrappers.py` for V-TYPES `ConvictionLeverage` definition +- Search `prod/bingx/execution.py` for legacy CEIL vs ROUND_HALF_EVEN divergence +- Trace `dolphin_actor.py` tag `lev:X.XX` → execution path + +--- + +## Additional Findings (Extended Search) + +### 1. `prod/bingx/sizing_mode.py` — Sizing Mode Contract +- Three modes: `engine` (default, no BingX payload), `testnet`, `live_market` +- `build_split_sizing_payload()` emits BingX-ready sizing with `exchange_leverage_cap` +- Delegates to `prod.utils.trade_sizing_bridge.build_engine_ready_sizing()` + +### 2. `prod/utils/trade_sizing_bridge.py` — Engine-Ready Sizing Translation +**Core function:** `size_trade_from_sizing_lev()` — the complete translation pipeline: + +```python +# Input: sizing_lev (conviction), capital, mark_price, etc. +# Output: TradeSizingResult with: +# - internal_leverage: cubic-convex conviction ∈ [0.5, 9.0] +# - exchange_leverage_target: float (pre-round, linear map) +# - exchange_leverage: int (ROUND_HALF_EVEN + clamp to [1, exchange_cap]) +# - effective_notional: min(venue_cap, margin_budget × exchange_leverage) +# - quantity: floor(effective_notional / mark_price / step_size) × step_size +# - margin_to_capital, notional_to_capital ratios +``` + +**Key constants:** +- `DEFAULT_BINGX_EXCHANGE_LEVERAGE_CAP = 3` +- `DEFAULT_MIN_INTERNAL_LEVERAGE = 0.5` +- `DEFAULT_MAX_INTERNAL_LEVERAGE = 9.0` +- `DEFAULT_LEVERAGE_CONVEXITY = 3.0` (cubic!) +- `DEFAULT_MARGIN_BUDGET_FRACTION = 0.20` + +**Convexity note:** The "cubic" in "max-3× cubic translator" refers to the **conviction sizing curve** (`strength_cubic = clamp(...)³`), NOT the exchange leverage mapping. The exchange mapping is **linear** with **ROUND_HALF_EVEN**. + +### 3. `prod/clean_arch/adapters/bingx_direct.py` — DITAv2 Venue Adapter +- Uses `map_internal_conviction_to_exchange_leverage()` from `prod.bingx.leverage` +- Default `exchange_leverage_cap = 3` +- Applies leverage per-symbol via cache `_configured_leverage` + +### 4. `prod/clean_arch/dita_v2/blue_parity.py` — BLUE Parity Wrapper +**DUAL-LEVERAGE INVARIANT (docstring):** +> "the fractional leverage produced here is STRATEGY conviction — it sizes the quantity. At-exchange leverage is derived from it at the venue boundary via map_internal_conviction_to_exchange_leverage() (linear [0.5, 9.0] → [1, cap], bankers rounding, security cap)." + +### 5. `prod/clean_arch/dita_v2/test_blue_parity.py` — Parity Tests +**TestConvictionToExchangeLeverage class validates:** +```python +m(0.5) == 1 # conviction floor → exchange floor +m(9.0) == 3 # conviction ceiling → exchange cap (3) +m(4.75) == 2 # exact midpoint [0.5, 9.0] → target 2.0 → round_half_even(2.0) = 2 +m(0.1) == 1 # clamped below conviction floor +m(50.0) == 3 # clamped above conviction ceiling +# monotonic: {1, 2, 3} across conviction range +``` + +### 6. `prod/docs/NAUTILUS_DOLPHIN_SPEC.md` — Sizing Formula +``` +leverage = min_leverage + (max_leverage - min_leverage) × (signal_strength)^leverage_convexity +# leverage_convexity = 3.0 → CUBIC +strength_cubic = clamp((threshold - vel_div) / (threshold - extreme), 0, 1) ** 3 +``` + +### 7. `prod/docs/SYSTEM_BIBLE_v7.md` §38.5 (margin-sizing addendum) +> "internal sizing leverage and BingX exchange leverage are separate layers. Exchange leverage controls the required margin; strategy leverage controls sizing intent." + +--- + +## Complete Leverage Flow (End-to-End) + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ BLUE STRATEGY (esf_alpha_orchestrator) │ +│ signal_strength = clamp((|vel_div| - threshold) / (extreme - threshold)) │ +│ strength_cubic = signal_strength ** 3.0 ← CUBIC CONVEXITY │ +│ raw_leverage = base × DC_boost × ACB_regime × OB_consensus × EsoF_haircut │ +│ clamped to [0.5, 9.0] │ +└──────────────────────────────────┬──────────────────────────────────────────┘ + │ conviction ∈ [0.5, 9.0] + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ PINK / VIOLET VENUE BOUNDARY │ +│ target = map_internal_conviction_to_exchange_leverage_target(conviction) │ +│ = 1.0 + (conviction - 0.5) / 8.5 × (3.0 - 1.0) ← LINEAR │ +│ ∈ [1.0, 3.0] (float) │ +│ xlev = normalize_bingx_leverage_value(target) │ +│ = ROUND_HALF_EVEN(target) clamped to [1, 3] ← BANKER'S ROUNDING │ +│ ∈ {1, 2, 3} (int) │ +└──────────────────────────────────┬──────────────────────────────────────────┘ + │ exchange_leverage ∈ {1, 2, 3} + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ BINGX EXECUTION │ +│ POST /trade/leverage {"symbol": "...", "side": "BOTH", "leverage": xlev} │ +│ margin = notional / xlev │ +└──────────────────────────────────┬──────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ ACCOUNTING (PnL) │ +│ qty = notional / entry_price │ +│ PnL = qty × (exit_price - entry_price) ← LEVERAGE-FREE │ +│ our_leverage = (size × entry_price) / capital ← PUBLISHED TO Hz │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Critical Distinction: CEIL vs ROUND_HALF_EVEN + +| Context | Rounding | Source | +|---------|----------|--------| +| **Old execution.py fix (2025-04-24)** | `ceil(fractional_lev)` | `FRACTIONAL_LEVERAGE_TO_BINGX_FIX.md` | +| **Current production `leverage.py`** | `ROUND_HALF_EVEN` (banker's) | `prod/bingx/leverage.py` | +| **VIOLET L3 wrapper** | `ROUND_HALF_EVEN` (bit-identical gate) | `VIOLET_SUB_SPEC__L3_EXCHANGE_LEVERAGE.md` | + +**The CEIL fix was superseded** by the cleaner `leverage.py` module with banker's rounding. The production code now uses `prod/bingx/leverage.py` exclusively. + +--- + +## ROUND_HALF_EVEN Boundary Cases (Tested) + +| Conviction | Target (float) | ROUND_HALF_EVEN | Final xlev | +|------------|----------------|-----------------|------------| +| 0.5 | 1.0 | 1 | 1 | +| ~2.82 | 1.5 | 2 | 2 | +| 4.75 | 2.0 | 2 | 2 | +| ~6.68 | 2.5 | 2 | 2 ← BANKER'S: 2.5 → 2 | +| 9.0 | 3.0 | 3 | 3 | + +The "max-3× cubic translator" phrase in VIOLET docs refers to: +- **Cubic** = conviction sizing curve (strength³) +- **3×** = exchange leverage cap (1–3) +- **Translator** = the linear + ROUND_HALF_EVEN mapper + +--- + +## Source Code Inventory (All Leverage-Related) + +| File | Role | +|------|------| +| `prod/bingx/leverage.py` | **SOURCE OF TRUTH** — pure functions, 83 lines, no callers | +| `prod/bingx/config.py` | `exchange_leverage_cap: PositiveInt = 3` default | +| `prod/bingx/execution.py` | Venue client, wraps leverage.py functions | +| `prod/bingx/sizing_mode.py` | Sizing mode contract (engine/testnet/live) | +| `prod/utils/trade_sizing_bridge.py` | Full sizing pipeline with margin math | +| `prod/clean_arch/adapters/bingx_direct.py` | DITAv2 venue adapter | +| `prod/clean_arch/dita_v2/blue_parity.py` | BLUE parity wrapper (docstrings the invariant) | +| `prod/clean_arch/dita_v2/test_blue_parity.py` | Parity tests including dual-leverage | +| `prod/clean_arch/runtime/pink_direct.py` | PINK runtime, `_hz_publish` computes `our_leverage` | +| `prod/clean_arch/violet/exchange_leverage.py` | VIOLET L3 typed wrapper (bit-identity gated) | +| `prod/clean_arch/violet/test_violet_exchange_leverage.py` | VIOLET L3 gate tests (N≥1e6 MC) | +| `prod/clean_arch/violet/exec_intent.py` | VIOLET PASS4 DARK intent projection | + +--- + +## Mutation Litmus (What Breaks If Wrong) + +| Mutation | Test That Catches It | +|----------|---------------------| +| Use `exchange_leverage` in PnL formula | `test_pink_ditav2_accounting_invariants.py` | +| Use `conviction` directly as BingX leverage | Margin rejection (BingX max 3× for PINK) | +| ROUND_HALF_UP instead of ROUND_HALF_EVEN | `test_violet_exchange_leverage.py::test_round_half_even_boundary_cases` (2.5→3 fails) | +| Drop clamp to [1,3] | BingX API rejects leverage >3 | +| Conflate the two leverage concepts | `PINK_ACCOUNTING_EXEC_FIX.md` HARD INVARIANT violation | + +--- + +## Search Provenance (Complete) + +``` +# Primary searches +grep -r "dual.leverage\|map_internal_conviction_to_exchange" prod/docs --include="*.md" +grep -r "CONVICTION_MIN\|EXCHANGE_LEV_MAX\|LEVERAGE_MAPPING_RULE" prod --include="*.py" +grep -r "round_half_even\|ROUND_HALF_EVEN" prod --include="*.py" +grep -r "exchange_leverage_cap" prod --include="*.py" + +# Key files examined +prod/bingx/leverage.py ← SOURCE OF TRUTH +prod/bingx/config.py ← Default cap = 3 +prod/bingx/execution.py ← Venue client +prod/bingx/sizing_mode.py ← Mode contract +prod/utils/trade_sizing_bridge.py ← Full pipeline +prod/clean_arch/adapters/bingx_direct.py ← DITAv2 adapter +prod/clean_arch/dita_v2/blue_parity.py ← BLUE parity + invariant docstring +prod/clean_arch/dita_v2/test_blue_parity.py ← Parity tests +prod/clean_arch/runtime/pink_direct.py ← PINK runtime, _hz_publish +prod/clean_arch/violet/exchange_leverage.py ← VIOLET L3 wrapper +prod/clean_arch/violet/test_violet_exchange_leverage.py ← VIOLET gate tests +prod/clean_arch/violet/exec_intent.py ← VIOLET PASS4 intent + +# Spec docs +prod/docs/FRACTIONAL_LEVERAGE_TO_BINGX_FIX.md ← Origin story (CEIL fix) +prod/docs/PINK_ACCOUNTING_EXEC_FIX.md ← Forensic HARD INVARIANT +prod/docs/VIOLET_SUB_SPEC__L3_EXCHANGE_LEVERAGE.md ← VIOLET L3 spec +prod/docs/VIOLET_V3_FINDINGS.md ← V3 findings +prod/docs/BINGX_MARGIN_SIZING_RULE.md ← Operational rule +prod/docs/SYSTEM_BIBLE_v7.md ← §38.5 margin-sizing addendum +prod/docs/NAUTILUS_DOLPHIN_SPEC.md ← Cubic sizing formula +``` + +--- + +## CRITICAL CORRECTION: Actual PINK Runtime Was DITA v1 (NOT DITAv2) + +**The running PINK system that traded on BingX VST used `prod/clean_arch/dita/` (DITA v1), NOT `prod/clean_arch/dita_v2/`.** + +DITAv2 (`prod/clean_arch/dita_v2/`) was a later rewrite that preserved the same dual-leverage invariant but was NOT the system that ran live. + +### Actual Running PINK Stack (DITA v1) + +| Layer | File | Role | +|-------|------|------| +| **Launcher** | `prod/launch_dolphin_pink.py` (baseline in `prod/refactor_snapshots_20260527_222130/`) | Wired DITA v1 + BingX direct adapter | +| **Decision** | `prod/clean_arch/dita/decision.py` | `DecisionEngine` — computes `leverage` (conviction) + `our_leverage` (notional/capital) | +| **Intent** | `prod/clean_arch/dita/intent.py` | `IntentEngine` — passes `leverage` from decision to `Intent` | +| **Trade FSM** | `prod/clean_arch/dita/trade.py` | `TradeExecutor` — `TradePosition.leverage` = conviction from intent | +| **Account** | `prod/clean_arch/dita/account.py` | `AccountProjection` — `snapshot.leverage` = `open_notional / capital` (**our_leverage**) | +| **Venue Adapter** | `prod/clean_arch/adapters/bingx_direct.py` | `submit_intent()` — **dual-leverage translation happens HERE** | +| **TP Curve** | `prod/clean_arch/tp_curve.py` | `compute_our_leverage(notional, capital)` — used for TP tightening | + +### Dual-Leverage Translation in Production Code + +**`prod/clean_arch/adapters/bingx_direct.py:submit_intent()` (lines 599-606):** +```python +# intent.leverage is the STRATEGY conviction (fractional, 0.5–9.0) and +# already sized the quantity. At-exchange leverage is derived from it +# via the linear conviction map → integer [1, cap], bankers rounding. +leverage = map_internal_conviction_to_exchange_leverage( + float(intent.leverage or self._config.default_leverage), + exchange_max=self._config.exchange_leverage_cap, # = 3 +) +await self._ensure_leverage(symbol, leverage) # POST to BingX /trade/leverage +``` + +**`prod/clean_arch/tp_curve.py`:** +```python +def compute_our_leverage(*, notional, capital) -> float: + """Return the current system leverage implied by sizing, NOT exchange leverage.""" + return abs(notional) / capital # our_leverage = notional/capital +``` + +**`prod/clean_arch/dita/decision.py`:** +```python +our_leverage = compute_our_leverage(notional=target_exposure, capital=context.capital) +# ... passed in Decision.metadata["our_leverage"] for TP curve +tp_effective_pct = compute_soft_tp_pct(tp_base_pct, our_leverage) +``` + +### Three Leverage Concepts in the Live System + +| Name | Variable | Range | Computed Where | Purpose | +|------|----------|-------|----------------|---------| +| **Conviction** | `intent.leverage`, `Decision.leverage` | 0.5–9.0 | Sizer (cubic-convex) | Sizes QUANTITY | +| **Exchange** | `leverage` (BingX API) | 1–3 (int) | `map_internal_conviction_to_exchange_leverage()` | Controls MARGIN = notional/exchange_lev | +| **Our/System** | `our_leverage` | 0.0–~1.8 | `compute_our_leverage(notional, capital)` | TP curve tightening, Hz publishing | + +### DITAv2 Migration Note +`prod/clean_arch/dita_v2/` was a **later rewrite** that re-implemented the same architecture with a Rust kernel (`ExecutionKernel`). It preserved the dual-leverage invariant (documented in `PINK_ACCOUNTING_EXEC_FIX.md` §0 and `blue_parity.py` docstring) but the live PINK system that actually traded used **DITA v1**. + +### Files That Were Actually Running Live +- `prod/launch_dolphin_pink.py` (the launcher) +- `prod/clean_arch/runtime/pink_direct.py` (the runtime — uses DITA v1 components) +- `prod/clean_arch/dita/` (decision, intent, trade, account) +- `prod/clean_arch/adapters/bingx_direct.py` (venue adapter with dual-leverage translation) +- `prod/clean_arch/tp_curve.py` (leverage-conditioned TP) + + +--- + +## VIOLET Contracts — Dual-Leverage in Data Types + +### `prod/clean_arch/violet/alpha_wrappers.py` — `SizeDecision` (PASS3a) + +```python +class SizeDecision(StrictModel): + """Bet-sizer output. notional_fraction = fraction * conviction_leverage + is the realized notional/capital (== the recorded our_leverage); it is + the conviction side of the dual-leverage and is exchange-agnostic.""" + + fraction: Fraction + conviction_leverage: ConvictionLeverage # ∈ [0.5, 9.0] — internal sizing + notional_fraction: float = Field(ge=0.0) # == our_leverage = fraction × conviction_leverage + bucket_idx: int + strength_score: float + signal_bucket: str +``` + +**Key invariant:** `notional_fraction = fraction × conviction_leverage` — this IS the recorded `our_leverage` (system leverage = notional/capital). + +### `prod/clean_arch/violet/decision_engine.py` — `ShadowDecision` (PASS3c) + +```python +class ShadowDecision(StrictModel): + """One muted decision — what BLUE *would* do this scan. Never executed.""" + + ts_ns: int + scan_number: int + asset: Symbol + side: str + vel_div: float + fraction: float # base_fraction (0.20) + conviction_leverage: float # ∈ [0.5, 9.0] — full BLUE conviction (5-factor) + notional_fraction: float # == our_leverage = fraction × conviction_leverage + target_exposure: float # = capital × notional_fraction + ars_score: float + bucket_idx: int + actuated: bool + # 5-factor breakdown (V3.4): + base_leverage: Optional[float] # base cubic from AlphaBetSizer + dc_lev_mult: Optional[float] # DC confirmation boost + regime_size_mult: Optional[float] # ACB boost × meta × MC_scale (the "steepener") + market_ob_mult: Optional[float] # OB consensus 0.85–1.20 + esof_size_mult: Optional[float] # EsoF haircut [0, 1] +``` + +**Key points:** +- `conviction_leverage` = full 5-factor BLUE conviction (base × DC × ACB-regime × OB × EsoF) +- `notional_fraction` = `fraction × conviction_leverage` = `our_leverage` (system leverage) +- `target_exposure` = `capital × notional_fraction` = notional +- Exchange leverage is **L3 only** — never in L1 decision + +### `prod/clean_arch/violet/contracts_v3.py` — `ExecIntent` (PASS4) + +```python +class ExecIntent(StrictModel): + """DARK would-be order intent. Data only; never sent to a venue here.""" + + asset: Symbol + side: Literal["SHORT", "LONG"] + qty: Qty + exchange_leverage: Annotated[int, Field(ge=1)] # ← L3: exchange leverage + maker_policy: str + target_notional: float + ts_ns: MonoNs + reason: Literal["ENTRY", "EXIT"] +``` + +### `prod/clean_arch/violet/exec_intent.py` — L1→L3 Projection (PASS4 Task 17) + +```python +def to_exec_intent( + decision: ShadowDecision, + *, + capital: float, + reference_price: float, + maker_policy: str = "maker_both", +) -> ExecIntent: + # target_notional = capital × notional_fraction (our_leverage side) + target_notional = capital * decision.notional_fraction + qty = target_notional / reference_price + + # L3: conviction → exchange leverage via prod/bingx/leverage.py + exchange = _exchange_leverage_for(decision.conviction_leverage) + + return ExecIntent( + asset=decision.asset, + side=decision.side, + qty=qty, + exchange_leverage=exchange, + maker_policy=maker_policy, + target_notional=target_notional, + ts_ns=decision.ts_ns, + reason="ENTRY", + ) + +def _exchange_leverage_for(conviction_leverage: float) -> int: + # Wraps VioletExchangeLeverage (bit-identical to prod/bingx/leverage.py) + return VioletExchangeLeverage().to_exchange(conviction_leverage).exchange_leverage +``` + +--- + +## Complete Dual-Leverage Architecture Across All Systems + +``` +┌─────────────────────────────────────────────────────────────────────────────────┐ +│ BLUE (nautilus_event_trader.py) │ +│ esf_alpha_orchestrator: 5-factor conviction (base × DC × ACB-regime × OB × EsoF)│ +│ our_leverage = compute_our_leverage(notional, capital) # for TP curve │ +│ target_notional = capital × 0.20 × conviction_leverage │ +└─────────────────────────────────────────────────────────────────────────────────┘ + │ + ┌─────────────────┼─────────────────┐ + ▼ ▼ ▼ + ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ + │ PINK │ │ PRODGREEN │ │ VIOLET │ + │ (DITA v1 live) │ │ (BLUE mirror) │ │ (shadow/UV) │ + └──────────────────┘ └──────────────────┘ └──────────────────┘ + │ │ │ + ┌──────────┴──────────┐ │ ┌──────────┴──────────┐ + ▼ ▼ ▼ ▼ ▼ + ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ + │ decision.py │ │ decision.py │ │ alpha_wrap │ │decision_eng │ + │ DecisionEng │ │ DecisionEng │ │ SizeDecision│ │ ShadowDec │ + │ leverage= │ │ leverage= │ │ conviction_ │ │conviction_ │ + │ conviction │ │ conviction │ │ leverage │ │leverage │ + └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ + │ │ │ │ + ▼ ▼ ▼ ▼ + ┌─────────────────────────────────────────────────────────────────────┐ + │ VENUE BOUNDARY (dual-leverage translation) │ + │ │ + │ PINK: prod/clean_arch/adapters/bingx_direct.py:submit_intent() │ + │ leverage = map_internal_conviction_to_exchange_leverage( │ + │ intent.leverage, exchange_max=3) │ + │ │ + │ VIOLET: prod/clean_arch/violet/exec_intent.py:to_exec_intent() │ + │ exchange = VioletExchangeLeverage().to_exchange( │ + │ decision.conviction_leverage).exchange_leverage │ + │ │ + │ BLUE: prod/bingx/execution.py:_ensure_leverage() │ + │ leverage = map_internal_conviction_to_exchange_leverage( │ + │ sizing_lev, exchange_max=config.exchange_leverage_cap)│ + │ │ + │ ALL use: prod/bingx/leverage.py (SOURCE OF TRUTH) │ + └─────────────────────────────────────────────────────────────────────┘ + │ │ │ │ + ▼ ▼ ▼ ▼ + ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ + │ BingX API │ │ BingX API │ │ BingX API │ │ BingX API │ + │ /trade/ │ │ /trade/ │ │ /trade/ │ │ /trade/ │ + │ leverage │ │ leverage │ │ leverage │ │ leverage │ + │ (int 1-3) │ │ (int 1-3) │ │ (int 1-3) │ │ (int 1-3) │ + └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ + │ │ │ │ + ▼ ▼ ▼ ▼ + ┌─────────────────────────────────────────────────────────────────────┐ + │ ACCOUNTING (leverage-free) │ + │ │ + │ PnL = qty × (exit_price - entry_price) [side-signed] │ + │ our_leverage = (size × entry_price) / capital [Hz publishing] │ + │ margin = notional / exchange_leverage │ + │ │ + │ HARD INVARIANT (PINK_ACCOUNTING_EXEC_FIX.md §0): │ + │ "slot.size = exchange quantity; slot.leverage = exchange leverage │ + │ (1-3x cap, set at BingX API); our_leverage (conviction) = │ + │ size × entry_price / capital, computed ONLY at _hz_publish. │ + │ PnL is therefore LEVERAGE-FREE: qty × Δprice, side-signed." │ + └─────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Mutation Litmus — Complete + +| Mutation | Where It Breaks | Catching Test | +|----------|----------------|---------------| +| Use `exchange_leverage` in PnL formula | `prod/clean_arch/dita/trade.py:apply_fill()` | `test_pink_ditav2_accounting_invariants.py` | +| Use `conviction_leverage` as BingX leverage | `prod/clean_arch/adapters/bingx_direct.py:submit_intent()` | BingX API rejects >3× for PINK | +| ROUND_HALF_UP instead of ROUND_HALF_EVEN | `prod/bingx/leverage.py:normalize_bingx_leverage_value()` | `test_violet_exchange_leverage.py::test_round_half_even_boundary_cases` (2.5→2) | +| Drop clamp to [1,3] | `prod/bingx/leverage.py:_clamp_exchange_bounds()` | BingX API rejects leverage >3 | +| Conflate `our_leverage` with `exchange_leverage` | Any accounting code | `PINK_ACCOUNTING_EXEC_FIX.md` HARD INVARIANT violation | +| Skip dual-leverage in VIOLET L3 | `prod/clean_arch/violet/exec_intent.py:_exchange_leverage_for()` | `test_violet_exchange_leverage.py::test_gate_exchange_leverage_bit_identity` (N≥1e6) | + +--- + +## Search Complete — All Systems Mapped + +| System | Decision/Sizing | Intent | Venue Translation | Accounting | +|--------|----------------|--------|-------------------|------------| +| **BLUE** | `esf_alpha_orchestrator` (5-factor) | `nautilus_event_trader.py` | `prod/bingx/execution.py` | `compute_our_leverage()` for TP | +| **PINK (live)** | `prod/clean_arch/dita/decision.py` | `prod/clean_arch/dita/intent.py` | `prod/clean_arch/adapters/bingx_direct.py` | `AccountProjection.leverage = our_leverage` | +| **PINK (DITAv2)** | `prod/clean_arch/dita_v2/blue_parity.py` | `prod/clean_arch/dita/intent.py` | `prod/clean_arch/adapters/bingx_direct.py` | `AccountProjection.leverage = our_leverage` | +| **PRODGREEN** | Same as BLUE | Same | `prod/bingx/execution.py` | Same | +| **VIOLET (shadow)** | `prod/clean_arch/violet/decision_engine.py` | `prod/clean_arch/violet/exec_intent.py` | `prod/clean_arch/violet/exchange_leverage.py` | `CapitalState.capital` anchor | + +**All paths converge on `prod/bingx/leverage.py` — the single source of truth for conviction→exchange mapping.** diff --git a/prod/docs/VIOLET_STUDY_SPEC__BASE_FRACTION_SIZING.md b/prod/docs/VIOLET_STUDY_SPEC__BASE_FRACTION_SIZING.md new file mode 100644 index 00000000..d2ce3397 --- /dev/null +++ b/prod/docs/VIOLET_STUDY_SPEC__BASE_FRACTION_SIZING.md @@ -0,0 +1,126 @@ +# VIOLET Study Spec — Base-Fraction / Capital-Utilization Sizing Study + +**Status:** TODO (research spec, written 2026-06-13). Gated AFTER the regime-robustness +study (#1). Feeds VIOLET V3 Layer-3 sizing mechanics and any base-fraction change to +the live PINK/BLUE `AlphaBetSizer`. + +**Owner intent:** the [[blue_margin_envelope_study]] proved BLUE's capital is badly +*under-utilized* (median trade ties up ~3.4% of wallet at 2× exchange leverage; 100% of +trades feasible at 2×; max realized `our_leverage` = notional/capital ≈ 1.81). The ROI +lever is the **base fraction** (currently `base_fraction = 0.20` in `AlphaBetSizer`), +NOT exchange leverage. Question this study answers: **how far above 0.20 can base +fraction be pushed for more ROI, risk-bounded, and where do hard constraints bind?** + +--- + +## 0. Doctrine / non-negotiables + +- **ROI is driven by `notional/capital` = `base_fraction × conviction_leverage`**, not by + exchange leverage. Exchange leverage (PINK/VIOLET max-3× **linear** translator) is a + margin-efficiency knob only. Confirmed empirically: + `notional = capital × 0.20 × leverage`, `leverage` = cubic-convex conviction ∈ [0.5, 9]. +- **The edge is regime-concentrated** (≈95% of clean edge in choppy-bearish; bull is the + separate EFSM long-reversal algo's domain). Therefore sizing-up amplifies exposure to + the worst observed regime AND to the untested-by-this-strategy tails. This study MUST + output a fraction recommendation **conditioned on the regime-robustness result (#1)**, + not a raw-ROI maximizer. +- **Counterfactual honesty:** resizing past trades assumes the *same trades would have + filled at the larger size*. That assumption degrades with size (market impact). The + study MUST estimate and discount for slippage/impact, not assume linear scaling. + +## 1. The hard constraint that binds first — the 3× translator ceiling + +`our_leverage = base_fraction × conviction`, max conviction = 9.0. To finance a position +the exchange leverage must satisfy `exch_lev ≥ our_leverage`. PINK/VIOLET's translator +caps exchange leverage at **3×**. Therefore the **maximum financeable base fraction** +before the cap binds on the highest-conviction trades is: + +``` +base_fraction_max ≈ 3.0 / 9.0 ≈ 0.333 (i.e. our_leverage_max = 0.333 × 9 = 3.0 = cap) +``` + +- At `f = 0.20`: max our_leverage 1.8 → 2× suffices, comfortable. +- At `f ≈ 0.333`: max our_leverage 3.0 → exactly the 3× cap (no buffer on max-conviction + trades). +- At `f > 0.333`: highest-conviction trades CANNOT be financed at 3× → they clip + (under-size) or require raising the translator cap (a separate margin-risk decision). + +**Deliverable 1:** the exact binding curve `f → fraction of trades that clip at 3× cap`, +using the real conviction distribution (most trades are low-conviction, so the cap may +bind on very few trades well above 0.333 — quantify it, don't assume the 0.333 worst case +dominates). + +## 2. Method + +Operate on the **clean deduped trade set** (one row per `trade_id`; drop `HIBERNATE_HALT` +and `bars_held = 0`; see [[blue_margin_envelope_study]] for the cleaning that yields ++$47k / 2121 trades). Required per-trade fields: `pnl`, `pnl_pct`, `entry_price`, +`quantity`, `capital_before`, `leverage` (conviction), `our_leverage`, regime hash tags +(join to `maras_fingerprint.composite_hash`), and execution-quality (slippage) from +`trade_execution_quality` / `execution_quality_json`. + +### 2a. Counterfactual resize grid +For `f ∈ {0.20, 0.25, 0.30, 0.333, 0.40, 0.50}` (and finer near the optimum): +- Per trade, resized notional scales by `f / 0.20`; **`pnl_pct` is size-invariant**, so + resized `$pnl = pnl_pct × resized_notional` **before** slippage discount. +- Apply the §2c slippage discount. +- Apply the §1 cap clip: if `f × conviction > 3.0`, clip notional to `3.0 × capital`. + +### 2b. Path-dependent equity reconstruction +Replay trades in time order, compounding each resized `$pnl` onto a running capital base +(bigger size → bigger swings → different compounding path; do NOT just sum). Seed from the +real starting capital of the tracked window. Produce per-`f`: +- final capital, CAGR +- **max drawdown**, Calmar/MAR (CAGR ÷ maxDD), longest-underwater days +- Sharpe, Sortino, downside deviation +- risk-of-ruin estimate + +### 2c. Slippage / market-impact model (critical — do NOT skip) +The largest real-world degrader. From the maker-fill telemetry estimate whether larger +notionals get worse fills / more requotes / more taker fallback: +- regress realized fill slippage (and maker→taker fallback rate) against order notional + / notional-vs-ADV where available +- build a `slippage_bps(notional)` discount applied in §2a +- if data is insufficient, state so and use a conservative parametric impact assumption + (document it); flag the result as impact-uncertain + +### 2d. Kelly / fractional-Kelly anchor +Estimate the growth-optimal fraction from the empirical win-rate + payoff distribution. +Recommend **fractional Kelly (¼–½)** given the edge is **non-stationary and +regime-conditional** — full Kelly assumes a stationary edge we have explicitly shown does +not hold. Compare the Kelly-implied fraction to the §1 cap ceiling and the §2b +drawdown-optimal fraction. + +### 2e. Regime-conditioned drawdown (the binding test) +Re-run §2b conditioned on the regime **hash** buckets from #1 (NOT the MARAS label — the +label is held untrusted; sub-regimes within choppy-bearish are expected). The binding +drawdown is the **worst-hash-bucket** drawdown, not the aggregate. Add a **stress +scenario**: inject a hypothetical adverse excursion sized to the worst plausible +unsampled-regime loss and report each `f`'s survival. + +## 3. Deliverables + +1. Table: `f` × {final capital, CAGR, maxDD, Calmar, Sharpe, ruin-prob, %trades-clipped-at-3×}. +2. The §1 cap-binding curve. +3. The §2c slippage discount model + its effect on the optimum. +4. A **recommended base fraction** (or a conviction-conditioned fraction *schedule*), + with the explicit risk statement: how much extra ROI, at what extra drawdown, under + what regime assumption. +5. Machine-readable report → `prod/VIOLET_dev/reports/base_fraction_study_.json`; + 1-page FINDINGS alongside. + +## 4. Caveats to carry into every conclusion + +- Non-stationary, regime-concentrated edge — the optimum is conditional, not universal. +- Counterfactual resizing assumes fillability at scale (mitigated by §2c, never eliminated). +- Single-slot (no concurrency) — confirmed; if that ever changes, margin math changes. +- The clean set still may carry minor residual pollution; corroborate against the + corrected-capital trajectory as in the parent study. +- Do not let raw-ROI maximization override drawdown/ruin constraints. The under-utilized + capital is an *opportunity bounded by regime risk*, not free money. + +## 5. Related + +[[blue_margin_envelope_study]] · [[violet_v3_alpha_doctrine]] · +`prod/bingx/leverage.py` (translator) · `nautilus_dolphin/nautilus/alpha_bet_sizer.py` +(base_fraction) · `prod/clean_arch/dita_v2/blue_parity.py` (PINK wrapper, note 8 vs 9 drift). diff --git a/prod/docs/VIOLET_V3_FINDINGS.md b/prod/docs/VIOLET_V3_FINDINGS.md index 29cb2155..dbaa50a7 100644 --- a/prod/docs/VIOLET_V3_FINDINGS.md +++ b/prod/docs/VIOLET_V3_FINDINGS.md @@ -48,7 +48,7 @@ Self-consistent at row level vs recorded `dolphin.trade_events`: - **DUAL-LEVERAGE:** conviction leverage sizes the QUANTITY (internal); exchange leverage mapped at the venue boundary via `prod/bingx/leverage.py` `map_internal_conviction_to_exchange_leverage_target` (round_half_even linear - 0.5–9.0 → 1..cap; PINK/VIOLET use a max-3× cubic translator). + 0.5–9.0 → 1..cap; PINK/VIOLET use a max-3× **linear** translator). ## 3. blue_parity drift (doctrine validated by evidence)