"""TRD04 — Supertrend(period, multiplier)
Classic ATR-band trend flip: long when price above supertrend line, short/flat below.
Grid: (period, mult) in [(10,3),(14,3),(10,2),(14,2)] — 4 configs x 2 TFs x 2 assets = 16 backtests.
Style: continuous weights (vol-targeted, long-flat).
"""
import sys
sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt")
import altlib as al
import numpy as np
import pandas as pd


def supertrend_direction(df: pd.DataFrame, period: int = 10, mult: float = 3.0) -> np.ndarray:
    """Compute Supertrend and return causal direction in {0, 1}.
    Long (1) when close > supertrend, flat (0) otherwise.
    The Supertrend uses ATR-based bands and flips only when price crosses the band.
    Causal: at bar i we use data up to and including close[i].
    """
    h = df["high"].values.astype(float)
    l = df["low"].values.astype(float)
    c = df["close"].values.astype(float)
    n = len(c)

    # ATR via EWM (causal, same as al.atr)
    a = al.atr(df, period)

    hl2 = (h + l) / 2.0
    upper = hl2 + mult * a
    lower = hl2 - mult * a

    # Final upper/lower bands (adjusted to not widen against trend)
    final_upper = upper.copy()
    final_lower = lower.copy()
    direction = np.zeros(n, dtype=float)  # 1 = uptrend (long), 0 = downtrend (flat)

    # Warm-up: first bar
    final_upper[0] = upper[0]
    final_lower[0] = lower[0]
    direction[0] = 1.0 if c[0] > hl2[0] else 0.0

    for i in range(1, n):
        # Tighten upper: new upper only replaces if lower than previous (or if prev close was above)
        if upper[i] < final_upper[i-1] or c[i-1] > final_upper[i-1]:
            final_upper[i] = upper[i]
        else:
            final_upper[i] = final_upper[i-1]

        # Tighten lower: new lower only replaces if higher than previous (or if prev close was below)
        if lower[i] > final_lower[i-1] or c[i-1] < final_lower[i-1]:
            final_lower[i] = lower[i]
        else:
            final_lower[i] = final_lower[i-1]

        # Determine direction (trend)
        prev_dir = direction[i-1]
        if prev_dir == 0.0:  # was downtrend (flat)
            if c[i] > final_upper[i]:
                direction[i] = 1.0  # flip to uptrend
            else:
                direction[i] = 0.0  # stay flat
        else:  # was uptrend
            if c[i] < final_lower[i]:
                direction[i] = 0.0  # flip to downtrend (flat)
            else:
                direction[i] = 1.0  # stay in uptrend

    return direction


def make_target(period: int, mult: float):
    """Returns a target_fn(df) that computes vol-targeted Supertrend weights."""
    def target_fn(df: pd.DataFrame) -> np.ndarray:
        direction = supertrend_direction(df, period=period, mult=mult)
        # vol-targeted: scale by realized vol, cap at 2x leverage, long-flat only
        return al.vol_target(direction, df, target_vol=0.20, vol_win_days=30, leverage_cap=2.0)
    return target_fn


# Small internal grid: 4 param sets
GRID = [
    (10, 3.0),
    (14, 3.0),
    (10, 2.0),
    (14, 2.0),
]

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

# Run each config on both TFs
best_rep = None
best_score = -999.0

print("=== TRD04: Supertrend Grid Search ===")
for period, mult in GRID:
    label = f"TRD04-ST({period},{mult})"
    fn = make_target(period, mult)
    rep = al.study_weights(label, fn, tfs=TFS)
    v = rep["verdict"]
    score = v.get("best_holdout_sharpe", -9)
    print(al.fmt(rep))
    print()
    if score > best_score:
        best_score = score
        best_rep = rep
        best_period = period
        best_mult = mult

print("\n" + "="*60)
print(f"BEST CONFIG: period={best_period}, mult={best_mult}")
print(al.fmt(best_rep))
print("JSON:", al.as_json(best_rep))
