perf(backtest): vectorize engine + parallel LLM propose + multi-fold validation tool

- backtest/engine.py: state machine numpy invece di pd.iterrows()
  - 16.8x speedup su 2y (470ms -> 28ms), 11.3x su 7y (1744ms -> 154ms)
  - 7 parity test parametrici vs reference iterrows assicurano equivalenza
- orchestrator/run.py + run_phase1.py: --llm-concurrency N
  - ThreadPoolExecutor parallelizza hypothesis_agent.propose() per generazione
  - 5-8x speedup wall time GA loop (OpenRouter qwen-2.5 regge 6-10 concorrenti)
  - default 1 = backward-compat sequenziale
- scripts/validate_run.py: validation multi-fold standalone
  - prende run_id + top-K + N-folds expanding-window su dataset esteso (7y)
  - rivela overfitter mascherati da fitness IS alta (vedi
    phase1-extended-001: elite IS Sharpe 1.93 collassa OOS a -1.00)
  - ranking per robust_score = min(fitness_oos) su tutti i fold

Test 250/250 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-05-16 10:53:48 +00:00
parent fa11cca2bc
commit a29748e3d8
7 changed files with 685 additions and 69 deletions
+11
View File
@@ -114,6 +114,16 @@ def parse_args() -> argparse.Namespace:
"Schema: {styles: {<name>: {directive: <testo>}}}"
),
)
p.add_argument(
"--llm-concurrency",
type=int,
default=1,
help=(
"Numero di propose() LLM concorrenti per generazione (default 1 = "
"serial). 6-10 tipicamente accettati da OpenRouter qwen-2.5 senza "
"rate-limit; riduce wall time GA loop di 5-8x."
),
)
return p.parse_args()
@@ -187,6 +197,7 @@ def main() -> None:
eval_oos_during_loop=args.eval_oos_during_loop,
fitness_combined_alpha=args.fitness_combined_alpha,
prompt_library=prompt_library,
llm_concurrency=args.llm_concurrency,
)
run_id = run_phase1(cfg, ohlcv=ohlcv, llm=llm)