"""SKH_P_LOCAL2 — refine: combine the two winning axes (ptn_n DD-cut + sl/tp hold-lift) and CHECK MARGINAL clean-year(2025) uplift on the top few, since that is the true gate (robust_oos requires clean_year_uplift>0.02 AND multicut_persistent).""" from __future__ import annotations import sys sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/skyhook") import skyhooklib as sk from src.strategies.skyhook import SkyhookParams V1 = dict(ptn_n=55, sl_atr=2.5, tp_atr=6.0, vola_lo=35.0, vola_hi=95.0, vol_lo=0.0) def evalp(**over): p = SkyhookParams(**{**V1, **over}) out = {a: sk.run_asset(a, p, fee_rt=sk.FEE_RT) for a in ("BTC","ETH")} return dict(p=p, over=over, min_full=min(out[a]["full"]["sharpe"] for a in out), min_hold=min(out[a]["holdout"]["sharpe"] for a in out), min_tr=min(out[a]["full"]["n_trades"] for a in out), max_dd=max(out[a]["full"]["maxdd"] for a in out), btc_dd=out["BTC"]["full"]["maxdd"], eth_dd=out["ETH"]["full"]["maxdd"]) def row(tag, r): elig = (r["min_full"]>=0.5 and r["min_tr"]>=20 and r["min_hold"]>=0.5) print(f"{tag:<26} minFull={r['min_full']:+.2f} minHold={r['min_hold']:+.2f} " f"maxDD={r['max_dd']*100:>3.0f}% (b{r['btc_dd']*100:.0f}/e{r['eth_dd']*100:.0f}) " f"minTr={r['min_tr']:>3} {'OK' if elig else 'x'}") return r print("=== SKH_P_LOCAL2 combine ptn_n x sl/tp (fee 0.10%RT) ===") cands=[] for ptn in (40, 45, 48): for sl,tp in ((2.0,6.0),(2.0,7.0),(2.25,6.0),(2.25,7.0),(2.5,7.0)): over=dict(ptn_n=ptn, sl_atr=sl, tp_atr=tp) cands.append((f"ptn{ptn}_sl{sl}_tp{tp}", row(f"ptn{ptn}_sl{sl}_tp{tp}", evalp(**over)))) # also ptn45 with exit-bar asymmetry that lifted hold for ul,us in ((30,18),(24,18)): over=dict(ptn_n=45, uscitalong=ul, uscitashort=us) cands.append((f"ptn45_ex{ul}/{us}", row(f"ptn45_ex{ul}/{us}", evalp(**over)))) elig=[(t,r) for (t,r) in cands if r["min_full"]>=0.5 and r["min_tr"]>=20 and r["min_hold"]>=0.5] elig.sort(key=lambda tr:(tr[1]["max_dd"], -round(tr[1]["min_hold"],3))) print(f"\nEligible: {len(elig)} (sorted by lowest DD)") for t,r in elig: print(f" {t:<24} maxDD={r['max_dd']*100:.0f}% minHold={r['min_hold']:+.2f} minFull={r['min_full']:+.2f} over={r['over']}") # Check MARGINAL clean-year uplift on the lowest-DD eligible + the best-hold eligible. def marg_check(tag, over): p = SkyhookParams(**{**V1, **over}) mg = sk.marginal(p) print(f"\n--- MARGINAL {tag} over={over} ---") print(f" verdict={mg.get('marginal_verdict')} corr_full={mg.get('corr_full')} " f"robust_oos={mg.get('robust_oos')} multicut_persistent={mg.get('multicut_persistent')}") print(f" clean_year_uplift={mg.get('clean_year_uplift')} jackknife_min={mg.get('jackknife_min_uplift')} " f"has_insample_edge={mg.get('has_insample_edge')} is_hedge={mg.get('is_hedge')}") print(f" blend w25 uplift_hold={mg.get('blends',{}).get('w25',{}).get('uplift_hold')} " f"uplift_full={mg.get('blends',{}).get('w25',{}).get('uplift_full')}") return mg # pick up to 4 distinct configs to marginal-check seen=set(); checked=0 for t,r in elig: key=tuple(sorted(r["over"].items())) if key in seen: continue seen.add(key); marg_check(t, r["over"]); checked+=1 if checked>=5: break