From d916520f2c00c4785b74e8440813705d58f6c944 Mon Sep 17 00:00:00 2001 From: Adriano Dal Pastro Date: Mon, 22 Jun 2026 22:32:28 +0000 Subject: [PATCH] research(cross-market): sweep 65-agenti crypto->mercati IB -> fenomeno gap robustissimo ma NON edge Goal: >=50 agenti, migliore soluzione, diversi mercati e timing, su piu' anni. Setup: 26 ETF certificati (IB) + BTC/ETH 1h; harness parametrizzato (lead overnight crypto -> gap/intraday equity, t-incrementale, Sharpe IS/OOS, hit per-anno); workflow 416 config = 52 sweep + 12 verifica avversariale + 1 sintesi = 65 agenti. RISULTATO: cluster fortissimo crypto-overnight -> GAP apertura equity (tutti i target risk-on). Migliori: ETH->IWM/QQQ/XLK gap (Sh OOS 2.4-2.5, t 17), BTC->QQQ gap (Sh OOS 2.31, t 15, 9/9 ANNI). Regge stress 10bps e OOS recente. MA due killer (verificatori concordi): 1. NON tradabile via ETF (gap gia' all'open) -> serve future overnight (MNQ/MES), fuori dal capitale $0.5-2k (margin/liquidazione); 2. e' RISK-BETA non alpha: finestra-lead ~contemporanea al gap (stesso shock macro), forza solo negli anni alta-vol (2022), beta implicito ~37%. Unico ETF-tradabile (ETH->XLE intraday) crolla a 10bps (0.48->0.15), t 2.38 sotto Bonferroni/416. VERDETTO: nessun edge proprietario deployabile a basso capitale. Migliore FENOMENO da forward-monitor = BTC->QQQ gap overnight (9/9 anni). Coerente col soffitto del progetto. Valore: aver classificato il fenomeno (risk-beta overnight) invece di scambiarlo per alpha. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../2026-06-22-crypto-lead-50agent-sweep.md | 62 ++++++++ scripts/research/crypto_lead_harness.py | 126 +++++++++++++++ scripts/research/fetch_ib_equities.py | 4 +- scripts/research/wf_crypto_lead.js | 145 ++++++++++++++++++ 4 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 docs/diary/2026-06-22-crypto-lead-50agent-sweep.md create mode 100644 scripts/research/crypto_lead_harness.py create mode 100644 scripts/research/wf_crypto_lead.js diff --git a/docs/diary/2026-06-22-crypto-lead-50agent-sweep.md b/docs/diary/2026-06-22-crypto-lead-50agent-sweep.md new file mode 100644 index 0000000..2dbabb1 --- /dev/null +++ b/docs/diary/2026-06-22-crypto-lead-50agent-sweep.md @@ -0,0 +1,62 @@ +# 2026-06-22 — Sweep 65-agenti: crypto -> mercati IB (mercati × timing × anni) + +## Obiettivo (goal utente) +Usare >=50 agenti per prendere l'anticipazione crypto->equity e trovare la MIGLIORE soluzione, +provando diversi mercati e timing, su piu' anni. + +## Setup +- **Dati**: universo IB esteso a **26 ETF certificati** (azioni US/settori/intl/bond/credito/oro/ + commodity/REIT), cache su disco (`fetch_ib_equities.py` + BROAD2). Crypto BTC/ETH 1h (Deribit). +- **Harness onesto** (`crypto_lead_harness.py`): per ogni sessione equity, lead = crypto nella + finestra equity-CHIUSO [P 21:00 -> D 13:00 UTC] (overnight; il weekend e' il caso lungo). Predice + gap/intraday/full. Metriche: corr, **t incrementale vs sessione equity precedente**, Sharpe + eseguibile (sign(lead)*predict, net costi) FULL/IS/OOS, **hit per-anno**. +- **Workflow** (`wf_crypto_lead.js`): grid 416 config (2 lead × 26 mercati × 2 giorni × 2 predict × + 2 finestre). **52 agenti sweep** -> **12 agenti verifica avversariale** (stress 10bps + OOS 2024+ + + multi-anno) -> **1 sintesi**. Totale **65 agenti**, 1.7M token. + +## Risultato + +### Fenomeno fortissimo: crypto overnight -> GAP di apertura equity +Cluster coerente in cima, TUTTI predict=gap/overnight, su ogni target risk-on: +| lead->target | t-incr | Sh OOS@4bps | @10bps | OOS-recente | anni+ | +|---|---|---|---|---|---| +| ETH->IWM gap | 17.1 | 2.49 | 1.96 | 2.41 | 7/8 | +| ETH->QQQ gap | 17.9 | 2.36 | 1.83 | 2.31 | 7/8 | +| ETH->XLK gap | 17.4 | 2.40 | 1.93 | 2.30 | 7/8 | +| **BTC->QQQ gap** | 15.0 | 2.31 | 1.78 | 2.16 | **9/9** | +| BTC->SPY gap | 14.4 | 2.14 | 1.69(lf) | 2.03 | 9/9 | + +Statisticamente schiacciante (t 14-18, sopra Bonferroni su 416 test), regge stress costi e OOS +recente, **positivo 8-9 anni su 8-9**. + +### Ma DUE killer (i verificatori avversariali concordi) +1. **NON tradabile via ETF**: il gap e' gia' prezzato all'open dell'ETF -> serve un FUTURE indice + tenuto overnight (MNQ/MES/M2K). A $0.5-2k il margin overnight di anche un micro consuma il + capitale e rischia la liquidazione su un gap avverso -> **fuori portata per costruzione**. +2. **E' RISK-BETA, non alpha**: la finestra-lead crypto e' quasi CONTEMPORANEA al gap (stesso shock + macro overnight, equity chiuso). t enorme = co-movimento risk-on/off, non ETH/BTC che *anticipa*. + Firma: la forza e' negli anni alta-vol (2022 hit 0.71-0.75), piatta negli anni calmi (2019/21/23). + corr ~0.37 -> beta implicito ~37%, alpha residuo piccolo. + +### L'unico tradabile via ETF e' troppo debole +ETH->XLE intraday 6h (compri XLE al day-open, chiudi +6h): Sh OOS 0.48@4bps **-> 0.15@10bps** (annuo +4.1%->1.0%), t-incr 2.38 **sotto Bonferroni** (~3.5 su 416 test). Edge netto onesto ~ZERO. + +## Verdetto (sintesi multi-agente) +**Nessun edge proprietario deployabile a basso capitale.** Il fenomeno crypto->equity-overnight e' +statisticamente reale e robustissimo su 9 anni, ma e' (a) risk-beta condiviso, non anticipazione +sfruttabile, e (b) catturabile solo con futures overnight, fuori dal nostro capitale. L'unica +versione ETF-eseguibile e' dentro il rumore da multiple-testing. Coerente col soffitto del progetto: +"niente di nuovo regge" alla verifica onesta. + +**Migliore soluzione (come FENOMENO da forward-monitor, non deploy):** BTC->QQQ gap overnight — la +storia piu' lunga (9/9 anni), lead noto prima dell'open. Da monitorare; deployabile solo con capitale +~>$20-30k su micro-futures indice e con i costi notturni modellati. + +## Lezione +Anche con 65 agenti e una ricerca esaustiva su mercati/timing/anni, la disciplina onesta +(tradabilita' al capitale reale + multiple-testing + beta-vs-alpha) riduce un "Sharpe 2.5 su 9 anni" +a un non-edge per noi. Il valore della ricerca: aver QUANTIFICATO e CLASSIFICATO il fenomeno +(risk-beta overnight) invece di scambiarlo per alpha. +Artefatti: `crypto_lead_harness.py`, `wf_crypto_lead.js`. diff --git a/scripts/research/crypto_lead_harness.py b/scripts/research/crypto_lead_harness.py new file mode 100644 index 0000000..fd37419 --- /dev/null +++ b/scripts/research/crypto_lead_harness.py @@ -0,0 +1,126 @@ +"""HARNESS parametrizzato — anticipazione crypto -> mercato (lead-lag eseguibile, onesto). + +Generalizza l'effetto weekend: la finestra-LEAD e' l'intervallo in cui l'equity e' CHIUSO e la crypto +no (prev close 21:00 UTC -> next open 13:30 UTC). Il weekend e' il caso lungo (Ven 21:00 -> Lun 13:30). +Per ogni sessione equity D (con sessione precedente P): + lead = crypto return su [lead_start, D 13:00] (lead_start = P 21:00 se hours='overnight', else D13:00-hours) + predict target: gap = open[D]/close[P]-1 ; intraday = close[D]/open[D]-1 ; full = close[D]/close[P]-1 + control = rendimento sessione precedente equity (close[P]/close[P_prev]-1) -> test INCREMENTALE +Filtro giorni: all | mon (solo lunedi'/weekend) | nonmon. + +Output JSON per config: n, corr, beta+t-stat del lead AL NETTO del control (incrementale), Sharpe +settimanale/annualizzato del trade eseguibile (sign(lead)*predict - costo) FULL/IS/OOS(2022+), +hit-rate, e PER-ANNO (hit e mean) per la robustezza multi-anno. + + uv run python scripts/research/crypto_lead_harness.py --configs '[{"lead":"BTC","target":"QQQ","day":"mon","predict":"intraday","hours":"overnight"}]' +Dati: cache su disco (crypto 1h, ETF eq_*). Nessun IB online. Vettoriale, veloce. +""" +import sys, json, argparse +from pathlib import Path +import numpy as np, pandas as pd + +ROOT = Path(__file__).resolve().parents[2] +sys.path.insert(0, str(ROOT)); sys.path.insert(0, str(ROOT / "scripts" / "research")) +from src.data.downloader import load_data +import eqlib + +OOS_DEFAULT = "2022-01-01" +OPEN_H = 13 # ~apertura US 13:30 UTC -> uso barra 13:00 (info nota prima dell'open per il lead) +CLOSE_H = 21 # ~chiusura US 21:00 UTC + +_CRYPTO = {} +def crypto_hourly(asset): + if asset not in _CRYPTO: + s = load_data(asset, "1h").set_index("datetime")["close"].astype(float) + full = pd.date_range(s.index[0].floor("h"), s.index[-1].ceil("h"), freq="h", tz="UTC") + _CRYPTO[asset] = s.reindex(s.index.union(full)).ffill().reindex(full) + return _CRYPTO[asset] + + +def at(series, ts): + try: + return float(series.asof(ts)) + except Exception: + return np.nan + + +def evaluate(cfg, cost_rt=0.0004, oos=OOS_DEFAULT): + OOS = pd.Timestamp(oos, tz="UTC") + lead = cfg["lead"]; tgt = cfg["target"]; day = cfg.get("day", "all") + predict = cfg.get("predict", "intraday"); hours = cfg.get("hours", "overnight") + bc = crypto_hourly(lead) + try: + oc = eqlib.load_eq(tgt)["open"].astype(float); cc = eqlib.load_eq(tgt)["close"].astype(float) + except Exception as e: + return {**cfg, "err": f"no data {tgt}"} + idx = cc.index + rows = [] + for j in range(2, len(idx)): + D = idx[j]; P = idx[j-1]; Pp = idx[j-2] + if day == "mon" and D.weekday() != 0: continue + if day == "nonmon" and D.weekday() == 0: continue + d_open = D.normalize() + pd.Timedelta(hours=OPEN_H) + p_close = P.normalize() + pd.Timedelta(hours=CLOSE_H) + lead_start = p_close if hours == "overnight" else d_open - pd.Timedelta(hours=int(hours)) + c1 = at(bc, d_open); c0 = at(bc, lead_start) + if not (np.isfinite(c1) and np.isfinite(c0) and c0 > 0): continue + ld = c1 / c0 - 1.0 + gap = oc[D] / cc[P] - 1.0 + intr = cc[D] / oc[D] - 1.0 + full = cc[D] / cc[P] - 1.0 + ctrl = cc[P] / cc[Pp] - 1.0 + rows.append((D, ld, gap, intr, full, ctrl)) + if len(rows) < 60: + return {**cfg, "err": f"n={len(rows)}"} + D_ = pd.DataFrame(rows, columns=["d", "lead", "gap", "intraday", "full", "ctrl"]).set_index("d") + y = D_[predict].values; x = D_["lead"].values; ctrl = D_["ctrl"].values + + def z(a): + sd = a.std(); return (a - a.mean()) / sd if sd > 0 else a * 0 + corr = float(np.corrcoef(x, y)[0, 1]) + # incrementale vs control (OLS standardizzato) + X = np.column_stack([np.ones(len(y)), z(x), z(ctrl)]) + beta, *_ = np.linalg.lstsq(X, z(y), rcond=None) + resid = z(y) - X @ beta + dof = max(len(y) - 3, 1) + se = np.sqrt(np.sum(resid**2) / dof * np.diag(np.linalg.inv(X.T @ X))) + t_inc = float(beta[1] / se[1]) if se[1] > 0 else 0.0 + # trade eseguibile: long-short e long-flat su segno del lead, intraday/predict, net costi + sign = np.sign(x) + def sharpe(r): + r = r[np.isfinite(r)] + return float(np.mean(r) / np.std(r) * np.sqrt(52)) if len(r) > 5 and np.std(r) > 0 else 0.0 + ls = sign * y - cost_rt + lf = np.where(x > 0, y, 0.0) - np.where(x > 0, cost_rt, 0.0) + yrs = D_.index.year.values + def per_year(r): + out = {} + for yv in sorted(set(yrs)): + m = yrs == yv + if m.sum() >= 8: + out[int(yv)] = round(float(np.mean(np.sign(x[m]) == np.sign(y[m]))), 2) + return out + is_m = D_.index < OOS; oos_m = D_.index >= OOS + py = per_year(ls) + return {**cfg, "n": len(D_), "corr": round(corr, 3), "t_incremental": round(t_inc, 2), + "hit": round(float(np.mean(sign == np.sign(y))), 3), + "sh_ls_full": round(sharpe(ls), 2), "sh_ls_is": round(sharpe(ls[is_m]), 2), + "sh_ls_oos": round(sharpe(ls[oos_m]), 2), + "sh_lf_full": round(sharpe(lf), 2), "sh_lf_oos": round(sharpe(lf[oos_m]), 2), + "ann_ls_pct": round(float(np.nanmean(ls) * 52 * 100), 1), + "years_pos": int(sum(1 for v in py.values() if v > 0.5)), "years_tot": len(py), + "per_year_hit": py} + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--configs", required=True) + ap.add_argument("--cost", type=float, default=0.0004) + ap.add_argument("--oos", default=OOS_DEFAULT) + args = ap.parse_args() + cfgs = json.loads(args.configs) + print(json.dumps([evaluate(c, cost_rt=args.cost, oos=args.oos) for c in cfgs])) + + +if __name__ == "__main__": + main() diff --git a/scripts/research/fetch_ib_equities.py b/scripts/research/fetch_ib_equities.py index 44dabe1..199992b 100644 --- a/scripts/research/fetch_ib_equities.py +++ b/scripts/research/fetch_ib_equities.py @@ -28,7 +28,9 @@ RAW.mkdir(parents=True, exist_ok=True) SECTORS = ["XLK", "XLF", "XLE", "XLV", "XLI", "XLP", "XLY", "XLU", "XLB", "XLRE", "XLC"] BROAD = ["SPY", "QQQ", "IWM", "TLT", "GLD", "HYG"] -UNIVERSE = SECTORS + BROAD +# espansione "diversi mercati" (intl / bond / credito / commodity / settori extra) per il lead-lag crypto +BROAD2 = ["DIA", "EFA", "EEM", "FXI", "EWJ", "AGG", "LQD", "IEF", "USO", "SLV", "DBC", "VNQ"] +UNIVERSE = SECTORS + BROAD + BROAD2 def certify(sym: str, df: pd.DataFrame) -> dict: diff --git a/scripts/research/wf_crypto_lead.js b/scripts/research/wf_crypto_lead.js new file mode 100644 index 0000000..61ee3e7 --- /dev/null +++ b/scripts/research/wf_crypto_lead.js @@ -0,0 +1,145 @@ +export const meta = { + name: 'crypto-lead-sweep', + description: 'Sweep multi-agente dell\'anticipazione crypto->mercati IB (mercati x timing x lead), verifica avversariale multi-anno, sintesi della soluzione migliore', + phases: [ + { title: 'Sweep', detail: '~52 agenti: grid (lead x mercato x giorno x predict x finestra) via harness onesto' }, + { title: 'Verify', detail: 'top candidati: stress costi + OOS recente + multi-anno' }, + { title: 'Synthesize', detail: 'migliore soluzione robusta + caveat di tradabilita' }, + ], +} + +// ---- universo mercati certificati (cache su disco) ---- +const MARKETS = ["SPY","QQQ","IWM","DIA","XLK","XLF","XLE","XLV","XLI","XLP","XLY","XLU","XLB","XLRE","XLC", + "HYG","TLT","IEF","GLD","SLV","USO","DBC","VNQ","EEM","FXI","EWJ"] +const LEADS = ["BTC","ETH"] +const DAYS = ["all","mon"] +const PREDICTS = ["gap","intraday"] +const HOURS = ["overnight","6"] + +// ---- genera la grid completa ---- +const grid = [] +for (const lead of LEADS) for (const target of MARKETS) for (const day of DAYS) + for (const predict of PREDICTS) for (const hours of HOURS) + grid.push({ lead, target, day, predict, hours }) +log(`grid totale: ${grid.length} configurazioni (mercati ${MARKETS.length} x lead 2 x giorno 2 x predict 2 x finestra 2)`) + +// ---- chunk in batch da 8 -> ~52 agenti ---- +const BATCH = 8 +const batches = [] +for (let i = 0; i < grid.length; i += BATCH) batches.push(grid.slice(i, i + BATCH)) +log(`sweep: ${batches.length} agenti, ${BATCH} config ciascuno`) + +const RAW_SCHEMA = { + type: "object", + properties: { raw: { type: "string", description: "stdout JSON ESATTO dell'harness, senza modifiche" } }, + required: ["raw"], +} + +// ---- PHASE 1: SWEEP ---- +phase('Sweep') +const sweepResults = await parallel(batches.map((batch, bi) => () => + agent( + `Sei un esecutore deterministico. Esegui ESATTAMENTE questo comando dalla root del repo e restituisci il suo stdout.\n\n` + + `uv run python scripts/research/crypto_lead_harness.py --configs '${JSON.stringify(batch)}'\n\n` + + `Il comando stampa un array JSON di risultati. Mettilo VERBATIM nel campo "raw" (nessun commento, nessuna modifica ai numeri). ` + + `Se il comando fallisce, metti il messaggio d'errore in "raw".`, + { label: `sweep:${bi}`, phase: 'Sweep', schema: RAW_SCHEMA, effort: 'low' } + ) +)) + +// ---- parse + flatten ---- +const all = [] +for (const r of sweepResults) { + if (!r || !r.raw) continue + try { + const arr = JSON.parse(r.raw.trim()) + for (const x of arr) if (x && !x.err) all.push(x) + } catch (e) { /* skip batch non parsabile */ } +} +log(`risultati validi raccolti: ${all.length}/${grid.length}`) + +// ---- ranking robustezza: tutti gli anni positivi + t-stat alto + OOS positivo ---- +function score(x) { + const yr = x.years_tot ? x.years_pos / x.years_tot : 0 + const oosOK = (x.sh_ls_oos > 0 || x.sh_lf_oos > 0) ? 1 : 0 + return yr * Math.abs(x.t_incremental || 0) * (1 + Math.max(x.sh_ls_oos || 0, x.sh_lf_oos || 0)) * oosOK +} +all.sort((a, b) => score(b) - score(a)) +const top = all.slice(0, 12) +// separa per tradabilita': intraday = ETF-tradabile; gap = fenomeno (serve future) +const topIntraday = all.filter(x => x.predict === 'intraday').slice(0, 6) +const topGap = all.filter(x => x.predict === 'gap').slice(0, 6) +log(`TOP overall: ${top.map(x => `${x.lead}->${x.target}/${x.day}/${x.predict} t=${x.t_incremental} oos=${Math.max(x.sh_ls_oos,x.sh_lf_oos)} ${x.years_pos}/${x.years_tot}y`).join(' | ')}`) + +// ---- PHASE 2: VERIFY (stress costi + OOS recente, multi-anno) ---- +phase('Verify') +const VERDICT_SCHEMA = { + type: "object", + properties: { + config: { type: "string" }, + robust: { type: "boolean", description: "regge stress (costi alti + OOS recente) e multi-anno?" }, + tradeable_via: { type: "string", description: "etf-intraday | futures-gap | none" }, + sh_oos_4bps: { type: "number" }, sh_oos_10bps: { type: "number" }, sh_oos_recent: { type: "number" }, + years_pos: { type: "number" }, years_tot: { type: "number" }, + note: { type: "string", description: "1-2 frasi: cosa regge, cosa no, spiegazione alternativa" }, + }, + required: ["config", "robust", "tradeable_via", "note"], +} +const cands = [...new Map([...topIntraday, ...topGap, ...top].map(x => [`${x.lead}|${x.target}|${x.day}|${x.predict}|${x.hours}`, x])).values()].slice(0, 12) +const verified = await parallel(cands.map((c) => () => { + const cfg = JSON.stringify([{ lead: c.lead, target: c.target, day: c.day, predict: c.predict, hours: c.hours }]) + return agent( + `Verifica avversariale di UN candidato lead-lag crypto->mercato. Config: ${JSON.stringify(c)}.\n` + + `Esegui questi 3 comandi dalla root e leggi i campi t_incremental, sh_ls_oos, sh_lf_oos, years_pos, years_tot:\n` + + `1) base 4bps: uv run python scripts/research/crypto_lead_harness.py --cost 0.0004 --oos 2022-01-01 --configs '${cfg}'\n` + + `2) stress 10bps: uv run python scripts/research/crypto_lead_harness.py --cost 0.0010 --oos 2022-01-01 --configs '${cfg}'\n` + + `3) OOS recente: uv run python scripts/research/crypto_lead_harness.py --cost 0.0004 --oos 2024-01-01 --configs '${cfg}'\n\n` + + `Giudica: robust=true SOLO se l'edge resta positivo a 10bps E nell'OOS recente (2024+) E years_pos/years_tot>=0.6. ` + + `tradeable_via: "etf-intraday" se predict=intraday e regge (eseguibile comprando l'ETF al Monday/giorno open); ` + + `"futures-gap" se predict=gap e regge (il gap si cattura solo con i futures indice overnight, NON con l'ETF); "none" se non regge. ` + + `note: spiega anche un'alternativa plausibile (e' solo risk-beta? autocorrelazione? multiple-testing su ${grid.length} test?).`, + { label: `verify:${c.lead}->${c.target}/${c.predict}`, phase: 'Verify', schema: VERDICT_SCHEMA } + ) +})) +const robust = verified.filter(v => v && v.robust) +log(`candidati robusti: ${robust.length}/${cands.length}`) + +// ---- PHASE 3: SYNTHESIZE ---- +phase('Synthesize') +const SYNTH_SCHEMA = { + type: "object", + properties: { + best_solution: { type: "string", description: "la migliore soluzione: lead+mercato+timing+predict+come si tradea" }, + why: { type: "string" }, + expected_edge: { type: "string", description: "Sharpe OOS onesto (post-stress), hit, anni positivi" }, + tradeability: { type: "string", description: "ETF intraday vs futures overnight; eseguibile a $0.5-2k?" }, + multi_year: { type: "string", description: "evidenza su piu' anni (per-anno)" }, + caveats: { type: "string" }, + runner_ups: { type: "string" }, + }, + required: ["best_solution", "why", "expected_edge", "tradeability", "multi_year", "caveats"], +} +const synthesis = await agent( + `Sei l'analista quant capo, disciplina ONESTA (questo progetto uccide i falsi positivi: multiple-testing, hold-out-luck, ` + + `tradabilita' reale a basso capitale). Obiettivo: dalla ricerca multi-agente sull'anticipazione crypto->mercati IB, ` + + `determina la SOLUZIONE MIGLIORE (mercato + timing + lead) verificata su PIU' ANNI.\n\n` + + `TOP candidati (sweep, ${grid.length} config testate): ${JSON.stringify(top)}\n\n` + + `VERDETTI di verifica avversariale (stress costi 10bps + OOS recente 2024+): ${JSON.stringify(verified)}\n\n` + + `Candidati robusti: ${JSON.stringify(robust)}\n\n` + + `Fatti noti: (a) il GAP di apertura (predict=gap) ha t-stat altissimi ma NON e' catturabile con l'ETF (serve un future ` + + `indice tradato overnight, es. MNQ/MES su IB); (b) l'INTRADAY (predict=intraday) e' debole ma eseguibile comprando l'ETF; ` + + `(c) abbiamo testato ${grid.length} configurazioni -> correggi mentalmente per multiple-testing (un t-stat ~2 non basta qui).\n\n` + + `Produci la sintesi: la soluzione migliore REALMENTE utile (distingui fenomeno-forte-non-tradabile da edge-tradabile), ` + + `il suo edge atteso onesto post-stress, come si tradea a $0.5-2k, l'evidenza multi-anno, i caveat, e i runner-up.`, + { label: 'synthesize', phase: 'Synthesize', schema: SYNTH_SCHEMA, effort: 'high' } +) + +return { + grid_size: grid.length, + sweep_agents: batches.length, + results_collected: all.length, + top12: top, + verified, + robust_count: robust.length, + synthesis, +}