Files
sanguo_vnpy_v2/sanguo_trader/account.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

59 lines
2.4 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.
"""模拟盘总账:资金 T+0 / 合并持仓 / 净值盯市(spec §7 双层记账总账层)。
- cash 资金 T+0:卖出回笼资金当日即可再买(A 股硬规则)
- 股票 T+1:买入持仓由 PositionLedger.frozen 管,次日 unfreeze_all 解冻
- transfer_feematcher 已出双向总额(review H3),Account 直接用,不再 ×2
- 资金检查 cash_enough 在买单 apply 前由 PaperEngine 调用
"""
from .models import OrderSide, PaperTrade
from .position_ledger import PositionLedger
class Account:
def __init__(self, initial_capital: float) -> None:
self.cash: float = float(initial_capital)
self.positions: dict[str, PositionLedger] = {}
self.market_value: 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 cash_enough(self, trade: PaperTrade) -> bool:
"""买单检查现金是否足够(卖出不检查,持仓检查在 PositionLedger)。"""
if trade.side != OrderSide.BUY:
return True
cost = trade.price * trade.volume + trade.commission + trade.transfer_fee
return self.cash >= cost
def apply_trade(self, trade: PaperTrade) -> None:
pos = self._position(trade.symbol)
if trade.side == OrderSide.BUY:
cost = trade.price * trade.volume + trade.commission + trade.transfer_fee
self.cash -= cost
pos.apply_buy(trade.price, trade.volume)
else:
proceeds = (
trade.price * trade.volume
- trade.commission - trade.stamp_duty - trade.transfer_fee
)
self.cash += proceeds # 资金 T+0:卖出现金立即可用
pos.apply_sell(trade.price, trade.volume)
def unfreeze_all(self) -> None:
"""每日开盘前:T+1 解冻所有持仓。"""
for p in self.positions.values():
p.unfreeze()
def mark_to_market(self, bars_raw: dict[str, float]) -> None:
"""按 raw 收盘价重估合并持仓市值。bars_raw: {symbol: close_raw}。"""
self.market_value = sum(
p.volume * bars_raw.get(sym, p.avg_price)
for sym, p in self.positions.items()
)
@property
def equity(self) -> float:
return self.cash + self.market_value