8d69a0cef5
- Gioco GRID TRADERS (sessione 3, regola STRATEGIA_GRIGLIA.md): grid_engine (backtest causale fee-aware della griglia geometrica), grid_brief (digest anonimo per dimensionare la griglia), grid_arena (torneo 100 agenti); diario docs/diary/2026-06-10-grid-traders-game3.md - Gioco OPZIONI: options_engine (BS + skew fittato + DVOL storica), options_arena, opt_calibrate (superficie premi REALE da cerbero-bite) - Gioco SESSION: session_engine/session_arena (pattern orari intraday) - arena: vincolo GAME_NO_LIVE=1 (vieta pairs e fade zscore/breakout/momentum gia' live, coercizione a trend/ma_cross) + normalize del candidato PRIMA della valutazione nel hill-climb - Gate: grid_game_gate (griglia ETH vincitrice vs PORT06, mark-to-market), pairs30m_gate (ETH/BTC 30m ridondante col 15m gia' deployato?) - reset_flatten: flatten one-shot del conto testnet per il reset portafoglio - .gitignore: data/portfolio_paper_stats/ (stato runtime sleeve paper-only) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
93 lines
4.2 KiB
Python
93 lines
4.2 KiB
Python
"""GATE: aggiungere ETH/BTC 30m (vincitore gioco sessione 2) AL BLEND attuale (1h+15m)?
|
|
|
|
Domanda: il 30m e' un 3o timeframe utile dello spread ETH/BTC, o e' ridondante col 15m
|
|
adiacente gia' deployato? Test (engine pairs_sim_flat, == worker):
|
|
[1] correlazioni: 30m vs 1h, 30m vs 15m (se ~1 col 15m -> ridondante).
|
|
[2] gate PORT06: baseline ATTUALE (6 pairs, incl 15m) vs +30m (7 pairs), mezza size.
|
|
[3] robustezza ai costi (fee sweep) del 30m.
|
|
|
|
uv run python scripts/analysis/pairs30m_gate.py
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pandas as pd
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
sys.path.insert(0, str(PROJECT_ROOT))
|
|
|
|
from scripts.analysis.combine_portfolio import port_returns, metrics, SPLIT, OOS_DATE
|
|
from scripts.analysis.pairs_research import pairs_sim, pairs_sim_flat
|
|
from scripts.analysis.report_families import daily_from
|
|
from scripts.portfolios._defs import PORTFOLIOS
|
|
from src.portfolio.sleeves import all_sleeve_equities
|
|
from src.portfolio import weighting as W
|
|
|
|
WIN_30M = dict(n=53, z_in=1.947, z_exit=1.0, max_bars=24) # vincitore gioco sess.2
|
|
|
|
|
|
def daily(cfg, tf, flat_skip, pos=0.15):
|
|
if flat_skip:
|
|
r = pairs_sim_flat("ETH", "BTC", tf=tf, **cfg, flat_skip=True, pos=pos)
|
|
else:
|
|
r = pairs_sim("ETH", "BTC", tf=tf, **cfg, pos=pos)
|
|
return daily_from(r["eq_ts"], r["eq_v"]), r
|
|
|
|
|
|
def port_metrics(members, ids, clusters, caps):
|
|
dr = pd.DataFrame({i: members[i].pct_change().fillna(0.0) for i in ids})
|
|
w = W.weight_vector("cap", ids, dr, caps=caps, clusters=clusters)
|
|
drp = port_returns({i: members[i] for i in ids}, w)
|
|
return metrics(drp), metrics(drp, lo=SPLIT), w
|
|
|
|
|
|
def main():
|
|
p = PORTFOLIOS["PORT06"]
|
|
eq_base = dict(all_sleeve_equities()) # include gia' PR_ETHBTC (1h) e PR_ETHBTC_15M
|
|
e1h = eq_base["PR_ETHBTC"]
|
|
e15 = eq_base["PR_ETHBTC_15M"]
|
|
e30h, r30 = daily(WIN_30M, "30m", flat_skip=True, pos=0.075) # half size come il 15m
|
|
|
|
print("=" * 92)
|
|
print(" GATE — ETH/BTC 30m (vincitore gioco sess.2) sopra il BLEND 1h+15m attuale")
|
|
print(f" 30m: {r30['trades']} trade, {r30.get('n_skip_entry',0)} ingressi flat saltati")
|
|
print("=" * 92)
|
|
|
|
def corr(a, b): return a.pct_change().fillna(0).corr(b.pct_change().fillna(0))
|
|
print("\n[1] CORRELAZIONI (rendimenti giornalieri):")
|
|
print(f" 30m vs 1h : {corr(e30h, e1h):.3f}")
|
|
print(f" 30m vs 15m: {corr(e30h, e15):.3f} <-- se alta, ridondante col 15m gia' deployato")
|
|
print(f" (rif) 15m vs 1h: {corr(e15, e1h):.3f}")
|
|
|
|
print(f"\n[2] GATE PORT06 (cap PAIRS 0.33 + SHAPE 0.0588) | OOS da {OOS_DATE}:")
|
|
ids0 = list(p.sleeve_ids)
|
|
cl0 = p.clusters
|
|
caps = p.caps
|
|
f0, o0, _ = port_metrics(eq_base, ids0, cl0, caps)
|
|
# + 30m
|
|
mem1 = dict(eq_base); mem1["PR_ETHBTC_30M"] = e30h
|
|
ids1 = ids0 + ["PR_ETHBTC_30M"]
|
|
cl1 = dict(cl0); cl1["PR_ETHBTC_30M"] = "ETH-rev"
|
|
f1, o1, w1 = port_metrics(mem1, ids1, cl1, caps)
|
|
print(f" {'config':<22}{'FULL Sh':>8}{'FULL DD%':>9}{'OOS Sh':>8}{'OOS DD%':>8}")
|
|
print(f" {'ATTUALE (1h+15m)':<22}{f0['sharpe']:>8.2f}{f0['dd']:>9.2f}{o0['sharpe']:>8.2f}{o0['dd']:>8.2f}")
|
|
print(f" {'+30m (1h+15m+30m)':<22}{f1['sharpe']:>8.2f}{f1['dd']:>9.2f}{o1['sharpe']:>8.2f}{o1['dd']:>8.2f}")
|
|
ok = o1["sharpe"] >= o0["sharpe"] - 0.02 and o1["dd"] <= o0["dd"] + 1e-9 \
|
|
and f1["sharpe"] >= f0["sharpe"] - 0.02 and f1["dd"] <= f0["dd"] + 1e-9
|
|
print(f" => {'MIGLIORA (promosso)' if ok else 'NON migliora (bocciato)'}")
|
|
print(f" peso pairs ETH/BTC: 1h {w1.get('PR_ETHBTC',0)*100:.1f}% + 15m "
|
|
f"{w1.get('PR_ETHBTC_15M',0)*100:.1f}% + 30m {w1.get('PR_ETHBTC_30M',0)*100:.1f}% "
|
|
f"= {(w1.get('PR_ETHBTC',0)+w1.get('PR_ETHBTC_15M',0)+w1.get('PR_ETHBTC_30M',0))*100:.1f}% su 7 coppie")
|
|
|
|
print("\n[3] ROBUSTEZZA AI COSTI (30m standalone, Sharpe per fee RT/coppia):")
|
|
for fee, lbl in [(0.001, "0.20% 1x"), (0.002, "0.40% 2x"), (0.003, "0.60% 3x"),
|
|
(0.004, "0.80% 4x"), (0.006, "1.20% 6x")]:
|
|
r = pairs_sim_flat("ETH", "BTC", tf="30m", **WIN_30M, flat_skip=True, fee_rt=fee)
|
|
print(f" {lbl:<10} Sharpe {r['sharpe']:>6.2f}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|