#!/usr/bin/env python3 """ 验证修复后的回测结果是否与文档一致 文档预期结果 (Mode A - 指数信号+指数收益): CAGR: 11.80%, 最大回撤: -29.49%, 夏普: 0.818, Calmar: 0.400 文档预期结果 (Mode B - 指数信号+ETF收益): CAGR: 28.07%, 最大回撤: -13.34%, 夏普: 1.685, Calmar: 2.104 """ import sys from pathlib import Path project_root = Path(__file__).parent.parent sys.path.insert(0, str(project_root)) from dotenv import load_dotenv load_dotenv() import pandas as pd import numpy as np import yaml from datetime import datetime from strategies.rotation.strategy import RotationStrategy def calculate_metrics(nav: pd.Series) -> dict: """计算绩效指标""" start_date = nav.index[0] end_date = nav.index[-1] days = (end_date - start_date).days years = days / 365 total_return = nav.iloc[-1] - 1 cagr = (nav.iloc[-1] / nav.iloc[0]) ** (1/years) - 1 daily_ret = nav.pct_change().dropna() sharpe = daily_ret.mean() / daily_ret.std() * np.sqrt(252) if daily_ret.std() > 0 else 0 peak = nav.cummax() drawdown = (nav - peak) / peak max_dd = drawdown.min() calmar = cagr / abs(max_dd) if max_dd != 0 else 0 win_rate = (daily_ret > 0).sum() / len(daily_ret) return { 'start_date': start_date.strftime('%Y-%m-%d'), 'end_date': end_date.strftime('%Y-%m-%d'), 'years': years, 'days': len(nav), 'total_return': total_return, 'cagr': cagr, 'max_dd': max_dd, 'sharpe': sharpe, 'calmar': calmar, 'win_rate': win_rate } def main(): # 加载配置 config_path = project_root / 'strategies/rotation/config.yaml' with open(config_path, 'r') as f: config = yaml.safe_load(f) # 设置回测区间(文档中的测试区间) config['start_date'] = '2020-01-02' config['end_date'] = '2026-05-19' print('='*70) print('修复后回测结果验证') print('='*70) print(f'回测区间: {config["start_date"]} ~ {config["end_date"]}') # 初始化策略 strategy = RotationStrategy(config) # 获取数据并执行回测 print('\n获取数据...') data = strategy.get_data(use_flask_api=False) print('\n执行回测...') result = strategy.run_backtest(data=data) if result.get('result') is None: print('❌ 回测未生成结果') return # 计算指标 nav = result['result']['策略净值'] metrics = calculate_metrics(nav) # 输出结果 print('\n' + '='*70) print('修复后回测结果') print('='*70) print(f"回测区间: {metrics['start_date']} ~ {metrics['end_date']}") print(f"回测年数: {metrics['years']:.2f} 年") print(f"交易天数: {metrics['days']} 天") print('-'*70) print(f"CAGR: {metrics['cagr']:.2%}") print(f"最大回撤: {metrics['max_dd']:.2%}") print(f"夏普比率: {metrics['sharpe']:.3f}") print(f"Calmar比率: {metrics['calmar']:.3f}") print(f"日胜率: {metrics['win_rate']:.2%}") print(f"累计收益: {metrics['total_return']:.2%}") print(f"调仓次数: {len(result.get('rebalance_events', []))} 次") print('='*70) # 文档预期结果对比 print('\n' + '='*70) print('文档预期结果对比') print('='*70) print("\nMode A (指数信号 → 指数收益):") print(" 预期: CAGR 11.80%, MaxDD -29.49%, Sharpe 0.818, Calmar 0.400") print("\nMode B (指数信号 → ETF收益):") print(" 预期: CAGR 28.07%, MaxDD -13.34%, Sharpe 1.685, Calmar 2.104") # 判断当前模式 print('\n' + '-'*70) cagr_diff_a = abs(metrics['cagr'] - 0.1180) cagr_diff_b = abs(metrics['cagr'] - 0.2807) if cagr_diff_a < 0.03: print(f"✓ 当前结果接近 Mode A (CAGR差异: {cagr_diff_a:.2%})") print(" 说明: 当前回测使用指数收盘价计算收益") elif cagr_diff_b < 0.03: print(f"✓ 当前结果接近 Mode B (CAGR差异: {cagr_diff_b:.2%})") print(" 说明: 当前回测使用ETF价格计算收益") else: print(f"⚠ 当前结果与文档预期有差异") print(f" Mode A CAGR差异: {cagr_diff_a:.2%}") print(f" Mode B CAGR差异: {cagr_diff_b:.2%}") print('='*70) return metrics if __name__ == '__main__': main()