"""分析相关 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"" 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"" 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"" 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"" 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"" 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"" 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"" 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"" 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"" 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"" 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"" 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"" 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"" 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""