246 lines
9.6 KiB
Python
246 lines
9.6 KiB
Python
from sqlalchemy import Column, String, Float, Text, DateTime, Integer
|
||
from sqlalchemy.ext.declarative import declarative_base
|
||
from datetime import datetime
|
||
|
||
Base = declarative_base()
|
||
|
||
"""
|
||
数据库表结构设计说明
|
||
====================
|
||
|
||
核心原则:一份数据只存储一次,通过 JOIN 关联查询
|
||
|
||
数据表分类:
|
||
1. 原始数据表 - 存储从API获取的原始数据
|
||
- FundBasicInfo: 基本信息、业绩数据
|
||
- FundTrend: 净值走势、排名趋势
|
||
- FundExtraData: 持有人结构、资产配置、基金经理
|
||
- FundEstimate: 实时估值
|
||
- FundPortfolio: 持仓信息
|
||
|
||
2. 计算指标表 - 基于原始数据计算
|
||
- FundRiskMetrics: 风险指标(回撤、波动率、夏普等)
|
||
|
||
3. 筛选专用表 - 存储同类排名等筛选特有数据
|
||
- FundScreeningRank: 同类排名百分位、4433标记
|
||
|
||
4. 用户数据表
|
||
- FundWatchlist: 自选基金
|
||
- FundWatchlistGroup: 自选分组
|
||
|
||
使用方式:
|
||
- 基金详情:FundBasicInfo + FundTrend + FundExtraData + FundRiskMetrics
|
||
- 基金对比:同上
|
||
- 基金筛选:FundBasicInfo + FundRiskMetrics + FundScreeningRank
|
||
"""
|
||
|
||
|
||
# ==================== 原始数据表 ====================
|
||
|
||
class FundBasicInfo(Base):
|
||
"""
|
||
基金基础信息表
|
||
数据来源: pingzhongdata.js API
|
||
"""
|
||
__tablename__ = 'fund_basic_info'
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
fund_code = Column(String(6), unique=True, nullable=False, index=True)
|
||
fund_name = Column(String(100), nullable=False)
|
||
fund_type = Column(String(50), index=True) # 基金类型
|
||
original_rate = Column(Float) # 原始费率
|
||
current_rate = Column(Float) # 当前费率
|
||
min_subscription_amount = Column(String(50)) # 最低申购金额
|
||
is_hb = Column(String(10)) # 是否货币基金
|
||
return_1y = Column(Float) # 近1年收益率(用于排序)
|
||
basic_json = Column(Text) # 完整基本信息JSON
|
||
performance_json = Column(Text) # 业绩数据JSON (收益率)
|
||
created_time = Column(DateTime, default=datetime.now)
|
||
updated_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||
|
||
|
||
class FundTrend(Base):
|
||
"""
|
||
基金走势数据表
|
||
数据来源: pingzhongdata.js API
|
||
"""
|
||
__tablename__ = 'fund_trend'
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
fund_code = Column(String(6), unique=True, nullable=False, index=True)
|
||
net_worth_trend_json = Column(Text) # 单位净值走势
|
||
accumulated_net_worth_json = Column(Text) # 累计净值走势
|
||
position_trend_json = Column(Text) # 仓位变动趋势
|
||
total_return_trend_json = Column(Text) # 总收益率走势
|
||
ranking_trend_json = Column(Text) # 同类排名走势
|
||
ranking_percentage_json = Column(Text) # 排名百分位走势
|
||
scale_fluctuation_json = Column(Text) # 规模变动数据
|
||
updated_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||
|
||
|
||
class FundEstimate(Base):
|
||
"""
|
||
基金实时估值表
|
||
数据来源: fundgz.js API
|
||
"""
|
||
__tablename__ = 'fund_estimate'
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
fund_code = Column(String(6), unique=True, nullable=False, index=True)
|
||
name = Column(String(100))
|
||
net_worth = Column(String(50)) # 最新净值
|
||
net_worth_date = Column(String(50)) # 净值日期
|
||
estimate_value = Column(String(50)) # 估算净值
|
||
estimate_change = Column(String(50)) # 估算涨跌幅
|
||
estimate_time = Column(String(50)) # 估算时间
|
||
updated_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||
|
||
|
||
class FundPortfolio(Base):
|
||
"""
|
||
基金持仓表
|
||
数据来源: pingzhongdata.js API
|
||
"""
|
||
__tablename__ = 'fund_portfolio'
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
fund_code = Column(String(6), unique=True, nullable=False, index=True)
|
||
stock_codes_json = Column(Text) # 股票持仓
|
||
bond_codes_json = Column(Text) # 债券持仓
|
||
stock_codes_new_json = Column(Text) # 最新股票持仓
|
||
bond_codes_new_json = Column(Text) # 最新债券持仓
|
||
updated_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||
|
||
|
||
class FundExtraData(Base):
|
||
"""
|
||
基金扩展数据表
|
||
数据来源: pingzhongdata.js API
|
||
"""
|
||
__tablename__ = 'fund_extra_data'
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
fund_code = Column(String(6), unique=True, nullable=False, index=True)
|
||
holder_structure_json = Column(Text) # 持有人结构
|
||
asset_allocation_json = Column(Text) # 资产配置
|
||
performance_evaluation_json = Column(Text) # 业绩评价
|
||
fund_managers_json = Column(Text) # 基金经理信息
|
||
subscription_redemption_json = Column(Text) # 申购赎回状态
|
||
same_type_funds_json = Column(Text) # 同类型基金
|
||
updated_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||
|
||
|
||
# ==================== 计算指标表 ====================
|
||
|
||
class FundRiskMetrics(Base):
|
||
"""
|
||
基金风险指标表
|
||
数据来源: 根据 FundTrend.net_worth_trend 计算
|
||
"""
|
||
__tablename__ = 'fund_risk_metrics'
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
fund_code = Column(String(6), unique=True, nullable=False, index=True)
|
||
|
||
# 最大回撤(百分比)
|
||
max_drawdown_3m = Column(Float) # 近3月
|
||
max_drawdown_6m = Column(Float) # 近6月
|
||
max_drawdown_1y = Column(Float) # 近1年
|
||
max_drawdown_3y = Column(Float) # 近3年
|
||
max_drawdown_all = Column(Float) # 成立以来
|
||
|
||
# 夏普比率
|
||
sharpe_ratio_1y = Column(Float) # 近1年
|
||
sharpe_ratio_3y = Column(Float) # 近3年
|
||
|
||
# 年化波动率(百分比)
|
||
volatility_1y = Column(Float) # 近1年
|
||
volatility_3y = Column(Float) # 近3年
|
||
|
||
# 年化收益率(百分比)
|
||
annual_return_1y = Column(Float) # 近1年
|
||
annual_return_3y = Column(Float) # 近3年
|
||
|
||
# 卡玛比率
|
||
calmar_ratio_1y = Column(Float) # 近1年
|
||
calmar_ratio_3y = Column(Float) # 近3年
|
||
|
||
updated_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||
|
||
|
||
# ==================== 筛选专用表 ====================
|
||
|
||
class FundScreeningRank(Base):
|
||
"""
|
||
基金筛选排名表
|
||
只存储筛选功能特有的数据:同类排名百分位、4433标记
|
||
其他数据通过 JOIN 查询 FundBasicInfo、FundRiskMetrics
|
||
"""
|
||
__tablename__ = 'fund_screening_rank'
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
fund_code = Column(String(6), unique=True, nullable=False, index=True)
|
||
|
||
# 同类排名百分位(值越小越好,前10%=10)
|
||
rank_pct_1m = Column(Float) # 近1月
|
||
rank_pct_3m = Column(Float) # 近3月
|
||
rank_pct_6m = Column(Float) # 近6月
|
||
rank_pct_1y = Column(Float) # 近1年
|
||
rank_pct_2y = Column(Float) # 近2年
|
||
rank_pct_3y = Column(Float) # 近3年
|
||
|
||
# 筛选标记
|
||
pass_4433 = Column(Integer, default=0) # 是否通过4433法则
|
||
|
||
updated_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||
|
||
|
||
# ==================== 用户数据表 ====================
|
||
|
||
class FundWatchlistGroup(Base):
|
||
"""自选分组表"""
|
||
__tablename__ = 'fund_watchlist_group'
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
name = Column(String(50), nullable=False)
|
||
sort_order = Column(Integer, default=0)
|
||
created_time = Column(DateTime, default=datetime.now)
|
||
updated_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||
|
||
|
||
class FundWatchlist(Base):
|
||
"""基金自选表"""
|
||
__tablename__ = 'fund_watchlist'
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
fund_code = Column(String(6), unique=True, nullable=False, index=True)
|
||
fund_name = Column(String(100), nullable=False)
|
||
fund_type = Column(String(50))
|
||
group_id = Column(Integer, default=None)
|
||
sort_order = Column(Integer, default=0)
|
||
created_time = Column(DateTime, default=datetime.now)
|
||
updated_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||
|
||
|
||
class DailyMarketSummary(Base):
|
||
"""
|
||
每日市场行情摘要缓存表
|
||
用于存储AI生成的市场分析报告,避免重复调用LLM
|
||
"""
|
||
__tablename__ = 'daily_market_summary'
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
date = Column(String(10), unique=True, nullable=False, index=True) # 日期: YYYY-MM-DD
|
||
status = Column(String(20), default='pending') # pending / step_1_search / step_2_llm / completed / error
|
||
current_step = Column(Integer, default=0) # 当前步骤: 0-未开始, 1-搜索新闻, 2-AI分析, 3-完成
|
||
step_message = Column(String(200)) # 当前步骤描述
|
||
market_sentiment = Column(String(50)) # 市场情绪
|
||
summary = Column(Text) # 市场总结
|
||
indices_json = Column(Text) # 指数数据 JSON
|
||
hot_sectors_json = Column(Text) # 热门板块 JSON
|
||
key_news_json = Column(Text) # 关键新闻 JSON
|
||
outlook = Column(Text) # 后市展望
|
||
error_message = Column(Text) # 错误信息(如有)
|
||
created_time = Column(DateTime, default=datetime.now)
|
||
updated_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|