918bbed0fc
- 修复 deps.py 中 get_vn_service 的引用错误 (vn_service.vn_service -> vn_service) - 移除登录页面上的明文密码提示 - 改进前端错误处理,避免数据加载失败导致登录显示错误
368 lines
8.7 KiB
Python
368 lines
8.7 KiB
Python
"""
|
|
Pydantic 数据模型定义
|
|
用于 API 请求和响应的数据验证
|
|
"""
|
|
from datetime import datetime
|
|
from typing import Optional, List, Any
|
|
from enum import Enum
|
|
from pydantic import BaseModel, Field, field_validator
|
|
|
|
|
|
# ============================================
|
|
# 认证模型
|
|
# ============================================
|
|
|
|
class LoginRequest(BaseModel):
|
|
"""登录请求"""
|
|
username: str = Field(..., min_length=1, max_length=50)
|
|
password: str = Field(..., min_length=1, max_length=100)
|
|
|
|
@field_validator('username', 'password')
|
|
def no_whitespace(cls, v):
|
|
if v.strip() != v:
|
|
raise ValueError('不能包含前后空格')
|
|
return v
|
|
|
|
|
|
class TokenResponse(BaseModel):
|
|
"""Token 响应"""
|
|
access_token: str
|
|
token_type: str = "bearer"
|
|
expires_in: int # 秒数
|
|
refresh_token: Optional[str] = None
|
|
|
|
|
|
class TokenVerifyRequest(BaseModel):
|
|
"""Token 验证请求"""
|
|
token: str
|
|
|
|
|
|
class TokenVerifyResponse(BaseModel):
|
|
"""Token 验证响应"""
|
|
valid: bool
|
|
user_info: Optional[dict] = None
|
|
|
|
|
|
# ============================================
|
|
# 用户模型
|
|
# ============================================
|
|
|
|
class User(BaseModel):
|
|
"""用户信息"""
|
|
username: str
|
|
email: Optional[str] = None
|
|
full_name: Optional[str] = None
|
|
is_active: bool = True
|
|
created_at: datetime
|
|
|
|
|
|
class UserCreate(BaseModel):
|
|
"""创建用户"""
|
|
username: str = Field(..., min_length=3, max_length=50)
|
|
password: str = Field(..., min_length=6, max_length=100)
|
|
email: Optional[str] = None
|
|
full_name: Optional[str] = None
|
|
|
|
|
|
class UserUpdate(BaseModel):
|
|
"""更新用户"""
|
|
email: Optional[str] = None
|
|
full_name: Optional[str] = None
|
|
password: Optional[str] = None
|
|
|
|
|
|
# ============================================
|
|
# 交易模型
|
|
# ============================================
|
|
|
|
class OrderDirection(str, Enum):
|
|
"""订单方向"""
|
|
BUY = "buy"
|
|
SELL = "sell"
|
|
|
|
|
|
class OrderType(str, Enum):
|
|
"""订单类型"""
|
|
LIMIT = "limit"
|
|
MARKET = "market"
|
|
STOP = "stop"
|
|
|
|
|
|
class SendOrderRequest(BaseModel):
|
|
"""发送订单请求"""
|
|
symbol: str = Field(..., description="交易品种代码")
|
|
exchange: str = Field(..., description="交易所代码")
|
|
direction: OrderDirection
|
|
order_type: OrderType
|
|
volume: float = Field(..., gt=0, description="数量")
|
|
price: Optional[float] = Field(None, gt=0, description="价格(限价单必填)")
|
|
stop_price: Optional[float] = Field(None, gt=0, description="止损价")
|
|
reference: Optional[str] = Field(None, description="客户引用")
|
|
|
|
|
|
class CancelOrderRequest(BaseModel):
|
|
"""撤单请求"""
|
|
order_id: str = Field(..., description="订单号")
|
|
|
|
|
|
class OrderResponse(BaseModel):
|
|
"""订单响应"""
|
|
order_id: str
|
|
symbol: str
|
|
exchange: str
|
|
direction: str
|
|
order_type: str
|
|
volume: float
|
|
price: Optional[float]
|
|
traded: float
|
|
status: str
|
|
time: datetime
|
|
reference: Optional[str] = None
|
|
|
|
|
|
# ============================================
|
|
# 行情数据模型
|
|
# ============================================
|
|
|
|
class TickData(BaseModel):
|
|
"""Tick 数据"""
|
|
symbol: str
|
|
exchange: str
|
|
datetime: datetime
|
|
name: Optional[str] = None
|
|
last_price: float
|
|
bid_price_1: Optional[float] = None
|
|
ask_price_1: Optional[float] = None
|
|
bid_volume_1: Optional[float] = None
|
|
ask_volume_1: Optional[float] = None
|
|
volume: Optional[float] = None
|
|
open_interest: Optional[float] = None
|
|
|
|
|
|
class KlineRequest(BaseModel):
|
|
"""K线数据请求"""
|
|
symbol: str = Field(..., description="交易品种代码")
|
|
exchange: str = Field(..., description="交易所代码")
|
|
interval: str = Field(..., description="周期: 1m, 5m, 15m, 1h, 4h, 1d")
|
|
start: Optional[datetime] = Field(None, description="开始时间")
|
|
end: Optional[datetime] = Field(None, description="结束时间")
|
|
limit: int = Field(1000, ge=1, le=10000, description="数据条数限制")
|
|
|
|
|
|
class KlineData(BaseModel):
|
|
"""K线数据"""
|
|
symbol: str
|
|
exchange: str
|
|
datetime: datetime
|
|
interval: str
|
|
open_price: float
|
|
high_price: float
|
|
low_price: float
|
|
close_price: float
|
|
volume: float
|
|
open_interest: Optional[float] = None
|
|
|
|
|
|
class SubscribeRequest(BaseModel):
|
|
"""订阅行情请求"""
|
|
symbol: str = Field(..., description="交易品种代码")
|
|
exchange: str = Field(..., description="交易所代码")
|
|
gateway_name: Optional[str] = Field(None, description="网关名称")
|
|
|
|
|
|
class UnsubscribeRequest(BaseModel):
|
|
"""取消订阅请求"""
|
|
symbol: str = Field(..., description="交易品种代码")
|
|
exchange: str = Field(..., description="交易所代码")
|
|
gateway_name: Optional[str] = Field(None, description="网关名称")
|
|
|
|
|
|
# ============================================
|
|
# 持仓数据模型
|
|
# ============================================
|
|
|
|
class PositionData(BaseModel):
|
|
"""持仓数据"""
|
|
symbol: str
|
|
exchange: str
|
|
direction: str
|
|
volume: float
|
|
price: float
|
|
pnl: float
|
|
pnl_ratio: float
|
|
frozen: float = 0.0
|
|
yd_volume: float = 0.0
|
|
|
|
|
|
# ============================================
|
|
# 账户数据模型
|
|
# ============================================
|
|
|
|
class AccountData(BaseModel):
|
|
"""账户数据"""
|
|
account_id: str
|
|
balance: float
|
|
available: float
|
|
frozen: float = 0.0
|
|
margin: float = 0.0
|
|
|
|
|
|
class TradeData(BaseModel):
|
|
"""成交数据"""
|
|
trade_id: str
|
|
order_id: str
|
|
symbol: str
|
|
exchange: str
|
|
direction: str
|
|
volume: float
|
|
price: float
|
|
time: datetime
|
|
|
|
|
|
class AccountResponse(BaseModel):
|
|
"""账户响应"""
|
|
account: AccountData
|
|
positions: List[PositionData]
|
|
orders: List[OrderResponse]
|
|
|
|
|
|
# ============================================
|
|
# 网关模型
|
|
# ============================================
|
|
|
|
class GatewayType(str, Enum):
|
|
"""网关类型"""
|
|
CTP = "ctp"
|
|
IB = "ib"
|
|
OKX = "okx"
|
|
BINAANCE = "binance"
|
|
TEST = "test"
|
|
|
|
|
|
class GatewayStatus(BaseModel):
|
|
"""网关状态"""
|
|
gateway_name: str
|
|
gateway_type: GatewayType
|
|
status: str # connected, disconnected, connecting
|
|
connected_time: Optional[datetime] = None
|
|
message: Optional[str] = None
|
|
|
|
|
|
class GatewayConnectRequest(BaseModel):
|
|
"""连接网关请求"""
|
|
gateway_name: str = Field(..., description="网关名称")
|
|
gateway_type: GatewayType
|
|
setting: dict = Field(..., description="网关配置参数")
|
|
|
|
|
|
class GatewayDisconnectRequest(BaseModel):
|
|
"""断开网关请求"""
|
|
gateway_name: str
|
|
|
|
|
|
# ============================================
|
|
# 策略模型
|
|
# ============================================
|
|
|
|
class StrategyStatus(str, Enum):
|
|
"""策略状态"""
|
|
CREATED = "created"
|
|
RUNNING = "running"
|
|
STOPPED = "stopped"
|
|
PAUSED = "paused"
|
|
|
|
|
|
class StrategyInfo(BaseModel):
|
|
"""策略信息"""
|
|
strategy_name: str
|
|
class_name: str
|
|
status: StrategyStatus
|
|
created_at: datetime
|
|
variables: Optional[dict] = None
|
|
|
|
|
|
class StrategyCreateRequest(BaseModel):
|
|
"""创建策略请求"""
|
|
strategy_name: str = Field(..., min_length=1, max_length=50)
|
|
class_name: str = Field(..., description="策略类名")
|
|
setting: dict = Field(default_factory=dict, description="策略参数")
|
|
|
|
|
|
class StrategyInitRequest(BaseModel):
|
|
"""初始化策略请求"""
|
|
strategy_name: str
|
|
|
|
|
|
class StrategyStartRequest(BaseModel):
|
|
"""启动策略请求"""
|
|
strategy_name: str
|
|
|
|
|
|
class StrategyStopRequest(BaseModel):
|
|
"""停止策略请求"""
|
|
strategy_name: str
|
|
|
|
|
|
class StrategyEditRequest(BaseModel):
|
|
"""编辑策略请求"""
|
|
strategy_name: str
|
|
setting: dict
|
|
|
|
|
|
# ============================================
|
|
# 响应模型
|
|
# ============================================
|
|
|
|
class ApiResponse(BaseModel):
|
|
"""通用 API 响应"""
|
|
success: bool
|
|
message: Optional[str] = None
|
|
data: Optional[Any] = None
|
|
|
|
|
|
class PaginatedResponse(BaseModel):
|
|
"""分页响应"""
|
|
total: int
|
|
page: int
|
|
page_size: int
|
|
data: List[Any]
|
|
|
|
|
|
# ============================================
|
|
# 系统模型
|
|
# ============================================
|
|
|
|
class HealthResponse(BaseModel):
|
|
"""健康检查响应"""
|
|
status: str
|
|
service: str
|
|
version: str
|
|
timestamp: datetime
|
|
|
|
|
|
class SystemInfo(BaseModel):
|
|
"""系统信息"""
|
|
version: str
|
|
vnpy_version: str
|
|
python_version: str
|
|
uptime: float
|
|
connected_gateways: int
|
|
active_strategies: int
|
|
|
|
|
|
# ============================================
|
|
# WebSocket 模型
|
|
# ============================================
|
|
|
|
class WSSubscribeRequest(BaseModel):
|
|
"""WebSocket 订阅请求"""
|
|
type: str # tick, order, position, trade
|
|
symbols: Optional[List[str]] = None
|
|
|
|
|
|
class WSMessage(BaseModel):
|
|
"""WebSocket 消息"""
|
|
type: str
|
|
data: Any
|
|
timestamp: datetime
|