"""VOL06 — Realized-vol target standalone (pure inverse-vol risk control, long-only).

HYPOTHESIS: No trend signal. Position = target_vol / realized_vol, capped at leverage_cap.
Long-only (direction always +1). Pure inverse-vol scaling — is risk-scaling alone an edge?

We test a small grid of (vol_win_days, target_vol) on 1d and 12h to find the best config
while keeping total backtests <= 6.
"""
import sys
sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt")
import altlib as al
import numpy as np

# Grid: 2 vol windows × 1 target_vol = 2 param sets × 2 TFs = 4 total backtests (within limit)
CONFIGS = [
    {"vol_win_days": 21, "target_vol": 0.20, "leverage_cap": 2.0},
    {"vol_win_days": 60, "target_vol": 0.20, "leverage_cap": 2.0},
]

TFS = ("1d", "12h")

def make_target(vol_win_days: int, target_vol: float, leverage_cap: float):
    """Returns a function df -> target array (long-only inverse-vol)."""
    def target_fn(df):
        c = df["close"].values.astype(float)
        bpd = al.bars_per_day(df)
        bpy = bpd * 365.25
        r = al.simple_returns(c)
        vol = al.realized_vol(r, max(2, vol_win_days * bpd), bpy)
        # Long-only: direction = +1 always; scale by target_vol / realized_vol
        pos = np.where(
            (vol > 0) & np.isfinite(vol),
            np.clip(target_vol / vol, 0.0, leverage_cap),
            0.0,
        )
        pos[~np.isfinite(pos)] = 0.0
        return pos
    return target_fn


# Run grid
best_rep = None
best_score = -np.inf

for cfg in CONFIGS:
    name = f"VOL06_w{cfg['vol_win_days']}_tv{int(cfg['target_vol']*100)}"
    fn = make_target(cfg["vol_win_days"], cfg["target_vol"], cfg["leverage_cap"])
    rep = al.study_weights(name, fn, tfs=TFS)

    # Score = min across assets of average(full_sharpe, holdout_sharpe)
    score_vals = []
    for cell in rep["cells"]:
        for asset in ("BTC", "ETH"):
            pa = cell["per_asset"].get(asset, {})
            if pa:
                fs = pa["full"]["sharpe"]
                hs = pa["holdout"]["sharpe"]
                score_vals.append((fs + hs) / 2)

    score = min(score_vals) if score_vals else -np.inf
    print(f"\n--- Config: {cfg} ---")
    print(al.fmt(rep))
    print("JSON:", al.as_json(rep))

    if score > best_score:
        best_score = score
        best_rep = rep

print("\n\n=== BEST CONFIG ===")
print(al.fmt(best_rep))
print("JSON:", al.as_json(best_rep))
