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/app/analysis_models.py

450 lines
23 KiB

"""
期货智析数据模型
"""
from datetime import datetime
from sqlalchemy import Column, String, Integer, Float, Text, DateTime, Boolean, Index, UniqueConstraint, JSON
from app.analysis_db import AnalysisBase
class FuturesAnalysis(AnalysisBase):
"""期货分析报告表"""
__tablename__ = "futures_analysis"
id = Column(Integer, primary_key=True, autoincrement=True)
symbol = Column(String(32), nullable=False, index=True, comment="品种合约代码")
analysis_time = Column(DateTime, nullable=False, default=datetime.now, index=True, comment="分析时间")
period = Column(String(16), nullable=False, default="15min", comment="分析周期")
# 分析结果
suggestion = Column(String(32), nullable=True, comment="交易建议: 逢低做多/逢高做空/观望等待")
suggestion_type = Column(String(16), nullable=True, comment="建议类型: up/down/neutral")
entry_price = Column(Float, nullable=True, comment="建议入场价")
target_price = Column(Float, nullable=True, comment="目标价位")
stop_loss = Column(Float, nullable=True, comment="止损价位")
risk_level = Column(String(16), nullable=True, comment="风险等级: 低/中/高")
# 技术指标
macd_signal = Column(String(16), nullable=True, comment="MACD信号")
rsi_value = Column(Float, nullable=True, comment="RSI值")
boll_signal = Column(String(16), nullable=True, comment="布林带信号")
kdj_signal = Column(String(16), nullable=True, comment="KDJ信号")
# 趋势评分
trend_score = Column(Integer, nullable=True, comment="趋势评分 0-100")
success_rate = Column(Float, nullable=True, comment="交易成功率")
# 关键点位
resistance_levels = Column(JSON, nullable=True, comment="压力位列表")
support_levels = Column(JSON, nullable=True, comment="支撑位列表")
# 多周期趋势
period_trends = Column(JSON, nullable=True, comment="各周期趋势")
def __repr__(self):
return f"<FuturesAnalysis {self.symbol} {self.analysis_time}>"
class WatchedSymbol(AnalysisBase):
"""用户关注品种表"""
__tablename__ = "watched_symbols"
id = Column(Integer, primary_key=True, autoincrement=True)
symbol = Column(String(32), nullable=False, unique=True, comment="品种合约代码")
name = Column(String(64), nullable=True, comment="品种名称")
note = Column(Text, nullable=True, comment="备注")
created_at = Column(DateTime, nullable=False, default=datetime.now)
updated_at = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)
def __repr__(self):
return f"<WatchedSymbol {self.symbol}>"
class AIModelConfig(AnalysisBase):
"""AI模型配置表"""
__tablename__ = "ai_model_configs"
id = Column(Integer, primary_key=True, autoincrement=True)
provider = Column(String(32), nullable=False, comment="AI提供商: openai/anthropic/google等")
model_name = Column(String(64), nullable=False, comment="模型名称")
api_key = Column(String(256), nullable=False, comment="API密钥")
api_base = Column(String(256), nullable=True, comment="API基础URL")
model_id = Column(String(64), nullable=True, comment="模型ID")
temperature = Column(Float, nullable=True, default=0.7, comment="温度参数")
max_tokens = Column(Integer, nullable=True, default=2000, comment="最大输出token")
enabled = Column(Boolean, nullable=False, default=True, comment="是否启用")
is_active = Column(Boolean, nullable=False, default=False, comment="是否为当前活跃模型")
created_at = Column(DateTime, nullable=False, default=datetime.now)
updated_at = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)
def __repr__(self):
return f"<AIModelConfig {self.provider} {self.model_name}>"
class AnalysisSettings(AnalysisBase):
"""分析设置表(单例配置)"""
__tablename__ = "analysis_settings"
id = Column(Integer, primary_key=True, autoincrement=True)
key = Column(String(64), nullable=False, unique=True, comment="配置键")
value = Column(JSON, nullable=False, comment="配置值")
updated_at = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)
def __repr__(self):
return f"<AnalysisSettings {self.key}>"
class AIAnalysisCache(AnalysisBase):
"""AI分析缓存表"""
__tablename__ = "ai_analysis_cache"
id = Column(Integer, primary_key=True, autoincrement=True)
symbol = Column(String(32), nullable=False, index=True, comment="品种合约代码")
analysis_data = Column(JSON, nullable=False, comment="AI分析结果数据")
kline_timestamp = Column(DateTime, nullable=True, comment="分析时K线数据的时间戳")
created_at = Column(DateTime, nullable=False, default=datetime.now, index=True, comment="分析时间")
def __repr__(self):
return f"<AIAnalysisCache {self.symbol} {self.created_at}>"
class ReviewDate(AnalysisBase):
"""复盘日期表"""
__tablename__ = "review_dates"
id = Column(Integer, primary_key=True, autoincrement=True)
review_date = Column(String(16), nullable=False, unique=True, index=True, comment="复盘日期 YYYY-MM-DD")
week_day = Column(String(8), nullable=True, comment="星期")
created_at = Column(DateTime, nullable=False, default=datetime.now)
def __repr__(self):
return f"<ReviewDate {self.review_date}>"
class SymbolRanking(AnalysisBase):
"""品种排名表"""
__tablename__ = "symbol_rankings"
id = Column(Integer, primary_key=True, autoincrement=True)
review_date_id = Column(Integer, nullable=False, index=True, comment="关联复盘日期ID")
symbol = Column(String(32), nullable=False, comment="品种合约代码")
name = Column(String(64), nullable=True, comment="品种名称")
rank_type = Column(String(32), nullable=False, comment="排名类型: volume/amplitude/change/open_interest")
rank = Column(Integer, nullable=False, comment="排名")
value = Column(String(64), nullable=True, comment="数值(如成交量、振幅等)")
price = Column(String(32), nullable=True, comment="价格")
change_pct = Column(String(16), nullable=True, comment="涨跌幅")
def __repr__(self):
return f"<SymbolRanking {self.symbol} {self.rank_type} rank={self.rank}>"
class TradingPlan(AnalysisBase):
"""交易计划表"""
__tablename__ = "trading_plans"
id = Column(Integer, primary_key=True, autoincrement=True)
review_date_id = Column(Integer, nullable=False, index=True, comment="关联复盘日期ID")
symbol = Column(String(32), nullable=False, comment="品种合约代码")
name = Column(String(64), nullable=True, comment="品种名称")
plan_type = Column(String(16), nullable=False, comment="计划类型: long/short")
score = Column(Integer, nullable=False, comment="评分 0-100")
logic = Column(Text, nullable=True, comment="多空逻辑")
reason = Column(Text, nullable=True, comment="入选理由")
entry_price = Column(String(64), nullable=True, comment="入场价位")
stop_loss = Column(String(32), nullable=True, comment="止损价位")
take_profit = Column(String(64), nullable=True, comment="止盈价位")
confidence = Column(String(16), nullable=True, comment="置信度: 高/中高/中/低")
position_suggestion = Column(String(32), nullable=True, comment="仓位建议")
created_at = Column(DateTime, nullable=False, default=datetime.now)
def __repr__(self):
return f"<TradingPlan {self.symbol} {self.plan_type} score={self.score}>"
# ==================== V2 复盘计划模型 ====================
class SymbolScoreV2(AnalysisBase):
"""V2 品种多维度评分表"""
__tablename__ = "symbol_scores_v2"
id = Column(Integer, primary_key=True, autoincrement=True)
review_date_id = Column(Integer, nullable=False, index=True, comment="关联复盘日期ID")
symbol = Column(String(32), nullable=False, comment="品种合约代码")
name = Column(String(64), nullable=True, comment="品种名称")
close_price = Column(Float, nullable=True, comment="收盘价")
prev_close = Column(Float, nullable=True, comment="昨收价")
high_price = Column(Float, nullable=True, comment="当日最高")
low_price = Column(Float, nullable=True, comment="当日最低")
volume = Column(Float, nullable=True, comment="当日成交量")
avg_volume_5 = Column(Float, nullable=True, comment="近5日均量")
# 5维度评分
amplitude_score = Column(Float, nullable=True, comment="振幅得分 0-100")
volume_score = Column(Float, nullable=True, comment="量能得分 0-100")
change_score = Column(Float, nullable=True, comment="涨跌幅得分 0-100")
trend_score = Column(Float, nullable=True, comment="趋势得分 -100~100")
activity_score = Column(Float, nullable=True, comment="活跃度得分 0-100")
# 综合
composite_score = Column(Float, nullable=True, comment="综合评分 0-100")
# 原始数据
amplitude_pct = Column(Float, nullable=True, comment="振幅百分比")
change_pct = Column(Float, nullable=True, comment="涨跌幅百分比")
volume_ratio = Column(Float, nullable=True, comment="量比")
# 趋势明细
trend_60m = Column(Float, nullable=True, comment="60分钟趋势分")
trend_15m = Column(Float, nullable=True, comment="15分钟趋势分")
trend_5m = Column(Float, nullable=True, comment="5分钟趋势分")
# 方向标签
direction = Column(String(32), nullable=True, comment="方向标签: 多头共振/空头共振/偏多震荡/偏空震荡/多空交织")
direction_tag = Column(String(16), nullable=True, comment="方向标签简写: 强多/偏多/震荡/偏空/强空")
category = Column(String(16), nullable=True, comment="分类: green(交易机会)/yellow(重点关注)/red(规避)")
# 关键点位
pivot = Column(Float, nullable=True, comment="枢轴点")
r1 = Column(Float, nullable=True, comment="阻力位1")
r2 = Column(Float, nullable=True, comment="阻力位2")
s1 = Column(Float, nullable=True, comment="支撑位1")
s2 = Column(Float, nullable=True, comment="支撑位2")
# 排名
rank = Column(Integer, nullable=True, comment="综合排名")
# 实际数据日期
data_date = Column(String(16), nullable=True, comment="实际数据日期 YYYY-MM-DD日线最后一根K线的日期")
def __repr__(self):
return f"<SymbolScoreV2 {self.symbol} score={self.composite_score}>"
class TradingPlanV2(AnalysisBase):
"""V2 交易计划表"""
__tablename__ = "trading_plans_v2"
id = Column(Integer, primary_key=True, autoincrement=True)
review_date_id = Column(Integer, nullable=False, index=True, comment="关联复盘日期ID")
symbol = Column(String(32), nullable=False, comment="品种合约代码")
name = Column(String(64), nullable=True, comment="品种名称")
direction = Column(String(16), nullable=False, comment="方向: long/short")
composite_score = Column(Float, nullable=True, comment="综合评分")
# 交易计划
entry_low = Column(Float, nullable=True, comment="入场区间下限")
entry_high = Column(Float, nullable=True, comment="入场区间上限")
stop_loss = Column(Float, nullable=True, comment="止损位")
target1 = Column(Float, nullable=True, comment="目标位1")
target2 = Column(Float, nullable=True, comment="目标位2")
trigger = Column(String(128), nullable=True, comment="触发条件")
# 评分明细
amplitude_score = Column(Float, nullable=True, comment="振幅得分")
volume_score = Column(Float, nullable=True, comment="量能得分")
trend_score = Column(Float, nullable=True, comment="趋势得分")
activity_score = Column(Float, nullable=True, comment="活跃度得分")
# 分类
category = Column(String(16), nullable=True, comment="分类: green/yellow/red")
def __repr__(self):
return f"<TradingPlanV2 {self.symbol} {self.direction} score={self.composite_score}>"
class SectorHeat(AnalysisBase):
"""板块热度表"""
__tablename__ = "sector_heat"
id = Column(Integer, primary_key=True, autoincrement=True)
review_date_id = Column(Integer, nullable=False, index=True, comment="关联复盘日期ID")
sector_name = Column(String(32), nullable=False, comment="板块名称")
avg_score = Column(Float, nullable=True, comment="板块均分")
avg_trend = Column(Float, nullable=True, comment="平均趋势分")
direction = Column(String(16), nullable=True, comment="方向: 多头/空头/震荡")
heat_level = Column(Integer, nullable=True, comment="热度等级 0-3")
leader_symbol = Column(String(32), nullable=True, comment="龙头品种代码")
leader_score = Column(Float, nullable=True, comment="龙头品种评分")
members = Column(JSON, nullable=True, comment="板块成员 [{symbol, name, score}]")
def __repr__(self):
return f"<SectorHeat {self.sector_name} avg={self.avg_score}>"
class ReviewPlanV2(AnalysisBase):
"""V2 复盘计划总表 - 存储每次生成的完整报告元数据"""
__tablename__ = "review_plans_v2"
id = Column(Integer, primary_key=True, autoincrement=True)
review_date = Column(String(16), nullable=False, unique=True, index=True, comment="复盘日期 YYYY-MM-DD")
week_day = Column(String(8), nullable=True, comment="星期")
data_basis = Column(String(128), nullable=True, comment="数据基准说明")
core_conclusion = Column(String(128), nullable=True, comment="核心结论")
bull_count = Column(Integer, nullable=True, comment="多头品种数")
bear_count = Column(Integer, nullable=True, comment="空头品种数")
neutral_count = Column(Integer, nullable=True, comment="震荡品种数")
opportunity_count = Column(Integer, nullable=True, comment="交易机会数")
risk_warnings = Column(JSON, nullable=True, comment="风险提示列表")
actual_data_date = Column(String(16), nullable=True, comment="实际数据日期 YYYY-MM-DD")
data_date_matches = Column(Integer, nullable=True, comment="数据日期是否与复盘日期一致 1=是 0=否")
created_at = Column(DateTime, nullable=False, default=datetime.now)
def __repr__(self):
return f"<ReviewPlanV2 {self.review_date}>"
# ==================== 交易复盘模型 ====================
class TradeRecord(AnalysisBase):
"""交易记录表 - 从期货结算单导入的逐笔交易明细"""
__tablename__ = "trade_records"
id = Column(Integer, primary_key=True, autoincrement=True)
trade_type = Column(String(8), nullable=False, comment="类型: 期货/期权")
symbol = Column(String(32), nullable=False, index=True, comment="合约代码 AG2606")
variety = Column(String(16), nullable=False, index=True, comment="品种代码 AG")
symbol_name = Column(String(64), nullable=True, comment="品种名称 沪银")
direction = Column(String(8), nullable=False, comment="买卖方向: 买/卖")
offset = Column(String(8), nullable=True, comment="开平标志: 开/平")
price = Column(Float, nullable=True, comment="成交价/权利金单价")
volume = Column(Float, nullable=True, comment="手数/成交量")
amount = Column(Float, nullable=True, comment="成交额/权利金")
close_pnl = Column(Float, nullable=True, default=0.0, comment="平仓盈亏")
commission = Column(Float, nullable=True, default=0.0, comment="手续费")
trade_date = Column(String(16), nullable=True, index=True, comment="成交日期 YYYY-MM-DD")
trade_time = Column(String(32), nullable=True, comment="成交时间 HH:MM:SS")
import_batch = Column(String(64), nullable=False, index=True, comment="导入批次号 UUID")
source_file = Column(String(128), nullable=True, comment="来源文件名")
created_at = Column(DateTime, nullable=False, default=datetime.now)
__table_args__ = (
Index('ix_trade_records_date_variety', 'trade_date', 'variety'),
)
def __repr__(self):
return f"<TradeRecord {self.symbol} {self.direction} {self.offset} {self.trade_date}>"
class TradeImportBatch(AnalysisBase):
"""交易导入批次表 - 记录每次导入的元信息"""
__tablename__ = "trade_import_batches"
id = Column(Integer, primary_key=True, autoincrement=True)
batch_id = Column(String(64), nullable=False, unique=True, index=True, comment="批次号 UUID")
source_file = Column(String(128), nullable=False, comment="来源文件名")
futures_count = Column(Integer, nullable=False, default=0, comment="期货交易记录数")
options_count = Column(Integer, nullable=False, default=0, comment="期权交易记录数")
trade_dates = Column(String(256), nullable=True, comment="涉及交易日期范围")
created_at = Column(DateTime, nullable=False, default=datetime.now)
def __repr__(self):
return f"<TradeImportBatch {self.batch_id} {self.source_file}>"
# ==================== 交易反思系统模型 ====================
class TradePair(AnalysisBase):
"""交易配对表 - 将开仓和平仓配对为一个完整交易"""
__tablename__ = "trade_pairs"
id = Column(Integer, primary_key=True, autoincrement=True)
variety = Column(String(16), nullable=False, index=True, comment="品种代码 AG")
direction = Column(String(8), nullable=False, comment="方向: long/short")
open_record_ids = Column(JSON, nullable=False, comment="开仓记录ID列表 [id1, id2, ...]")
close_record_ids = Column(JSON, nullable=False, comment="平仓记录ID列表 [id1, id2, ...]")
open_price = Column(Float, nullable=True, comment="平均开仓价")
close_price = Column(Float, nullable=True, comment="平均平仓价")
total_volume = Column(Float, nullable=True, comment="总手数")
close_pnl = Column(Float, nullable=True, default=0.0, comment="平仓盈亏")
total_commission = Column(Float, nullable=True, default=0.0, comment="总手续费")
net_pnl = Column(Float, nullable=True, default=0.0, comment="净盈亏 = 平仓盈亏 - 手续费")
open_date = Column(String(16), nullable=True, index=True, comment="开仓日期")
close_date = Column(String(16), nullable=True, index=True, comment="平仓日期")
created_at = Column(DateTime, nullable=False, default=datetime.now)
__table_args__ = (
Index('ix_trade_pairs_variety_date', 'variety', 'open_date'),
)
def __repr__(self):
return f"<TradePair {self.variety} {self.direction} pnl={self.net_pnl}>"
class TradeReflection(AnalysisBase):
"""交易反思表 - 每笔交易的反思内容"""
__tablename__ = "trade_reflections"
id = Column(Integer, primary_key=True, autoincrement=True)
trade_pair_id = Column(Integer, nullable=False, index=True, comment="关联交易配对ID")
trade_date = Column(String(16), nullable=False, index=True, comment="交易日期")
# 模板字段
entry_reason = Column(Text, nullable=True, comment="入场理由")
entry_timing = Column(String(8), nullable=True, comment="入场时机评价: good/fair/poor")
position_management = Column(Text, nullable=True, comment="仓位管理反思")
exit_reason = Column(Text, nullable=True, comment="出场理由")
exit_timing = Column(String(8), nullable=True, comment="出场时机评价: good/fair/poor")
discipline_score = Column(Integer, nullable=True, comment="纪律评分 1-5")
# 自由反思
free_reflection = Column(Text, nullable=True, comment="自由反思内容")
# 状态
ai_analyzed = Column(Boolean, nullable=False, default=False, comment="是否已AI分析")
ai_version = Column(Integer, nullable=True, comment="AI分析版本号")
created_at = Column(DateTime, nullable=False, default=datetime.now)
updated_at = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)
def __repr__(self):
return f"<TradeReflection pair_id={self.trade_pair_id} date={self.trade_date}>"
class DailyReflection(AnalysisBase):
"""当日反思表 - 每天的整体反思"""
__tablename__ = "daily_reflections"
id = Column(Integer, primary_key=True, autoincrement=True)
reflection_date = Column(String(16), nullable=False, unique=True, index=True, comment="反思日期 YYYY-MM-DD")
emotion_state = Column(String(16), nullable=True, comment="情绪状态: 平静/兴奋/焦虑/恐惧/贪婪")
market_judgment = Column(Text, nullable=True, comment="市场判断")
discipline_score = Column(Integer, nullable=True, comment="执行纪律评分 1-5")
overall_rating = Column(Integer, nullable=True, comment="总体评价 1-5")
summary = Column(Text, nullable=True, comment="总结")
improvements = Column(Text, nullable=True, comment="改进方向")
created_at = Column(DateTime, nullable=False, default=datetime.now)
updated_at = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)
def __repr__(self):
return f"<DailyReflection {self.reflection_date}>"
class TradeTag(AnalysisBase):
"""标签定义表"""
__tablename__ = "trade_tags"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(32), nullable=False, unique=True, index=True, comment="标签名称")
category = Column(String(16), nullable=False, comment="分类: operation/mindset/discipline/technical/custom")
is_preset = Column(Boolean, nullable=False, default=False, comment="是否预设标签")
color = Column(String(16), nullable=True, comment="标签颜色(前端用)")
created_at = Column(DateTime, nullable=False, default=datetime.now)
def __repr__(self):
return f"<TradeTag {self.name} [{self.category}]>"
class TradeRecordTag(AnalysisBase):
"""交易-标签关联表"""
__tablename__ = "trade_record_tags"
id = Column(Integer, primary_key=True, autoincrement=True)
trade_pair_id = Column(Integer, nullable=False, index=True, comment="交易配对ID")
tag_id = Column(Integer, nullable=False, index=True, comment="标签ID")
created_at = Column(DateTime, nullable=False, default=datetime.now)
__table_args__ = (
UniqueConstraint("trade_pair_id", "tag_id", name="uq_pair_tag"),
)
def __repr__(self):
return f"<TradeRecordTag pair_id={self.trade_pair_id} tag_id={self.tag_id}>"
class TradeExperience(AnalysisBase):
"""经验教训表"""
__tablename__ = "trade_experiences"
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String(128), nullable=False, comment="经验标题")
content = Column(Text, nullable=False, comment="经验内容")
exp_type = Column(String(16), nullable=False, comment="类型: lesson/tip/warning")
source_pair_id = Column(Integer, nullable=True, index=True, comment="来源交易配对ID")
source_date = Column(String(16), nullable=True, index=True, comment="来源交易日期")
tags = Column(JSON, nullable=True, comment="关联标签名称列表")
created_at = Column(DateTime, nullable=False, default=datetime.now)
updated_at = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)
def __repr__(self):
return f"<TradeExperience {self.title} [{self.exp_type}]>"