astock-agent/backend/app/data/models.py
2026-04-22 11:02:19 +08:00

179 lines
6.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Pydantic 数据模型"""
from pydantic import BaseModel
from datetime import datetime
class StockQuote(BaseModel):
ts_code: str
name: str
price: float
pct_chg: float
volume: float # 成交量(手)
amount: float # 成交额(万元)
turnover_rate: float # 换手率 %
pe: float | None = None
pb: float | None = None
circ_mv: float | None = None # 流通市值(亿)
total_mv: float | None = None # 总市值(亿)
volume_ratio: float | None = None # 量比
high: float | None = None
low: float | None = None
open: float | None = None
pre_close: float | None = None
limit_up: float | None = None
limit_down: float | None = None
amplitude: float | None = None # 振幅 %
class CapitalFlow(BaseModel):
ts_code: str
trade_date: str
buy_elg_amount: float = 0 # 特大单买入(万)
sell_elg_amount: float = 0
buy_lg_amount: float = 0 # 大单买入(万)
sell_lg_amount: float = 0
buy_md_amount: float = 0 # 中单买入(万)
sell_md_amount: float = 0
buy_sm_amount: float = 0 # 小单买入(万)
sell_sm_amount: float = 0
net_mf_amount: float = 0 # 主力净流入(万)
@property
def main_net_inflow(self) -> float:
"""主力净流入 = 特大单净买 + 大单净买"""
return (self.buy_elg_amount - self.sell_elg_amount +
self.buy_lg_amount - self.sell_lg_amount)
@property
def total_amount(self) -> float:
return (self.buy_elg_amount + self.sell_elg_amount +
self.buy_lg_amount + self.sell_lg_amount +
self.buy_md_amount + self.sell_md_amount +
self.buy_sm_amount + self.sell_sm_amount)
class SectorInfo(BaseModel):
sector_code: str
sector_name: str
pct_change: float = 0 # 涨跌幅 %
capital_inflow: float = 0 # 主力净流入万元原始数据来自Tushare亿元×10000
limit_up_count: int = 0 # 涨停数
days_continuous: int = 0 # 连续资金流入天数
heat_score: float = 0 # 热度综合评分
stage: str = "mid" # 板块阶段: early/mid/late/end
# ── 板块分析增强字段 ──
member_count: int = 0 # 成分股数量
leading_stocks: list[dict] = [] # 领涨股 [{ts_code, name, pct_chg, amount}]
capital_trend: list[float] = [] # 近5日资金净流入趋势
pct_trend: list[float] = [] # 近5日涨跌幅趋势
turnover_avg: float = 0 # 板块平均换手率
main_force_ratio: float = 0 # 主力资金占比(主力净流入/总成交额)
class MarketTemperature(BaseModel):
trade_date: str
up_count: int = 0 # 上涨家数
down_count: int = 0 # 下跌家数
limit_up_count: int = 0 # 涨停数(自然涨停)
limit_down_count: int = 0 # 跌停数
max_streak: int = 0 # 最高连板
broken_rate: float = 0 # 炸板率 %
index_above_ma20: bool = False # 上证在 MA20 上方
temperature: float = 0 # 综合温度 0-100
class TechnicalSignal(BaseModel):
ts_code: str
name: str = ""
ma_bullish: bool = False # 均线多头排列
volume_breakout: bool = False # 放量突破
macd_golden: bool = False # MACD金叉
rsi_healthy: bool = False # RSI健康区间
pullback_support: bool = False # 缩量回踩支撑
big_yang: bool = False # 底部放量长阳
boll_support: bool = False # 布林带下轨支撑
score: float = 0 # 信号触发计数分
trend_score: float = 0 # 趋势评分(推荐体系用的技术面分数)
signal_count: int = 0 # 满足的信号数量
# 位置安全评估(防追高)
rally_pct_5d: float = 0 # 近5日累计涨幅
rally_pct_10d: float = 0 # 近10日累计涨幅
distance_from_high: float = 0 # 距离60日高点 %(负=已回调)
position_score: float = 50 # 位置安全得分 0-100
# 价格参考
support_price: float | None = None # 支撑位
resist_price: float | None = None # 压力位
stop_loss_price: float | None = None # 止损价
class Recommendation(BaseModel):
ts_code: str
name: str
sector: str
score: float # 综合评分
market_temp_score: float
sector_score: float
capital_score: float
technical_score: float
supply_demand_score: float = 0 # 供需评分主评分50%权重)
price_action_score: float = 0 # 价格行为评分主评分40%权重)
position_score: float = 50 # 位置安全得分
valuation_score: float = 50 # 估值安全得分
signal: str # BUY / SELL / HOLD
entry_price: float | None = None
target_price: float | None = None
stop_loss: float | None = None
reasons: list[str] = []
risk_note: str = ""
level: str = "" # 强烈推荐/推荐/观望/回避
strategy: str = "trend_breakout" # trend_breakout / momentum(旧) / potential(旧)
entry_signal_type: str = "none" # breakout / pullback / launch / none
entry_timing: str = "" # 进场时机建议(盘中适用)
action_plan: str = "观察" # 可操作 / 重点关注 / 观察
trigger_condition: str = "" # 触发条件
invalidation_condition: str = "" # 失效条件
suggested_position_pct: float = 0 # 建议仓位 %
review_after_days: int = 3 # 建议复盘天数
lifecycle_status: str = "candidate" # candidate / actionable / tracking / closed
data_freshness: str = "" # 数据新鲜度说明
llm_analysis: str = "" # LLM 深度分析
llm_score: float | None = None # AI 评分 1-10
scan_session: str = ""
created_at: datetime | None = None
class StrategyFocus(BaseModel):
label: str
description: str
class StrategySectorFocus(BaseModel):
sector_name: str
stage: str = "mid"
heat_score: float = 0
pct_change: float = 0
limit_up_count: int = 0
view: str = ""
class StrategyBoard(BaseModel):
trade_date: str
market_regime: str
risk_level: str
action_bias: str
position_suggestion: str
summary: str
recommended_mode: str
strategy_focus: list[StrategyFocus] = []
watch_sectors: list[StrategySectorFocus] = []
avoid_rules: list[str] = []
iteration_notes: list[str] = []
iteration_report: dict = {}
metrics: dict = {}
ai_review: str = ""
generated_by: str = "rules"