Files
sanguo_vnpy_v2/sanguo_trader/strategy_runner.py
T
claude_dev e5e4eef807 feat(trader): Account总账+StrategyRunner分户(双层记账/资金T0/股票T1)
- Account: cash资金T0/合并持仓/equity盯市/cash_enough买单检查
- StrategyRunner: 分户持仓+realized_pnl归因/unrealized_pnl
- transfer_fee 直接用(matcher已双向,不再×2,review H3)
- unfreeze_all 对称(总账+分户,T+1每日解冻)
7 tests passed.
2026-07-07 11:50:40 +08:00

52 lines
2.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""模拟盘分户账:每策略持仓 + 已实现盈亏归因(spec §7 双层记账分户层)。
与 Account 共享同一笔 tradeAccount 记合并总账,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