7 Sprints 全部完成: Sprint 0: 基础设施 (DataManager + MariaDB) Sprint 1: 因子引擎 (34因子/12分类) Sprint 2: VectorBT 回测 (5策略+截面) Sprint 3: Optuna 优化 (+Walk-Forward) Sprint 4: ML 模型 (LightGBM+CatBoost) Sprint 5: Qwen 情绪因子 (三源新闻+日期对齐) Sprint 6: Agent 系统 (4Agent+日报.md/.html) 生产加固 (15项): Tushare双源fallback, SSH自动恢复, pool_pre_ping, save_daily先删后插, load_dotenv绝对路径, 日报5d/20d修复, RiskAgent改上证指数, 昨日对比+数据截止, mac_report utf8mb4, CLAUDE-*.md 9条已知Bug, demo全参数化, djapi数据源归一化, indexDatas API修正 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
90 lines
4.3 KiB
Python
90 lines
4.3 KiB
Python
"""
|
||
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()
|