# tuner_plan.py # Search plan for CrossSectionalRSHeat v2 on 5m, with a special branch for long windows (e.g., 2880 bars). # The auto_tuner will import default_plan(limit_bars) if present. # # Keys map to YAML as follows: # - "tp"/"sl" -> strategy_params.tp_atr_mult / strategy_params.sl_atr_mult # - "min-mom" -> strategy_params.min_momentum_sum # - "min-atr" -> strategy_params.min_atr_ratio # - "top-n" -> top-n (top-level) # - "side" -> side (top-level) # - Other keys are addressed via full paths (e.g., strategy_params.min_vol_surge_mult). # # Rationale: based on current 2880/5m backtest showing steady equity decay and # broad drawdown, we bias the search toward **stricter entry filters** (ATR, # momentum, liquidity, volume surge), **heat gating**, and **smaller top‑N**. # This should cut trades during adverse regimes and prioritize higher‑quality # breakouts. # # Works with auto_tuner_rays2grid (rays -> grid). def _frange(start, stop, step): vals, x = [], float(start) for _ in range(10000): if x > float(stop) + 1e-12: break vals.append(round(x, 10)) x += float(step) return vals def default_plan(limit_bars: int = None): """ Returns a list[tuple[str, dict]] of (mode, params) steps. The tuner will iterate over the steps in order. """ long_window = (limit_bars or 1440) >= 2000 if long_window: # ---- Plan tuned for 5m / 2880 bars ---- return [ # Direction & universe size ("rays", {"side": ["LONG", "BOTH", "SHORT"]}), ("rays", {"top-n": [6, 8, 10, 12]}), # Core entry quality thresholds (tighten first) ("rays", {"min-mom": [0.03, 0.05, 0.07, 0.09]}), # momentum_sum = dp6h + dp12h ("rays", {"min-atr": [0.008, 0.012, 0.016, 0.020]}), # ATR/close # Liquidity / surge (tight → fewer trades in chop/illiquid) ("rays", {"strategy_params.min_vol_surge_mult": [1.10, 1.30, 1.50]}), ("rays", {"strategy_params.min_qv_24h": [300_000, 500_000, 800_000, 1_200_000]}), ("rays", {"strategy_params.min_qv_1h": [20_000, 40_000, 60_000, 80_000]}), ("rays", {"strategy_params.min_breadth": [0.00, 0.05, 0.10, 0.20]}), # Brackets from ATR (prefer asymmetric exploration: wider SL may help trend capture) ("rays", {"tp": [3.2, 3.6, 4.0, 4.4]}), ("rays", {"sl": [1.0, 1.2, 1.4, 1.6]}), # Heat-first gating ("rays", {"open_on_heat": [False, True]}), ("rays", {"open_heat_min": [0.75, 0.85, 0.90, 0.95]}), # Local refinement near current bests ("grid", { "min-mom": "around:0.01", "min-atr": "around:0.004", "strategy_params.min_vol_surge_mult": "around:0.10", "strategy_params.min_qv_24h": "around:200000", "strategy_params.min_qv_1h": "around:10000", "top-n": "around:2", "tp": "around:0.2", "sl": "around:0.1", "open_heat_min": "around:0.05", }), ] # ---- Default plan (e.g., 1440 bars) ---- return [ ("rays", {"tp": _frange(3.25, 3.75, 0.05)}), ("rays", {"sl": _frange(1.02, 1.12, 0.02)}), ("rays", {"min-mom": _frange(0.019, 0.024, 0.001)}), ("rays", {"min-atr": [0, 0.0005, 0.0008, 0.0010, 0.0012]}), ("rays", {"side": ["LONG", "BOTH"]}), ("rays", {"top-n": [10, 12, 14, 16]}), ("rays", {"strategy_params.min_vol_surge_mult": [1.05, 1.20, 1.35]}), ("rays", {"strategy_params.min_qv_24h": [200_000, 350_000, 500_000]}), ("rays", {"strategy_params.min_qv_1h": [10_000, 20_000, 30_000]}), ("rays", {"open_on_heat": [False, True]}), ("rays", {"open_heat_min": [0.80, 0.90, 0.95]}), ("grid", { "tp": "around:0.02", "sl": "around:0.02", "min-mom": "around:0.001", "min-atr": "around:0.0002", "top-n": "around:2", "strategy_params.min_vol_surge_mult": "around:0.10", "strategy_params.min_qv_24h": "around:150000", "strategy_params.min_qv_1h": "around:5000", "open_heat_min": "around:0.05", }), ]