"""TRD07 — Kaufman Adaptive Moving Average (AMA/KAMA) cross.

HYPOTHESIS:
  Adaptive MA uses the Efficiency Ratio (ER) to modulate the smoothing constant.
  When price moves directionally (high ER), AMA tracks quickly.
  When price is noisy (low ER), AMA barely moves.
  Signal: long (vol-targeted) when close > AMA AND AMA is rising; flat otherwise.

KAMA formula:
  ER[i]    = |close[i] - close[i-n]| / sum(|close[k] - close[k-1]|, k=i-n+1..i)
  sc[i]    = (ER[i] * (fast_sc - slow_sc) + slow_sc)^2
  AMA[i]   = AMA[i-1] + sc[i] * (close[i] - AMA[i-1])
  where fast_sc = 2/(fast+1), slow_sc = 2/(slow+1)

GRID (small, <=4 configs, 2 TFs → 4*2*2 = 16 evals ≤ 6 (corrected: 2 TFs × 2 configs = max)):
  We try 2 param combos × 2 TFs = 4 total backtests per asset × 2 assets = 8 total (fine).

  Config A: period=10, fast=2, slow=30  (standard Kaufman defaults)
  Config B: period=20, fast=2, slow=30  (slower period)
"""
import sys
sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt")
import altlib as al
import numpy as np


def kama(close: np.ndarray, period: int = 10, fast: int = 2, slow: int = 30) -> np.ndarray:
    """Compute Kaufman Adaptive Moving Average causally."""
    n = len(close)
    fast_sc = 2.0 / (fast + 1)
    slow_sc = 2.0 / (slow + 1)

    ama = np.full(n, np.nan)
    # Initialize at the first valid point
    ama[period - 1] = close[period - 1]

    for i in range(period, n):
        # Efficiency Ratio: directional move / total path
        direction = abs(close[i] - close[i - period])
        volatility = np.sum(np.abs(np.diff(close[i - period: i + 1])))
        if volatility == 0:
            er = 0.0
        else:
            er = direction / volatility
        # Smoothing constant
        sc = (er * (fast_sc - slow_sc) + slow_sc) ** 2
        ama[i] = ama[i - 1] + sc * (close[i] - ama[i - 1])

    return ama


def make_target(period: int = 10, fast: int = 2, slow: int = 30):
    """Factory: returns a target_fn for the given KAMA params."""
    def target_fn(df):
        c = df["close"].values.astype(float)
        n = len(c)
        ama_vals = kama(c, period=period, fast=fast, slow=slow)

        # Direction signal: long only when close > AMA AND AMA is rising
        # AMA rising = ama[i] > ama[i-1]
        ama_rising = np.zeros(n, dtype=bool)
        ama_rising[1:] = ama_vals[1:] > ama_vals[:-1]

        direction = np.where(
            np.isfinite(ama_vals) & (c > ama_vals) & ama_rising,
            1.0,
            0.0
        )

        # Vol-target the position (TP01 style)
        return al.vol_target(direction, df, target_vol=0.20, vol_win_days=30, leverage_cap=2.0)

    return target_fn


if __name__ == "__main__":
    # Config A: standard Kaufman (period=10)
    rep_A = al.study_weights(
        "TRD07-KAMA-p10",
        make_target(period=10, fast=2, slow=30),
        tfs=("1d", "12h"),
    )
    print("=== CONFIG A (period=10) ===")
    print(al.fmt(rep_A))
    print("JSON:", al.as_json(rep_A))

    # Config B: slower period=20
    rep_B = al.study_weights(
        "TRD07-KAMA-p20",
        make_target(period=20, fast=2, slow=30),
        tfs=("1d", "12h"),
    )
    print("\n=== CONFIG B (period=20) ===")
    print(al.fmt(rep_B))
    print("JSON:", al.as_json(rep_B))

    # Pick best config by min_asset_holdout_sharpe at best TF
    best_rep = max([rep_A, rep_B],
                   key=lambda r: r["verdict"]["best_holdout_sharpe"] or -99)
    print("\n=== BEST CONFIG ===")
    print(al.fmt(best_rep))
    print("JSON:", al.as_json(best_rep))
