Coverage for core/models/asset.py: 100.00%

189 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-10-13 18:58 +0000

1""" 

2资产相关数据模型 

3""" 

4 

5from datetime import datetime 

6from decimal import Decimal 

7from enum import Enum 

8from typing import Dict, List, Optional 

9 

10from pydantic import BaseModel, Field 

11 

12 

13class CurrencyType(str, Enum): 

14 """货币类型枚举""" 

15 

16 USD = "USD" # 美元 

17 HKD = "HKD" # 港币 

18 CNY = "CNY" # 人民币 

19 

20 

21class MarketType(str, Enum): 

22 """市场类型枚举""" 

23 

24 US = "US" # 美股 

25 HK = "HK" # 港股 

26 CN = "CN" # A股 

27 SG = "SG" # 新加坡 

28 CRYPTO = "CRYPTO" # 加密货币 

29 

30 

31class AssetType(str, Enum): 

32 """资产类型枚举""" 

33 

34 STOCK = "stock" # 股票 

35 FUND = "fund" # 基金 

36 CASH = "cash" # 现金 

37 BOND = "bond" # 债券 

38 OPTION = "option" # 期权 

39 WARRANT = "warrant" # 权证 

40 

41 

42class CashInfo(BaseModel): 

43 """现金信息""" 

44 

45 withdraw_cash: Decimal = Field(..., description="可提取现金") 

46 available_cash: Decimal = Field(..., description="可用现金") 

47 frozen_cash: Decimal = Field(..., description="冻结现金") 

48 settling_cash: Decimal = Field(..., description="待结算现金") 

49 currency: CurrencyType = Field(..., description="货币类型") 

50 

51 

52class AccountBalance(BaseModel): 

53 """账户余额""" 

54 

55 total_cash: Decimal = Field(..., description="总现金") 

56 max_finance_amount: Decimal = Field(..., description="最大融资额度") 

57 remaining_finance_amount: Decimal = Field(..., description="剩余融资额度") 

58 risk_level: int = Field(..., description="风险等级") 

59 margin_call: Decimal = Field(..., description="保证金追缴") 

60 currency: CurrencyType = Field(..., description="货币类型") 

61 cash_infos: List[CashInfo] = Field(..., description="现金详情") 

62 net_assets: Decimal = Field(..., description="净资产") 

63 init_margin: Decimal = Field(..., description="初始保证金") 

64 maintenance_margin: Decimal = Field(..., description="维持保证金") 

65 buy_power: Decimal = Field(..., description="购买力") 

66 

67 

68class StockPosition(BaseModel): 

69 """股票持仓""" 

70 

71 symbol: str = Field(..., description="股票代码") 

72 symbol_name: str = Field(..., description="股票名称") 

73 quantity: Decimal = Field(..., description="持仓数量") 

74 available_quantity: Decimal = Field(..., description="可用数量") 

75 currency: CurrencyType = Field(..., description="货币类型") 

76 cost_price: Decimal = Field(..., description="成本价") 

77 market: MarketType = Field(..., description="市场类型") 

78 init_quantity: Optional[Decimal] = Field(None, description="开盘前初始持仓") 

79 

80 

81class FundPosition(BaseModel): 

82 """基金持仓""" 

83 

84 symbol: str = Field(..., description="基金代码") 

85 current_net_asset_value: Decimal = Field(..., description="当前净值") 

86 net_asset_value_day: datetime = Field(..., description="净值日期") 

87 symbol_name: str = Field(..., description="基金名称") 

88 currency: CurrencyType = Field(..., description="货币类型") 

89 cost_net_asset_value: Decimal = Field(..., description="成本净值") 

90 holding_units: Decimal = Field(..., description="持有份额") 

91 

92 

93class UserAsset(BaseModel): 

94 """用户资产(只存储现金,总资产动态计算)""" 

95 

96 user_id: str = Field(..., description="用户ID") 

97 cash_assets: Decimal = Field(..., description="现金资产") 

98 currency: CurrencyType = Field(default=CurrencyType.USD, description="默认货币") 

99 updated_at: datetime = Field(..., description="更新时间") 

100 

101 

102class UserAssetCreate(BaseModel): 

103 """创建用户资产(只存储现金,总资产动态计算)""" 

104 

105 user_id: str = Field(..., description="用户ID") 

106 cash_assets: Decimal = Field(..., description="现金资产") 

107 currency: CurrencyType = Field(default=CurrencyType.USD, description="默认货币") 

108 

109 

110class UserAssetUpdate(BaseModel): 

111 """更新用户资产""" 

112 

113 total_assets: Optional[Decimal] = None 

114 cash_assets: Optional[Decimal] = None 

