""" Sprint 2 验证脚本 — 回测引擎。 用法: python cli/demo_backtest.py python cli/demo_backtest.py --ts_code 600519.SH """ import sys, os, argparse sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from data.data_manager import DataManager from factors.engine import FactorEngine from factors.registry import get_factor from backtest.vectorbt.engine import VectorBTEngine from backtest.strategies.sma_cross import SMACrossStrategy from backtest.strategies.rsi_mean_revert import RSIMeanRevertStrategy from backtest.strategies.momentum_breakout import MomentumBreakoutStrategy from backtest.strategies.factor_cross import FactorCrossStrategy from backtest.strategies.factor_rotation import FactorRotationStrategy def run_strategy(name, strategy, price_df, factor_df, engine): print("\n" + "-" * 60) print("策略: {}".format(name)) try: report = engine.run(strategy, price_df, factor_df) print(report.summary()) return report except Exception as e: print(" [FAIL] {}".format(e)) return None def main(): p = argparse.ArgumentParser(description="Sprint 2 — 回测引擎验证") p.add_argument("--ts_code", default="000001.SZ", help="测试股票代码(默认: 000001.SZ)") args = p.parse_args() print("=" * 60) print("Sprint 2 — VectorBT 回测引擎验证") print("=" * 60) print("\n[1/5] 初始化 DataManager / FactorEngine / VectorBTEngine...") dm = DataManager(); dm.init_db() engine_fe = FactorEngine(dm) engine_bt = VectorBTEngine() price_df = dm.get_daily(args.ts_code).set_index("trade_date").sort_index() print(" 日线: {} 条 ({} ~ {})".format(len(price_df), price_df.index[0], price_df.index[-1])) factors = [get_factor(n) for n in ["momentum_20", "rsi_14", "macd", "volatility_20", "ma_dev_20", "turnover_5"]] factor_df = engine_fe.compute(args.ts_code, factors) print(" 因子: {} 个, {} 个交易日".format(factor_df.shape[1], factor_df.shape[0])) print("[OK] 就绪") results = [] print("\n[2/5] 测试均线交叉策略...") results.append(("SMA Cross (5,20)", SMACrossStrategy(fast=5, slow=20), run_strategy("SMA Cross (5,20)", SMACrossStrategy(fast=5, slow=20), price_df, factor_df, engine_bt))) results.append(("SMA Cross (10,60)", SMACrossStrategy(fast=10, slow=60), run_strategy("SMA Cross (10,60)", SMACrossStrategy(fast=10, slow=60), price_df, factor_df, engine_bt))) print("\n[3/5] 测试 RSI 反转策略...") results.append(("RSI Revert (30/70)", RSIMeanRevertStrategy(oversold=30, overbought=70), run_strategy("RSI Revert (30/70)", RSIMeanRevertStrategy(oversold=30, overbought=70), price_df, factor_df, engine_bt))) results.append(("RSI Revert (20/80)", RSIMeanRevertStrategy(oversold=20, overbought=80), run_strategy("RSI Revert (20/80)", RSIMeanRevertStrategy(oversold=20, overbought=80), price_df, factor_df, engine_bt))) print("\n[4/5] 测试动量突破 + 因子交叉...") results.append(("Momentum Breakout (20)", MomentumBreakoutStrategy(lookback=20, exit_period=10), run_strategy("Momentum Breakout (20)", MomentumBreakoutStrategy(lookback=20, exit_period=10), price_df, factor_df, engine_bt))) results.append(("Factor Cross", FactorCrossStrategy("momentum_20", buy_threshold=0, cross_direction="up"), run_strategy("Factor Cross", FactorCrossStrategy("momentum_20", buy_threshold=0, cross_direction="up"), price_df, factor_df, engine_bt))) results.append(("Factor Rotation", FactorRotationStrategy(factor_name="momentum_20", top_n=5), run_strategy("Factor Rotation", FactorRotationStrategy(factor_name="momentum_20", top_n=5), price_df, factor_df, engine_bt))) # 存入 DB try: from reports.storage import save_report summary = "## 回测验证 — {}\n\n".format(args.ts_code) for name, s, report in results: if report: summary += "### {}\n{}\n\n".format(name, report.summary()) save_report(summary, "回测验证", subject_type="stock", subject_code=args.ts_code) print("\n 报告已存入 DB") except Exception as e: print("\n [WARN] 报告入库失败: {}".format(e)) print("\n" + "=" * 60) print("Sprint 2 验证完成") print("=" * 60) if __name__ == "__main__": main()