Files
PythagorasGoal/docs/diary/2026-06-09-pairs15m-live-path.md
T
Adriano Dal Pastro d25d897fd1 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>
2026-06-09 11:48:15 +00:00

5.0 KiB

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).