population: extract strategy/population.py; live gate delegates to it

The tradeable population is now defined ONCE. trading_execution._population_reject
becomes a thin wrapper building a PopulationConfig from its settings and calling
strategy.population.population_reject — logic moved verbatim (dead-band 0.35/1.50
and squeeze rvol 5.0 are module CONSTANTS, gap floor / price band / volume floor
from config). Behaviour byte-identical: the pre-extraction characterization suite
stays green through the new public seam.

from_env mirrors ExecutionSettings.from_env (same 4 keys + the [0,1] _qfloat clamp)
so a live-shaped shell reconstructs the identical gate. gap_pct FRACTION contract
and the as_of open-knowable contract are documented for offline consumers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
momentum devandClaude Fable 5 committed 2026-07-13 22:36:59 -04:00
1 parent 256481910f
commit 66e81a48f3
3 files changed
+190 -31

No files matched your search

@@ -0,0 +1,62 @@
"""Module-level tests for strategy/population.py — the shared population gate.
Complements tests/unit/test_population_gate.py (which pins the LIVE seam through
the service). Here we test the module directly: from_env key parity with
production, the as_of contract docstring, and fail-open semantics.
"""
import inspect
from strategy.population import PopulationConfig, population_reject
def test_from_env_defaults_match_production_keys():
cfg = PopulationConfig.from_env(env={
"TRADING_PRICE_MIN": "2.0",
"TRADING_PRICE_MAX": "20.0",
"TRADING_MIN_ENTRY_GAP_PCT": "0.10",
"TRADING_MIN_DAY_VOLUME": "300000",
})
assert cfg.price_min == 2.0
assert cfg.price_max == 20.0
assert cfg.min_entry_gap_pct == 0.10
assert cfg.min_day_volume == 300_000
# constants are NOT env-driven
assert cfg.gap_dead_band_lo == 0.35
assert cfg.gap_dead_band_hi == 1.50
assert cfg.squeeze_rvol_min == 5.0
def test_from_env_bare_shell_disables_gap_gate():
# No production env => min_entry_gap_pct clamps to 0.0 (gap gate off), the
# exact hazard the plan warns offline consumers about.
cfg = PopulationConfig.from_env(env={})
assert cfg.min_entry_gap_pct == 0.0
assert population_reject(cfg, gap_pct=0.05, price=10.0, volume=None, rvol=None) is None
def test_from_env_clamps_gap_floor_to_unit_interval():
# mirrors trading_execution._qfloat: percent-typed 40 must NOT survive as 40.
assert PopulationConfig.from_env(env={"TRADING_MIN_ENTRY_GAP_PCT": "40"}).min_entry_gap_pct == 1.0
assert PopulationConfig.from_env(env={"TRADING_MIN_ENTRY_GAP_PCT": "junk"}).min_entry_gap_pct == 0.0
def test_as_of_contract_documented():
# day-end rejection is by-convention (review-enforced), so the contract MUST
# be spelled out in the signature + docstring.
assert "as_of" in inspect.signature(population_reject).parameters
doc = population_reject.__doc__ or ""
assert "FRACTION" in doc and "forbidden" in doc.lower()
def test_fail_open_on_all_missing():
cfg = PopulationConfig(min_entry_gap_pct=0.10, min_day_volume=300_000)
assert population_reject(cfg, gap_pct=None, price=None, volume=None, rvol=None) is None
def test_offline_consumer_must_pass_prod_thresholds():
# bare config admits everything; explicit prod thresholds gate correctly.
bare = PopulationConfig()
assert population_reject(bare, gap_pct=0.02, price=3.0, volume=1, rvol=None) is None
prod = PopulationConfig(min_entry_gap_pct=0.10, min_day_volume=300_000)
assert population_reject(prod, gap_pct=0.02, price=3.0, volume=1, rvol=None) is not None