"""
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()
