feat(adversarial): flat_too_long_threshold parametrico (CLI ablation)

Estende AdversarialAgent con flat_too_long_threshold (default 0.95)
configurabile, simmetrico a fees_eat_alpha_threshold. Propagato a
RunConfig.flat_too_long_threshold e flag CLI --flat-too-long-threshold.

Motivazione: pop30-combo ha registrato 75 finding flat_too_long HIGH
(secondo killer dopo fees_eat_alpha 87). Rilassare la soglia 0.95→0.98
ammette strategie più passive ma marginalmente attive — analogo
all'ablation fees già verificata (+23% stabile).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-12 13:45:38 +02:00
parent 597815a106
commit bf70acc322
3 changed files with 16 additions and 2 deletions
+7 -2
View File
@@ -63,9 +63,11 @@ class AdversarialAgent:
self,
fees_bp: float = 5.0,
fees_eat_alpha_threshold: float = 0.5,
flat_too_long_threshold: float = 0.95,
) -> None:
self._engine = BacktestEngine(fees_bp=fees_bp)
self._fees_eat_alpha_threshold = fees_eat_alpha_threshold
self._flat_too_long_threshold = flat_too_long_threshold
def review(self, strategy: Strategy, ohlcv: pd.DataFrame) -> AdversarialReport:
signal_fn = compile_strategy(strategy)
@@ -133,12 +135,15 @@ class AdversarialAgent:
n_active = int(((signals == Side.LONG) | (signals == Side.SHORT)).sum())
n_flat_or_nan = n_bars - n_active
flat_ratio = n_flat_or_nan / n_bars if n_bars > 0 else 1.0
if flat_ratio > 0.95:
if flat_ratio > self._flat_too_long_threshold:
report.findings.append(
Finding(
name="flat_too_long",
severity=Severity.HIGH,
detail=f"Signal flat for {flat_ratio * 100:.1f}% of bars (>95% threshold)",
detail=(
f"Signal flat for {flat_ratio * 100:.1f}% of bars "
f"(>{self._flat_too_long_threshold * 100:.0f}% threshold)"
),
)
)