feat(ga): fitness v0 (DSR - dd_penalty * max_dd, kill on adversarial high)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 20:11:13 +02:00
parent 3fbd5eba5e
commit 71cfcf786f
3 changed files with 89 additions and 0 deletions
View File
+44
View File
@@ -0,0 +1,44 @@
"""Fitness function v0 della Phase 1.
Combina :class:`FalsificationReport` (metriche di robustezza) e
:class:`AdversarialReport` (findings euristici) in uno scalare ``>= 0`` che il
GA usa per selezione e ranking.
Logica deliberatamente coarse: DSR penalizzato dal max drawdown, con due
kill-switch hard (no-trade, finding HIGH adversarial) che azzerano la fitness.
La penalita' lineare sul drawdown e' un compromesso volutamente semplice;
versioni successive potranno usare Calmar o utility convessa.
"""
from __future__ import annotations
from ..agents.adversarial import AdversarialReport, Severity
from ..agents.falsification import FalsificationReport
def compute_fitness(
falsification: FalsificationReport,
adversarial: AdversarialReport,
drawdown_penalty: float = 0.5,
) -> float:
"""Calcola la fitness scalare di una strategia.
Args:
falsification: report con DSR, max_drawdown, n_trades.
adversarial: report con eventuali findings euristici.
drawdown_penalty: peso lineare sul max drawdown (default 0.5).
Returns:
Fitness ``>= 0``. Zero indica strategia da scartare.
Logica:
1. ``n_trades == 0`` → 0 (nessuna evidenza, sega subito).
2. Almeno un finding ``HIGH`` adversarial → 0 (kill).
3. Altrimenti: ``dsr - drawdown_penalty * max_drawdown``, clamped a 0.
"""
if falsification.n_trades == 0:
return 0.0
if any(f.severity == Severity.HIGH for f in adversarial.findings):
return 0.0
raw = falsification.dsr - drawdown_penalty * falsification.max_drawdown
return max(0.0, float(raw))