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.
buffer_platform/buffer_platform_v2/app/models/analysis.py

322 lines
20 KiB

"""分析相关 ORM 模型 - 14 张表"""
from datetime import datetime
from sqlalchemy import JSON, Boolean, DateTime, Float, Index, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from app.database import Base
class FuturesAnalysis(Base):
"""期货分析报告表。"""
__tablename__ = "futures_analysis"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
symbol: Mapped[str] = mapped_column(String(32), nullable=False, index=True, comment="品种合约代码")
analysis_time: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.now, index=True, comment="分析时间")
period: Mapped[str] = mapped_column(String(16), nullable=False, default="15min", comment="分析周期")
suggestion: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="交易建议")
suggestion_type: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="建议类型: up/down/neutral")
entry_price: Mapped[float | None] = mapped_column(Float, nullable=True, comment="建议入场价")
target_price: Mapped[float | None] = mapped_column(Float, nullable=True, comment="目标价位")
stop_loss: Mapped[float | None] = mapped_column(Float, nullable=True, comment="止损价位")
risk_level: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="风险等级")
macd_signal: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="MACD信号")
rsi_value: Mapped[float | None] = mapped_column(Float, nullable=True, comment="RSI值")
boll_signal: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="布林带信号")
kdj_signal: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="KDJ信号")
trend_score: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="趋势评分 0-100")
success_rate: Mapped[float | None] = mapped_column(Float, nullable=True, comment="交易成功率")
resistance_levels: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="压力位列表")
support_levels: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="支撑位列表")
period_trends: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="各周期趋势")
def __repr__(self) -> str:
return f"<FuturesAnalysis {self.symbol} {self.analysis_time}>"
class WatchedSymbol(Base):
"""用户关注品种表。"""
__tablename__ = "watched_symbols"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
symbol: Mapped[str] = mapped_column(String(32), nullable=False, unique=True, comment="品种合约代码")
name: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="品种名称")
note: Mapped[str | None] = mapped_column(Text, nullable=True, comment="备注")
created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.now)
updated_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)
def __repr__(self) -> str:
return f"<WatchedSymbol {self.symbol}>"
class AIModelConfig(Base):
"""AI模型配置表。"""
__tablename__ = "ai_model_configs"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
provider: Mapped[str] = mapped_column(String(32), nullable=False, comment="AI提供商")
model_name: Mapped[str] = mapped_column(String(64), nullable=False, comment="模型名称")
api_key: Mapped[str] = mapped_column(String(256), nullable=False, comment="API密钥")
api_base: Mapped[str | None] = mapped_column(String(256), nullable=True, comment="API基础URL")
model_id: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="模型ID")
temperature: Mapped[float | None] = mapped_column(Float, nullable=True, default=0.7, comment="温度参数")
max_tokens: Mapped[int | None] = mapped_column(Integer, nullable=True, default=2000, comment="最大输出token")
enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True, comment="是否启用")
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, comment="是否为当前活跃模型")
created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.now)
updated_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)
def __repr__(self) -> str:
return f"<AIModelConfig {self.provider} {self.model_name}>"
class AnalysisSettings(Base):
"""分析设置表(单例配置)。"""
__tablename__ = "analysis_settings"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
key: Mapped[str] = mapped_column(String(64), nullable=False, unique=True, comment="配置键")
value: Mapped[dict] = mapped_column(JSON, nullable=False, comment="配置值")
updated_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)
def __repr__(self) -> str:
return f"<AnalysisSettings {self.key}>"
class AIAnalysisCache(Base):
"""AI分析缓存表。"""
__tablename__ = "ai_analysis_cache"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
symbol: Mapped[str] = mapped_column(String(32), nullable=False, index=True, comment="品种合约代码")
analysis_data: Mapped[dict] = mapped_column(JSON, nullable=False, comment="AI分析结果数据")
kline_timestamp: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, comment="分析时K线数据的时间戳")
created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.now, index=True, comment="分析时间")
def __repr__(self) -> str:
return f"<AIAnalysisCache {self.symbol} {self.created_at}>"
class ReviewDate(Base):
"""复盘日期表。"""
__tablename__ = "review_dates"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
review_date: Mapped[str] = mapped_column(String(16), nullable=False, unique=True, index=True, comment="复盘日期 YYYY-MM-DD")
week_day: Mapped[str | None] = mapped_column(String(8), nullable=True, comment="星期")
created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.now)
def __repr__(self) -> str:
return f"<ReviewDate {self.review_date}>"
class SymbolRanking(Base):
"""品种排名表。"""
__tablename__ = "symbol_rankings"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
review_date_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, comment="关联复盘日期ID")
symbol: Mapped[str] = mapped_column(String(32), nullable=False, comment="品种合约代码")
name: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="品种名称")
rank_type: Mapped[str] = mapped_column(String(32), nullable=False, comment="排名类型")
rank: Mapped[int] = mapped_column(Integer, nullable=False, comment="排名")
value: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="数值")
price: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="价格")
change_pct: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="涨跌幅")
def __repr__(self) -> str:
return f"<SymbolRanking {self.symbol} {self.rank_type} rank={self.rank}>"
class TradingPlan(Base):
"""交易计划表。"""
__tablename__ = "trading_plans"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
review_date_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, comment="关联复盘日期ID")
symbol: Mapped[str] = mapped_column(String(32), nullable=False, comment="品种合约代码")
name: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="品种名称")
plan_type: Mapped[str] = mapped_column(String(16), nullable=False, comment="计划类型: long/short")
score: Mapped[int] = mapped_column(Integer, nullable=False, comment="评分 0-100")
logic: Mapped[str | None] = mapped_column(Text, nullable=True, comment="多空逻辑")
reason: Mapped[str | None] = mapped_column(Text, nullable=True, comment="入选理由")
entry_price: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="入场价位")
stop_loss: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="止损价位")
take_profit: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="止盈价位")
confidence: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="置信度")
position_suggestion: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="仓位建议")
created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.now)
def __repr__(self) -> str:
return f"<TradingPlan {self.symbol} {self.plan_type} score={self.score}>"
class SymbolScoreV2(Base):
"""V2 品种多维度评分表。"""
__tablename__ = "symbol_scores_v2"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
review_date_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, comment="关联复盘日期ID")
symbol: Mapped[str] = mapped_column(String(32), nullable=False, comment="品种合约代码")
name: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="品种名称")
close_price: Mapped[float | None] = mapped_column(Float, nullable=True, comment="收盘价")
prev_close: Mapped[float | None] = mapped_column(Float, nullable=True, comment="昨收价")
high_price: Mapped[float | None] = mapped_column(Float, nullable=True, comment="当日最高")
low_price: Mapped[float | None] = mapped_column(Float, nullable=True, comment="当日最低")
volume: Mapped[float | None] = mapped_column(Float, nullable=True, comment="当日成交量")
avg_volume_5: Mapped[float | None] = mapped_column(Float, nullable=True, comment="近5日均量")
amplitude_score: Mapped[float | None] = mapped_column(Float, nullable=True, comment="振幅得分 0-100")
volume_score: Mapped[float | None] = mapped_column(Float, nullable=True, comment="量能得分 0-100")
change_score: Mapped[float | None] = mapped_column(Float, nullable=True, comment="涨跌幅得分 0-100")
trend_score: Mapped[float | None] = mapped_column(Float, nullable=True, comment="趋势得分 -100~100")
activity_score: Mapped[float | None] = mapped_column(Float, nullable=True, comment="活跃度得分 0-100")
composite_score: Mapped[float | None] = mapped_column(Float, nullable=True, comment="综合评分 0-100")
amplitude_pct: Mapped[float | None] = mapped_column(Float, nullable=True, comment="振幅百分比")
change_pct: Mapped[float | None] = mapped_column(Float, nullable=True, comment="涨跌幅百分比")
volume_ratio: Mapped[float | None] = mapped_column(Float, nullable=True, comment="量比")
trend_60m: Mapped[float | None] = mapped_column(Float, nullable=True, comment="60分钟趋势分")
trend_15m: Mapped[float | None] = mapped_column(Float, nullable=True, comment="15分钟趋势分")
trend_5m: Mapped[float | None] = mapped_column(Float, nullable=True, comment="5分钟趋势分")
direction: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="方向标签")
direction_tag: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="方向标签简写")
category: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="分类: green/yellow/red")
pivot: Mapped[float | None] = mapped_column(Float, nullable=True, comment="枢轴点")
r1: Mapped[float | None] = mapped_column(Float, nullable=True, comment="阻力位1")
r2: Mapped[float | None] = mapped_column(Float, nullable=True, comment="阻力位2")
s1: Mapped[float | None] = mapped_column(Float, nullable=True, comment="支撑位1")
s2: Mapped[float | None] = mapped_column(Float, nullable=True, comment="支撑位2")
rank: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="综合排名")
data_date: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="实际数据日期 YYYY-MM-DD")
def __repr__(self) -> str:
return f"<SymbolScoreV2 {self.symbol} score={self.composite_score}>"
class TradingPlanV2(Base):
"""V2 交易计划表。"""
__tablename__ = "trading_plans_v2"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
review_date_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, comment="关联复盘日期ID")
symbol: Mapped[str] = mapped_column(String(32), nullable=False, comment="品种合约代码")
name: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="品种名称")
direction: Mapped[str] = mapped_column(String(16), nullable=False, comment="方向: long/short")
composite_score: Mapped[float | None] = mapped_column(Float, nullable=True, comment="综合评分")
entry_low: Mapped[float | None] = mapped_column(Float, nullable=True, comment="入场区间下限")
entry_high: Mapped[float | None] = mapped_column(Float, nullable=True, comment="入场区间上限")
stop_loss: Mapped[float | None] = mapped_column(Float, nullable=True, comment="止损位")
target1: Mapped[float | None] = mapped_column(Float, nullable=True, comment="目标位1")
target2: Mapped[float | None] = mapped_column(Float, nullable=True, comment="目标位2")
trigger: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="触发条件")
amplitude_score: Mapped[float | None] = mapped_column(Float, nullable=True, comment="振幅得分")
volume_score: Mapped[float | None] = mapped_column(Float, nullable=True, comment="量能得分")
trend_score: Mapped[float | None] = mapped_column(Float, nullable=True, comment="趋势得分")
activity_score: Mapped[float | None] = mapped_column(Float, nullable=True, comment="活跃度得分")
category: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="分类: green/yellow/red")
def __repr__(self) -> str:
return f"<TradingPlanV2 {self.symbol} {self.direction} score={self.composite_score}>"
class SectorHeat(Base):
"""板块热度表。"""
__tablename__ = "sector_heat"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
review_date_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True, comment="关联复盘日期ID")
sector_name: Mapped[str] = mapped_column(String(32), nullable=False, comment="板块名称")
avg_score: Mapped[float | None] = mapped_column(Float, nullable=True, comment="板块均分")
avg_trend: Mapped[float | None] = mapped_column(Float, nullable=True, comment="平均趋势分")
direction: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="方向")
heat_level: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="热度等级 0-3")
leader_symbol: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="龙头品种代码")
leader_score: Mapped[float | None] = mapped_column(Float, nullable=True, comment="龙头品种评分")
members: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="板块成员")
def __repr__(self) -> str:
return f"<SectorHeat {self.sector_name} avg={self.avg_score}>"
class ReviewPlanV2(Base):
"""V2 复盘计划总表。"""
__tablename__ = "review_plans_v2"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
review_date: Mapped[str] = mapped_column(String(16), nullable=False, unique=True, index=True, comment="复盘日期 YYYY-MM-DD")
week_day: Mapped[str | None] = mapped_column(String(8), nullable=True, comment="星期")
data_basis: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="数据基准说明")
core_conclusion: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="核心结论")
bull_count: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="多头品种数")
bear_count: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="空头品种数")
neutral_count: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="震荡品种数")
opportunity_count: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="交易机会数")
risk_warnings: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="风险提示列表")
actual_data_date: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="实际数据日期")
data_date_matches: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="数据日期是否与复盘日期一致")
created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.now)
def __repr__(self) -> str:
return f"<ReviewPlanV2 {self.review_date}>"
class TradeRecord(Base):
"""交易记录表 - 从期货结算单导入的逐笔交易明细。"""
__tablename__ = "trade_records"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
trade_type: Mapped[str] = mapped_column(String(8), nullable=False, comment="类型: 期货/期权")
symbol: Mapped[str] = mapped_column(String(32), nullable=False, index=True, comment="合约代码")
variety: Mapped[str] = mapped_column(String(16), nullable=False, index=True, comment="品种代码")
symbol_name: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="品种名称")
direction: Mapped[str] = mapped_column(String(8), nullable=False, comment="买卖方向: 买/卖")
offset: Mapped[str | None] = mapped_column(String(8), nullable=True, comment="开平标志: 开/平")
price: Mapped[float | None] = mapped_column(Float, nullable=True, comment="成交价")
volume: Mapped[float | None] = mapped_column(Float, nullable=True, comment="手数")
amount: Mapped[float | None] = mapped_column(Float, nullable=True, comment="成交额")
close_pnl: Mapped[float | None] = mapped_column(Float, nullable=True, default=0.0, comment="平仓盈亏")
commission: Mapped[float | None] = mapped_column(Float, nullable=True, default=0.0, comment="手续费")
trade_date: Mapped[str | None] = mapped_column(String(16), nullable=True, index=True, comment="成交日期 YYYY-MM-DD")
trade_time: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="成交时间 HH:MM:SS")
import_batch: Mapped[str] = mapped_column(String(64), nullable=False, index=True, comment="导入批次号 UUID")
source_file: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="来源文件名")
created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.now)
__table_args__ = (
Index("ix_trade_records_date_variety", "trade_date", "variety"),
)
def __repr__(self) -> str:
return f"<TradeRecord {self.symbol} {self.direction} {self.offset} {self.trade_date}>"
class TradeImportBatch(Base):
"""交易导入批次表。"""
__tablename__ = "trade_import_batches"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
batch_id: Mapped[str] = mapped_column(String(64), nullable=False, unique=True, index=True, comment="批次号 UUID")
source_file: Mapped[str] = mapped_column(String(128), nullable=False, comment="来源文件名")
futures_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, comment="期货交易记录数")
options_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, comment="期权交易记录数")
trade_dates: Mapped[str | None] = mapped_column(String(256), nullable=True, comment="涉及交易日期范围")
created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.now)
def __repr__(self) -> str:
return f"<TradeImportBatch {self.batch_id} {self.source_file}>"