Repo cwd /mnt/dolphinng5_predict (git root), no remote (local-only) -> agent must run on this host in this dir; needs host-local eigenvalues data, live ClickHouse, and BLUE runtime for bit-identity. Adds CH creds + python path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
7.5 KiB
VIOLET Build Spec — Full Sizing Parity (orchestrator wrap-all → bit-identity)
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.
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-onlymust 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,StrictModelfor 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)
- 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. - 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. - THEN upstream — replay recorded
dolphin.trade_events(and/or live scans) through the wrapped chain; compare to recordedleverage. (Caveat: recordedboost_at_entry/beta_at_entryare mostly placeholder1.0— do NOT validate against those fields; validate againstleverageitself, 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()inmodulation.py/_import_blue_alpha()inalpha_wrappers.py.
7. Deliverables & acceptance
- New
prod/clean_arch/violet/sizing.py(or extendmodulation.py): aVioletSizerthat composes the 5 multipliers + caps, returning a V-TYPESSizeDecisionwith 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/.
- the upstream replay check. Gate report →
- ACCEPT when: bit-identity gate passes at N≥1e6; upstream replay matches recorded
leveragewithin 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_entryin trade_events = placeholder1.0(don't trust them).betarecorded 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_leveragefloor and the STALKER 2.0 cap are easy to forget — both are in the gate.