VIOLET build spec: full sizing parity (orchestrator wrap-all -> bit-identity)
Self-contained, agent-executable brief: objective, non-negotiable constraints
(wrap-don't-reimplement, zero shared-file edits, DARK, V-TYPES), the exact 5-factor
composition w/ op-order + caps, wrap surfaces (file:line + APIs), the MC->bit-identity
->upstream validation gate, reusable pieces, acceptance criteria, and learned watch-outs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 13:59:43 +02:00
|
|
|
|
# VIOLET Build Spec — Full Sizing Parity (orchestrator wrap-all → bit-identity)
|
|
|
|
|
|
|
2026-06-15 14:12:05 +02:00
|
|
|
|
**Status:** READY TO BUILD. Self-contained brief; no prior session context assumed.
|
|
|
|
|
|
|
|
|
|
|
|
**Repo cwd: `/mnt/dolphinng5_predict`** (git root). Branch
|
|
|
|
|
|
`exp/pink-ditav2-sprint0-20260530`. **No git remote — local-only repo.** ⟹ the build
|
|
|
|
|
|
agent MUST run ON THIS HOST in this directory; it cannot clone elsewhere, and the build
|
|
|
|
|
|
needs host-local resources regardless: the eigenvalues data on disk
|
|
|
|
|
|
(`/mnt/dolphin_training/data/eigenvalues` or sibling), the live ClickHouse
|
|
|
|
|
|
(`http://localhost:8123`, user `dolphin` / key `dolphin_ch_2026`), and BLUE's actual
|
|
|
|
|
|
code/runtime for the bit-identity comparison. Python: `/home/dolphin/siloqy_env/bin/python3`.
|
|
|
|
|
|
|
VIOLET build spec: full sizing parity (orchestrator wrap-all -> bit-identity)
Self-contained, agent-executable brief: objective, non-negotiable constraints
(wrap-don't-reimplement, zero shared-file edits, DARK, V-TYPES), the exact 5-factor
composition w/ op-order + caps, wrap surfaces (file:line + APIs), the MC->bit-identity
->upstream validation gate, reusable pieces, acceptance criteria, and learned watch-outs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 13:59:43 +02:00
|
|
|
|
Background/derivation: `VIOLET_V3_FINDINGS.md` §8b/§8c. Doctrine: memory
|
|
|
|
|
|
`violet_v3_alpha_doctrine` (if loaded) — key rules restated below.
|
|
|
|
|
|
|
|
|
|
|
|
## 1. Objective
|
|
|
|
|
|
|
|
|
|
|
|
Make VIOLET's sizing reproduce live BLUE's conviction-leverage **bit-for-bit**. VIOLET
|
|
|
|
|
|
already reproduces the base cubic curve (V3a) and the EsoF haircut (V3.2). What's missing
|
|
|
|
|
|
is the rest of BLUE's full sizing composition (3 more multipliers + cap logic), which lives
|
|
|
|
|
|
in `esf_alpha_orchestrator`, not in the base bet-sizer. Wrap those, compose exactly, and
|
|
|
|
|
|
prove identity with a Monte-Carlo gate.
|
|
|
|
|
|
|
|
|
|
|
|
## 2. Non-negotiable constraints
|
|
|
|
|
|
|
|
|
|
|
|
- **WRAP, DON'T REIMPLEMENT.** Call BLUE's actual kernels; do not re-derive their math.
|
|
|
|
|
|
Bit-identity is only achievable by running the real code. (Reimplementation will fail
|
|
|
|
|
|
the gate on float ordering.)
|
|
|
|
|
|
- **ZERO edits to shared files:** `prod/nautilus_event_trader.py`,
|
|
|
|
|
|
`prod/clean_arch/dita_v2/*`, `prod/clean_arch/dita/decision.py`,
|
|
|
|
|
|
`nautilus_dolphin/**`, `blue_parity.py`. Mechanical check per commit:
|
|
|
|
|
|
`git diff --name-only` must not contain them.
|
|
|
|
|
|
- **VIOLET stays DARK** — no execution, no orders. This is a sizing-math layer only.
|
|
|
|
|
|
- **V-TYPES** (`prod/clean_arch/violet/domain.py`): refined types at boundaries,
|
|
|
|
|
|
`@typed` (beartype) on public methods, `StrictModel` for value objects, reject-at-source.
|
|
|
|
|
|
- **Follow BLUE in all regards** — no filters/hygiene BLUE lacks.
|
|
|
|
|
|
|
|
|
|
|
|
## 3. The exact target composition (authoritative)
|
|
|
|
|
|
|
|
|
|
|
|
Source: `nautilus_dolphin/nautilus_dolphin/nautilus/esf_alpha_orchestrator.py` ~lines 597-619.
|
|
|
|
|
|
Reproduce in EXACT operation order (float order matters for bit-identity):
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
raw_leverage = size_result["leverage"] # base cubic (AlphaBetSizer)
|
|
|
|
|
|
* dc_lev_mult # signal_gen.dc_leverage_boost if signal.dc_status=="CONFIRM" else 1.0
|
|
|
|
|
|
* regime_size_mult # ACB: _day_base_boost * (1 + _day_beta * strength^3) * _day_mc_scale
|
|
|
|
|
|
* market_ob_mult # OB cross-asset consensus (1.0 default; 0.85..1.20)
|
|
|
|
|
|
* _esof_size_mult # EsoF haircut [0,1]
|
|
|
|
|
|
clamped_max = min(base_max_leverage * regime_size_mult * market_ob_mult * _esof_size_mult, abs_max_leverage)
|
|
|
|
|
|
if _day_posture == 'STALKER': clamped_max = min(clamped_max, 2.0)
|
|
|
|
|
|
leverage = min(raw_leverage, clamped_max)
|
|
|
|
|
|
leverage = max(bet_sizer.min_leverage, leverage)
|
|
|
|
|
|
notional = capital * size_result["fraction"] * leverage
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Gold-spec caps (`prod/docs/FROZEN_ALGO_SPEC_GOLD_REFERENCE.md`): `base_max_leverage=8.0`
|
|
|
|
|
|
(soft), `abs_max_leverage=9.0` (hard). NOTE V3a currently constructs the base sizer with
|
|
|
|
|
|
`max_leverage=9.0` — **change to 8.0** (the boost lifts toward 9).
|
|
|
|
|
|
|
|
|
|
|
|
## 4. Wrap surfaces (what to wrap, where)
|
|
|
|
|
|
|
|
|
|
|
|
| Multiplier | Wrap target | API |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| base `size_result` | `nautilus_dolphin/.../alpha_bet_sizer.py` `AlphaBetSizer.calculate_size` | already wrapped: `prod/clean_arch/violet/alpha_wrappers.py` `VioletBetSizer` (fix `max_leverage=8.0`) |
|
|
|
|
|
|
| `_esof_size_mult` | `nautilus_dolphin/.../esof_size_gate.py` `esof_size_mult_from_score` | already wrapped: `prod/clean_arch/violet/modulation.py` `VioletSizeModulation` |
|
|
|
|
|
|
| `regime_size_mult` | `nautilus_dolphin/.../adaptive_circuit_breaker.py` `AdaptiveCircuitBreaker` | `preload_w750([dates])`, `get_dynamic_boost_for_date(date)`/`get_dynamic_boost_from_hz(...)` → `{boost, beta}`; per-bar `regime_size_mult = base_boost*(1+beta*strength^3)*mc_scale` (orchestrator :901-909). Needs eigenvalues data (auto-resolves to `/mnt/dolphin_training/data/eigenvalues` etc.) |
|
|
|
|
|
|
| `dc_lev_mult` | `esf_alpha_orchestrator` signal_gen (`signal.dc_status`, `signal_gen.dc_leverage_boost`) | wrap the signal generator; `dc_lev_mult = dc_leverage_boost if dc_status=="CONFIRM" else 1.0` |
|
|
|
|
|
|
| `market_ob_mult` | `nautilus_dolphin/.../ob_features.py` `OBFeatureEngine` | `get_market(bar_idx, symbols)` → imbalance/agreement; formula at orchestrator :587-595 |
|
|
|
|
|
|
| `_day_posture` (STALKER) | orchestrator posture state | 2.0 cap when STALKER |
|
|
|
|
|
|
|
|
|
|
|
|
**Preferred approach (most faithful):** instantiate and drive the REAL
|
|
|
|
|
|
`esf_alpha_orchestrator` sizing path so the composition runs BLUE's own code. If full
|
|
|
|
|
|
orchestrator instantiation proves too heavy, the fallback is to wrap each component above
|
|
|
|
|
|
and replicate ONLY the ~8-line composition block verbatim (it is trivial deterministic
|
|
|
|
|
|
arithmetic — bit-identical if op-order is preserved). Decide after a spike on orchestrator
|
|
|
|
|
|
instantiation cost.
|
|
|
|
|
|
|
|
|
|
|
|
## 5. Validation gate (BINDING — operator-specified)
|
|
|
|
|
|
|
|
|
|
|
|
1. **Monte-Carlo the ENTIRE JOINT input universe** of both surfaces together:
|
|
|
|
|
|
`vel_div × ACB signals(funding/dvol/fng/taker) × w750_vel/β × esof_score × mc_scale ×
|
|
|
|
|
|
ob imbalance/agreement × posture × capital`. Hammer interactions (cap@9, EsoF-on-boosted,
|
|
|
|
|
|
STALKER). N ≥ 1e6 samples.
|
|
|
|
|
|
2. **Match to BIT IDENTITY** vs BLUE's actual-code output (float-for-float, `==`, not approx).
|
|
|
|
|
|
A statistical match HIDES composition bugs; bit-identity won't. Any mismatch = wrapper
|
|
|
|
|
|
bug (op order / rounding / cap) → fix → re-run.
|
|
|
|
|
|
3. **THEN upstream** — replay recorded `dolphin.trade_events` (and/or live scans) through the
|
|
|
|
|
|
wrapped chain; compare to recorded `leverage`. (Caveat: recorded `boost_at_entry`/
|
|
|
|
|
|
`beta_at_entry` are mostly placeholder `1.0` — do NOT validate against those fields;
|
|
|
|
|
|
validate against `leverage` itself, and use the live ACB to produce boosts.)
|
|
|
|
|
|
|
|
|
|
|
|
## 6. Reusable existing pieces
|
|
|
|
|
|
|
|
|
|
|
|
- `prod/clean_arch/violet/alpha_wrappers.py` — `VioletBetSizer`, `SizeDecision` (V-TYPES).
|
|
|
|
|
|
- `prod/clean_arch/violet/modulation.py` — `VioletSizeModulation` (EsoF fold, the wrap pattern).
|
|
|
|
|
|
- `prod/clean_arch/violet/test_violet_modulation.py` / `test_violet_alpha_wrappers.py` —
|
|
|
|
|
|
test patterns (hypothesis + drift-guards) to mirror.
|
|
|
|
|
|
- Import-root pattern for `nautilus_dolphin.nautilus.*`: see `_import_esof_gate()` in
|
|
|
|
|
|
`modulation.py` / `_import_blue_alpha()` in `alpha_wrappers.py`.
|
|
|
|
|
|
|
|
|
|
|
|
## 7. Deliverables & acceptance
|
|
|
|
|
|
|
|
|
|
|
|
- New `prod/clean_arch/violet/sizing.py` (or extend `modulation.py`): a `VioletSizer` that
|
|
|
|
|
|
composes the 5 multipliers + caps, returning a V-TYPES `SizeDecision` with the full
|
|
|
|
|
|
conviction leverage.
|
|
|
|
|
|
- `test_violet_sizing.py`: unit + hypothesis + the **MC bit-identity gate** (`@pytest.mark.gate`)
|
|
|
|
|
|
+ the upstream replay check. Gate report → `prod/VIOLET_dev/reports/`.
|
|
|
|
|
|
- ACCEPT when: bit-identity gate passes at N≥1e6; upstream replay matches recorded `leverage`
|
|
|
|
|
|
within tolerance attributable only to live-ACB vs recorded; full violet suite green;
|
|
|
|
|
|
shared-files-clean; VIOLET still DARK.
|
|
|
|
|
|
|
|
|
|
|
|
## 8. Watch-outs (learned)
|
|
|
|
|
|
|
|
|
|
|
|
- `boost_at_entry`/`beta_at_entry` in trade_events = placeholder `1.0` (don't trust them).
|
|
|
|
|
|
- `beta` recorded as {0,1} in some places vs config {0.2,0.8} — get beta from the live ACB,
|
|
|
|
|
|
not recorded fields.
|
|
|
|
|
|
- ACB needs eigenvalues data on disk; verify the path resolves on the prod host before the
|
|
|
|
|
|
upstream step.
|
|
|
|
|
|
- `min_leverage` floor and the STALKER 2.0 cap are easy to forget — both are in the gate.
|