population: characterization tests pinning live _population_reject (pre-extraction)
11 table-driven cases pin the CURRENT behaviour of the live population gate before plan 004 extracts it to strategy/population.py: in-band pass, below-gap, dead band, squeeze pass/fail, both price-band sides, volume floor, missing-data fail-open, the gap-is-a-FRACTION unit pin, and the gap-gate-disabled nesting. These must stay green byte-for-byte across the extraction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
23b3d01a00
commit
256481910f
1 file changed
+89
@@ -0,0 +1,89 @@
|
|||||||
|
"""Characterization tests pinning the CURRENT behaviour of the live population
|
||||||
|
gate (``TradingExecutionService._population_reject``) BEFORE it is extracted to
|
||||||
|
``strategy/population.py`` (plan 004).
|
||||||
|
|
||||||
|
CONTRACT: ``gap_pct`` is a FRACTION (0.12 == 12%). These tests must stay green
|
||||||
|
byte-for-byte across the extraction — a change in any outcome means the move
|
||||||
|
altered live behaviour, which the plan forbids (it MOVES code, it does not
|
||||||
|
retune).
|
||||||
|
"""
|
||||||
|
|
||||||
|
from trading_execution import ExecutionSettings, TradingExecutionService
|
||||||
|
|
||||||
|
# production-shaped settings (deploy/docker/truenas-compose.yml env block)
|
||||||
|
PROD = dict(
|
||||||
|
min_entry_gap_pct=0.10,
|
||||||
|
min_day_volume=300_000,
|
||||||
|
price_band_min=2.0,
|
||||||
|
price_band_max=20.0,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _gate(**overrides):
|
||||||
|
"""Return ``_population_reject`` bound to production-shaped settings.
|
||||||
|
|
||||||
|
Built the way the existing execution tests do it (``__new__`` + set
|
||||||
|
``.settings``) so nothing else in the service needs constructing.
|
||||||
|
"""
|
||||||
|
svc = TradingExecutionService.__new__(TradingExecutionService)
|
||||||
|
svc.settings = ExecutionSettings(**{**PROD, **overrides})
|
||||||
|
|
||||||
|
def call(gap_pct=0.12, cum_volume=1_000_000, price=10.0, rvol=None):
|
||||||
|
return svc._population_reject(gap_pct, cum_volume, price=price, rvol=rvol)
|
||||||
|
|
||||||
|
return call
|
||||||
|
|
||||||
|
|
||||||
|
def test_in_band_passes():
|
||||||
|
# $2-20, 12% open gap, healthy volume => tradeable
|
||||||
|
assert _gate()(gap_pct=0.12, price=10.0, cum_volume=1_000_000) is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_below_gap_rejects():
|
||||||
|
assert _gate()(gap_pct=0.05) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_dead_band_rejects():
|
||||||
|
assert _gate()(gap_pct=0.40) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_squeeze_exception_passes():
|
||||||
|
# >=150% gap re-admitted ONLY with a verified squeeze (rvol >= 5)
|
||||||
|
assert _gate()(gap_pct=1.60, rvol=6.0) is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_squeeze_rvol_fail_rejects():
|
||||||
|
assert _gate()(gap_pct=1.60, rvol=3.0) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_price_band_low_rejects():
|
||||||
|
assert _gate()(price=1.50) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_price_band_high_rejects():
|
||||||
|
assert _gate()(price=21.5) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_volume_floor_rejects():
|
||||||
|
assert _gate()(cum_volume=100_000) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_missing_data_fail_open():
|
||||||
|
# None gap / None volume / None price => never blocks
|
||||||
|
assert _gate()(gap_pct=None, cum_volume=None, price=None) is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_gap_is_a_fraction_not_percent():
|
||||||
|
# 0.40 (== 40%) lands in the 35-150% dead band. A caller that wrongly passed
|
||||||
|
# 40.0 (percent) would trip the >=150% squeeze branch instead — a DIFFERENT
|
||||||
|
# reason. The distinct reason strings pin the fraction contract.
|
||||||
|
assert "dead band" in _gate()(gap_pct=0.40)
|
||||||
|
assert "squeeze" in _gate()(gap_pct=40.0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_gap_gate_disabled_when_min_zero():
|
||||||
|
# The whole gap logic is nested under ``min_entry_gap_pct > 0``.
|
||||||
|
g = _gate(min_entry_gap_pct=0.0)
|
||||||
|
assert g(gap_pct=0.05) is None # below-floor not checked
|
||||||
|
assert g(gap_pct=0.40) is None # dead band not checked
|
||||||
|
assert g(gap_pct=1.60, rvol=1.0) is None # squeeze not checked
|
||||||
Reference in new issue
Block a user