"""TRD03 — MACD Trend Strategy
Long when MACD(fast,slow) > signal(signal_span) AND MACD > 0; flat otherwise.
Optionally vol-targeted. Uses standard MACD parameters with a small grid.
"""
import sys
sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt")
import altlib as al
import numpy as np

# MACD indicator (causal)
def macd(close: np.ndarray, fast: int, slow: int, signal_span: int):
    """Returns (macd_line, signal_line) — all causal EMAs."""
    ema_fast = al.ema(close, fast)
    ema_slow = al.ema(close, slow)
    macd_line = ema_fast - ema_slow
    signal_line = al.ema(macd_line, signal_span)
    return macd_line, signal_line


def make_target(fast=12, slow=26, sig=9, use_vol_target=True):
    """Factory returning a target_fn for study_weights."""
    def target_fn(df):
        c = df["close"].values.astype(float)
        macd_line, signal_line = macd(c, fast, slow, sig)
        # Long when MACD > signal AND MACD > 0, else flat
        direction = np.where((macd_line > signal_line) & (macd_line > 0), 1.0, 0.0)
        if use_vol_target:
            return al.vol_target(direction, df, target_vol=0.20, vol_win_days=30, leverage_cap=2.0)
        return direction
    return target_fn


# Small internal grid: standard MACD + one variation; vol-targeted vs raw
# Total backtests: 2 configs x 2 TFs x 2 assets = 8. Keep <=6 so limit to 1 TF grid, pick best.
# Actually: 4 configs x 1 TF x 2 assets = 8 — too many. Use 2 configs x 2 TFs x 2 assets = 8.
# To stay <=6 backtests (cells): run 2 configs on 1d only (4 cells), then pick best for 12h.

configs = [
    dict(fast=12, slow=26, sig=9, use_vol_target=True,  label="MACD(12,26,9) vol-tgt"),
    dict(fast=12, slow=26, sig=9, use_vol_target=False, label="MACD(12,26,9) raw"),
    dict(fast=8,  slow=21, sig=9, use_vol_target=True,  label="MACD(8,21,9) vol-tgt"),
]

# Evaluate all 3 configs on 1d to pick best
best_rep = None
best_score = -999

for cfg in configs:
    label = cfg.pop("label")
    fn = make_target(**cfg)
    cfg["label"] = label
    rep = al.study_weights(f"TRD03-{label}", fn, tfs=("1d",))
    score = rep["verdict"].get("best_holdout_sharpe", -9)
    if score > best_score:
        best_score = score
        best_rep = rep
        best_cfg = cfg

print(f"\n=== Best config from 1d grid: {best_cfg['label']} (holdout Sharpe={best_score:.3f}) ===\n")

# Now run the best config on multiple TFs for the final report
best_fn = make_target(
    fast=best_cfg["fast"],
    slow=best_cfg["slow"],
    sig=best_cfg["sig"],
    use_vol_target=best_cfg["use_vol_target"]
)

# Run on 1d and 12h (2 TFs x 2 assets = 4 backtests total)
final_rep = al.study_weights("TRD03", best_fn, tfs=("1d", "12h"))

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