Files
siloqy/prod/clean_arch/violet/test_violet_sizing.py

1813 lines
73 KiB
Python
Raw Normal View History

"""V3.3: full sizing-parity — VioletSizer composes BLUE's 5-multiplier conviction.
Test layers:
- unit: each factor producer matches BLUE's constants / formula; compose
applies the caps (soft/abs/STALKER) + floor in the right order.
- hypothesis: envelope invariants over the joint input space.
- @gate: (1) MC bit-identity, N>=1e6, vs BLUE's real kernels + the
orchestrator's own composition transcribed verbatim; (2) the same
chain driven through the REAL orchestrator ``_try_entry`` on a
subset (proves the transcription == BLUE's inline code); (3) a DC
CONFIRM end-to-end case; (4) upstream replay vs recorded
``dolphin.trade_events``. Gate report -> prod/VIOLET_dev/reports/.
Bit-identity is float-for-float (``==``): a statistical match hides composition
bugs (op-order / rounding / cap); exact equality does not.
"""
from __future__ import annotations
import json
import math
import sys
import threading
import time
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Optional, Tuple
import numpy as np
import pytest
from hypothesis import given, settings, strategies as st
sys.path.insert(0, "/mnt/dolphinng5_predict")
sys.path.insert(0, "/mnt/dolphinng5_predict/nautilus_dolphin")
from prod.clean_arch.violet.alpha_wrappers import SizeDecision
from prod.clean_arch.violet.sizing import (
FullSizeDecision, SizingBreakdown, VioletSizer,
)
REPORTS_DIR = Path("/mnt/dolphinng5_predict/prod/VIOLET_dev/reports")
PROJECT_ROOT = Path("/mnt/dolphinng5_predict")
def _sizer(**kw: Any) -> VioletSizer:
return VioletSizer(**kw)
def _orch():
"""The real BLUE orchestrator, gold-spec caps, sizing-only config."""
from nautilus_dolphin.nautilus.esf_alpha_orchestrator import NDAlphaEngine
return NDAlphaEngine(
initial_capital=69000.0, max_leverage=8.0, abs_max_leverage=9.0,
min_leverage=0.5, fraction=0.20, use_asset_selection=False,
use_direction_confirm=False,
)
class _MockOB:
"""Minimal OBFeatureEngine stand-in returning controlled market consensus."""
def __init__(self) -> None:
from nautilus_dolphin.nautilus.ob_features import (
OBMarketFeatures, OBPlacementFeatures,
)
self._M = OBMarketFeatures
self._P = OBPlacementFeatures
self._m = OBMarketFeatures(0.0, 0.5, 0.0)
def set(self, imbalance: float, agreement: float) -> None:
self._m = self._M(imbalance, agreement, 0.0)
def get_market(self, ts: float, assets: Any = None) -> Any:
return self._m
def get_placement(self, asset: str, bar_idx: int) -> Any:
return self._P(1e6, 1.0, 1.0, 1.0)
# ══════════════════════════════════════════════════════════════════════════════
# UNIT — factor producers match BLUE's constants / formula
# ══════════════════════════════════════════════════════════════════════════════
def test_gold_spec_caps_are_default():
sz = _sizer()
assert sz.base_max_leverage == 8.0 # soft cap (FROZEN_ALGO_SPEC §4)
assert sz.abs_max_leverage == 9.0 # hard cap
assert sz.min_leverage == 0.5
def test_base_sizer_max_leverage_is_base_soft_cap():
# The orchestrator builds bet_sizer with max_leverage == base_max_leverage;
# the sizer's own clamp must match (the boost lifts TOWARD abs, not past soft).
sz = _sizer()
assert sz._bet_sizer.max_leverage == 8.0
def test_rejects_base_above_abs():
with pytest.raises(ValueError):
_sizer(base_max_leverage=10.0, abs_max_leverage=9.0)
# ── strength_cubic: verbatim orchestrator _strength_cubic ─────────────────────
def test_strength_short_boundaries():
sz = _sizer()
assert sz.strength_cubic(-0.02) == 0.0 # at threshold -> 0
assert sz.strength_cubic(-0.05) == 1.0 # at extreme -> 1
assert sz.strength_cubic(-0.019) == 0.0 # above threshold -> 0
assert sz.strength_cubic(-1.0) == 1.0 # beyond extreme -> 1
def test_strength_long_boundaries():
sz = _sizer()
assert sz.strength_cubic(0.01, trade_direction=1) == 0.0 # threshold
assert sz.strength_cubic(0.04, trade_direction=1) == 1.0 # extreme
assert sz.strength_cubic(0.005, trade_direction=1) == 0.0 # below threshold
def test_strength_cubic_matches_orchestrator():
eng = _orch()
sz = _sizer()
for vd in np.linspace(-0.5, -0.021, 50):
assert sz.strength_cubic(float(vd)) == eng._strength_cubic(float(vd))
# ── regime_size_mult: 3-scale ACB formula ─────────────────────────────────────
def test_regime_beta_zero_is_boost_times_mc():
sz = _sizer()
assert sz.regime_size_mult(-0.10, boost=1.3, beta=0.0, mc_scale=1.0) == 1.3
assert sz.regime_size_mult(-0.10, boost=1.5, beta=0.0, mc_scale=0.5) == 0.75
def test_regime_beta_positive_uses_strength_cubed():
sz = _sizer()
# strength(-0.10) = 1.0 -> regime = 1.0*(1+0.8*1.0)*1.0 = 1.8
assert sz.regime_size_mult(-0.10, boost=1.0, beta=0.8, mc_scale=1.0) == 1.8
# strength(-0.035): raw=(-0.02+0.035)/0.03=0.5 -> 0.5^3=0.125
s = sz.strength_cubic(-0.035)
assert sz.regime_size_mult(-0.035, boost=1.0, beta=0.8, mc_scale=1.0) == 1.0 * (1.0 + 0.8 * s) * 1.0
def test_regime_matches_orchestrator_update():
eng = _orch()
sz = _sizer()
for vd in np.linspace(-0.5, -0.021, 40):
for beta in (0.0, 0.2, 0.8):
eng._day_base_boost = 1.3
eng._day_beta = beta
eng._day_mc_scale = 0.5
eng._update_regime_size_mult(float(vd))
assert sz.regime_size_mult(
float(vd), boost=1.3, beta=beta, mc_scale=0.5
) == eng.regime_size_mult
# ── esof_size_mult: wraps esof_size_mult_from_score (RAW, no clamp) ────────────
def test_esof_band_values():
from nautilus_dolphin.nautilus.esof_size_gate import (
ESOF_NEUTRAL_CORE_MULT, ESOF_STALE_FALLBACK_MULT, ESOF_UNFAVORABLE_CORE_MULT,
)
sz = _sizer()
assert sz.esof_size_mult(0.0) == ESOF_NEUTRAL_CORE_MULT # 0.80
assert sz.esof_size_mult(-0.5) == ESOF_UNFAVORABLE_CORE_MULT # 0.30
assert sz.esof_size_mult(None) == ESOF_STALE_FALLBACK_MULT # 0.40
assert sz.esof_size_mult(0.5) == 1.0 # full size
def test_esof_equals_blue_fn_raw():
from nautilus_dolphin.nautilus.esof_size_gate import esof_size_mult_from_score
sz = _sizer()
for sc in [0.3, 0.07, 0.05, 0.03, 0.0, -0.03, -0.07, -0.2, -0.25, -0.3, -1.0, None]:
assert sz.esof_size_mult(sc) == float(esof_size_mult_from_score(sc))
# ── market_ob_mult: verbatim orchestrator :587-595 ─────────────────────────────
def test_ob_no_consensus_is_one():
sz = _sizer()
# agreement below 0.70 -> no modulation
assert sz.market_ob_mult(-0.5, 0.50, trade_direction=-1) == 1.0
assert sz.market_ob_mult(0.5, 0.69, trade_direction=-1) == 1.0
# imbalance below 0.08 threshold
assert sz.market_ob_mult(-0.05, 0.90, trade_direction=-1) == 1.0
def test_ob_short_confirmed_boosts():
sz = _sizer()
# SHORT, negative imbalance (sell pressure confirms): eff_imb = +0.5
m = sz.market_ob_mult(-0.5, 0.90, trade_direction=-1)
assert m == 1.0 + min(0.20, 0.5 * 0.9 * 0.5)
assert m == pytest.approx(1.20) # capped at +20%
def test_ob_short_contradicted_haircuts():
sz = _sizer()
# SHORT, positive imbalance (contradicts): eff_imb = -0.5
m = sz.market_ob_mult(0.5, 0.90, trade_direction=-1)
assert m == max(0.85, 1.0 - 0.5 * 0.9 * 0.3)
assert m == pytest.approx(0.865)
def test_ob_boost_capped_at_20pct():
sz = _sizer()
# extreme imbalance would exceed 20% but is capped
m = sz.market_ob_mult(-1.0, 1.0, trade_direction=-1)
assert m == 1.20
def test_ob_haircut_floored_at_85pct():
sz = _sizer()
m = sz.market_ob_mult(1.0, 1.0, trade_direction=-1)
assert m == 0.85
def test_ob_long_flips_sign():
sz = _sizer()
# LONG, positive imbalance confirms: eff_imb = +0.5
assert sz.market_ob_mult(0.5, 0.90, trade_direction=1) == pytest.approx(1.20)
# LONG, negative imbalance contradicts
assert sz.market_ob_mult(-0.5, 0.90, trade_direction=1) == pytest.approx(0.865)
# ── dc_lev_mult ────────────────────────────────────────────────────────────────
def test_dc_lev_mult_confirm_vs_else():
sz_default = _sizer()
assert sz_default.dc_lev_mult("CONFIRM") == 1.0 # default boost
assert sz_default.dc_lev_mult("NONE") == 1.0
assert sz_default.dc_lev_mult("NEUTRAL") == 1.0
sz_boost = _sizer(dc_leverage_boost=1.25)
assert sz_boost.dc_lev_mult("CONFIRM") == 1.25
assert sz_boost.dc_lev_mult("NONE") == 1.0
# ══════════════════════════════════════════════════════════════════════════════
# UNIT — compose: caps / floor / STALKER / op-order / notional
# ══════════════════════════════════════════════════════════════════════════════
def _base(vel_div: float = -0.20) -> SizeDecision:
return _sizer().base_size(capital=69000.0, vel_div=vel_div, trade_direction=-1)
def test_compose_identity_multipliers_returns_base_clamped():
sz = _sizer()
base = _base(-0.035) # partial strength
d = sz.compose(base, dc_lev_mult=1.0, regime_size_mult=1.0,
market_ob_mult=1.0, esof_size_mult=1.0, posture="APEX")
assert d.conviction_leverage == base.conviction_leverage
assert d.fraction == base.fraction
def test_compose_abs_cap_9_enforced():
sz = _sizer()
base = _base(-0.20) # saturated at 8.0 (base soft cap)
# huge multipliers would push raw past 9 but abs cap holds
d = sz.compose(base, dc_lev_mult=1.5, regime_size_mult=1.5,
market_ob_mult=1.2, esof_size_mult=1.0, posture="APEX")
assert d.conviction_leverage == 9.0
def test_compose_soft_cap_path():
sz = _sizer()
base = _base(-0.035)
# clamped_max = min(8.0 * 1.0 * 1.0 * 0.8, 9.0) = 6.4
d = sz.compose(base, dc_lev_mult=1.0, regime_size_mult=1.0,
market_ob_mult=1.0, esof_size_mult=0.8, posture="APEX")
# raw = base * 0.8, clamped_max = 6.4; raw < clamped -> raw wins
assert d.conviction_leverage == pytest.approx(base.conviction_leverage * 0.8)
def test_compose_stalker_caps_at_2():
sz = _sizer()
base = _base(-0.20)
d = sz.compose(base, dc_lev_mult=1.0, regime_size_mult=1.0,
market_ob_mult=1.0, esof_size_mult=1.0, posture="STALKER")
assert d.conviction_leverage == 2.0
def test_compose_stalker_floor_wins_when_base_tiny():
sz = _sizer(min_leverage=0.5)
base = _base(-0.021) # near-threshold -> base ~ min_leverage
d = sz.compose(base, dc_lev_mult=1.0, regime_size_mult=0.5,
market_ob_mult=0.85, esof_size_mult=0.3, posture="STALKER")
# STALKER cap 2.0, but min_leverage floor 0.5 is higher than the haircut result
assert d.conviction_leverage == max(0.5, min(
base.conviction_leverage * 1.0 * 0.5 * 0.85 * 0.3, 2.0))
def test_compose_min_leverage_floor():
sz = _sizer(min_leverage=0.5)
base = _base(-0.021)
# aggressive haircut drives raw below floor
d = sz.compose(base, dc_lev_mult=1.0, regime_size_mult=1.0,
market_ob_mult=0.85, esof_size_mult=0.3, posture="APEX")
assert d.conviction_leverage == 0.5
def test_compose_preserves_fraction_notional_is_fraction_times_leverage():
sz = _sizer()
base = _base(-0.06)
d = sz.compose(base, dc_lev_mult=1.0, regime_size_mult=1.3,
market_ob_mult=1.1, esof_size_mult=0.8, posture="APEX")
assert d.fraction == base.fraction # multipliers scale leverage only
assert d.notional_fraction == pytest.approx(d.fraction * d.conviction_leverage)
def test_compose_op_order_matches_spec():
# The spec's exact op order: clamped = min(soft*regime*ob*esof, abs);
# raw = base*dc*regime*ob*esof; STALKER; leverage=min(raw,clamped); max(min,lev).
sz = _sizer()
base = _base(-0.10)
dc, rsm, obm, esm = 1.0, 1.8, 1.15, 0.8
clamped = min(8.0 * rsm * obm * esm, 9.0)
raw = base.conviction_leverage * dc * rsm * obm * esm
expect = max(0.5, min(raw, clamped))
d = sz.compose(base, dc_lev_mult=dc, regime_size_mult=rsm,
market_ob_mult=obm, esof_size_mult=esm, posture="APEX")
assert d.conviction_leverage == expect
def test_full_size_decision_returns_breakdown():
r = _sizer().size(capital=69000.0, vel_div=-0.10, boost=1.3, beta=0.8,
mc_scale=1.0, esof_score=0.0, posture="APEX")
assert isinstance(r, FullSizeDecision)
assert isinstance(r.breakdown, SizingBreakdown)
assert r.breakdown.dc_lev_mult == 1.0
assert r.breakdown.regime_size_mult > 1.0
# ══════════════════════════════════════════════════════════════════════════════
# V-TYPES / drift guards
# ══════════════════════════════════════════════════════════════════════════════
def test_size_decision_frozen():
from pydantic import ValidationError
d = _base()
with pytest.raises(ValidationError):
d.conviction_leverage = 99.0
def test_sizing_breakdown_frozen():
r = _sizer().size(capital=1000.0, vel_div=-0.05)
with pytest.raises(Exception):
r.breakdown.raw_leverage = -1.0
# ══════════════════════════════════════════════════════════════════════════════
# HYPOTHESIS — envelope invariants
# ══════════════════════════════════════════════════════════════════════════════
_short_vd = st.floats(min_value=-0.5, max_value=-0.021, allow_nan=False, allow_infinity=False)
_boost = st.floats(min_value=1.0, max_value=2.5, allow_nan=False, allow_infinity=False)
_beta = st.floats(min_value=0.0, max_value=1.0, allow_nan=False, allow_infinity=False)
_mc = st.sampled_from([0.5, 1.0])
_esof = st.floats(min_value=-1.0, max_value=1.0, allow_nan=False, allow_infinity=False)
_imb = st.floats(min_value=-1.0, max_value=1.0, allow_nan=False, allow_infinity=False)
_agree = st.floats(min_value=0.0, max_value=1.0, allow_nan=False, allow_infinity=False)
_cap = st.floats(min_value=1e4, max_value=1e6, allow_nan=False, allow_infinity=False)
@given(vel_div=_short_vd, boost=_boost, beta=_beta, mc_scale=_mc,
esof=_esof, imb=_imb, agree=_agree, cap=_cap)
@settings(max_examples=200, deadline=None)
def test_leverage_within_envelope(vel_div, boost, beta, mc_scale, esof, imb, agree, cap):
sz = _sizer()
r = sz.size(capital=cap, vel_div=vel_div, boost=boost, beta=beta,
mc_scale=mc_scale, esof_score=esof,
ob_median_imbalance=imb, ob_agreement_pct=agree, posture="APEX")
lev = r.decision.conviction_leverage
assert math.isfinite(lev)
assert sz.min_leverage - 1e-9 <= lev <= sz.abs_max_leverage + 1e-9
@given(vel_div=_short_vd, boost=_boost, beta=_beta, mc_scale=_mc, esof=_esof,
imb=_imb, agree=_agree, cap=_cap)
@settings(max_examples=100, deadline=None)
def test_stalker_caps_at_2(vel_div, boost, beta, mc_scale, esof, imb, agree, cap):
sz = _sizer()
r = sz.size(capital=cap, vel_div=vel_div, boost=boost, beta=beta,
mc_scale=mc_scale, esof_score=esof,
ob_median_imbalance=imb, ob_agreement_pct=agree, posture="STALKER")
lev = r.decision.conviction_leverage
assert math.isfinite(lev)
assert sz.min_leverage - 1e-9 <= lev <= 2.0 + 1e-9
@given(vel_div=_short_vd, cap=_cap)
@settings(max_examples=60, deadline=None)
def test_notional_fraction_identity(vel_div, cap):
sz = _sizer()
r = sz.size(capital=cap, vel_div=vel_div)
d = r.decision
assert d.notional_fraction == pytest.approx(d.fraction * d.conviction_leverage)
# ══════════════════════════════════════════════════════════════════════════════
# @gate — MC BIT-IDENTITY (N >= 1e6) vs BLUE's real kernels + verbatim composition
# ══════════════════════════════════════════════════════════════════════════════
def _blue_ref_leverage(eng, mob, sz, vd, boost, beta, mc, esof, imb, agree, posture, cap):
"""BLUE's actual-code sizing: the orchestrator's REAL bet_sizer + set_esof +
_update_regime_size_mult + OB formula + the verbatim composition (:600-619).
Uses the orchestrator's own kernel objects — only the ~8-line arithmetic is
transcribed (trivial deterministic float math). Validated == _try_entry below.
"""
eng._day_base_boost = boost
eng._day_beta = beta
eng._day_mc_scale = mc
eng._day_posture = posture
eng.set_esof_advisory_score(esof)
eng._update_regime_size_mult(vd)
sr = eng.bet_sizer.calculate_size(
capital=cap, vel_div=vd, vel_div_trend=0.0, trade_direction=-1)
obm = 1.0
if imb is not None:
mob.set(imb, agree)
om = mob.get_market(1.0, ["BTCUSDT"])
ei = -om.median_imbalance
if ei > 0.08 and om.agreement_pct > 0.70:
obm = 1.0 + min(0.20, ei * om.agreement_pct * 0.5)
elif ei < -0.08 and om.agreement_pct > 0.70:
obm = max(0.85, 1.0 - abs(ei) * om.agreement_pct * 0.3)
clamped = min(
eng.base_max_leverage * eng.regime_size_mult * obm * eng._esof_size_mult,
eng.abs_max_leverage)
raw = sr["leverage"] * 1.0 * eng.regime_size_mult * obm * eng._esof_size_mult
if posture == "STALKER":
clamped = min(clamped, 2.0)
return max(eng.bet_sizer.min_leverage, min(raw, clamped))
@pytest.mark.gate
def test_gate_mc_bit_identity():
"""N>=1e6: VIOLET == BLUE float-for-float across the ENTIRE joint input space."""
N = 1_000_000
rng = np.random.default_rng(20260615)
vel_div = rng.uniform(-0.50, -0.021, N)
boost = rng.uniform(1.0, 2.5, N)
beta = rng.choice([0.2, 0.8], N)
mc_scale = rng.choice([0.5, 1.0], N)
esof = rng.uniform(-1.0, 1.0, N)
imb = rng.uniform(-1.0, 1.0, N)
agree = rng.uniform(0.0, 1.0, N)
posture = rng.choice(["APEX", "STALKER", "RESTORED"], N)
capital = rng.uniform(1e4, 1e6, N)
# NOTE: boost>2.5, β∈{0,1}, mc=0, and the OB agreement boundary are covered by
# test_gate_mc_extreme_multipliers (typical-vs-extreme split — verified 2026-06-15).
sz = _sizer()
eng = _orch()
mob = _MockOB()
# JIT warmup (amortize numba compilation outside the timed comparison)
for _ in range(8):
eng.bet_sizer.calculate_size(capital=1.0, vel_div=-0.1)
sz._bet_sizer.calculate(capital=1.0, vel_div=-0.1)
blue = np.empty(N)
violet = np.empty(N)
t0 = time.time()
for i in range(N):
vd = float(vel_div[i]); bo = float(boost[i]); be = float(beta[i])
ms = float(mc_scale[i]); es = float(esof[i]); im = float(imb[i])
ag = float(agree[i]); po = str(posture[i]); cp = float(capital[i])
blue[i] = _blue_ref_leverage(eng, mob, sz, vd, bo, be, ms, es, im, ag, po, cp)
v = sz.size(capital=cp, vel_div=vd, boost=bo, beta=be, mc_scale=ms,
esof_score=es, ob_median_imbalance=im, ob_agreement_pct=ag,
posture=po)
violet[i] = v.decision.conviction_leverage
elapsed = time.time() - t0
mismatches = int(np.count_nonzero(blue != violet))
if mismatches:
idx = np.nonzero(blue != violet)[0][:10]
sample = [{
"i": int(k), "vd": float(vel_div[k]), "boost": float(boost[k]),
"beta": float(beta[k]), "mc": float(mc_scale[k]),
"esof": float(esof[k]), "imb": float(imb[k]), "agree": float(agree[k]),
"posture": str(posture[k]), "blue": float(blue[k]), "violet": float(violet[k]),
} for k in idx]
_write_gate_report("sizing", N=N, elapsed_s=elapsed, mismatches=mismatches,
sample_mismatches=sample, passed=False)
assert mismatches == 0, (
f"BIT-IDENTITY BROKEN: {mismatches}/{N} mismatches (first: "
f"vd={float(vel_div[idx[0]])} blue={float(blue[idx[0]])!r} "
f"violet={float(violet[idx[0]])!r})")
_write_gate_report("sizing", N=N, elapsed_s=elapsed, mismatches=0,
passed=True, note="float-for-float == vs BLUE kernels")
# ══════════════════════════════════════════════════════════════════════════════
# @gate — end-to-end _try_entry parity (transcription == BLUE's inline code)
# ══════════════════════════════════════════════════════════════════════════════
@pytest.mark.gate
def test_gate_try_entry_end_to_end():
"""Drive the REAL orchestrator _try_entry and confirm VIOLET matches its
INLINE composition (proves the MC reference transcription == BLUE's code)."""
N = 30_000
rng = np.random.default_rng(7)
vel_div = rng.uniform(-0.50, -0.021, N)
boost = rng.uniform(1.0, 2.5, N)
beta = rng.choice([0.2, 0.8], N)
mc_scale = rng.choice([0.5, 1.0], N)
esof = rng.uniform(-1.0, 1.0, N)
imb = rng.uniform(-1.0, 1.0, N)
agree = rng.uniform(0.0, 1.0, N)
posture = rng.choice(["APEX", "STALKER"], N)
capital = rng.uniform(1e4, 1e6, N)
sz = _sizer()
eng = _orch()
mob = _MockOB()
mismatches = 0
for i in range(N):
vd = float(vel_div[i]); bo = float(boost[i]); be = float(beta[i])
ms = float(mc_scale[i]); es = float(esof[i]); im = float(imb[i])
ag = float(agree[i]); po = str(posture[i]); cp = float(capital[i])
# --- BLUE: real _try_entry ---
eng.regime_direction = -1
eng.capital = cp
eng.position = None
eng._day_base_boost = bo
eng._day_beta = be
eng._day_mc_scale = ms
eng._day_posture = po
eng.set_esof_advisory_score(es)
eng._update_regime_size_mult(vd)
mob.set(im, ag)
eng.ob_engine = mob
res = eng._try_entry(bar_idx=1, vel_div=vd, prices={"BTCUSDT": 100.0},
price_histories=None)
blue_lev = res["leverage"] if res else None
# --- VIOLET ---
v = sz.size(capital=cp, vel_div=vd, boost=bo, beta=be, mc_scale=ms,
esof_score=es, ob_median_imbalance=im, ob_agreement_pct=ag,
posture=po)
violet_lev = v.decision.conviction_leverage
if blue_lev != violet_lev:
mismatches += 1
if mismatches <= 3:
print(f" MISMATCH i={i} vd={vd} blue={blue_lev!r} violet={violet_lev!r}")
assert mismatches == 0, f"{mismatches}/{N} _try_entry mismatches"
# ══════════════════════════════════════════════════════════════════════════════
# @gate — DC CONFIRM end-to-end (dc_lev_mult != 1.0 through real signal_gen)
# ══════════════════════════════════════════════════════════════════════════════
@pytest.mark.gate
def test_gate_dc_confirm_end_to_end():
"""Craft a CONFIRM price history; verify the dc boost flows through both the
real orchestrator and VIOLET bit-identically (dc_lev_mult != 1.0)."""
from nautilus_dolphin.nautilus.esf_alpha_orchestrator import NDAlphaEngine
# check_dc_nb compares prices[-1] vs prices[-lookback-1]; need >= 0.75 bps fall.
ph = [100.0] * 10 + [99.97] * 3 # ~3 bps fall in the last 7 bars
for boost in (1.25, 1.5):
eng = NDAlphaEngine(
initial_capital=69000.0, max_leverage=8.0, abs_max_leverage=9.0,
min_leverage=0.5, fraction=0.20, use_asset_selection=False,
use_direction_confirm=True, dc_leverage_boost=boost)
sz = _sizer(dc_leverage_boost=boost)
eng.regime_direction = -1
eng.set_esof_advisory_score(0.3) # ~full mult
eng._day_base_boost = 1.0
eng._day_beta = 0.0
eng._day_mc_scale = 1.0
eng._day_posture = "APEX"
eng._update_regime_size_mult(-0.035) # partial strength (not saturated)
sig = eng.signal_gen.generate(
vel_div=-0.035, vel_div_history=None, asset_price_history=ph,
trade_direction=-1, asset=None)
assert sig.dc_status == "CONFIRM", f"expected CONFIRM, got {sig.dc_status}"
res = eng._try_entry(bar_idx=13, vel_div=-0.035, prices={"BTCUSDT": 99.97},
price_histories={"BTCUSDT": ph})
blue_lev = res["leverage"]
v = sz.size(capital=69000.0, vel_div=-0.035, boost=1.0, beta=0.0,
mc_scale=1.0, esof_score=0.3, dc_status="CONFIRM", posture="APEX")
assert v.decision.conviction_leverage == blue_lev, (
f"dc boost={boost}: blue={blue_lev!r} violet={v.decision.conviction_leverage!r}")
assert v.breakdown.dc_lev_mult == boost
# ══════════════════════════════════════════════════════════════════════════════
# @gate — upstream replay vs recorded dolphin.trade_events
# ══════════════════════════════════════════════════════════════════════════════
def _load_recorded_trades(limit: int = 2000):
"""Pull (vel_div_entry, posture, capital_before, leverage, date) from CH."""
import urllib.request
sql = (
"WITH d AS (SELECT trade_id, any(vel_div_entry) vd, any(posture) po, "
"any(capital_before) cap, any(leverage) lev, any(date) dt "
"FROM dolphin.trade_events WHERE leverage>0 AND bars_held>0 "
"GROUP BY trade_id) "
f"SELECT vd, po, cap, lev, dt FROM d WHERE vd < -0.02 "
f"LIMIT {int(limit)} FORMAT TSV"
).encode()
req = urllib.request.Request(
"http://localhost:8123/", data=sql,
headers={"X-ClickHouse-User": "dolphin", "X-ClickHouse-Key": "dolphin_ch_2026"})
rows = []
with urllib.request.urlopen(req, timeout=30) as resp:
for line in resp.read().decode().splitlines():
a = line.split("\t")
rows.append((float(a[0]), a[1], float(a[2]), float(a[3]), a[4]))
return rows
@pytest.mark.gate
def test_gate_upstream_replay():
"""Replay recorded trade_events through the wrapped chain; compare to recorded
leverage. Tolerance accounts for live-ACB-vs-recorded + missing esof/OB at
entry (spec §5.3). The gate is: VIOLET tracks recorded leverage (positive
correlation, median within the modulation envelope), not bit-identity."""
try:
trades = _load_recorded_trades(limit=2000)
except Exception as exc:
pytest.skip(f"ClickHouse unreachable: {exc}")
if len(trades) < 50:
pytest.skip("insufficient recorded trades")
# Live ACB for boost/beta (spec: "use the live ACB to produce boosts").
acb = None
try:
from nautilus_dolphin.nautilus.adaptive_circuit_breaker import (
AdaptiveCircuitBreaker)
acb = AdaptiveCircuitBreaker()
dates = sorted({t[4] for t in trades})
acb.preload_w750(dates)
except Exception:
acb = None # eigenvalues data may not cover these dates -> defaults
sz = _sizer()
recorded, violet = [], []
for vd, posture, cap, lev, date in trades:
boost, beta = 1.0, 0.0
if acb is not None:
try:
info = acb.get_dynamic_boost_for_date(date)
boost = float(info["boost"])
beta = float(info["beta"])
except Exception:
pass
r = sz.size(capital=cap, vel_div=vd, boost=boost, beta=beta,
esof_score=None, posture=posture)
recorded.append(lev)
violet.append(r.decision.conviction_leverage)
recorded = np.array(recorded)
violet = np.array(violet)
abs_err = np.abs(violet - recorded)
med_err = float(np.median(abs_err))
# Pearson: VIOLET must track the recorded conviction direction.
mx, my = recorded.mean(), violet.mean()
sxy = np.sum((recorded - mx) * (violet - my))
sxx = np.sum((recorded - mx) ** 2)
syy = np.sum((violet - my) ** 2)
r_pearson = float(sxy / math.sqrt(sxx * syy)) if sxx > 0 and syy > 0 else 0.0
within_2 = float(np.mean(abs_err <= 2.0))
_write_gate_report(
"upstream_replay", n_trades=len(trades), median_abs_err=med_err,
pearson_r=r_pearson, pct_within_2x=within_2, acb_available=acb is not None,
passed=(r_pearson >= 0.80 and med_err <= 3.0),
note="approximate: recorded boost/beta are placeholder 1.0; esof/OB not "
"recorded at entry; gap attributable to live-ACB-vs-recorded (spec §5.3)")
# The gate: the wrapped chain TRACKS recorded leverage strongly. Observed r≈0.94,
# median_err≈1.44 (review 2026-06-15); thresholds set well inside that with margin
# for sample variation — meaningful, not the prior near-vacuous r>0.
assert r_pearson >= 0.80, (
f"upstream replay correlation too weak: r={r_pearson:.3f} "
f"(expected ≥0.80; median_err={med_err:.3f})")
assert med_err <= 3.0, (
f"upstream replay median abs error too large: {med_err:.3f} (expected ≤3.0)")
# ══════════════════════════════════════════════════════════════════════════════
# gate report helper
# ══════════════════════════════════════════════════════════════════════════════
def _write_gate_report(name: str, **fields: Any) -> None:
REPORTS_DIR.mkdir(parents=True, exist_ok=True)
ts = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
import socket
payload = {
"generated_utc": datetime.now(timezone.utc).isoformat(),
"host": socket.gethostname(),
"layer": f"violet_v3_{name}",
**fields,
}
path = REPORTS_DIR / f"violet_v3_{name}_{ts}.json"
path.write_text(json.dumps(payload, indent=2, default=str))
# ══════════════════════════════════════════════════════════════════════════════
# EXPANDED SUITE — error handling, off-by-ones, typing, fuzz/chaos, concurrency
# ══════════════════════════════════════════════════════════════════════════════
# ── A. Construction & initialization validation ────────────────────────────────
def test_construction_base_equals_abs_allowed():
sz = _sizer(base_max_leverage=8.0, abs_max_leverage=8.0)
assert sz.base_max_leverage == sz.abs_max_leverage == 8.0
def test_construction_preserves_vel_div_thresholds():
sz = _sizer(vel_div_threshold=-0.03, vel_div_extreme=-0.06)
assert sz.vel_div_threshold == -0.03
assert sz.vel_div_extreme == -0.06
def test_construction_long_thresholds_propagated():
sz = _sizer(long_vel_div_threshold=0.02, long_vel_div_extreme=0.05)
assert sz.long_vel_div_threshold == 0.02
assert sz.long_vel_div_extreme == 0.05
def test_construction_custom_dc_boost():
sz = _sizer(dc_leverage_boost=1.337)
assert sz.dc_leverage_boost == 1.337
def test_construction_leverage_convexity_propagated():
sz = _sizer(leverage_convexity=2.0)
assert sz.leverage_convexity == 2.0
def test_construction_min_leverage_propagated():
sz = _sizer(min_leverage=1.0)
assert sz.min_leverage == 1.0
assert sz._bet_sizer._sizer.min_leverage == 1.0
def test_rejects_base_just_above_abs():
with pytest.raises(ValueError):
_sizer(base_max_leverage=9.001, abs_max_leverage=9.0)
def test_construction_fraction_propagated():
sz = _sizer(base_fraction=0.15)
d = sz.base_size(capital=1000.0, vel_div=-0.10)
assert d.fraction <= 0.15
# ── B. strength_cubic: exhaustive boundary matrix ──────────────────────────────
def test_strength_short_just_above_threshold():
assert _sizer().strength_cubic(-0.019) == 0.0
def test_strength_short_just_below_threshold():
assert _sizer().strength_cubic(-0.021) > 0.0
def test_strength_short_at_extreme_returns_one():
assert _sizer().strength_cubic(-0.05) == 1.0
def test_strength_short_beyond_extreme():
assert _sizer().strength_cubic(-0.0500001) == 1.0
assert _sizer().strength_cubic(-1.0) == 1.0
def test_strength_short_midpoint_exact():
assert _sizer().strength_cubic(-0.035) == pytest.approx(0.125)
def test_strength_long_just_below_threshold():
assert _sizer().strength_cubic(0.009, trade_direction=1) == 0.0
def test_strength_long_at_extreme_returns_one():
assert _sizer().strength_cubic(0.04, trade_direction=1) == 1.0
def test_strength_long_midpoint():
assert _sizer().strength_cubic(0.025, trade_direction=1) == pytest.approx(0.125)
def test_strength_convexity_cubed_not_squared():
sz = _sizer(leverage_convexity=3.0)
assert sz.strength_cubic(-0.035) == pytest.approx(0.125)
assert sz.strength_cubic(-0.035) != pytest.approx(0.25)
def test_strength_nan_returns_zero():
assert _sizer().strength_cubic(float("nan")) == 0.0
def test_strength_inf_short_returns_zero():
assert _sizer().strength_cubic(float("inf")) == 0.0
def test_strength_neg_inf_short_returns_one():
assert _sizer().strength_cubic(float("-inf")) == 1.0
def test_strength_custom_convexity_changes_curve():
sz2 = _sizer(leverage_convexity=2.0)
sz3 = _sizer(leverage_convexity=3.0)
vd = -0.035
assert sz2.strength_cubic(vd) == pytest.approx(0.25)
assert sz3.strength_cubic(vd) == pytest.approx(0.125)
def test_strength_monotonic_short():
# Going from weak (-0.021) to strong (-0.05): strength increases monotonically.
sz = _sizer()
vals = [sz.strength_cubic(vd) for vd in np.linspace(-0.021, -0.05, 30)]
assert all(vals[i] <= vals[i + 1] + 1e-12 for i in range(len(vals) - 1))
def test_strength_monotonic_increasing_long():
sz = _sizer()
vals = [sz.strength_cubic(vd, trade_direction=1) for vd in np.linspace(0.011, 0.04, 30)]
assert all(vals[i] <= vals[i + 1] + 1e-12 for i in range(len(vals) - 1))
def test_strength_quarter_and_three_quarters():
sz = _sizer()
assert sz.strength_cubic(-0.0275) == pytest.approx(0.25 ** 3)
assert sz.strength_cubic(-0.0425) == pytest.approx(0.75 ** 3)
# ── C. regime_size_mult: formula edge cases ────────────────────────────────────
def test_regime_boost_zero_beta_zero():
assert _sizer().regime_size_mult(-0.10, boost=0.0, beta=0.0, mc_scale=1.0) == 0.0
def test_regime_mc_scale_zero():
assert _sizer().regime_size_mult(-0.10, boost=1.5, beta=0.8, mc_scale=0.0) == 0.0
def test_regime_beta_only_active_when_positive():
sz = _sizer()
r0 = sz.regime_size_mult(-0.035, boost=1.0, beta=0.0, mc_scale=1.0)
assert r0 == 1.0
r1 = sz.regime_size_mult(-0.035, boost=1.0, beta=0.8, mc_scale=1.0)
assert r1 == pytest.approx(1.0 * (1.0 + 0.8 * 0.125))
def test_regime_saturated_strength():
sz = _sizer()
assert sz.regime_size_mult(-0.10, boost=1.3, beta=0.8, mc_scale=0.5) == pytest.approx(1.3 * 1.8 * 0.5)
def test_regime_near_threshold_low_strength():
sz = _sizer()
r = sz.regime_size_mult(-0.021, boost=1.5, beta=0.8, mc_scale=1.0)
s = sz.strength_cubic(-0.021)
assert r == pytest.approx(1.5 * (1.0 + 0.8 * s) * 1.0)
def test_regime_matches_orchestrator_long_direction():
eng = _orch()
sz = _sizer()
eng.regime_direction = 1
for vd in np.linspace(0.011, 0.04, 20):
for beta in (0.0, 0.2, 0.8):
eng._day_base_boost = 1.2
eng._day_beta = beta
eng._day_mc_scale = 0.8
eng._update_regime_size_mult(float(vd))
assert sz.regime_size_mult(
float(vd), boost=1.2, beta=beta, mc_scale=0.8, trade_direction=1
) == eng.regime_size_mult
# ── D. esof_size_mult: band transitions & exotic inputs ────────────────────────
def test_esof_full_positive_above_edge():
assert _sizer().esof_size_mult(0.07) == 1.0
def test_esof_positive_shoulder_transition():
from nautilus_dolphin.nautilus.esof_size_gate import ESOF_NEUTRAL_CORE_MULT
val = _sizer().esof_size_mult(0.05)
assert ESOF_NEUTRAL_CORE_MULT < val < 1.0
def test_esof_neutral_negative_shoulder():
from nautilus_dolphin.nautilus.esof_size_gate import ESOF_NEUTRAL_CORE_MULT
val = _sizer().esof_size_mult(-0.05)
assert ESOF_NEUTRAL_CORE_MULT < val < 1.0
def test_esof_unfavorable_shoulder():
from nautilus_dolphin.nautilus.esof_size_gate import ESOF_UNFAVORABLE_CORE_MULT
val = _sizer().esof_size_mult(-0.25)
assert ESOF_UNFAVORABLE_CORE_MULT < val < 1.0
def test_esof_nan_returns_fallback():
from nautilus_dolphin.nautilus.esof_size_gate import ESOF_STALE_FALLBACK_MULT
assert _sizer().esof_size_mult(float("nan")) == ESOF_STALE_FALLBACK_MULT
def test_esof_inf_returns_fallback():
from nautilus_dolphin.nautilus.esof_size_gate import ESOF_STALE_FALLBACK_MULT
assert _sizer().esof_size_mult(float("inf")) == ESOF_STALE_FALLBACK_MULT
assert _sizer().esof_size_mult(float("-inf")) == ESOF_STALE_FALLBACK_MULT
def test_esof_string_coercible():
assert _sizer().esof_size_mult("0.5") == 1.0
def test_esof_string_non_coercible_fallback():
from nautilus_dolphin.nautilus.esof_size_gate import ESOF_STALE_FALLBACK_MULT
assert _sizer().esof_size_mult("not_a_number") == ESOF_STALE_FALLBACK_MULT
def test_esof_bool_true_is_full():
assert _sizer().esof_size_mult(True) == 1.0
def test_esof_bool_false_is_neutral():
from nautilus_dolphin.nautilus.esof_size_gate import ESOF_NEUTRAL_CORE_MULT
assert _sizer().esof_size_mult(False) == ESOF_NEUTRAL_CORE_MULT
def test_esof_object_fallback():
from nautilus_dolphin.nautilus.esof_size_gate import ESOF_STALE_FALLBACK_MULT
assert _sizer().esof_size_mult(object()) == ESOF_STALE_FALLBACK_MULT
def test_esof_list_fallback():
from nautilus_dolphin.nautilus.esof_size_gate import ESOF_STALE_FALLBACK_MULT
assert _sizer().esof_size_mult([0.5]) == ESOF_STALE_FALLBACK_MULT
def test_esof_range_never_below_unfavorable():
sz = _sizer()
for sc in np.linspace(-1.0, 1.0, 500):
assert sz.esof_size_mult(float(sc)) >= 0.30 - 1e-9
def test_esof_range_never_above_one_plus_epsilon():
sz = _sizer()
mx = max(sz.esof_size_mult(float(sc)) for sc in np.linspace(-1.0, 1.0, 1000))
assert mx <= 1.0 + 1e-9
def test_esof_raw_vs_modulation_clamped():
from prod.clean_arch.violet.modulation import VioletSizeModulation
mod = VioletSizeModulation()
sz = _sizer()
for sc in np.linspace(-1.0, 1.0, 300):
raw = sz.esof_size_mult(float(sc))
clamped = mod.mult_for(float(sc))
assert clamped == max(0.0, min(1.0, raw))
# ── E. market_ob_mult: threshold off-by-ones ───────────────────────────────────
def test_ob_at_exactly_008_positive_short():
assert _sizer().market_ob_mult(0.08, 0.80, trade_direction=-1) == 1.0
def test_ob_at_exactly_neg008_short():
assert _sizer().market_ob_mult(-0.08, 0.80, trade_direction=-1) == 1.0
def test_ob_at_exactly_070_agreement():
assert _sizer().market_ob_mult(-0.50, 0.70, trade_direction=-1) == 1.0
def test_ob_069_agreement_no_effect():
assert _sizer().market_ob_mult(-0.50, 0.69, trade_direction=-1) == 1.0
def test_ob_071_agreement_modulates():
assert _sizer().market_ob_mult(-0.50, 0.71, trade_direction=-1) > 1.0
def test_ob_just_above_008_boosts():
assert _sizer().market_ob_mult(-0.081, 0.80, trade_direction=-1) > 1.0
def test_ob_just_below_neg008_haircuts():
assert _sizer().market_ob_mult(0.081, 0.80, trade_direction=-1) < 1.0
def test_ob_boost_exactly_at_cap():
assert _sizer().market_ob_mult(-0.50, 0.80, trade_direction=-1) == 1.20
def test_ob_haircut_exactly_at_floor():
assert _sizer().market_ob_mult(0.50, 1.0, trade_direction=-1) == 0.85
def test_ob_neutral_zone_between_thresholds():
sz = _sizer()
for imb in np.linspace(-0.079, 0.079, 20):
assert sz.market_ob_mult(float(imb), 0.95, trade_direction=-1) == 1.0
def test_ob_short_zero_imbalance():
assert _sizer().market_ob_mult(0.0, 0.90, trade_direction=-1) == 1.0
def test_ob_long_zero_imbalance():
assert _sizer().market_ob_mult(0.0, 0.90, trade_direction=1) == 1.0
def test_ob_long_confirmed_boosts():
assert _sizer().market_ob_mult(0.50, 0.90, trade_direction=1) == pytest.approx(1.20)
def test_ob_long_contradicted_haircuts():
assert _sizer().market_ob_mult(-0.50, 0.90, trade_direction=1) == pytest.approx(0.865)
def test_ob_extreme_capped_and_floored():
sz = _sizer()
assert sz.market_ob_mult(-1.0, 1.0, trade_direction=-1) == 1.20
assert sz.market_ob_mult(1.0, 1.0, trade_direction=-1) == 0.85
def test_ob_long_mirrors_short_exactly():
sz = _sizer()
for imb in np.linspace(-1.0, 1.0, 50):
for agree in (0.5, 0.8, 1.0):
short_v = sz.market_ob_mult(float(imb), agree, trade_direction=-1)
long_v = sz.market_ob_mult(float(-imb), agree, trade_direction=1)
assert short_v == pytest.approx(long_v)
# ── F. dc_lev_mult: status matrix ──────────────────────────────────────────────
def test_dc_all_non_confirm_statuses():
sz = _sizer(dc_leverage_boost=1.5)
for status in ("NONE", "NEUTRAL", "CONTRADICT", "SKIP_CONTRADICT", "OB_SKIP", ""):
assert sz.dc_lev_mult(status) == 1.0
def test_dc_boost_zero():
assert _sizer(dc_leverage_boost=0.0).dc_lev_mult("CONFIRM") == 0.0
def test_dc_boost_large():
assert _sizer(dc_leverage_boost=3.0).dc_lev_mult("CONFIRM") == 3.0
def test_dc_lowercase_confirm_not_matched():
assert _sizer(dc_leverage_boost=1.5).dc_lev_mult("confirm") == 1.0
# ── G. compose: cap/floor/order edge cases ─────────────────────────────────────
def _base_dec(vel_div: float = -0.05) -> SizeDecision:
return _sizer().base_size(capital=69000.0, vel_div=vel_div, trade_direction=-1)
def test_compose_abs_cap_exact_boundary():
sz = _sizer()
base = _base_dec(-0.20)
d = sz.compose(base, dc_lev_mult=1.0, regime_size_mult=1.125,
market_ob_mult=1.0, esof_size_mult=1.0, posture="APEX")
assert d.conviction_leverage == 9.0
def test_compose_raw_equals_clamped_boundary():
sz = _sizer()
base = _base_dec(-0.035)
d = sz.compose(base, dc_lev_mult=1.0, regime_size_mult=1.0,
market_ob_mult=1.0, esof_size_mult=1.0, posture="APEX")
assert d.conviction_leverage == min(base.conviction_leverage, 8.0)
def test_compose_zero_regime_floors_to_min():
sz = _sizer()
base = _base_dec(-0.05)
d = sz.compose(base, dc_lev_mult=1.0, regime_size_mult=0.0,
market_ob_mult=1.0, esof_size_mult=1.0, posture="APEX")
assert d.conviction_leverage == 0.5
def test_compose_zero_all_mults_floors_to_min():
sz = _sizer()
base = _base_dec(-0.05)
d = sz.compose(base, dc_lev_mult=0.0, regime_size_mult=0.0,
market_ob_mult=0.0, esof_size_mult=0.0, posture="APEX")
assert d.conviction_leverage == 0.5
def test_compose_nan_dc_absorbed_by_min_max():
sz = _sizer()
base = _base_dec(-0.05)
d = sz.compose(base, dc_lev_mult=float("nan"), regime_size_mult=1.0,
market_ob_mult=1.0, esof_size_mult=1.0, posture="APEX")
assert math.isfinite(d.conviction_leverage)
assert d.conviction_leverage >= sz.min_leverage
def test_compose_stalker_caps_below_soft():
sz = _sizer()
base = _base_dec(-0.20)
d = sz.compose(base, dc_lev_mult=1.0, regime_size_mult=1.0,
market_ob_mult=1.0, esof_size_mult=1.0, posture="STALKER")
assert d.conviction_leverage == 2.0
def test_compose_stalker_when_raw_below_2():
sz = _sizer()
base = _base_dec(-0.025)
d = sz.compose(base, dc_lev_mult=1.0, regime_size_mult=1.0,
market_ob_mult=1.0, esof_size_mult=1.0, posture="STALKER")
assert d.conviction_leverage < 2.0 + 1e-9
def test_compose_bucket_idx_preserved():
base = _base_dec(-0.10)
d = _sizer().compose(base, dc_lev_mult=1.0, regime_size_mult=1.0,
market_ob_mult=1.0, esof_size_mult=1.0)
assert d.bucket_idx == base.bucket_idx
def test_compose_signal_bucket_preserved():
base = _base_dec(-0.10)
d = _sizer().compose(base, dc_lev_mult=1.0, regime_size_mult=1.0,
market_ob_mult=1.0, esof_size_mult=1.0)
assert d.signal_bucket == base.signal_bucket
def test_compose_strength_score_preserved():
base = _base_dec(-0.10)
d = _sizer().compose(base, dc_lev_mult=1.0, regime_size_mult=1.0,
market_ob_mult=1.0, esof_size_mult=1.0)
assert d.strength_score == base.strength_score
def test_compose_notional_fraction_exact_identity():
sz = _sizer()
base = _base_dec(-0.07)
d = sz.compose(base, dc_lev_mult=1.0, regime_size_mult=1.3,
market_ob_mult=1.1, esof_size_mult=0.9, posture="APEX")
assert d.notional_fraction == d.fraction * d.conviction_leverage
def test_compose_op_order_raw_first_then_clamp():
sz = _sizer()
base = _base_dec(-0.10)
dc, rsm, obm, esm = 1.0, 1.5, 1.0, 0.8
raw = base.conviction_leverage * dc * rsm * obm * esm
clamped = min(8.0 * rsm * obm * esm, 9.0)
expect = max(0.5, min(raw, clamped))
d = sz.compose(base, dc_lev_mult=dc, regime_size_mult=rsm,
market_ob_mult=obm, esof_size_mult=esm, posture="APEX")
assert d.conviction_leverage == expect
def test_compose_extreme_multipliers_abs_holds():
sz = _sizer()
base = _base_dec(-0.05)
d = sz.compose(base, dc_lev_mult=100.0, regime_size_mult=100.0,
market_ob_mult=1.20, esof_size_mult=1.0, posture="APEX")
assert d.conviction_leverage == 9.0
# ── H. size(): end-to-end coverage ─────────────────────────────────────────────
def test_size_all_defaults():
r = _sizer().size(capital=69000.0, vel_div=-0.05)
assert r.decision.conviction_leverage >= 0.5
assert r.breakdown.regime_size_mult == 1.0
assert r.breakdown.market_ob_mult == 1.0
assert r.breakdown.dc_lev_mult == 1.0
def test_size_without_ob_is_ob_one():
r = _sizer().size(capital=1000.0, vel_div=-0.05, esof_score=0.0)
assert r.breakdown.market_ob_mult == 1.0
def test_size_without_esof_is_stale_fallback():
from nautilus_dolphin.nautilus.esof_size_gate import ESOF_STALE_FALLBACK_MULT
r = _sizer().size(capital=1000.0, vel_div=-0.05, esof_score=None)
assert r.breakdown.esof_size_mult == ESOF_STALE_FALLBACK_MULT
def test_size_long_direction():
r = _sizer().size(capital=69000.0, vel_div=0.03, trade_direction=1)
assert r.decision.conviction_leverage >= 0.5
def test_size_all_postures_envelope():
sz = _sizer()
for posture in ("APEX", "STALKER", "RESTORED", "TURTLE", "HIBERNATE"):
r = sz.size(capital=69000.0, vel_div=-0.05, posture=posture)
assert sz.min_leverage - 1e-9 <= r.decision.conviction_leverage <= sz.abs_max_leverage + 1e-9
def test_size_breakdown_contains_all_factors():
r = _sizer().size(capital=69000.0, vel_div=-0.10, boost=1.3, beta=0.8,
mc_scale=0.5, esof_score=0.0, dc_status="CONFIRM",
posture="STALKER")
bd = r.breakdown
assert bd.dc_lev_mult == 1.0
assert bd.regime_size_mult > 0
assert bd.esof_size_mult == 0.8
assert bd.posture == "STALKER"
assert bd.base_max_leverage == 8.0
assert bd.abs_max_leverage == 9.0
assert bd.min_leverage == 0.5
assert math.isfinite(bd.raw_leverage)
assert math.isfinite(bd.clamped_max_leverage)
def test_size_capital_does_not_affect_leverage():
sz = _sizer()
r1 = sz.size(capital=1000.0, vel_div=-0.05)
r2 = sz.size(capital=100000.0, vel_div=-0.05)
assert r1.decision.conviction_leverage == r2.decision.conviction_leverage
def test_size_dc_confirm_flows_through():
sz = _sizer(dc_leverage_boost=1.5)
r = sz.size(capital=69000.0, vel_div=-0.035, dc_status="CONFIRM")
assert r.breakdown.dc_lev_mult == 1.5
# ── I. V-TYPES rejection: boundary poison rejection ────────────────────────────
def test_vtypes_size_decision_rejects_nan_leverage():
with pytest.raises(Exception):
SizeDecision(fraction=0.2, conviction_leverage=float("nan"),
notional_fraction=0.2, bucket_idx=0, strength_score=0.5,
signal_bucket="x")
def test_vtypes_size_decision_rejects_inf_notional():
with pytest.raises(Exception):
SizeDecision(fraction=0.2, conviction_leverage=1.0,
notional_fraction=float("inf"), bucket_idx=0,
strength_score=0.5, signal_bucket="x")
def test_vtypes_size_decision_rejects_neg_fraction():
with pytest.raises(Exception):
SizeDecision(fraction=-0.1, conviction_leverage=1.0,
notional_fraction=0.2, bucket_idx=0, strength_score=0.5,
signal_bucket="x")
def test_vtypes_size_decision_rejects_bad_bucket_high():
with pytest.raises(Exception):
SizeDecision(fraction=0.2, conviction_leverage=1.0,
notional_fraction=0.2, bucket_idx=5, strength_score=0.5,
signal_bucket="x")
def test_vtypes_size_decision_rejects_bad_bucket_neg():
with pytest.raises(Exception):
SizeDecision(fraction=0.2, conviction_leverage=1.0,
notional_fraction=0.2, bucket_idx=-1, strength_score=0.5,
signal_bucket="x")
def test_vtypes_size_decision_rejects_neg_strength():
with pytest.raises(Exception):
SizeDecision(fraction=0.2, conviction_leverage=1.0,
notional_fraction=0.2, bucket_idx=0, strength_score=-1.0,
signal_bucket="x")
def test_vtypes_size_decision_rejects_extra_field():
with pytest.raises(Exception):
SizeDecision(fraction=0.2, conviction_leverage=1.0,
notional_fraction=0.2, bucket_idx=0, strength_score=0.5,
signal_bucket="x", evil="payload")
def test_vtypes_size_decision_rejects_leverage_over_64():
with pytest.raises(Exception):
SizeDecision(fraction=0.2, conviction_leverage=100.0,
notional_fraction=0.2, bucket_idx=0, strength_score=0.5,
signal_bucket="x")
def test_vtypes_size_decision_rejects_leverage_neg():
with pytest.raises(Exception):
SizeDecision(fraction=0.2, conviction_leverage=-1.0,
notional_fraction=0.2, bucket_idx=0, strength_score=0.5,
signal_bucket="x")
def test_vtypes_size_decision_rejects_fraction_over_one():
with pytest.raises(Exception):
SizeDecision(fraction=1.5, conviction_leverage=1.0,
notional_fraction=0.2, bucket_idx=0, strength_score=0.5,
signal_bucket="x")
def test_vtypes_breakdown_rejects_nan_raw():
from prod.clean_arch.violet.sizing import SizingBreakdown
with pytest.raises(Exception):
SizingBreakdown(
base_leverage=1.0, base_fraction=0.2, dc_lev_mult=1.0,
regime_size_mult=1.0, market_ob_mult=1.0, esof_size_mult=1.0,
strength_cubic=0.5, raw_leverage=float("nan"),
clamped_max_leverage=8.0, posture="APEX", min_leverage=0.5,
base_max_leverage=8.0, abs_max_leverage=9.0)
def test_vtypes_breakdown_rejects_neg_base_leverage():
from prod.clean_arch.violet.sizing import SizingBreakdown
with pytest.raises(Exception):
SizingBreakdown(
base_leverage=-1.0, base_fraction=0.2, dc_lev_mult=1.0,
regime_size_mult=1.0, market_ob_mult=1.0, esof_size_mult=1.0,
strength_cubic=0.5, raw_leverage=1.0,
clamped_max_leverage=8.0, posture="APEX", min_leverage=0.5,
base_max_leverage=8.0, abs_max_leverage=9.0)
def test_vtypes_breakdown_rejects_extra_field():
from prod.clean_arch.violet.sizing import SizingBreakdown
with pytest.raises(Exception):
SizingBreakdown(
base_leverage=1.0, base_fraction=0.2, dc_lev_mult=1.0,
regime_size_mult=1.0, market_ob_mult=1.0, esof_size_mult=1.0,
strength_cubic=0.5, raw_leverage=1.0,
clamped_max_leverage=8.0, posture="APEX", min_leverage=0.5,
base_max_leverage=8.0, abs_max_leverage=9.0, extra="bad")
def test_vtypes_breakdown_rejects_inf_dc_mult():
from prod.clean_arch.violet.sizing import SizingBreakdown
with pytest.raises(Exception):
SizingBreakdown(
base_leverage=1.0, base_fraction=0.2, dc_lev_mult=float("inf"),
regime_size_mult=1.0, market_ob_mult=1.0, esof_size_mult=1.0,
strength_cubic=0.5, raw_leverage=1.0,
clamped_max_leverage=8.0, posture="APEX", min_leverage=0.5,
base_max_leverage=8.0, abs_max_leverage=9.0)
def test_vtypes_full_decision_rejects_bad_nested():
bad_decision = {
"fraction": 0.2, "conviction_leverage": float("nan"),
"notional_fraction": 0.2, "bucket_idx": 0,
"strength_score": 0.5, "signal_bucket": "x",
}
bad_breakdown = {
"base_leverage": 1.0, "base_fraction": 0.2, "dc_lev_mult": 1.0,
"regime_size_mult": 1.0, "market_ob_mult": 1.0, "esof_size_mult": 1.0,
"strength_cubic": 0.5, "raw_leverage": 1.0,
"clamped_max_leverage": 8.0, "posture": "APEX", "min_leverage": 0.5,
"base_max_leverage": 8.0, "abs_max_leverage": 9.0,
}
with pytest.raises(Exception):
FullSizeDecision(decision=bad_decision, breakdown=bad_breakdown)
# ── J. beartype / @typed enforcement ───────────────────────────────────────────
def test_typed_strength_rejects_str():
with pytest.raises(Exception):
_sizer().strength_cubic("hello")
def test_typed_strength_rejects_none():
with pytest.raises(Exception):
_sizer().strength_cubic(None)
def test_typed_strength_rejects_list():
with pytest.raises(Exception):
_sizer().strength_cubic([1, 2])
def test_typed_base_size_rejects_str_capital():
with pytest.raises(Exception):
_sizer().base_size(capital="abc", vel_div=-0.1)
def test_typed_base_size_rejects_none_vel_div():
with pytest.raises(Exception):
_sizer().base_size(capital=1000.0, vel_div=None)
def test_typed_regime_rejects_str_boost():
with pytest.raises(Exception):
_sizer().regime_size_mult(-0.1, boost="high", beta=0.8, mc_scale=1.0)
def test_typed_compose_rejects_str_mult():
base = _base_dec(-0.05)
with pytest.raises(Exception):
_sizer().compose(base, dc_lev_mult="x", regime_size_mult=1.0,
market_ob_mult=1.0, esof_size_mult=1.0)
def test_typed_market_ob_rejects_str_imbalance():
with pytest.raises(Exception):
_sizer().market_ob_mult("big", 0.8)
def test_typed_strength_accepts_int_as_float():
assert _sizer().strength_cubic(-0.05) == 1.0
def test_typed_esof_accepts_any_type():
assert _sizer().esof_size_mult(0.0) == 0.8
assert _sizer().esof_size_mult(None) == 0.4
# ── K. Fuzz / chaos / property-based ───────────────────────────────────────────
@given(vel_div=_short_vd, boost=_boost, beta=_beta, mc_scale=_mc,
esof=_esof, imb=_imb, agree=_agree, cap=_cap)
@settings(max_examples=150, deadline=None)
def test_fuzz_leverage_never_negative(vel_div, boost, beta, mc_scale, esof, imb, agree, cap):
r = _sizer().size(capital=cap, vel_div=vel_div, boost=boost, beta=beta,
mc_scale=mc_scale, esof_score=esof,
ob_median_imbalance=imb, ob_agreement_pct=agree)
assert r.decision.conviction_leverage >= 0.0
@given(vel_div=_short_vd, boost=_boost, beta=_beta, mc_scale=_mc,
esof=_esof, imb=_imb, agree=_agree, cap=_cap)
@settings(max_examples=150, deadline=None)
def test_fuzz_notional_fraction_exact_identity(vel_div, boost, beta, mc_scale, esof, imb, agree, cap):
r = _sizer().size(capital=cap, vel_div=vel_div, boost=boost, beta=beta,
mc_scale=mc_scale, esof_score=esof,
ob_median_imbalance=imb, ob_agreement_pct=agree)
d = r.decision
assert d.notional_fraction == pytest.approx(d.fraction * d.conviction_leverage, rel=1e-12, abs=1e-15)
@given(vel_div=_short_vd, boost=_boost, beta=_beta, mc_scale=_mc, esof=_esof,
imb=_imb, agree=_agree)
@settings(max_examples=120, deadline=None)
def test_fuzz_final_leverage_leq_raw(vel_div, boost, beta, mc_scale, esof, imb, agree):
r = _sizer().size(capital=1000.0, vel_div=vel_div, boost=boost, beta=beta,
mc_scale=mc_scale, esof_score=esof,
ob_median_imbalance=imb, ob_agreement_pct=agree)
assert r.decision.conviction_leverage <= max(r.breakdown.raw_leverage, 0.5) + 1e-9
@given(vel_div=_short_vd, boost=_boost, beta=_beta, mc_scale=_mc, esof=_esof,
imb=_imb, agree=_agree)
@settings(max_examples=100, deadline=None)
def test_fuzz_fraction_unchanged_by_compose(vel_div, boost, beta, mc_scale, esof, imb, agree):
sz = _sizer()
base = sz.base_size(capital=1000.0, vel_div=vel_div)
r = sz.size(capital=1000.0, vel_div=vel_div, boost=boost, beta=beta,
mc_scale=mc_scale, esof_score=esof,
ob_median_imbalance=imb, ob_agreement_pct=agree)
assert r.decision.fraction == base.fraction
@given(vel_div=_short_vd, boost=_boost, beta=_beta, mc_scale=_mc)
@settings(max_examples=100, deadline=None)
def test_fuzz_regime_geq_boost_times_mc(vel_div, boost, beta, mc_scale):
sz = _sizer()
rsm = sz.regime_size_mult(vel_div, boost=boost, beta=beta, mc_scale=mc_scale)
assert rsm >= boost * mc_scale - 1e-9
@given(score=st.floats(min_value=-1.0, max_value=1.0, allow_nan=False, allow_infinity=False))
@settings(max_examples=100, deadline=None)
def test_fuzz_esof_range_valid_scores(score):
v = _sizer().esof_size_mult(score)
assert 0.30 - 1e-9 <= v <= 1.0 + 1e-9
@given(imb=_imb, agree=_agree)
@settings(max_examples=100, deadline=None)
def test_fuzz_ob_range(imb, agree):
v = _sizer().market_ob_mult(imb, agree, trade_direction=-1)
assert 0.85 - 1e-9 <= v <= 1.20 + 1e-9
@given(vel_div=_short_vd, boost=_boost, beta=_beta, mc_scale=_mc,
esof=_esof, imb=_imb, agree=_agree)
@settings(max_examples=50, deadline=None)
def test_fuzz_deterministic_same_inputs(vel_div, boost, beta, mc_scale, esof, imb, agree):
sz = _sizer()
kwargs = dict(capital=1000.0, vel_div=vel_div, boost=boost, beta=beta,
mc_scale=mc_scale, esof_score=esof,
ob_median_imbalance=imb, ob_agreement_pct=agree)
r1 = sz.size(**kwargs)
r2 = sz.size(**kwargs)
assert r1.decision.conviction_leverage == r2.decision.conviction_leverage
@given(imb=_imb, agree=st.floats(min_value=0.71, max_value=1.0, allow_nan=False))
@settings(max_examples=80, deadline=None)
def test_fuzz_long_ob_mirrors_short(imb, agree):
sz = _sizer()
short_val = sz.market_ob_mult(imb, agree, trade_direction=-1)
long_val = sz.market_ob_mult(-imb, agree, trade_direction=1)
assert short_val == pytest.approx(long_val)
@given(vd=st.floats(min_value=-0.50, max_value=-0.021, allow_nan=False))
@settings(max_examples=50, deadline=None)
def test_fuzz_strength_monotonic_short(vd):
sz = _sizer()
assert sz.strength_cubic(vd - 0.001) >= sz.strength_cubic(vd) - 1e-12
@given(vd=st.floats(min_value=0.011, max_value=0.04, allow_nan=False))
@settings(max_examples=50, deadline=None)
def test_fuzz_strength_monotonic_long(vd):
sz = _sizer()
assert sz.strength_cubic(vd + 0.001, trade_direction=1) >= sz.strength_cubic(vd, trade_direction=1) - 1e-12
@given(vel_div=_short_vd, boost=_boost, beta=_beta, mc_scale=_mc,
esof=_esof, imb=_imb, agree=_agree)
@settings(max_examples=80, deadline=None)
def test_fuzz_stalker_never_exceeds_2(vel_div, boost, beta, mc_scale, esof, imb, agree):
r = _sizer().size(capital=1000.0, vel_div=vel_div, boost=boost, beta=beta,
mc_scale=mc_scale, esof_score=esof,
ob_median_imbalance=imb, ob_agreement_pct=agree, posture="STALKER")
assert r.decision.conviction_leverage <= 2.0 + 1e-9
@given(vel_div=_short_vd, boost=_boost, beta=_beta, mc_scale=_mc,
esof=_esof, imb=_imb, agree=_agree)
@settings(max_examples=80, deadline=None)
def test_fuzz_abs_cap_never_exceeded(vel_div, boost, beta, mc_scale, esof, imb, agree):
r = _sizer().size(capital=1000.0, vel_div=vel_div, boost=boost, beta=beta,
mc_scale=mc_scale, esof_score=esof,
ob_median_imbalance=imb, ob_agreement_pct=agree, posture="APEX")
assert r.decision.conviction_leverage <= 9.0 + 1e-9
@given(vel_div=_short_vd, boost=_boost, beta=_beta, mc_scale=_mc,
esof=_esof, imb=_imb, agree=_agree)
@settings(max_examples=80, deadline=None)
def test_fuzz_min_floor_never_breached(vel_div, boost, beta, mc_scale, esof, imb, agree):
r = _sizer().size(capital=1000.0, vel_div=vel_div, boost=boost, beta=beta,
mc_scale=mc_scale, esof_score=esof,
ob_median_imbalance=imb, ob_agreement_pct=agree)
assert r.decision.conviction_leverage >= 0.5 - 1e-9
def test_chaos_extreme_multipliers_no_crash():
sz = _sizer()
base = sz.base_size(capital=1000.0, vel_div=-0.05)
d = sz.compose(base, dc_lev_mult=100.0, regime_size_mult=100.0,
market_ob_mult=1.20, esof_size_mult=1.0, posture="APEX")
assert d.conviction_leverage == 9.0
def test_chaos_all_esof_zones():
sz = _sizer()
for sc in [0.5, 0.06, 0.04, 0.0, -0.04, -0.06, -0.20, -0.24, -0.26, -0.50]:
v = sz.esof_size_mult(sc)
assert math.isfinite(v)
assert 0.3 - 1e-9 <= v <= 1.0 + 1e-9
def test_chaos_alternating_postures():
sz = _sizer()
for _ in range(100):
for posture in ("APEX", "STALKER", "RESTORED"):
r = sz.size(capital=69000.0, vel_div=-0.05, posture=posture)
assert math.isfinite(r.decision.conviction_leverage)
def test_chaos_tiny_capital():
r = _sizer().size(capital=0.01, vel_div=-0.10)
assert math.isfinite(r.decision.conviction_leverage)
def test_chaos_huge_capital():
r = _sizer().size(capital=1e12, vel_div=-0.10)
assert math.isfinite(r.decision.conviction_leverage)
def test_chaos_all_dc_statuses():
sz = _sizer(dc_leverage_boost=1.5)
for status in ("CONFIRM", "NONE", "NEUTRAL", "CONTRADICT", "SKIP_CONTRADICT",
"OB_SKIP", "", "UNKNOWN"):
r = sz.size(capital=69000.0, vel_div=-0.05, dc_status=status)
assert math.isfinite(r.decision.conviction_leverage)
def test_chaos_rapid_alternating_size_calls():
sz = _sizer()
results = []
for i in range(200):
vd = -0.02 - 0.001 * (i % 100)
r = sz.size(capital=1000.0, vel_div=vd, posture="APEX" if i % 2 else "STALKER")
results.append(r.decision.conviction_leverage)
assert all(math.isfinite(x) for x in results)
assert len(set(results)) > 1
# ── L. State isolation / determinism / concurrency ─────────────────────────────
def test_determinism_1000_repeated_identical():
sz = _sizer()
vals = set()
for _ in range(1000):
r = sz.size(capital=69000.0, vel_div=-0.07, boost=1.3, beta=0.8,
mc_scale=1.0, esof_score=0.0, posture="APEX")
vals.add(r.decision.conviction_leverage)
assert len(vals) == 1
def test_two_sizers_independent():
sa = _sizer(dc_leverage_boost=1.5)
sb = _sizer(dc_leverage_boost=2.0)
assert sa.dc_lev_mult("CONFIRM") == 1.5
assert sb.dc_lev_mult("CONFIRM") == 2.0
assert sa.dc_lev_mult("CONFIRM") == 1.5
def test_factor_producers_are_pure():
sz = _sizer()
assert sz.strength_cubic(-0.035) == sz.strength_cubic(-0.035)
assert sz.regime_size_mult(-0.035, boost=1.3, beta=0.8, mc_scale=1.0) == \
sz.regime_size_mult(-0.035, boost=1.3, beta=0.8, mc_scale=1.0)
def test_thread_safe_concurrent_identical():
sz = _sizer()
results = []
errors = []
barrier = threading.Barrier(8)
def worker():
barrier.wait()
try:
for _ in range(200):
r = sz.size(capital=69000.0, vel_div=-0.05, boost=1.3,
beta=0.8, mc_scale=1.0, esof_score=0.0, posture="APEX")
results.append(r.decision.conviction_leverage)
except Exception as e:
errors.append(e)
threads = [threading.Thread(target=worker) for _ in range(8)]
[t.start() for t in threads]
[t.join() for t in threads]
assert len(errors) == 0
assert len(results) == 1600
assert len(set(results)) == 1
def test_thread_safe_concurrent_different_inputs():
sz = _sizer()
errors = []
all_results = []
def worker(seed):
rng = np.random.default_rng(seed)
try:
for _ in range(100):
vd = float(rng.uniform(-0.5, -0.021))
r = sz.size(capital=1000.0, vel_div=vd, posture="APEX")
all_results.append(r.decision.conviction_leverage)
except Exception as e:
errors.append(e)
threads = [threading.Thread(target=worker, args=(i,)) for i in range(8)]
[t.start() for t in threads]
[t.join() for t in threads]
assert len(errors) == 0
assert len(all_results) == 800
assert all(math.isfinite(x) for x in all_results)
def test_compose_no_side_effects_on_base():
sz = _sizer()
base = sz.base_size(capital=1000.0, vel_div=-0.10)
original_lev = base.conviction_leverage
original_frac = base.fraction
for _ in range(100):
sz.compose(base, dc_lev_mult=1.5, regime_size_mult=1.3,
market_ob_mult=1.1, esof_size_mult=0.8, posture="APEX")
assert base.conviction_leverage == original_lev
assert base.fraction == original_frac
def test_base_size_caches_nothing_between_calls():
sz = _sizer()
d1 = sz.base_size(capital=1000.0, vel_div=-0.03)
d2 = sz.base_size(capital=1000.0, vel_div=-0.10)
assert d1.conviction_leverage != d2.conviction_leverage
def test_size_call_does_not_mutate_sizer_state():
sz = _sizer()
orig_boost = sz.dc_leverage_boost
orig_base_max = sz.base_max_leverage
sz.size(capital=69000.0, vel_div=-0.10, boost=1.5, beta=0.8,
esof_score=0.0, posture="STALKER")
assert sz.dc_leverage_boost == orig_boost
assert sz.base_max_leverage == orig_base_max
def test_orchestrator_position_isolation():
"""The orchestrator accumulates position/trade state; verify VIOLET does not."""
eng = _orch()
sz = _sizer()
eng.regime_direction = -1
eng._day_base_boost = 1.0; eng._day_beta = 0.0
eng._day_mc_scale = 1.0; eng._day_posture = "APEX"
eng.set_esof_advisory_score(0.0)
eng._update_regime_size_mult(-0.05)
eng.ob_engine = None
for _ in range(5):
eng.position = None
eng._try_entry(bar_idx=1, vel_div=-0.05, prices={"BTCUSDT": 100.0}, price_histories=None)
for _ in range(5):
r = sz.size(capital=69000.0, vel_div=-0.05)
assert r.decision.conviction_leverage == sz.size(
capital=69000.0, vel_div=-0.05).decision.conviction_leverage
# ── M. Additional @gate stress tests ───────────────────────────────────────────
@pytest.mark.gate
def test_gate_mc_long_direction_bit_identity():
"""MC bit-identity for LONG direction (strength_cubic long + OB sign flip)."""
N = 200_000
rng = np.random.default_rng(20260616)
vel_div = rng.uniform(0.011, 0.50, N)
boost = rng.uniform(1.0, 2.5, N)
beta = rng.choice([0.2, 0.8], N)
mc_scale = rng.choice([0.5, 1.0], N)
esof = rng.uniform(-1.0, 1.0, N)
imb = rng.uniform(-1.0, 1.0, N)
agree = rng.uniform(0.0, 1.0, N)
posture = rng.choice(["APEX", "STALKER"], N)
capital = rng.uniform(1e4, 1e6, N)
sz = _sizer()
eng = _orch()
mob = _MockOB()
mismatches = 0
for i in range(N):
vd = float(vel_div[i]); bo = float(boost[i]); be = float(beta[i])
ms = float(mc_scale[i]); es = float(esof[i]); im = float(imb[i])
ag = float(agree[i]); po = str(posture[i]); cp = float(capital[i])
eng._day_base_boost = bo; eng._day_beta = be; eng._day_mc_scale = ms
eng._day_posture = po
eng.regime_direction = 1 # LONG: orchestrator _strength_cubic uses this
eng.set_esof_advisory_score(es)
eng._update_regime_size_mult(vd)
sr = eng.bet_sizer.calculate_size(
capital=cp, vel_div=vd, vel_div_trend=0.0, trade_direction=1)
obm = 1.0
mob.set(im, ag)
om = mob.get_market(1.0, ["x"])
ei = om.median_imbalance
if ei > 0.08 and om.agreement_pct > 0.70:
obm = 1.0 + min(0.20, ei * om.agreement_pct * 0.5)
elif ei < -0.08 and om.agreement_pct > 0.70:
obm = max(0.85, 1.0 - abs(ei) * om.agreement_pct * 0.3)
clamped = min(
eng.base_max_leverage * eng.regime_size_mult * obm * eng._esof_size_mult,
eng.abs_max_leverage)
raw = sr["leverage"] * 1.0 * eng.regime_size_mult * obm * eng._esof_size_mult
if po == "STALKER":
clamped = min(clamped, 2.0)
blue = max(eng.bet_sizer.min_leverage, min(raw, clamped))
v = sz.size(capital=cp, vel_div=vd, boost=bo, beta=be, mc_scale=ms,
esof_score=es, ob_median_imbalance=im, ob_agreement_pct=ag,
posture=po, trade_direction=1)
if blue != v.decision.conviction_leverage:
mismatches += 1
if mismatches <= 3:
print(f" MISMATCH i={i} vd={vd} blue={blue!r} violet={v.decision.conviction_leverage!r}")
assert mismatches == 0, f"{mismatches}/{N} LONG-direction mismatches"
@pytest.mark.gate
def test_gate_mc_extreme_multipliers():
"""MC bit-identity with extreme multiplier combos (cap@9, floor@min, STALKER@2)."""
N = 200_000
rng = np.random.default_rng(999)
vel_div = rng.choice([-0.50, -0.30, -0.05, -0.021], N)
boost = rng.uniform(1.0, 5.0, N)
beta = rng.choice([0.0, 0.2, 0.8, 1.0], N)
mc_scale = rng.choice([0.0, 0.5, 1.0], N)
esof = rng.choice([-1.0, -0.5, -0.25, 0.0, 0.5, 1.0], N)
imb = rng.choice([-1.0, -0.5, 0.0, 0.5, 1.0], N)
agree = rng.choice([0.0, 0.5, 0.69, 0.71, 1.0], N)
posture = rng.choice(["APEX", "STALKER", "RESTORED"], N)
sz = _sizer()
eng = _orch()
mob = _MockOB()
mismatches = 0
for i in range(N):
vd = float(vel_div[i]); bo = float(boost[i]); be = float(beta[i])
ms = float(mc_scale[i]); es = float(esof[i]); im = float(imb[i])
ag = float(agree[i]); po = str(posture[i])
blue = _blue_ref_leverage(eng, mob, sz, vd, bo, be, ms, es, im, ag, po, 1000.0)
v = sz.size(capital=1000.0, vel_div=vd, boost=bo, beta=be, mc_scale=ms,
esof_score=es, ob_median_imbalance=im, ob_agreement_pct=ag, posture=po)
if blue != v.decision.conviction_leverage:
mismatches += 1
if mismatches <= 3:
print(f" MISMATCH i={i} vd={vd} boost={bo} beta={be} mc={ms} "
f"esof={es} imb={im} agree={ag} post={po}")
print(f" blue={blue!r} violet={v.decision.conviction_leverage!r}")
assert mismatches == 0, f"{mismatches}/{N} extreme-multiplier mismatches"