"""TRD14 — Turtle Midline Trend

HYPOTHESIS: Long when close > Donchian(20) midline (mid-channel support),
exit when close crosses below Donchian(10) opposite midline.
Trend-rider using midline as entry/exit instead of channel extremes.

LOGIC:
- Donchian(N) midline = (N-bar high + N-bar low) / 2
- Entry (go long): close > Donchian(20) midline
- Exit (flat): close < Donchian(10) midline
- Long-flat only (crypto-native: no shorting costs, better hold-out)
- Vol-targeted to 20% annualized (TP01-style for fair comparison)

SMALL GRID: vary (slow_win, fast_win) combinations
  - (20, 10) — canonical Turtle
  - (40, 20) — longer memory
  - (60, 20) — even longer
  <= 4 param sets, 2 TFs -> 4x2x2 = 16 total but we limit to 2 TFs x 4 params = 8 evaluations
"""
import sys
sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt")
import altlib as al
import numpy as np


def make_target(slow_win: int = 20, fast_win: int = 10):
    """Return a target_fn for the given (slow_win, fast_win) parameters."""
    def target_fn(df):
        c = df["close"].values.astype(float)
        n = len(c)

        # Donchian midlines: causal (uses data up to bar i-1 due to shift in donchian())
        hi_slow, lo_slow = al.donchian(df, slow_win)
        hi_fast, lo_fast = al.donchian(df, fast_win)
        mid_slow = (hi_slow + lo_slow) / 2.0  # entry signal
        mid_fast = (hi_fast + lo_fast) / 2.0  # exit signal

        # Signal logic: long when c > mid_slow, exit when c < mid_fast
        # Both mid_slow and mid_fast use shifted donchian -> causal at close[i]
        pos = np.full(n, np.nan)
        for i in range(n):
            if np.isnan(mid_slow[i]) or np.isnan(mid_fast[i]):
                pos[i] = 0.0
                continue
            if c[i] > mid_slow[i]:
                pos[i] = 1.0   # enter / stay long
            elif c[i] < mid_fast[i]:
                pos[i] = 0.0   # exit / stay flat

        # Forward-fill: if neither entry nor exit triggered, hold previous position
        direction = (
            __import__("pandas").Series(pos)
            .ffill()
            .fillna(0.0)
            .values
        )
        # Vol-target: scale to 20% annualized, cap leverage at 2x
        return al.vol_target(direction, df, target_vol=0.20, vol_win_days=30, leverage_cap=2.0)

    return target_fn


# Grid: (slow_win, fast_win) combinations
GRID = [
    (20, 10),   # Canonical Turtle
    (40, 20),   # Longer memory
    (60, 20),   # Even longer
    (60, 30),   # Long slow, medium fast
]

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

best_rep = None
best_min_hold = -999.0

for slow_win, fast_win in GRID:
    name = f"TRD14(D{slow_win},D{fast_win})"
    fn = make_target(slow_win, fast_win)
    rep = al.study_weights(name, fn, tfs=TFS)
    # Track best by min_asset_holdout_sharpe across all TFs
    for cell in rep["cells"]:
        mh = cell.get("min_asset_holdout_sharpe", -999.0)
        if mh > best_min_hold:
            best_min_hold = mh
            best_rep = rep

print(al.fmt(best_rep))
print("JSON:", al.as_json(best_rep))
