feat(pairs): attiva ETH/BTC 15m flat-skip in PORT06 (BLEND, mezza size)
Origine: gioco "Blind Traders" (100 agenti ciechi su BTC/ETH anonimizzati) -> vincitore = spread ETH/BTC reversion a 15m. Testato sul serio col gate PORT06: non duplicato (corr 1h vs 15m = 0.37), robusto (16/16 celle Sharpe>1), edge NON artefatto delle candele flat ETH 15m (filtrandole resta l'83% dello Sharpe). Percorso live costruito e validato: - pairs_research.pairs_sim_flat: engine generalizzato con exit LIVE-REALIZABLE (arma exit_ready, esce alla 1a barra pulita); regression-lock a pairs_sim. - PairsWorker: flat_skip + exit_ready + rilevamento flat da OHLC (1h byte-exact). - runner: fetch diretto dei timeframe sub-orari + override position_size per-sleeve. - validate_worker_pairs: replay worker == backtest a 15m (8452 vs 8453 trade). - _defs/build_everything: sleeve PR_ETHBTC_15M (mezza size, pos 0.10) -> PORT06 FULL 6.43->7.20, OOS 8.58->9.66, DD giu'. Rischio bilanciato col 1h. - smoke live: Cerbero serve candele 15m fresche; worker ticca. Diari docs/diary/2026-06-09-*. Caveat slippage: mezza size = blend-tilt prudente. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
# 2026-06-09 — Gioco "Blind Traders": 100 agenti ciechi
|
||||
|
||||
## Setup
|
||||
100 agenti LLM (haiku) ricevono due serie anonime **X** e **Y** — in realta'
|
||||
**BTC** e **ETH** 1h/15m/5m, mai etichettate — e devono proporre UNA regola che
|
||||
"anticipi" i movimenti per un PnL netto positivo (fee 0.10% RT) con **>=10
|
||||
trade/mese**. Non sanno cosa siano i dati. L'orchestratore (engine deterministico)
|
||||
valuta ogni strategia, assegna un punteggio su **PNL + %win**, da' **90 epoche di
|
||||
elaborazione** (hill-climb dei parametri) e **ogni 10 epoche blocca il 10% meno
|
||||
profittevole** -> restano i **10 piu' profittevoli**.
|
||||
|
||||
Infrastruttura in `scripts/games/`:
|
||||
- `engine.py` — dati anonimizzati, 6 famiglie segnale (zscore/breakout/ma_cross/
|
||||
rsi/momentum/pairs), backtester causale fee-aware, scoring (>=10 tpm o squalifica).
|
||||
- `agent_brief.py` — digest ANONIMO (stat aggregate + finestra normalizzata) + menu.
|
||||
- `arena.py` — torneo a **3 finestre**: TRAIN (hill-climb), VALID (cull+rank
|
||||
dell'orchestratore), TEST (OOS puro, mai ottimizzato). Anti-overfit.
|
||||
- `run_game.py` — carica le 100 spec degli agenti e lancia il torneo.
|
||||
|
||||
## Risultato emergente
|
||||
I 100 agenti ciechi, leggendo SOLO le statistiche anonime (autocorrelazione
|
||||
negativa, "after_big_move_continues_pct" ~30-40% => le mosse estreme rientrano),
|
||||
hanno **riscoperto da soli che il mercato e' mean-reverting**: 100/100 reversion,
|
||||
67 hanno scelto il detector pairs, 30 zscore. Esattamente la lezione storica del
|
||||
progetto (edge = reversione; pairs ETH/BTC il piu' robusto) — senza sapere che
|
||||
fosse crypto.
|
||||
|
||||
## Classifica finale (top 10) — tutti PAIRS su 15m
|
||||
Vincitore **agente #91** (15m, pairs market-neutral sul log-ratio X/Y):
|
||||
- TEST/OOS puro: **PnL +3126%**, **win 77%**, **108.9 trade/mese**, **Sharpe 20.3**
|
||||
- Full-period: PnL +8052%, win 70%, 94 tpm, Sharpe 12.2 (9604 trade)
|
||||
- params: lookback 66, entry 1.67σ, exit 1.0σ, max_bars 35
|
||||
- ipotesi (cieca): "Y altamente reversivo, X/Y log-ratio strong mean-reversion
|
||||
(-0.43 autocorr), bassa correlazione cross-asset -> pairs market-neutral".
|
||||
|
||||
Tutti i 10 finalisti: pairs 15m, TEST Sharpe medio 19.9, tpm 66-109 (>>10).
|
||||
|
||||
## Caveat onesti
|
||||
- Numeri OOS ottimistici: PnL additivo a notional fisso, **niente slippage sulle 2
|
||||
gambe**, finestra OOS calma, 15m molti trade. Coerente col caveat PR01 del
|
||||
progetto (Sharpe reale atteso ~4-5, non 20). Il valore del gioco e' il **metodo**
|
||||
(scoperta cieca + selezione anti-overfit), non il livello assoluto di Sharpe.
|
||||
- La convergenza su pairs conferma robustezza ma riduce la diversita': i 10 finalisti
|
||||
sono varianti della stessa idea (ETH/BTC spread). Per un portafoglio servirebbe
|
||||
diversificare (gia' fatto altrove: fade + honest + shape).
|
||||
|
||||
## Re-run "sobrio" con slippage (0.05%/lato)
|
||||
`GAME_SLIP=0.0005` -> i pairs pagano +0.20% RT extra (4 lati). Lo slippage spinge
|
||||
l'ottimizzatore verso **meno churn**: tpm dei finalisti 66-109 -> **40-47**, Sharpe
|
||||
top-10 ~20 -> ~13.5. Vincitore **#43** (15m pairs): TEST PnL **+2091%**, win 77%,
|
||||
**46.9 tpm**, Sharpe **15.6**. La gerarchia (pairs 15m domina) e la robustezza
|
||||
reggono lo stress; lo Sharpe reale atteso resta ~4-5 (OOS calmo + PnL additivo).
|
||||
Log: `data/games/game_slip.log`.
|
||||
|
||||
Artefatti: `data/games/tournament_result.json`, `data/games/specs/agent_*.json`,
|
||||
`engine.set_slippage()` (env `GAME_SLIP`).
|
||||
@@ -0,0 +1,82 @@
|
||||
# 2026-06-09 — Percorso live 15m per ETH/BTC pairs: COSTRUITO e VALIDATO
|
||||
|
||||
Seguito di `2026-06-09-pairs15m-port06-gate.md` (il gate passa, edge reale e non
|
||||
artefatto flat). Qui si costruisce e VALIDA l'infrastruttura per eseguire il pairs
|
||||
ETH/BTC a 15m con flat-skip, alla pari del backtest (disciplina validate_worker_pairs).
|
||||
|
||||
## 1. Engine canonico (regression-locked)
|
||||
`scripts/analysis/pairs_research.py`: aggiunti `aligned_ohlc`, `is_flat_ohlc`,
|
||||
`pairs_sim_flat(..., flat_skip, scan_buffer)`. Regola di uscita **LIVE-REALIZABLE**:
|
||||
la condizione (|z|<=z_exit O bars>=max_bars) ARMA `exit_ready`; si esce al CLOSE della
|
||||
PRIMA barra PULITA successiva (mai a un prezzo passato come faceva il prototipo push-back).
|
||||
- **Regression-lock**: `pairs_sim_flat(flat_skip=False)` == `pairs_sim` ESATTO
|
||||
(ETH/BTC 1h 1756 trade, 15m 9388 trade, ret/dd/sharpe identici al bit).
|
||||
|
||||
## 2. PairsWorker esteso (retrocompatibile)
|
||||
`src/live/pairs_worker.py`: param `flat_skip`, stato `exit_ready` (persistito), tick
|
||||
ora fa merge OHLC e rileva le candele flat (O=H=L=C in UNA gamba). Entry saltato su barra
|
||||
stale; uscita con la stessa regola exit_ready dell'engine. **Default off = comportamento
|
||||
1h storico invariato** (se mancano le colonne OHLC, flat=False).
|
||||
|
||||
## 3. Runner: fetch sub-orario (inerte finche' non c'e' uno sleeve 15m)
|
||||
`src/portfolio/runner.py`: `_SUBHOURLY={5m,15m,30m}`, `_LOOKBACK_DAYS` esteso; il loop
|
||||
fetcha DIRETTO da Cerbero i timeframe sub-orari per (asset,tf) (non resamplabili dal 1h) e
|
||||
un router `_series_for` instrada la serie giusta a ogni worker. Zero impatto sul live
|
||||
attuale: nessuno sleeve e' 15m → `subhourly_needs` vuoto → ramo morto.
|
||||
|
||||
## 4. VALIDAZIONE (validate_worker_pairs.py) — TUTTO OK
|
||||
Replay bar-per-bar del worker == backtest:
|
||||
| caso | worker | backtest | match |
|
||||
|---|---|---|---|
|
||||
| ETH/BTC 1h | 1756 trd, cap 2.886.616 | 1756, 2.886.616 | **OK esatto** |
|
||||
| BTC/LTC 1h | 599 trd, cap 16.861 | 599, 16.861 | **OK esatto** |
|
||||
| **ETH/BTC 15m-flat** | **8452 trd** | **8453 trd** (cap entro 0.15%) | **OK** |
|
||||
(1 trade di differenza = posizione finale aperta non chiusa nel replay, atteso.)
|
||||
|
||||
## 5. Gate finale (engine == worker) — PROMOSSO
|
||||
`pairs15m_gate_final.py` (corr 1h vs 15m = 0.372, 3201 ingressi flat saltati):
|
||||
| variante ETH/BTC | FULL Sh | FULL DD | OOS Sh | OOS DD |
|
||||
|---|---|---|---|---|
|
||||
| baseline 1h | 6.43 | 3.96 | 8.58 | 1.36 |
|
||||
| **SWAP 15m-flat** | 7.31 | 3.55 | **9.95** | **1.26** |
|
||||
| **BLEND 1h+15m** | 7.03 | 3.66 | 9.57 | 1.24 |
|
||||
Entrambi PROMOSSI (a fee backtest). Caveat slippage del gate precedente invariato → il
|
||||
BLEND e' la forma raccomandata (meta' allocazione sul 1h pulito, slippage-robusto).
|
||||
|
||||
## Stato e attivazione (NON fatta — decisione di deploy)
|
||||
Tutto il PERCORSO e' pronto e validato, ma il 15m **non e' attivo nel portafoglio live**:
|
||||
attivarlo cambia il trading reale e va deciso esplicitamente. Per accenderlo:
|
||||
1. `_defs.py`: aggiungere SleeveSpec pairs ETH/BTC a 15m (tf="15m",
|
||||
params={n:66,z_in:1.674,z_exit:1.0,max_bars:35,flat_skip:True}) — come SWAP della 1h o
|
||||
come 2a sleeve (BLEND) sotto il cap PAIRS.
|
||||
2. `report_families.build_everything` / `sleeves`: l'equity del nuovo sleeve dal
|
||||
`pairs_sim_flat(tf=15m, flat_skip=True)` (per parita' backtest==report).
|
||||
3. Shadow smoke su testnet (come `live_smoke_pairs.py`) prima del paper reale.
|
||||
4. `deploy.sh` (bump+rebuild) — il runner gia' fetcha 15m e passa flat_skip via spec.params.
|
||||
|
||||
Test suite: nessuna regressione (1h byte-exact). Artefatti: pairs_research.py,
|
||||
pairs_worker.py, runner.py, validate_worker_pairs.py, pairs15m_gate_final.py.
|
||||
|
||||
## ATTIVAZIONE IN REALE (2026-06-09) — BLEND, mezza size
|
||||
Deciso: BLEND (sleeve 15m ACCANTO al 1h, non swap). Implementato:
|
||||
- `_defs.py`: SleeveSpec `PR_ETHBTC_15M` (tf=15m, flat_skip, params.position_size=0.10
|
||||
= meta' del family PAIRS 0.20) in PAIRS -> entra in PORT04/05/06.
|
||||
- `report_families.build_everything`: equity da `pairs_sim_flat(tf=15m, flat_skip=True, pos=0.075)`
|
||||
(mezza size, == intento live) con sid PR_ETHBTC_15M.
|
||||
- `runner.pos_for_spec`: override PER-SLEEVE (params.position_size) > famiglia > globale.
|
||||
- **Mezza size perche'** a peso pieno il 15m pesava il 25.8% del rischio PORT06 (vs 9.5% del
|
||||
1h): dimezzato -> 11.5% vs 10.6%, bilanciato. Disciplina come la cap SHAPE; rispetta il
|
||||
caveat slippage (il 15m non domina il book).
|
||||
|
||||
**PORT06 col BLEND (mezza size)**: FULL Sharpe **6.43->7.20** DD **3.96->3.68**,
|
||||
OOS Sharpe **8.58->9.66** DD **1.36->1.31**. Migliora tutto.
|
||||
|
||||
**Smoke live 15m** (`pairs15m_live_smoke.py`): Cerbero serve candele 15m FRESCHE per
|
||||
ETH e BTC (ultima barra 0 min fa, flat live 2-3%), worker flat-skip ticca OK. Esecuzione
|
||||
reale a 2 gambe gia' coperta da `live_pairs_smoke.py` (livello strumento, tf-indipendente).
|
||||
|
||||
**Regression-lock aggiornati** (miglioria attesa, non regressione): test_definitions
|
||||
(17->18 sleeve), test_backtest_parity_cap (FULL 6.47->7.20, OOS 8.82->9.66). Suite verde.
|
||||
|
||||
Live: il runner fetcha 15m diretto, costruisce il PairsWorker(flat_skip) col pos 0.10,
|
||||
e lo esegue reale a 2 gambe (pairs_enabled). Attivazione via deploy (bump+rebuild).
|
||||
@@ -0,0 +1,89 @@
|
||||
# 2026-06-09 — ETH/BTC pairs a 15m: gate PORT06 (dal gioco Blind Traders)
|
||||
|
||||
## Origine
|
||||
Il gioco "Blind Traders" (100 agenti ciechi) ha eletto come vincitore una variante
|
||||
ETH/BTC pairs su **15m** (config #43: n=66 z_in=1.67 z_exit=1.0 max_bars=35). Domanda:
|
||||
e' un vero miglioramento o un duplicato piu' veloce della sleeve PR01 ETH/BTC gia'
|
||||
deployata a 1h? Testato sul serio con l'engine di PRODUZIONE `pairs_sim` + gate PORT06.
|
||||
Script: `scripts/analysis/pairs15m_port06_gate.py`.
|
||||
|
||||
## Risultati
|
||||
- **Parita' OK** (corr 1.00000): l'harness riproduce esattamente il sleeve canonico
|
||||
PR_ETHBTC → gate affidabile.
|
||||
- **CORRELAZIONE 1h vs 15m = 0.349** (rendimenti giornalieri). **SMENTISCE la mia
|
||||
ipotesi iniziale "duplicato ridondante"**: a 15m cattura eventi di reversione DIVERSI
|
||||
→ e' un diversificatore reale, non una doppia scommessa sullo stesso spread.
|
||||
- **Robustezza 15m**: griglia n×z_in → **16/16 celle Sharpe>1** (9-12), plateau non picco.
|
||||
Non e' un punto overfit del gioco.
|
||||
- **Standalone**: 15m fa 9388 trade (vs 1756 a 1h), Sharpe 11.7 (vs 4.36), DD 54% (vs 48%),
|
||||
8/9 anni+ . (Le % FULL sono esplose dal compounding pos0.15·lev3 su 9k trade → guardare
|
||||
Sharpe/DD/anni, non il livello %.)
|
||||
|
||||
## Gate PORT06 (pos0.15 lev3 canonico, OOS da 2024-10-12)
|
||||
| variante ETH/BTC | FULL Sh | FULL DD | OOS Sh | OOS DD |
|
||||
|---|---|---|---|---|
|
||||
| **baseline 1h** | 6.43 | 3.96 | 8.58 | 1.36 |
|
||||
| **SWAP 15m** | 7.64 | 3.49 | **10.39** | **1.26** |
|
||||
| **BLEND 1h+15m** | 7.30 | 3.63 | 9.95 | 1.24 |
|
||||
|
||||
A fee di backtest (0.20% RT/coppia) **entrambe PROMOSSE**: Sharpe su e DD giu' ovunque.
|
||||
|
||||
## Stress slippage a livello PORT06 (il vero rischio: 15m = 5× i trade)
|
||||
| fee_rt | RT/coppia | PORT06 FULL Sh | FULL DD | OOS Sh | OOS DD | std Sh | std oDD |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| baseline 1h | 0.20% | 6.43 | 3.96 | 8.58 | 1.36 | 4.36 | 16% |
|
||||
| 15m | 0.20% | 7.64 | 3.49 | 10.39 | 1.26 | 11.7 | 13% |
|
||||
| 15m | 0.40% | 7.04 | 4.08 | 9.78 | 1.45 | 8.5 | 27% |
|
||||
| 15m | 0.60% | 6.43 | 4.67 | 9.15 | 1.66 | 5.3 | 47% |
|
||||
|
||||
**Degradazione graziosa ma reale**: il vantaggio di **Sharpe** sopravvive fino a slippage
|
||||
pessimista (OOS 9.15 > 8.58 anche a 0.60%), ma il vantaggio di **DD si perde gia' a 0.40%**
|
||||
(FULL DD 4.08 > 3.96 baseline; standalone oDD esplode 13→27→47%). La regola del progetto
|
||||
("ri-gateare ogni filtro quando cambiano i costi") qui taglia: la frequenza 5× rende la
|
||||
sleeve slippage-sensitive.
|
||||
|
||||
## Verdetto
|
||||
- **NON un duplicato** (corr 0.35) e **NON overfit** (16/16 robusto) → la mia liquidazione
|
||||
iniziale era SBAGLIATA, lo dico chiaro.
|
||||
- **Passa il gate a fee di backtest, marginale sotto slippage**: migliora Sharpe sempre, ma
|
||||
sotto slippage realistico (≥0.40% RT) peggiora leggermente il DD di portafoglio.
|
||||
- **Due rischi di produzione NON ancora quantificati**: (a) qualita' dati ETH 15m (14-30%/anno
|
||||
candele flat O=H=L=C → fill non eseguibili che gonfierebbero il backtest), (b) fill/liquidita'
|
||||
reale a 2 gambe a 15m (5× ordini). Il worker pairs e' validato a 1h, non a 15m.
|
||||
|
||||
**Raccomandazione**: NON swap diretto in live. Candidato promettente → percorso forward:
|
||||
preferire il **BLEND 1h+15m** (tiene il DD pulito del 1h e raccoglie il rendimento
|
||||
decorrelato del 15m) **dopo** un check sull'impatto delle candele flat 15m sui pairs.
|
||||
Allineato a come il progetto tratta FR01 (robusto ma non deployato finche' non domina pulito).
|
||||
Resta come record di ricerca; deploy solo se il check flat-candle e' pulito.
|
||||
|
||||
## CHECK FLAT-CANDLE (pairs15m_flatcheck.py) — PULITO
|
||||
Rischio: ETH 15m ha molte candele flat (O=H=L=C) → close stale che gonfia z-score →
|
||||
reversione FINTA non eseguibile. Test:
|
||||
- **Prevalenza**: ETH 15m **16.4% medio** (fino 30% nel 2022); BTC 15m solo 3.5%. Reale.
|
||||
- **Fill toccati**: 12.9% degli entry e 15.2% degli exit cadono su una barra flat.
|
||||
- **Test decisivo** (entry/exit SOLO su barre pulite, non-flat in entrambe le gambe):
|
||||
rimuove 11.2% dei trade, **Sharpe trattenuto all'83%** (11.74→9.70; OOS Sharpe 18.4).
|
||||
Se l'edge fosse un artefatto flat, filtrando crollerebbe → **NON crolla. NON e' artefatto.**
|
||||
- **Gate PORT06 col 15m FLAT-FILTRATO** (corr 1h vs 15m-flat = 0.366, ancora decorrelato):
|
||||
- SWAP 15m-flat: FULL 7.32/3.55, OOS **9.99/1.26** → PROMOSSO
|
||||
- BLEND 1h+15m-flat: FULL 7.05/3.66, OOS **9.60/1.24** → PROMOSSO
|
||||
|
||||
## Conclusione (3 box su 4 puliti)
|
||||
✅ NON duplicato (corr 0.35-0.37) ✅ robusto (16/16) ✅ NON artefatto flat (83% Sharpe)
|
||||
⚠️ slippage-sensitive: a fee backtest passa pulito; a slippage ≥0.40% RT il vantaggio di
|
||||
Sharpe regge ma il DD-edge si assottiglia. Il **BLEND** mitiga (meta' allocazione resta sul
|
||||
1h pulito e slippage-robusto) → e' la forma deployabile.
|
||||
|
||||
## Realta' del deploy (perche' NON tocco ancora il live)
|
||||
Il gate passa a livello BACKTEST. Ma il live NON puo' eseguire un sleeve 15m oggi:
|
||||
- la live pairs gira SOLO a 1h (`PairsWorker`, validato da `validate_worker_pairs` a 1h);
|
||||
il runner risampla a 1h/4h/1d, non gestisce un leg pairs a 15m.
|
||||
- un BLEND richiede DUE sotto-sleeve ETH/BTC (1h + 15m) dentro il cap PAIRS, e il
|
||||
**flat-skip va replicato nel worker live** (altrimenti il live tradera' le barre stale che
|
||||
il backtest esclude → divergenza backtest-vs-live, la classe di bug che il progetto teme).
|
||||
Editare `_defs.py` cambierebbe solo il backtest/report, NON il live → sarebbe ingannevole.
|
||||
**Percorso deploy corretto** (da confermare): (1) estendere `PairsWorker`/runner al 15m +
|
||||
flat-skip; (2) `validate_worker_pairs` a 15m (replay == backtest esatto); (3) aggiungere lo
|
||||
sleeve 15m sotto il cap PAIRS; (4) shadow su testnet prima del paper. Finche' (1)-(2) non
|
||||
sono fatti e validati, resta **record di ricerca PROMOSSO ma non live**.
|
||||
Reference in New Issue
Block a user