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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""
期货智析数据模型
"""
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}]>"