""" 回测引擎数据模型 — 配置、交易记录、绩效指标和结果 """ from dataclasses import dataclass, field from datetime import datetime from typing import Optional @dataclass class BacktestConfig: """回测配置 Attributes: symbol: 交易对(如 BTCUSDT) exchange: 交易所标识 interval: K 线周期 start_time: 回测起始时间(None 表示从最早可用数据开始) end_time: 回测结束时间(None 表示到最新可用数据结束) commission_pct: 手续费率(0.001 = 0.1%) slippage_pct: 滑点率(0.0005 = 0.05%) min_order_qty: 最小下单量 initial_capital: 初始资金(Quote 币种,如 USDT) warmup_bars: 预热 K 线条数(策略初始化指标所需最少数据量) """ symbol: str exchange: str = "binance" interval: str = "1h" start_time: Optional[datetime] = None end_time: Optional[datetime] = None # 交易成本 commission_pct: float = 0.001 slippage_pct: float = 0.0005 min_order_qty: float = 0.001 # 资金 initial_capital: float = 10_000.0 # 数据 warmup_bars: int = 100 @dataclass class BacktestTrade: """单笔回测交易记录""" timestamp: float """成交时间(Unix 毫秒)""" symbol: str """交易对""" side: str """方向:BUY / SELL""" price: float """成交价格(含滑点)""" quantity: float """成交数量(Base 币种)""" notional: float """成交额(Quote 币种 = price × quantity)""" commission: float """手续费""" slippage: float """滑点成本""" pnl: Optional[float] = None """平仓盈亏(BUY 时为 None,SELL 时有效)""" reason: str = "" """交易原因(来自 Signal.reason)""" @dataclass class BacktestMetrics: """回测绩效指标""" total_return_pct: float = 0.0 """总收益率(%)""" annual_return_pct: float = 0.0 """年化收益率(%)""" sharpe_ratio: float = 0.0 """夏普比率(无风险利率假定为 0)""" max_drawdown_pct: float = 0.0 """最大回撤(%),以负值表示""" max_drawdown_duration_days: int = 0 """最大回撤持续天数""" win_rate: float = 0.0 """胜率(0-1)""" profit_factor: float = 0.0 """盈亏比(总盈利 / 总亏损绝对值)""" total_trades: int = 0 """总交易次数""" avg_trade_pnl: float = 0.0 """平均每笔盈亏""" best_trade_pnl: float = 0.0 """最佳单笔盈亏""" worst_trade_pnl: float = 0.0 """最差单笔盈亏""" calmar_ratio: float = 0.0 """卡尔玛比率(年化收益 / 最大回撤绝对值)""" final_equity: float = 0.0 """最终权益""" @dataclass class BacktestResult: """完整回测结果""" config: BacktestConfig """回测配置""" strategy_config: dict """策略配置(转为 dict 便于序列化)""" metrics: BacktestMetrics """绩效指标""" trades: list[BacktestTrade] = field(default_factory=list) """交易记录""" equity_curve: list[dict] = field(default_factory=list) """资金曲线 [{"timestamp": float, "equity": float, "drawdown": float}, ...]""" @property def total_bars(self) -> int: """回测 K 线总数""" return len(self.equity_curve) def summary(self) -> str: """生成人类可读的摘要""" m = self.metrics lines = [ "=" * 60, f" 回测结果摘要 — {self.config.symbol} {self.config.interval}", "=" * 60, f" 初始资金: {self.config.initial_capital:>12.2f} USDT", f" 最终权益: {m.final_equity:>12.2f} USDT", f" 总收益率: {m.total_return_pct:>11.2f}%", f" 年化收益率: {m.annual_return_pct:>11.2f}%", f" 夏普比率: {m.sharpe_ratio:>12.2f}", f" 卡尔玛比率: {m.calmar_ratio:>12.2f}", f" 最大回撤: {m.max_drawdown_pct:>11.2f}%", f" 回撤持续: {m.max_drawdown_duration_days:>9} 天", f" 总交易次数: {m.total_trades:>11}", f" 胜率: {m.win_rate:>11.1%}", f" 盈亏比: {m.profit_factor:>12.2f}", f" 平均盈亏: {m.avg_trade_pnl:>12.4f} USDT", f" 最佳盈亏: {m.best_trade_pnl:>12.4f} USDT", f" 最差盈亏: {m.worst_trade_pnl:>12.4f} USDT", "=" * 60, ] return "\n".join(lines)