Files
simonandClaude Opus 4.7 271a9343a5 Initial commit: cc-cursor 全链路量化研究平台
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>
2026-06-07 15:59:05 +08:00

90 lines
4.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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()