""" 策略交付包导出器 — 生成策略文件 + Markdown 报告 + CSV 明细 交付包结构: deliverables/{strategy_name}_{timestamp}/ ├── {strategy_name}.py 策略源文件 (从 strategies/ 复制) ├── STRATEGY_REPORT.md 策略交付报告 (完整分析) ├── optimization.csv 参数优化响应面 ├── walkforward.csv Walk-forward 逐窗口明细 └── backtest_metrics.csv 最优参数回测指标 用法: from exporter import StrategyExporter exporter = StrategyExporter() path = exporter.deliver( strategy_name="sma_cross", opt_result=opt_result, wf_result=wf_result, accept_report=accept_report, df=df, symbol="XAUUSD", ) print(f"交付包: {path}") """ from __future__ import annotations import os import shutil from datetime import datetime from typing import Optional import numpy as np import pandas as pd import raptorbt from strategies import get_strategy from strategies.base import Strategy from .optimizer import OptimizationResult from .walk_forward import WalkForwardResult from .acceptance import AcceptanceReport class StrategyExporter: """ 策略交付包导出器 将策略文件 + 优化结果 + walk-forward 结果 + 验收报告 打包成一个完整的交付目录 """ def __init__(self, output_dir: str = "deliverables"): self.output_dir = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), output_dir ) def deliver( self, strategy_name: str, df: pd.DataFrame, symbol: str, opt_result: OptimizationResult, wf_result: WalkForwardResult, accept_report: AcceptanceReport, param_grid: Optional[dict] = None, data_info: Optional[dict] = None, ) -> str: """ 生成完整交付包 参数: strategy_name: 策略名称 df: K 线数据 symbol: 标的 opt_result: 优化结果 wf_result: walk-forward 结果 accept_report: 验收报告 param_grid: 参数搜索空间 (用于报告) data_info: 数据信息 (如 {"source": "Mt5Bridge", "range": "2026-01~2026-06"}) 返回: 交付包目录路径 """ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") pkg_name = f"{strategy_name}_{timestamp}" pkg_dir = os.path.join(self.output_dir, pkg_name) os.makedirs(pkg_dir, exist_ok=True) strategy = get_strategy(strategy_name) # 1. 复制策略源文件 src_path = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "strategies", f"{strategy_name}.py", ) if os.path.exists(src_path): shutil.copy2(src_path, os.path.join(pkg_dir, f"{strategy_name}.py")) # 2. 导出 CSV 明细 opt_result.export(os.path.join(pkg_dir, "optimization.csv")) wf_result.export(os.path.join(pkg_dir, "walkforward.csv")) # 3. 用最优参数跑完整回测, 导出指标 best_metrics = self._run_best_backtest(strategy_name, opt_result.best_params, df, symbol) if best_metrics: pd.DataFrame(list(best_metrics.items()), columns=["metric", "value"]).to_csv( os.path.join(pkg_dir, "backtest_metrics.csv"), index=False, encoding="utf-8-sig", ) # 4. 生成 Markdown 报告 report = self._generate_report( strategy_name=strategy_name, strategy=strategy, symbol=symbol, opt_result=opt_result, wf_result=wf_result, accept_report=accept_report, param_grid=param_grid, data_info=data_info, best_metrics=best_metrics, ) report_path = os.path.join(pkg_dir, "STRATEGY_REPORT.md") with open(report_path, "w", encoding="utf-8") as f: f.write(report) return pkg_dir def _run_best_backtest(self, strategy_name, best_params, df, symbol) -> Optional[dict]: """用最优参数跑完整回测, 返回指标字典""" try: strategy = get_strategy(strategy_name) # 用最优参数重新实例化 strategy_cls = type(strategy) strategy = strategy_cls(**best_params) signals = strategy.generate_signals(df) config = strategy.build_config() arr = Strategy.to_arrays(df) result = raptorbt.run_single_backtest( timestamps=arr["timestamps"], open=arr["open"], high=arr["high"], low=arr["low"], close=arr["close"], volume=arr["volume"], entries=signals.entries, exits=signals.exits, direction=signals.direction, weight=1.0, symbol=symbol, config=config, ) m = result.metrics return { "total_return_pct": m.total_return_pct, "sharpe_ratio": m.sharpe_ratio, "max_drawdown_pct": m.max_drawdown_pct, "total_trades": m.total_trades, "win_rate_pct": m.win_rate_pct, "profit_factor": m.profit_factor, } except Exception as e: print(f" ⚠️ 最优参数回测失败: {e}") return None def _generate_report( self, strategy_name, strategy, symbol, opt_result, wf_result, accept_report, param_grid, data_info, best_metrics, ) -> str: """生成 Markdown 交付报告""" now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") params_str = ", ".join(f"{k}={v}" for k, v in opt_result.best_params.items()) grid_str = ", ".join( f'{k}={v}' for k, v in (param_grid or {}).items() ) if param_grid else "N/A" data_info = data_info or {} # 验收结果表 accept_lines = [] for c in accept_report.criteria: status = "✅" if c.passed else "❌" accept_lines.append( f"| {c.name} | {c.threshold:.2f} | {c.actual:.2f} | {status} |" ) accept_table = "\n".join(accept_lines) or "| (无) | | | |" # 参数稳定性 stability_lines = [] for param, dist in wf_result.param_stability.items(): dist_str = ", ".join( f"{k}×{v}" for k, v in sorted(dist.items(), key=lambda x: -x[1]) ) stability_lines.append(f"- **{param}**: {dist_str}") stability_str = "\n".join(stability_lines) or "- (无)" # 最优参数回测指标 if best_metrics: metrics_lines = [ f"| {k} | {v:.4f} |" for k, v in best_metrics.items() ] metrics_table = "\n".join(metrics_lines) else: metrics_table = "| (回测失败) | |" # Top 5 参数组合 top5 = opt_result.top_n(5) if len(top5) > 0: cols = opt_result.param_names + [opt_result.metric, "total_trades"] cols = [c for c in cols if c in top5.columns] top5_lines = ["| " + " | ".join(cols) + " |", "|" + "|".join(["---"] * len(cols)) + "|"] for _, row in top5.iterrows(): vals = [] for c in cols: v = row[c] if isinstance(v, float): vals.append(f"{v:.4f}") else: vals.append(str(v)) top5_lines.append("| " + " | ".join(vals) + " |") top5_table = "\n".join(top5_lines) else: top5_table = "(无有效结果)" verdict = "✅ 通过验收,可交付" if accept_report.passed else "❌ 未通过验收,不可交付" return f"""# 策略交付报告: {strategy_name} > 生成时间: {now} > 引擎: RaptorBT v{raptorbt.__version__} ## 1. 策略概述 | 项目 | 内容 | |------|------| | 策略名称 | `{strategy_name}` | | 描述 | {strategy.description()} | | 交易标的 | {symbol} | | 最优参数 | {params_str} | | 参数搜索空间 | {grid_str} | | 预热期 | {strategy.warmup_bars()} bars | ## 2. 参数优化 **目标指标**: {opt_result.metric} ({opt_result.direction}) **搜索组合数**: {len(opt_result.results)} **有效结果数**: {opt_result.results[opt_result.metric].notna().sum()} ### Top 5 参数组合 {top5_table} ## 3. Walk-Forward 验证 | 指标 | IS (训练集) | OOS (测试集) | |------|------------|-------------| | 平均夏普比率 | {wf_result.is_sharpe_avg:.4f} | {wf_result.oos_sharpe_avg:.4f} | | 平均收益率 | - | {wf_result.oos_return_avg:.2f}% | | 平均最大回撤 | - | {wf_result.oos_max_drawdown_avg:.2f}% | | 总交易数 | - | {wf_result.oos_trades_total} | | 平均胜率 | - | {wf_result.oos_win_rate_avg:.1f}% | **衰减比 (OOS/IS)**: {wf_result.decay_ratio:.2%} **过拟合判定**: {'⚠️ 是 (衰减比 < 50%)' if wf_result.is_overfit else '✅ 否'} **验证窗口数**: {wf_result.n_windows} ### 参数稳定性 {stability_str} ## 4. 验收结果 **总体结论**: {verdict} | 标准 | 阈值 | 实际值 | 结果 | |------|------|--------|------| {accept_table} ## 5. 最优参数完整回测 | 指标 | 值 | |------|-----| {metrics_table} ## 6. 数据信息 | 项目 | 内容 | |------|------| | 数据源 | {data_info.get('source', 'Mt5Bridge')} | | 数据范围 | {data_info.get('range', 'N/A')} | | K 线数量 | {data_info.get('bars', 'N/A')} | | 时间周期 | {data_info.get('timeframe', 'N/A')} | ## 7. 风险提示 1. **回测不等于实盘**: 历史表现不保证未来收益,滑点和延迟可能影响实际执行 2. **参数敏感性**: 请关注参数稳定性分析,参数值频繁变化的策略稳健性较差 3. **市场环境**: 策略可能在特定市场条件下表现优异,其他条件下表现不佳 4. **过拟合风险**: {'⚠️ 检测到过拟合,OOS 表现显著低于 IS' if wf_result.is_overfit else '未检测到明显过拟合'} 5. **交易成本**: 回测已包含手续费和滑点,但实际成本可能更高 ## 8. 复现方式 ```bash # 使用最优参数回测 python main.py run --strategy {strategy_name} --symbol {symbol} --export # 重新验证 python main.py validate --strategy {strategy_name} --param <参数>=<值> ``` --- *本报告由 RaptorBT 策略自动化框架自动生成* """