Compare commits
2 Commits
3fcad79f8d
...
67ae6ff74e
| Author | SHA1 | Date | |
|---|---|---|---|
| 67ae6ff74e | |||
| 1a1dfb7a73 |
@@ -81,6 +81,21 @@ def parse_args() -> argparse.Namespace:
|
||||
default=5,
|
||||
help="Walk-forward: quanti top genomi rivalutare OOS (default 5)",
|
||||
)
|
||||
p.add_argument(
|
||||
"--eval-oos-during-loop",
|
||||
action="store_true",
|
||||
help=(
|
||||
"Multi-objective: eval ogni genome anche su test_ohlcv durante "
|
||||
"il loop e usa combined = alpha*IS + (1-alpha)*OOS per selection. "
|
||||
"Richiede --wfa-train-split. 2x costo backtest engine."
|
||||
),
|
||||
)
|
||||
p.add_argument(
|
||||
"--fitness-combined-alpha",
|
||||
type=float,
|
||||
default=0.5,
|
||||
help="Multi-objective: peso IS (1-alpha = OOS). 1.0=solo IS, 0.5=bilanciato, 0.0=solo OOS",
|
||||
)
|
||||
return p.parse_args()
|
||||
|
||||
|
||||
@@ -144,6 +159,8 @@ def main() -> None:
|
||||
fitness_adversarial_soft_penalty=args.fitness_soft_penalty,
|
||||
wfa_train_split=args.wfa_train_split,
|
||||
wfa_top_k=args.wfa_top_k,
|
||||
eval_oos_during_loop=args.eval_oos_during_loop,
|
||||
fitness_combined_alpha=args.fitness_combined_alpha,
|
||||
)
|
||||
|
||||
run_id = run_phase1(cfg, ohlcv=ohlcv, llm=llm)
|
||||
|
||||
@@ -105,6 +105,25 @@ Esempi di gating temporale:
|
||||
Leaf - letterale numerico:
|
||||
{{"kind": "literal", "value": 70.0}}
|
||||
|
||||
PATTERN GUIDANCE (oltre agli indicatori, considera forma delle curve e ripetibilità):
|
||||
|
||||
Forme di curva:
|
||||
- Trend ascendente: SMA(short) > SMA(long) E close > SMA(short)
|
||||
- Trend discendente: SMA(short) < SMA(long) E close < SMA(short)
|
||||
- Compressione di volatilità (pre-breakout): ATR(N) < soglia bassa
|
||||
- Espansione di volatilità: ATR(N) > ATR(N*2) (vol corta > vol lunga)
|
||||
- Mean reversion strutturale: |close - SMA(long)| eccessivo → reversal atteso
|
||||
|
||||
Ripetibilità dell'andamento:
|
||||
- Eventi crossover/crossunder ricorrenti (golden/death cross, RSI cross zone)
|
||||
- Pattern intra-day: usa 'hour' per sfruttare orari di forte volatilità ricorrente
|
||||
- Pattern settimanali: usa 'dow' o 'is_weekend' per cicli mercato
|
||||
- Doppio top approx: RSI > 70 + crossunder RSI 70 (1° picco), poi entro N bar
|
||||
nuovo crossover RSI 70 a livello close simile → entry short
|
||||
- Range breakout: close > SMA(N) con SMA(short) > SMA(long) (compressione + spinta)
|
||||
|
||||
Cerca pattern che si REPLICANO nei dati storici, non singoli eventi rari.
|
||||
|
||||
VINCOLI
|
||||
- Gli indicator NON sono annidabili: 'params' accetta solo numeri, mai altri nodi.
|
||||
- Le regole sono valutate in ordine; la prima che matcha vince per ogni timestamp.
|
||||
|
||||
@@ -32,6 +32,26 @@ from ..agents.adversarial import AdversarialReport, Severity
|
||||
from ..agents.falsification import FalsificationReport
|
||||
|
||||
|
||||
def compute_combined_fitness(
|
||||
fitness_train: float,
|
||||
fitness_oos: float | None,
|
||||
alpha: float = 0.5,
|
||||
) -> float:
|
||||
"""Combina fitness IS e OOS in uno scalare per selection multi-objective.
|
||||
|
||||
Formula::
|
||||
|
||||
combined = alpha * fitness_train + (1 - alpha) * fitness_oos
|
||||
|
||||
Se ``fitness_oos`` è ``None`` o NaN, ritorna ``fitness_train`` (fallback).
|
||||
alpha=1.0 → solo IS (= comportamento default). alpha=0.0 → solo OOS.
|
||||
alpha=0.5 → bilanciato.
|
||||
"""
|
||||
if fitness_oos is None or fitness_oos != fitness_oos: # noqa: PLR0124 (NaN check)
|
||||
return fitness_train
|
||||
return alpha * fitness_train + (1.0 - alpha) * fitness_oos
|
||||
|
||||
|
||||
def compute_fitness(
|
||||
falsification: FalsificationReport,
|
||||
adversarial: AdversarialReport,
|
||||
|
||||
@@ -61,6 +61,12 @@ class RunConfig:
|
||||
# dei top genomi sui restanti. None/0 = no WFA (eval full ohlcv).
|
||||
wfa_train_split: float | None = None
|
||||
wfa_top_k: int = 5 # quanti top genomi rivalutare OOS
|
||||
# Multi-objective selection: se True, ogni genome viene valutato anche su
|
||||
# test_ohlcv durante il loop e la fitness usata per tournament/elite è
|
||||
# combined = alpha*IS + (1-alpha)*OOS. Richiede wfa_train_split attivo.
|
||||
# 2x costo backtest engine.
|
||||
eval_oos_during_loop: bool = False
|
||||
fitness_combined_alpha: float = 0.5 # peso IS (1-alpha = OOS)
|
||||
|
||||
|
||||
def run_phase1(
|
||||
@@ -176,6 +182,31 @@ def run_phase1(
|
||||
hard_kill_findings=cfg.fitness_hard_kill_findings,
|
||||
adversarial_soft_penalty=cfg.fitness_adversarial_soft_penalty,
|
||||
)
|
||||
# Multi-objective: se attivo, eval OOS subito e combina via alpha.
|
||||
if (
|
||||
cfg.eval_oos_during_loop
|
||||
and test_ohlcv is not None
|
||||
and len(test_ohlcv) >= 100
|
||||
and fit > 0
|
||||
):
|
||||
try:
|
||||
fals_oos_inloop = falsification_agent.evaluate(
|
||||
proposal.strategy, test_ohlcv
|
||||
)
|
||||
adv_oos_inloop = adversarial_agent.review(
|
||||
proposal.strategy, test_ohlcv
|
||||
)
|
||||
fit_oos_inloop = compute_fitness(
|
||||
fals_oos_inloop, adv_oos_inloop,
|
||||
hard_kill_findings=cfg.fitness_hard_kill_findings,
|
||||
adversarial_soft_penalty=cfg.fitness_adversarial_soft_penalty,
|
||||
)
|
||||
fit = (
|
||||
cfg.fitness_combined_alpha * fit
|
||||
+ (1.0 - cfg.fitness_combined_alpha) * fit_oos_inloop
|
||||
)
|
||||
except Exception: # noqa: BLE001
|
||||
pass # fallback: usa solo IS
|
||||
repo.save_evaluation(
|
||||
run_id=run_id,
|
||||
genome_id=genome.id,
|
||||
|
||||
Reference in New Issue
Block a user