from __future__ import annotations import copy import json import sys from pathlib import Path import pandas as pd PACKAGE_PARENT = Path(__file__).resolve().parents[2] if str(PACKAGE_PARENT) not in sys.path: sys.path.insert(0, str(PACKAGE_PARENT)) from strategy29.backtest.window_analysis import evaluate_window_result, slice_bundle from strategy32.backtest.simulator import Strategy32Backtester from strategy32.config import PROFILE_V5_BASELINE, build_strategy32_config from strategy32.data import build_strategy32_market_bundle WINDOWS = [(30, "1m"), (365, "1y"), (1095, "3y"), (1825, "5y")] def build_variants() -> list[tuple[str, dict[str, bool]]]: return [ ("baseline_v5", {}), ("no_sideways", {"enable_sideways_engine": False}), ("strong_kill_switch", {"enable_strong_kill_switch": True}), ("daily_trend_filter", {"enable_daily_trend_filter": True}), ("expanded_hedge", {"enable_expanded_hedge": True}), ("max_holding_exit", {"enable_max_holding_exit": True}), ] def main() -> None: base = build_strategy32_config(PROFILE_V5_BASELINE) end = pd.Timestamp("2026-03-15 00:00:00", tz="UTC") start = end - pd.Timedelta(days=max(days for days, _ in WINDOWS) + base.warmup_days + 14) print("fetching bundle...") bundle, latest_completed_bar, accepted_symbols, rejected_symbols, quote_by_symbol = build_strategy32_market_bundle( symbols=base.symbols, auto_discover_symbols=base.auto_discover_symbols, quote_assets=base.quote_assets, excluded_base_assets=base.excluded_base_assets, min_quote_volume_24h=base.discovery_min_quote_volume_24h, start=start, end=end, timeframe=base.timeframe, max_staleness_days=base.max_symbol_staleness_days, ) print("latest", latest_completed_bar) results: dict[str, dict[str, dict[str, float | int | str]]] = {} for name, overrides in build_variants(): cfg = copy.deepcopy(base) for key, value in overrides.items(): setattr(cfg, key, value) variant_results = {} print("\nVARIANT", name) for days, label in WINDOWS: eval_end = latest_completed_bar eval_start = eval_end - pd.Timedelta(days=days) raw_start = eval_start - pd.Timedelta(days=cfg.warmup_days) sliced = slice_bundle(bundle, raw_start, eval_end) backtester = Strategy32Backtester(cfg, sliced, trade_start=eval_start) backtester.engine_config.initial_capital = 1000.0 result = backtester.run() metrics = evaluate_window_result(result, eval_start=eval_start, bars_per_day=backtester.engine_config.bars_per_day) metrics["engine_pnl"] = result.engine_pnl metrics["total_trades"] = result.total_trades variant_results[label] = metrics print( label, "ret", round(float(metrics["total_return"]) * 100, 2), "mdd", round(float(metrics["max_drawdown"]) * 100, 2), "sharpe", round(float(metrics["sharpe"]), 2), "trades", metrics["trade_count"], ) results[name] = variant_results payload = { "strategy": "strategy32", "analysis": "v6_single_change_ablation", "initial_capital": 1000.0, "auto_discover_symbols": base.auto_discover_symbols, "latest_completed_bar": str(latest_completed_bar), "requested_symbols": [] if base.auto_discover_symbols else base.symbols, "accepted_symbols": accepted_symbols, "rejected_symbols": rejected_symbols, "quote_by_symbol": quote_by_symbol, "timeframe": base.timeframe, "results": results, } out = Path("/tmp/strategy32_v6_ablation.json") out.write_text(json.dumps(payload, indent=2), encoding="utf-8") print("\nwrote", out) if __name__ == "__main__": main()