"""模拟盘分户账:每策略持仓 + 已实现盈亏归因(spec §7 双层记账分户层)。 与 Account 共享同一笔 trade:Account 记合并总账,StrategyRunner 记该策略归因。 """ from .models import OrderSide, PaperTrade from .position_ledger import PositionLedger class StrategyRunner: def __init__(self, strategy_id: str, strategy=None, paper_cta_engine=None) -> None: self.strategy_id: str = strategy_id self.strategy = strategy self.paper_cta_engine = paper_cta_engine self.positions: dict[str, PositionLedger] = {} self.realized_pnl: float = 0.0 self.commission_paid: float = 0.0 def _position(self, symbol: str) -> PositionLedger: if symbol not in self.positions: self.positions[symbol] = PositionLedger(symbol) return self.positions[symbol] def apply_trade(self, trade: PaperTrade) -> None: pos = self._position(trade.symbol) if trade.side == OrderSide.BUY: pos.apply_buy(trade.price, trade.volume) self.commission_paid += trade.commission + trade.transfer_fee else: avg = pos.avg_price realized = ( (trade.price - avg) * trade.volume - trade.commission - trade.stamp_duty - trade.transfer_fee ) self.realized_pnl += realized self.commission_paid += ( trade.commission + trade.stamp_duty + trade.transfer_fee ) pos.apply_sell(trade.price, trade.volume) def unfreeze_all(self) -> None: """每日开盘前:T+1 解冻分户持仓(与 Account.unfreeze_all 对称)。""" for p in self.positions.values(): p.unfreeze() def unrealized_pnl(self, bars_raw: dict[str, float]) -> float: """按 raw 收盘价算浮动盈亏(未实现)。""" total = 0.0 for sym, p in self.positions.items(): if p.volume > 0: total += (bars_raw.get(sym, p.avg_price) - p.avg_price) * p.volume return total