"""SKH_P_LOCAL — coordinate/local search around SKH01-V1.

V1: SkyhookParams(ptn_n=55, sl_atr=2.5, tp_atr=6.0, vola_lo=35, vola_hi=95, vol_lo=0.0)
    -> minFull +0.69, minHold +0.64 (BTC0.64/ETH0.64), maxDD ~49% (BTC), clean_year(2025)=0.014
       robust_oos=False ONLY because clean_year_uplift 0.014 < 0.02.

GOAL: (a) push 2025 clean-year uplift > 0.02 (-> robust_oos True, fully earns slot),
      (b) cut DD toward <35%, keeping minHold>=0.5, minFull>=0.5, fee survives 0.30%RT, >=20 trades.

Strategy: V1's 2025 is weak (BTC+2/ETH-2). Cleaner regime gating + tighter SL can both lift the
2025 contribution AND cut the BTC DD. Local coordinate sweep on the high-leverage knobs, each near V1.
"""
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 = {}
    for a in ("BTC", "ETH"):
        out[a] = sk.run_asset(a, p, fee_rt=sk.FEE_RT)
    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)
    return dict(p=p, over=over, min_full=min_full, min_hold=min_hold, min_tr=min_tr, max_dd=max_dd,
                btc_dd=out["BTC"]["full"]["maxdd"], eth_dd=out["ETH"]["full"]["maxdd"],
                btc_h=out["BTC"]["holdout"]["sharpe"], eth_h=out["ETH"]["holdout"]["sharpe"])

def row(tag, r):
    elig = (r["min_full"] >= 0.5 and r["min_tr"] >= 20)
    print(f"{tag:<28} minFull={r['min_full']:+.2f} minHold={r['min_hold']:+.2f} "
          f"maxDD={r['max_dd']*100:>3.0f}% (btc{r['btc_dd']*100:.0f}/eth{r['eth_dd']*100:.0f}) "
          f"minTr={r['min_tr']:>3} {'OK' if elig else 'x'}")
    return r

print("=== SKH_P_LOCAL coordinate search around V1 (fee 0.10%RT) ===")
base = row("V1", evalp())
cands = [("V1", base)]

# Axis 1: SL tighter to cut DD (V1 sl=2.5). Lower sl -> lower DD, but may cut hold.
for sl in (1.75, 2.0, 2.25, 2.5):
    for tp in (5.0, 6.0, 7.0):
        cands.append((f"sl{sl}_tp{tp}", row(f"sl{sl}_tp{tp}", evalp(sl_atr=sl, tp_atr=tp))))

# Axis 2: regime band — tighten vola top (avoid blow-off) & raise vola_lo to skip dead vol.
for vlo, vhi in ((40,90),(45,90),(40,85),(35,90),(45,85),(50,90)):
    cands.append((f"vola{vlo}-{vhi}", row(f"vola{vlo}-{vhi}", evalp(vola_lo=float(vlo), vola_hi=float(vhi)))))

# Axis 3: add a volume floor (V1 vol_lo=0 = no vol gate). A floor concentrates into live regimes.
for vol_lo in (30.0, 40.0, 50.0):
    cands.append((f"vol_lo{vol_lo}", row(f"vol_lo{vol_lo}", evalp(vol_lo=vol_lo))))

# Axis 4: ptn_n around 55.
for ptn in (45, 50, 60, 65):
    cands.append((f"ptn{ptn}", row(f"ptn{ptn}", evalp(ptn_n=ptn))))

# Axis 5: exit bars (asymmetry).
for ul, us in ((24,18),(30,18),(20,14),(28,14)):
    cands.append((f"ex{ul}/{us}", row(f"ex{ul}/{us}", evalp(uscitalong=ul, uscitashort=us))))

# Filter eligible (the constraints), rank by min_hold then lower DD.
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]
print(f"\nEligible (minFull>=0.5, minHold>=0.5, minTr>=20): {len(elig)}")
elig.sort(key=lambda tr: (-round(tr[1]["min_hold"],3), tr[1]["max_dd"]))
for t,r in elig[:10]:
    print(f"  {t:<22} minHold={r['min_hold']:+.2f} minFull={r['min_full']:+.2f} maxDD={r['max_dd']*100:.0f}% over={r['over']}")

# Low-DD subset
print("\nLowest-DD eligible:")
for t,r in sorted(elig, key=lambda tr:(tr[1]["max_dd"], -tr[1]["min_hold"]))[:8]:
    print(f"  {t:<22} maxDD={r['max_dd']*100:.0f}% minHold={r['min_hold']:+.2f} minFull={r['min_full']:+.2f} over={r['over']}")
