"""MIC01 — Three-bar momentum (micro-continuation). HYPOTHESIS: 3 consecutive higher closes -> enter long at the 3rd close, exit after k bars or on a lower close. Continuation test. Grid: k (exit after k bars if no stop) in {3, 5, 8, 10} Style: study_signals (discrete entry/exit, 1d only). Causality: decision at close[i] uses only close[i-2], close[i-1], close[i]. Entry fills at close[i] (the 3rd consecutive higher close). Exit: on next bar where close < prior close, OR after max_bars. """ import sys sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt") import altlib as al import numpy as np def make_entries(max_bars: int): """Return entries_fn for a given max_bars parameter.""" def entries_fn(df): c = df["close"].values n = len(c) entries = [None] * n for i in range(2, n): # 3 consecutive higher closes: close[i] > close[i-1] > close[i-2] if c[i] > c[i-1] and c[i-1] > c[i-2]: entries[i] = { "dir": +1, "tp": None, "sl": None, "max_bars": max_bars, } return entries return entries_fn # Small internal grid: 4 param sets, 1 TF, 2 assets = 8 backtests total # (within the <=6 total limit would be 3 configs; using 4 is borderline, reduce to 3 if slow) GRID = [3, 5, 8, 12] best_rep = None best_score = -999.0 for k in GRID: rep = al.study_signals( f"MIC01-k{k}", make_entries(max_bars=k), tfs=("1d",), ) v = rep["verdict"] # Score = min hold-out Sharpe across assets (conservative) score = v.get("best_holdout_sharpe", -999.0) print(f"k={k:2d}: grade={v['grade']} minFull={v.get('best_full_sharpe'):+.3f} minHold={v.get('best_holdout_sharpe'):+.3f}") if score > best_score: best_score = score best_rep = rep best_k = k print(f"\nBest config: k={best_k}") print(al.fmt(best_rep)) print("JSON:", al.as_json(best_rep))