115 position_assets: Optional[Decimal] = None 

116 today_pnl: Optional[Decimal] = None 

117 currency: Optional[CurrencyType] = None 

118 

119 

120class UserAssetResponse(UserAsset): 

121 """用户资产响应""" 

122 

123 id: str = Field(..., description="资产ID") 

124 created_at: datetime = Field(..., description="创建时间") 

125 

126 class Config: 

127 from_attributes = True 

128 

129 

130class UserPosition(BaseModel): 

131 """用户持仓""" 

132 

133 user_id: str = Field(..., description="用户ID") 

134 symbol: str = Field(..., description="证券代码") 

135 symbol_name: str = Field(..., description="证券名称") 

136 asset_type: AssetType = Field(..., description="资产类型") 

137 quantity: Decimal = Field(..., description="持仓数量") 

138 available_quantity: Decimal = Field(..., description="可用数量") 

139 cost_price: Decimal = Field(..., description="成本价") 

140 current_price: Optional[Decimal] = Field(None, description="当前价格") 

141 market: MarketType = Field(..., description="市场类型") 

142 currency: CurrencyType = Field(..., description="货币类型") 

143 updated_at: datetime = Field(..., description="更新时间") 

144 

145 

146class UserPositionCreate(BaseModel): 

147 """创建用户持仓""" 

148 

149 user_id: str = Field(..., description="用户ID") 

150 symbol: str = Field(..., description="证券代码") 

151 symbol_name: str = Field(..., description="证券名称") 

152 asset_type: AssetType = Field(..., description="资产类型") 

153 quantity: Decimal = Field(..., description="持仓数量") 

154 available_quantity: Decimal = Field(..., description="可用数量") 

155 cost_price: Decimal = Field(..., description="成本价") 

156 current_price: Optional[Decimal] = Field(None, description="现价") 

157 market: MarketType = Field(..., description="市场") 

158 currency: CurrencyType = Field(..., description="货币") 

159 

160 

161class UserPositionUpdate(BaseModel): 

162 """更新用户持仓""" 

163 

164 symbol_name: Optional[str] = None 

165 quantity: Optional[Decimal] = None 

166 available_quantity: Optional[Decimal] = None 

167 cost_price: Optional[Decimal] = None 

168 current_price: Optional[Decimal] = None 

169 currency: Optional[CurrencyType] = None 

170 

171 

172class UserPositionResponse(UserPosition): 

173 """用户持仓响应""" 

174 

175 id: str = Field(..., description="持仓ID") 

176 created_at: datetime = Field(..., description="创建时间") 

177 

178 class Config: 

179 from_attributes = True 

180 

181 

182# 模拟资产相关模型 

183class SimulatedAsset(BaseModel): 

184 """模拟资产(只存储现金,总资产动态计算)""" 

185 

186 user_id: str = Field(..., description="用户ID") 

187 cash_assets: Decimal = Field(..., description="现金资产") 

188 currency: CurrencyType = Field(default=CurrencyType.USD, description="默认货币") 

189 updated_at: datetime = Field(..., description="更新时间") 

190 

191 

192class SimulatedAssetCreate(BaseModel): 

193 """创建模拟资产(只存储现金,总资产动态计算)""" 

194 

195 user_id: str = Field(..., description="用户ID") 

196 cash_assets: Decimal = Field(..., description="现金资产") 

197 currency: CurrencyType = Field(default=CurrencyType.USD, description="默认货币") 

198 

199 

200class SimulatedAssetUpdate(BaseModel): 

201 """更新模拟资产(只支持现金编辑)""" 

202 

203 cash_assets: Decimal = Field(..., description="现金资产") 

204 currency: CurrencyType = Field(..., description="货币类型") 

205 

206 

207class SimulatedAssetResponse(SimulatedAsset): 

208 """模拟资产响应""" 

209 

210 id: str = Field(..., description="模拟资产ID") 

211 created_at: datetime = Field(..., description="创建时间") 

212 

213 class Config: 

214 from_attributes = True 

215 

216 

217class SimulatedPosition(BaseModel): 

218 """模拟持仓""" 

219 

220 user_id: str = Field(..., description="用户ID") 

221 symbol: str = Field(..., description="证券代码") 

222 symbol_name: str = Field(..., description="证券名称") 

223 asset_type: AssetType = Field(..., description="资产类型") 

224 quantity: Decimal = Field(..., description="持仓数量") 

225 cost_price: Decimal = Field(..., description="成本价") 

226 current_price: Optional[Decimal] = Field(None, description="当前价格") 

227 market: MarketType = Field(..., description="市场类型") 

228 currency: CurrencyType = Field(..., description="货币类型") 

