"""领域模型契约(单一事实源的载体)。 MVP 第一周必须定稿的核心类型。回测引擎、指标、API、(未来的)前端类型化客户端 都基于这些契约——保证"图表/回测/实盘"用同一套语义。 注意:回测/图表的指标值由后端唯一计算(app.indicators),前端不另算。 """ from __future__ import annotations from dataclasses import dataclass from datetime import datetime from enum import Enum class Side(str, Enum): BUY = "buy" SELL = "sell" class Timeframe(str, Enum): """K 线周期。分钟级已预留(用户选了分钟级回测)。""" M1 = "1m" M5 = "5m" M15 = "15m" M30 = "30m" H1 = "1h" D1 = "1d" W1 = "1w" @dataclass(frozen=True) class Bar: """一根 K 线(OHLCV + 时间戳)。复权标识后续扩展。 amount(成交额,元)与 turnover(换手率 %)是名义量, 不随复权换算缩放;周期聚合时求和。缺数据为 None。 """ ts: datetime open: float high: float low: float close: float volume: float amount: float | None = None turnover: float | None = None @dataclass(frozen=True) class Signal: """策略产生的交易信号(用于在图上标注买卖点)。""" ts: datetime side: Side price: float strength: float = 1.0 @dataclass(frozen=True) class Fill: """一笔成交(含费用明细)。回测中由 PaperBroker 产生。""" ts: datetime side: Side price: float qty: float commission: float = 0.0 stamp_duty: float = 0.0 # 印花税(仅卖出) transfer_fee: float = 0.0 # 过户费(双边) @property def total_cost(self) -> float: return self.commission + self.stamp_duty + self.transfer_fee @dataclass class Position: """持仓状态。T+1:locked_qty 为当日买入、次日才可卖的部分。""" symbol: str = "" holdings: float = 0.0 # 可卖数量 locked: float = 0.0 # 当日买入(T+1 锁定) avg_price: float = 0.0 @property def qty(self) -> float: return self.holdings + self.locked