You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

229 lines
5.4 KiB

"""
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)