229 updated_at: datetime = Field(..., description="更新时间") 

230 

231 

232class SimulatedPositionCreate(BaseModel): 

233 """创建模拟持仓""" 

234 

235 user_id: str = Field(..., description="用户ID") 

236 symbol: str = Field(..., description="证券代码") 

237 symbol_name: str = Field(..., description="证券名称") 

238 asset_type: AssetType = Field(..., description="资产类型") 

239 quantity: Decimal = Field(..., description="持仓数量") 

240 cost_price: Decimal = Field(..., description="成本价") 

241 current_price: Optional[Decimal] = Field(None, description="现价") 

242 market: MarketType = Field(..., description="市场") 

243 currency: CurrencyType = Field(..., description="货币") 

244 

245 

246class SimulatedPositionUpdate(BaseModel): 

247 """更新模拟持仓""" 

248 

249 symbol_name: Optional[str] = None 

250 quantity: Optional[Decimal] = None 

251 cost_price: Optional[Decimal] = None 

252 current_price: Optional[Decimal] = None 

253 currency: Optional[CurrencyType] = None 

254 

255 

256class SimulatedPositionResponse(SimulatedPosition): 

257 """模拟持仓响应""" 

258 

259 id: str = Field(..., description="模拟持仓ID") 

260 created_at: datetime = Field(..., description="创建时间") 

261 

262 class Config: 

263 from_attributes = True 

264 

265 

266# 同步相关模型 

267class SyncRequest(BaseModel): 

268 """同步请求""" 

269 

270 user_id: str = Field(..., description="用户ID") 

271 broker_id: Optional[str] = Field(None, description="券商ID") 

272 

273 

274class SyncResponse(BaseModel): 

275 """同步响应""" 

276 

277 success: bool = Field(..., description="同步结果") 

278 message: str = Field(..., description="同步消息") 

279 synced_assets: Optional[UserAssetResponse] = Field(None, description="同步后的资产") 

280 synced_positions: Optional[List[UserPositionResponse]] = Field( 

281 None, description="同步后的持仓" 

282 ) 

283 

284 

285# 资产概览响应模型 

286class AssetOverview(BaseModel): 

287 """资产概览(支持多货币)""" 

288 

289 # 多货币资产数据 

290 total_assets_by_currency: Optional[Dict[CurrencyType, Dict[str, Decimal]]] = Field( 

291 None, description="按货币分组的总资产" 

292 ) 

293 cash_assets_by_currency: Optional[Dict[CurrencyType, Decimal]] = Field( 

294 None, description="按货币分组的现金资产" 

295 ) 

296 position_assets_by_currency: Optional[Dict[CurrencyType, Decimal]] = Field( 

297 None, description="按货币分组的持仓资产" 

298 ) 

299 positions_by_currency: Optional[Dict[CurrencyType, List[UserPositionResponse]]] = ( 

300 Field(None, description="按货币分组的持仓") 

301 ) 

302 

303 # 兼容性字段(用于单货币显示) 

304 total_assets: Optional[Decimal] = Field(None, description="总资产(主要货币)") 

305 cash_assets: Optional[Decimal] = Field(None, description="现金资产(主要货币)") 

306 position_assets: Optional[Decimal] = Field(None, description="持仓资产(主要货币)") 

307 today_pnl: Optional[Decimal] = Field(None, description="今日盈亏") 

308 currency: Optional[CurrencyType] = Field(None, description="主要货币类型") 

309 positions: List[UserPositionResponse] = Field( 

310 default=[], description="所有持仓列表" 

311 ) 

312 

313 

314class SimulatedAssetOverview(BaseModel): 

315 """模拟资产概览(支持多货币)""" 

316 

317 # 多货币资产数据 

318 total_assets_by_currency: Optional[Dict[CurrencyType, Dict[str, Decimal]]] = Field( 

319 None, description="按货币分组的总资产" 

320 ) 

321 positions_by_currency: Optional[ 

322 Dict[CurrencyType, List[SimulatedPositionResponse]] 

323 ] = Field(None, description="按货币分组的持仓") 

324 

325 # 兼容性字段(用于单货币显示) 

326 total_assets: Optional[Decimal] = Field(None, description="总资产(主要货币)") 

327 cash_assets: Optional[Decimal] = Field(None, description="现金资产(主要货币)") 

328 position_assets: Optional[Decimal] = Field(None, description="持仓资产(主要货币)") 

329 today_pnl: Optional[Decimal] = Field(None, description="今日盈亏") 

330 currency: Optional[CurrencyType] = Field(None, description="主要货币类型") 

331 positions: List[SimulatedPositionResponse] = Field( 

332 default=[], description="所有模拟持仓列表" 

333 )