196 lines
4.6 KiB
Python
196 lines
4.6 KiB
Python
"""场内基金模拟交易 API Schemas(§T 用户自助端点)。
|
|||
|
|
|
||
|
|
按 `docs/05` §T 端点清单设计:账户看板、委托、持仓、成交、资金明细。
|
||
|
|
请求/响应模型只承载字段契约,**业务校验**(产品可用性、适当性、持仓比例、
|
||
|
|
成交价快照)由 Service 层在调用行情/账户后处理。
|
||
|
|
"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from datetime import datetime
|
||
|
|
from decimal import Decimal
|
||
|
|
from typing import Literal
|
||
|
|
|
||
|
|
from pydantic import BaseModel, ConfigDict, Field
|
||
|
|
|
||
|
|
OrderSide = Literal["buy", "sell"]
|
||
|
|
PriceType = Literal["market"] # 首版只支持市价(基线 §6.2 明确)
|
||
|
|
|
||
|
|
|
||
|
|
class AccountSummary(BaseModel):
|
||
|
|
"""虚拟资金账户快照。"""
|
||
|
|
|
||
|
|
model_config = ConfigDict(extra="forbid")
|
||
|
|
|
||
|
|
account_no: str
|
||
|
|
status: str
|
||
|
|
currency: str
|
||
|
|
initial_balance: Decimal
|
||
|
|
cash_balance: Decimal
|
||
|
|
available_cash: Decimal
|
||
|
|
frozen_cash: Decimal
|
||
|
|
|
||
|
|
|
||
|
|
class PortfolioSummary(BaseModel):
|
||
|
|
"""组合汇总指标。"""
|
||
|
|
|
||
|
|
model_config = ConfigDict(extra="forbid")
|
||
|
|
|
||
|
|
total_asset: Decimal
|
||
|
|
total_market_value: Decimal
|
||
|
|
total_cost: Decimal
|
||
|
|
total_profit_loss: Decimal
|
||
|
|
total_profit_loss_ratio: Decimal
|
||
|
|
today_profit_loss: Decimal
|
||
|
|
today_profit_loss_ratio: Decimal
|
||
|
|
|
||
|
|
|
||
|
|
class HoldingItem(BaseModel):
|
||
|
|
"""单只基金持仓(前端可直接渲染)。"""
|
||
|
|
|
||
|
|
model_config = ConfigDict(extra="forbid")
|
||
|
|
|
||
|
|
product_id: int
|
||
|
|
product_code: str
|
||
|
|
product_name: str
|
||
|
|
total_quantity: Decimal
|
||
|
|
available_quantity: Decimal
|
||
|
|
frozen_quantity: Decimal
|
||
|
|
average_cost: Decimal
|
||
|
|
cost_amount: Decimal
|
||
|
|
latest_price: Decimal
|
||
|
|
market_value: Decimal
|
||
|
|
profit_loss: Decimal
|
||
|
|
profit_loss_ratio: Decimal
|
||
|
|
today_profit_loss: Decimal
|
||
|
|
|
||
|
|
|
||
|
|
class AccountDashboardResponse(BaseModel):
|
||
|
|
"""T001 `GET /api/v1/users/me/account/dashboard` 响应。"""
|
||
|
|
|
||
|
|
model_config = ConfigDict(extra="forbid")
|
||
|
|
|
||
|
|
account: AccountSummary
|
||
|
|
summary: PortfolioSummary
|
||
|
|
holdings: list[HoldingItem]
|
||
|
|
as_of: datetime
|
||
|
|
|
||
|
|
|
||
|
|
class OrderCreateRequest(BaseModel):
|
||
|
|
"""T002 提交委托请求。"""
|
||
|
|
|
||
|
|
model_config = ConfigDict(extra="forbid")
|
||
|
|
|
||
|
|
product_code: str = Field(min_length=1, max_length=32)
|
||
|
|
order_side: OrderSide
|
||
|
|
quantity: Decimal = Field(gt=Decimal("0"))
|
||
|
|
price_type: PriceType = "market"
|
||
|
|
|
||
|
|
|
||
|
|
class OrderCreateResponse(BaseModel):
|
||
|
|
"""T002 提交委托响应(市价立即成交,首版 status='已成交')。"""
|
||
|
|
|
||
|
|
model_config = ConfigDict(extra="forbid")
|
||
|
|
|
||
|
|
order_no: str
|
||
|
|
status: str
|
||
|
|
executed_quantity: Decimal
|
||
|
|
executed_price: Decimal
|
||
|
|
gross_amount: Decimal
|
||
|
|
fee_amount: Decimal
|
||
|
|
net_amount: Decimal
|
||
|
|
executed_at: datetime
|
||
|
|
|
||
|
|
|
||
|
|
class OrderSummary(BaseModel):
|
||
|
|
"""委托列表项(T003 / T004)。"""
|
||
|
|
|
||
|
|
model_config = ConfigDict(extra="forbid")
|
||
|
|
|
||
|
|
order_no: str
|
||
|
|
product_id: int
|
||
|
|
product_code: str
|
||
|
|
product_name: str
|
||
|
|
order_side: OrderSide
|
||
|
|
price_type: PriceType
|
||
|
|
quantity: Decimal
|
||
|
|
limit_price: Decimal | None
|
||
|
|
quote_price: Decimal
|
||
|
|
quote_at: datetime
|
||
|
|
filled_quantity: Decimal
|
||
|
|
average_executed_price: Decimal | None
|
||
|
|
status: str
|
||
|
|
submitted_at: datetime
|
||
|
|
cancelled_at: datetime | None
|
||
|
|
reject_reason: str | None
|
||
|
|
|
||
|
|
|
||
|
|
class OrderCancelResponse(BaseModel):
|
||
|
|
"""T005 撤单响应。"""
|
||
|
|
|
||
|
|
model_config = ConfigDict(extra="forbid")
|
||
|
|
|
||
|
|
order_no: str
|
||
|
|
status: str
|
||
|
|
cancelled_at: datetime
|
||
|
|
|
||
|
|
|
||
|
|
class HoldingListResponse(BaseModel):
|
||
|
|
"""T006 持仓列表响应。"""
|
||
|
|
|
||
|
|
model_config = ConfigDict(extra="forbid")
|
||
|
|
|
||
|
|
holdings: list[HoldingItem]
|
||
|
|
|
||
|
|
|
||
|
|
class TransactionItem(BaseModel):
|
||
|
|
"""成交记录列表项(T007 / T008)。"""
|
||
|
|
|
||
|
|
model_config = ConfigDict(extra="forbid")
|
||
|
|
|
||
|
|
transaction_no: str
|
||
|
|
order_no: str
|
||
|
|
product_id: int
|
||
|
|
product_code: str
|
||
|
|
product_name: str
|
||
|
|
order_side: OrderSide
|
||
|
|
executed_price: Decimal
|
||
|
|
executed_quantity: Decimal
|
||
|
|
gross_amount: Decimal
|
||
|
|
fee_amount: Decimal
|
||
|
|
net_amount: Decimal
|
||
|
|
quote_at: datetime
|
||
|
|
executed_at: datetime
|
||
|
|
|
||
|
|
|
||
|
|
class TransactionListResponse(BaseModel):
|
||
|
|
"""T007 成交列表响应。"""
|
||
|
|
|
||
|
|
model_config = ConfigDict(extra="forbid")
|
||
|
|
|
||
|
|
transactions: list[TransactionItem]
|
||
|
|
next_cursor: str | None = None
|
||
|
|
|
||
|
|
|
||
|
|
class CashLedgerItem(BaseModel):
|
||
|
|
"""资金明细项(T009)。"""
|
||
|
|
|
||
|
|
model_config = ConfigDict(extra="forbid")
|
||
|
|
|
||
|
|
ledger_no: str
|
||
|
|
entry_type: str
|
||
|
|
amount: Decimal
|
||
|
|
balance_after: Decimal
|
||
|
|
available_cash_after: Decimal
|
||
|
|
frozen_cash_after: Decimal
|
||
|
|
transaction_no: str | None
|
||
|
|
occurred_at: datetime
|
||
|
|
|
||
|
|
|
||
|
|
class CashLedgerResponse(BaseModel):
|
||
|
|
"""T009 资金明细响应。"""
|
||
|
|
|
||
|
|
model_config = ConfigDict(extra="forbid")
|
||
|
|
|
||
|
|
entries: list[CashLedgerItem]
|
||
|
|
next_cursor: str | None = None
|