|
|
|
|
|
"""
|
|
|
|
|
|
Pydantic Schemas - 请求/响应数据验证
|
|
|
|
|
|
"""
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
from typing import Optional, List
|
|
|
|
|
|
from pydantic import BaseModel, Field, EmailStr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 通用响应 ====================
|
|
|
|
|
|
|
|
|
|
|
|
class ResponseBase(BaseModel):
|
|
|
|
|
|
"""基础响应"""
|
|
|
|
|
|
code: int = 0
|
|
|
|
|
|
message: str = "success"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ResponseData(ResponseBase):
|
|
|
|
|
|
"""带数据的响应"""
|
|
|
|
|
|
data: Optional[dict] = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ResponseList(ResponseBase):
|
|
|
|
|
|
"""带列表的响应"""
|
|
|
|
|
|
data: List[dict] = []
|
|
|
|
|
|
total: int = 0
|
|
|
|
|
|
page: int = 1
|
|
|
|
|
|
page_size: int = 10
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 认证相关 ====================
|
|
|
|
|
|
|
|
|
|
|
|
class LoginRequest(BaseModel):
|
|
|
|
|
|
"""登录请求"""
|
|
|
|
|
|
username: str = Field(..., min_length=3, max_length=50)
|
|
|
|
|
|
password: str = Field(..., min_length=6)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TokenResponse(BaseModel):
|
|
|
|
|
|
"""令牌响应"""
|
|
|
|
|
|
access_token: str
|
|
|
|
|
|
refresh_token: str
|
|
|
|
|
|
token_type: str = "Bearer"
|
|
|
|
|
|
expires_in: int = 3600
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RefreshTokenRequest(BaseModel):
|
|
|
|
|
|
"""刷新令牌请求"""
|
|
|
|
|
|
refresh_token: str
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 用户相关 ====================
|
|
|
|
|
|
|
|
|
|
|
|
class UserBase(BaseModel):
|
|
|
|
|
|
"""用户基础信息"""
|
|
|
|
|
|
username: str = Field(..., min_length=3, max_length=50)
|
|
|
|
|
|
email: Optional[EmailStr] = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UserCreate(UserBase):
|
|
|
|
|
|
"""创建用户"""
|
|
|
|
|
|
password: str = Field(..., min_length=6)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UserResponse(UserBase):
|
|
|
|
|
|
"""用户响应"""
|
|
|
|
|
|
id: int
|
|
|
|
|
|
role: str
|
|
|
|
|
|
is_active: bool
|
|
|
|
|
|
created_at: datetime
|
|
|
|
|
|
|
|
|
|
|
|
class Config:
|
|
|
|
|
|
from_attributes = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UserUpdate(BaseModel):
|
|
|
|
|
|
"""更新用户"""
|
|
|
|
|
|
email: Optional[EmailStr] = None
|
|
|
|
|
|
password: Optional[str] = Field(None, min_length=6)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== K 线数据相关 ====================
|
|
|
|
|
|
|
|
|
|
|
|
class KlineRequest(BaseModel):
|
|
|
|
|
|
"""K 线数据查询请求"""
|
|
|
|
|
|
symbol: str = Field(..., description="品种代码,如 IF2406")
|
|
|
|
|
|
period: str = Field(..., description="周期,如 1m, 5m, 1h, 1d")
|
|
|
|
|
|
start: datetime
|
|
|
|
|
|
end: datetime
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class KlineDataItem(BaseModel):
|
|
|
|
|
|
"""单条 K 线数据"""
|
|
|
|
|
|
time: datetime
|
|
|
|
|
|
open: float
|
|
|
|
|
|
high: float
|
|
|
|
|
|
low: float
|
|
|
|
|
|
close: float
|
|
|
|
|
|
volume: int
|
|
|
|
|
|
amount: Optional[float] = None
|
|
|
|
|
|
open_interest: Optional[int] = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class KlineResponse(ResponseBase):
|
|
|
|
|
|
"""K 线数据响应"""
|
|
|
|
|
|
data: List[KlineDataItem] = []
|
|
|
|
|
|
symbol: str
|
|
|
|
|
|
period: str
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 实时行情相关 ====================
|
|
|
|
|
|
|
|
|
|
|
|
class RealtimeQuoteItem(BaseModel):
|
|
|
|
|
|
"""实时行情数据"""
|
|
|
|
|
|
time: datetime
|
|
|
|
|
|
symbol: str
|
|
|
|
|
|
last_price: float
|
|
|
|
|
|
open_price: Optional[float] = None
|
|
|
|
|
|
high_price: Optional[float] = None
|
|
|
|
|
|
low_price: Optional[float] = None
|
|
|
|
|
|
prev_close: Optional[float] = None
|
|
|
|
|
|
volume: Optional[int] = None
|
|
|
|
|
|
amount: Optional[float] = None
|
|
|
|
|
|
bid_price_1: Optional[float] = None
|
|
|
|
|
|
bid_volume_1: Optional[int] = None
|
|
|
|
|
|
ask_price_1: Optional[float] = None
|
|
|
|
|
|
ask_volume_1: Optional[int] = None
|
|
|
|
|
|
position: Optional[int] = None
|
|
|
|
|
|
change_percent: Optional[float] = None # 涨跌幅
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SubscribeRequest(BaseModel):
|
|
|
|
|
|
"""订阅请求"""
|
|
|
|
|
|
symbols: List[str] = Field(..., description="品种代码列表")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UnsubscribeRequest(BaseModel):
|
|
|
|
|
|
"""取消订阅请求"""
|
|
|
|
|
|
symbols: List[str] = Field(..., description="品种代码列表")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 告警相关 ====================
|
|
|
|
|
|
|
|
|
|
|
|
class AlertBase(BaseModel):
|
|
|
|
|
|
"""告警基础信息"""
|
|
|
|
|
|
symbol: str = Field(..., description="品种代码")
|
|
|
|
|
|
condition_type: str = Field(..., description="条件类型:greater_than, less_than, equals")
|
|
|
|
|
|
condition_value: float = Field(..., description="条件值")
|
|
|
|
|
|
alert_type: str = Field(default="price", description="告警类型:price, percent_change")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AlertCreate(AlertBase):
|
|
|
|
|
|
"""创建告警"""
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AlertResponse(AlertBase):
|
|
|
|
|
|
"""告警响应"""
|
|
|
|
|
|
id: int
|
|
|
|
|
|
user_id: int
|
|
|
|
|
|
status: str
|
|
|
|
|
|
triggered_at: Optional[datetime] = None
|
|
|
|
|
|
created_at: datetime
|
|
|
|
|
|
updated_at: datetime
|
|
|
|
|
|
|
|
|
|
|
|
class Config:
|
|
|
|
|
|
from_attributes = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AlertUpdate(BaseModel):
|
|
|
|
|
|
"""更新告警"""
|
|
|
|
|
|
condition_value: Optional[float] = None
|
|
|
|
|
|
status: Optional[str] = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 订阅相关 ====================
|
|
|
|
|
|
|
|
|
|
|
|
class SubscriptionBase(BaseModel):
|
|
|
|
|
|
"""订阅基础信息"""
|
|
|
|
|
|
symbol: str = Field(..., description="品种代码")
|
|
|
|
|
|
period: Optional[str] = Field(None, description="周期")
|
|
|
|
|
|
subscription_type: str = Field(default="kline", description="订阅类型:kline, realtime")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SubscriptionCreate(SubscriptionBase):
|
|
|
|
|
|
"""创建订阅"""
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SubscriptionResponse(SubscriptionBase):
|
|
|
|
|
|
"""订阅响应"""
|
|
|
|
|
|
id: int
|
|
|
|
|
|
user_id: int
|
|
|
|
|
|
is_active: bool
|
|
|
|
|
|
created_at: datetime
|
|
|
|
|
|
|
|
|
|
|
|
class Config:
|
|
|
|
|
|
from_attributes = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== API Key 相关 ====================
|
|
|
|
|
|
|
|
|
|
|
|
class APIKeyCreate(BaseModel):
|
|
|
|
|
|
"""创建 API Key"""
|
|
|
|
|
|
name: Optional[str] = None
|
|
|
|
|
|
permissions: Optional[List[str]] = None
|
|
|
|
|
|
expires_days: Optional[int] = None # 过期天数
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class APIKeyResponse(BaseModel):
|
|
|
|
|
|
"""API Key 响应"""
|
|
|
|
|
|
id: int
|
|
|
|
|
|
name: Optional[str]
|
|
|
|
|
|
key: str # 仅创建时返回
|
|
|
|
|
|
permissions: Optional[List[str]]
|
|
|
|
|
|
expires_at: Optional[datetime]
|
|
|
|
|
|
is_active: bool
|
|
|
|
|
|
created_at: datetime
|
|
|
|
|
|
|
|
|
|
|
|
class Config:
|
|
|
|
|
|
from_attributes = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==================== 分页参数 ====================
|
|
|
|
|
|
|
|
|
|
|
|
class PageParams(BaseModel):
|
|
|
|
|
|
"""分页参数"""
|
|
|
|
|
|
page: int = Field(1, ge=1)
|
|
|
|
|
|
page_size: int = Field(10, ge=1, le=100)
|