"""BRK03 — Keltner Channel Breakout HYPOTHESIS: Long when close > EMA20 + k*ATR(20); flat when close < EMA20. Try k in {1.5, 2.0, 2.5}. Vol-targeted continuous weights. """ import sys sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt") import altlib as al import numpy as np def keltner_breakout(df, k: float) -> np.ndarray: """Long (vol-targeted) when close > EMA20 + k*ATR(20); flat when close < EMA20. All values causal: EMA/ATR at i use data <= i. Decision at close[i] -> held during bar i+1. """ c = df["close"].values.astype(float) ema20 = al.ema(c, span=20) atr20 = al.atr(df, win=20) upper_band = ema20 + k * atr20 # Direction: +1 if close > upper_band (breakout above), else 0 (flat) # Exit: go flat when close < EMA20 (mean reversion back below center) n = len(c) direction = np.zeros(n, dtype=float) # Vectorized: long when above upper band; we then hold until close < EMA20 # Implement as a state machine in_trade = False for i in range(n): if np.isnan(ema20[i]) or np.isnan(atr20[i]): direction[i] = 0.0 continue if not in_trade: # Enter long on breakout above upper keltner band if c[i] > upper_band[i]: in_trade = True direction[i] = 1.0 else: # Exit when price drops back below EMA if c[i] < ema20[i]: in_trade = False direction[i] = 0.0 else: direction[i] = 1.0 # Apply vol-targeting to scale position size pos = al.vol_target(direction, df, target_vol=0.20, vol_win_days=30, leverage_cap=2.0) return pos # Grid: k in {1.5, 2.0, 2.5} — try all 3 param sets; pick best by min_asset_holdout_sharpe best_rep = None best_score = -999.0 best_k = None for k_val in [1.5, 2.0, 2.5]: name = f"BRK03-k{k_val}" print(f"\n--- Running {name} ---") rep = al.study_weights( name, lambda df, k=k_val: keltner_breakout(df, k), tfs=("1d", "12h") ) score = rep["verdict"].get("best_holdout_sharpe", -999.0) or -999.0 print(al.fmt(rep)) if score > best_score: best_score = score best_rep = rep best_k = k_val print("\n" + "="*60) print(f"BEST CONFIG: k={best_k}") print("="*60) print(al.fmt(best_rep)) print("JSON:", al.as_json(best_rep))