05d74fc2c1
M1: PaperOrder+limit+matcher 加 listing_days(创业/科创/北交所前5日不锁,0=已过) M3: is_locked_for_*_symbol cfg 注解 AccountConfig M4: matcher NaN bar 拒单 bar_missing L3: PositionLedger price/volume 正数校验 L5: PaperOrder __post_init__ volume 类型校验(拒 float/bool) M5: current_close 契约 docstring + H3 残留注释修正(transfer_fee 双向) 79 tests passed.
90 lines
2.6 KiB
Python
90 lines
2.6 KiB
Python
"""模拟盘数据模型(immutable DTOs)。
|
||
|
||
数据类承载配置与订单/成交/拒单状态,跨模块传递时保持不可变。
|
||
费率默认值见 §6.4(Issue #3 费率参数化)。
|
||
"""
|
||
from dataclasses import dataclass
|
||
from enum import Enum
|
||
|
||
|
||
class MatchSession(str, Enum):
|
||
"""撮合时点(spec §6.1)。
|
||
|
||
- NEXT_OPEN:下一根 bar 的 open(收盘型策略,安全)
|
||
- CURRENT_CLOSE:当根 bar 的 close(尾盘抓涨停型,策略不得用当根 OHLC)
|
||
- CALL_AUCTION:集合竞价(首版预留)
|
||
"""
|
||
|
||
NEXT_OPEN = "next_open"
|
||
CURRENT_CLOSE = "current_close"
|
||
CALL_AUCTION = "call_auction"
|
||
|
||
|
||
class OrderSide(str, Enum):
|
||
BUY = "buy"
|
||
SELL = "sell"
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class AccountConfig:
|
||
"""账户费率/撮合参数(Issue #3 全字段可配)。"""
|
||
|
||
initial_capital: float
|
||
rate: float = 0.0003 # 佣金率
|
||
min_commission: float = 5.0 # 最低佣金 5 元
|
||
stamp_duty_rate: float = 0.0005 # 印花税(仅卖,2023.8.28 起 0.05%)
|
||
transfer_fee_rate: float = 0.00001 # 过户费率(沪深双向,matcher 出 ×2 总额,review H3)
|
||
slippage: float = 0.0
|
||
pricetick: float = 0.01
|
||
size: float = 1.0
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class PaperOrder:
|
||
"""策略下单请求。match_session 决定撮合时点。
|
||
|
||
listing_days:上市天数(新股涨跌停特判,0=已过新股期;spec §6.2)。
|
||
current_close 契约:策略 on_bar 内不得访问当根 close/high/low,否则前瞻偏差。
|
||
"""
|
||
|
||
strategy_id: str
|
||
symbol: str
|
||
side: OrderSide
|
||
price: float
|
||
volume: int
|
||
is_market: bool = True
|
||
match_session: MatchSession = MatchSession.NEXT_OPEN
|
||
listing_days: int = 0
|
||
|
||
def __post_init__(self) -> None:
|
||
if not isinstance(self.volume, int) or isinstance(self.volume, bool):
|
||
raise TypeError(f"volume 必须是 int,收到 {type(self.volume).__name__}")
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class PaperTrade:
|
||
"""已成交记录(含费用拆分)。transfer_fee 为沪深双向总额(review H3,Account 不再 ×2)。"""
|
||
|
||
strategy_id: str
|
||
symbol: str
|
||
side: OrderSide
|
||
price: float
|
||
volume: int
|
||
commission: float
|
||
stamp_duty: float
|
||
transfer_fee: float
|
||
bar_date: str
|
||
match_session: MatchSession
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class PaperReject:
|
||
"""拒单记录。reason 枚举:limit_up_locked / limit_down_locked /
|
||
limit_not_touched / volume_below_min_lot / unsupported_match_session /
|
||
insufficient_cash / blocked_by_strategy=<id>。"""
|
||
|
||
strategy_id: str
|
||
symbol: str
|
||
reason: str
|
||
bar_date: str
|