Fix post-cluster neutral strength ablation

This commit is contained in:
2026-07-12 23:51:28 +02:00
parent 8df76d3288
commit b891122936
4 changed files with 64 additions and 1 deletions
+24
View File
@@ -156,6 +156,28 @@ def _sr_research_variant() -> str:
return value return value
def _apply_zone_strength_variant(zone_levels: list[Any], sr_variant: str) -> list[Any]:
"""Apply post-cluster research controls without changing zone geometry."""
if sr_variant == "legacy_geometry_neutral":
# Neutrality must be enforced after the shared zone cluster: its legacy
# sum mode can otherwise turn two 50-strength constituents back into a
# 100-strength target and silently invalidate the ablation.
for level in zone_levels:
level.strength = 50
return zone_levels
def _apply_zone_strength_variant(zone_levels: list[Any], sr_variant: str) -> list[Any]:
"""Apply post-cluster research controls without changing zone geometry."""
if sr_variant == "legacy_geometry_neutral":
# Neutrality must be enforced after the shared zone cluster: its legacy
# sum mode can otherwise turn two 50-strength constituents back into a
# 100-strength target and silently invalidate the ablation.
for level in zone_levels:
level.strength = 50
return zone_levels
def _backtest_entry_bounds() -> tuple[date | None, date | None]: def _backtest_entry_bounds() -> tuple[date | None, date | None]:
"""Optional research-only entry bounds used to protect validation data.""" """Optional research-only entry bounds used to protect validation data."""
parsed: list[date | None] = [] parsed: list[date | None] = []
@@ -328,6 +350,8 @@ def _window_setups(
entry, entry,
strength_mode=zone_strength_mode, strength_mode=zone_strength_mode,
) )
zone_levels = _apply_zone_strength_variant(zone_levels, sr_variant)
zone_levels = _apply_zone_strength_variant(zone_levels, sr_variant)
targets = target_generator.generate_targets(direction, entry, stop, zone_levels, atr) targets = target_generator.generate_targets(direction, entry, stop, zone_levels, atr)
if not targets: if not targets:
fallback_k = _atr_target_fallback_k() fallback_k = _atr_target_fallback_k()
+23
View File
@@ -498,6 +498,29 @@ Run on macOS:
Do not validate any traffic arm yet. First establish whether geometry, pivots, or Do not validate any traffic arm yet. First establish whether geometry, pivots, or
the range-occupancy grid reproduces production on pre-2024 training data. the range-occupancy grid reproduces production on pre-2024 training data.
Initial result:
| arm | Sharpe | CAGR | MaxDD | net avg R | ex-top-5% |
|---|---:|---:|---:|---:|---:|
| production control | 1.28 | 28.8% | 21.4% | 0.230 | 0.066 |
| pivots only | 1.38 | 32.9% | 25.2% | 0.236 | 0.076 |
| traffic grid only | **1.72** | **41.8%** | **16.8%** | **0.271** | **0.136** |
The traffic grid is the first research arm to beat control simultaneously on
Sharpe, CAGR, drawdown, and robust expectancy. It retains 264 production setups,
adds 240 positive-expectancy setups, and removes 412 weaker setups. This supports
the hypothesis that the useful legacy feature is the volume-weighted range-
occupancy grid, not pivots or visually meaningful S/R.
The first geometry-neutral result is not interpretable: neutral strength was set
before the shared zone cluster, which summed multiple 50-strength constituents
back to 100. Neutrality is now enforced after clustering. Rerun only that arm:
```bash
.venv/bin/python scripts/run_sr_v2_matrix.py traffic \
--only-arm legacy_geometry_neutral --workers 14
```
**Next runs, if picked back up:** **Next runs, if picked back up:**
- A **per-name target model** for clear-air setups instead of a constant k×ATR. This - A **per-name target model** for clear-air setups instead of a constant k×ATR. This
+8 -1
View File
@@ -50,6 +50,12 @@ def _args() -> argparse.Namespace:
help="Isolate legacy geometry, pivots, and price-traffic grid on training data.", help="Isolate legacy geometry, pivots, and price-traffic grid on training data.",
) )
_add_common(traffic) _add_common(traffic)
traffic.add_argument(
"--only-arm",
choices=TRAFFIC_ARMS,
default=None,
help="Rerun one hidden-feature arm without repeating the full matrix.",
)
validate = commands.add_parser( validate = commands.add_parser(
"validate", "validate",
help="Run production control and one locked arm from 2024-07-01.", help="Run production control and one locked arm from 2024-07-01.",
@@ -135,7 +141,8 @@ def main() -> None:
if args.command == "train": if args.command == "train":
_train(args, TRAINING_ARMS, "backtest-sr-v2-train") _train(args, TRAINING_ARMS, "backtest-sr-v2-train")
elif args.command == "traffic": elif args.command == "traffic":
_train(args, TRAFFIC_ARMS, "backtest-sr-traffic-train") arms = (args.only_arm,) if args.only_arm else TRAFFIC_ARMS
_train(args, arms, "backtest-sr-traffic-train")
else: else:
_validate(args) _validate(args)
+9
View File
@@ -766,6 +766,15 @@ def test_sr_research_variant_is_explicit_and_validated(monkeypatch):
bt._sr_research_variant() bt._sr_research_variant()
def test_geometry_neutral_strength_is_enforced_after_zone_clustering():
levels = [
SimpleNamespace(strength=100),
SimpleNamespace(strength=75),
]
result = bt._apply_zone_strength_variant(levels, "legacy_geometry_neutral")
assert [level.strength for level in result] == [50, 50]
def test_backtest_entry_bounds_validate_dates(monkeypatch): def test_backtest_entry_bounds_validate_dates(monkeypatch):
monkeypatch.setenv("BACKTEST_ENTRY_START", "2024-07-01") monkeypatch.setenv("BACKTEST_ENTRY_START", "2024-07-01")
monkeypatch.setenv("BACKTEST_ENTRY_END", "2024-12-31") monkeypatch.setenv("BACKTEST_ENTRY_END", "2024-12-31")