Files
stock_cursor_v0/backend/models.py

224 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""数据中台 ORM 模型SQLAlchemy 2.0)。"""
from __future__ import annotations
import datetime as dt
from sqlalchemy import (BigInteger, Date, DateTime, Float, Integer, String,
Text, UniqueConstraint, func)
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class Security(Base):
"""证券基础信息。"""
__tablename__ = "securities"
code: Mapped[str] = mapped_column(String(12), primary_key=True)
name: Mapped[str] = mapped_column(String(40))
market: Mapped[str] = mapped_column(String(8), default="A")
updated_at: Mapped[dt.datetime] = mapped_column(DateTime, server_default=func.now())
class DailyQuote(Base):
"""个股日线(前复权)。"""
__tablename__ = "quotes_daily"
__table_args__ = (UniqueConstraint("code", "date", name="uq_quote_code_date"),)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
code: Mapped[str] = mapped_column(String(12), index=True)
date: Mapped[dt.date] = mapped_column(Date, index=True)
open: Mapped[float] = mapped_column(Float)
high: Mapped[float] = mapped_column(Float)
low: Mapped[float] = mapped_column(Float)
close: Mapped[float] = mapped_column(Float)
volume: Mapped[int] = mapped_column(BigInteger, default=0)
amount: Mapped[float] = mapped_column(Float, default=0.0)
class IndexDaily(Base):
"""指数日线。"""
__tablename__ = "index_daily"
__table_args__ = (UniqueConstraint("code", "date", name="uq_index_code_date"),)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
code: Mapped[str] = mapped_column(String(12), index=True)
name: Mapped[str] = mapped_column(String(40), default="")
date: Mapped[dt.date] = mapped_column(Date, index=True)
open: Mapped[float] = mapped_column(Float)
high: Mapped[float] = mapped_column(Float)
low: Mapped[float] = mapped_column(Float)
close: Mapped[float] = mapped_column(Float)
volume: Mapped[int] = mapped_column(BigInteger, default=0)
class SectorDaily(Base):
"""板块每日快照。"""
__tablename__ = "sector_daily"
__table_args__ = (UniqueConstraint("date", "name", name="uq_sector_date_name"),)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
date: Mapped[dt.date] = mapped_column(Date, index=True)
name: Mapped[str] = mapped_column(String(40))
pct: Mapped[float] = mapped_column(Float, default=0.0)
amount: Mapped[float] = mapped_column(Float, default=0.0)
count: Mapped[int] = mapped_column(Integer, default=0)
leader: Mapped[str] = mapped_column(String(40), default="")
class FundFlowDaily(Base):
"""行业资金流每日快照。"""
__tablename__ = "fund_flow_daily"
__table_args__ = (UniqueConstraint("date", "name", name="uq_fund_date_name"),)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
date: Mapped[dt.date] = mapped_column(Date, index=True)
name: Mapped[str] = mapped_column(String(40))
net: Mapped[float] = mapped_column(Float, default=0.0)
pct: Mapped[float] = mapped_column(Float, default=0.0)
class SentimentDaily(Base):
"""市场情绪每日快照。"""
__tablename__ = "sentiment_daily"
date: Mapped[dt.date] = mapped_column(Date, primary_key=True)
up: Mapped[int] = mapped_column(Integer, default=0)
down: Mapped[int] = mapped_column(Integer, default=0)
flat: Mapped[int] = mapped_column(Integer, default=0)
limit_up: Mapped[int] = mapped_column(Integer, default=0)
limit_down: Mapped[int] = mapped_column(Integer, default=0)
class DragonTiger(Base):
"""龙虎榜明细。"""
__tablename__ = "dragon_tiger"
__table_args__ = (UniqueConstraint("date", "code", "reason", name="uq_lhb"),)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
date: Mapped[dt.date] = mapped_column(Date, index=True)
code: Mapped[str] = mapped_column(String(12))
name: Mapped[str] = mapped_column(String(40), default="")
pct: Mapped[float] = mapped_column(Float, default=0.0)
net: Mapped[float] = mapped_column(Float, default=0.0)
reason: Mapped[str] = mapped_column(String(120), default="")
class StockMetric(Base):
"""个股最新因子快照(供全市场选股快速查询)。"""
__tablename__ = "stock_metrics"
code: Mapped[str] = mapped_column(String(12), primary_key=True)
name: Mapped[str] = mapped_column(String(40), default="")
date: Mapped[dt.date] = mapped_column(Date, index=True)
close: Mapped[float] = mapped_column(Float, default=0.0)
pct: Mapped[float] = mapped_column(Float, default=0.0, index=True)
ma5: Mapped[float] = mapped_column(Float, default=0.0)
ma10: Mapped[float] = mapped_column(Float, default=0.0)
ma20: Mapped[float] = mapped_column(Float, default=0.0)
ma60: Mapped[float] = mapped_column(Float, default=0.0)
vol_ratio: Mapped[float] = mapped_column(Float, default=0.0)
ret5: Mapped[float] = mapped_column(Float, default=0.0, index=True)
ret20: Mapped[float] = mapped_column(Float, default=0.0)
ret60: Mapped[float] = mapped_column(Float, default=0.0)
pos60: Mapped[float] = mapped_column(Float, default=0.0) # 0~160日价格分位
rsi14: Mapped[float] = mapped_column(Float, default=0.0)
macd_gold: Mapped[bool] = mapped_column(default=False)
ma_bull: Mapped[bool] = mapped_column(default=False)
up_streak: Mapped[int] = mapped_column(Integer, default=0)
amount: Mapped[float] = mapped_column(Float, default=0.0)
class Trade(Base):
"""交易记录(用于持仓盈亏与归因)。"""
__tablename__ = "trades"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
date: Mapped[dt.date] = mapped_column(Date, index=True)
code: Mapped[str] = mapped_column(String(12), index=True)
name: Mapped[str] = mapped_column(String(40), default="")
side: Mapped[str] = mapped_column(String(4)) # buy / sell
price: Mapped[float] = mapped_column(Float)
qty: Mapped[int] = mapped_column(Integer)
fee: Mapped[float] = mapped_column(Float, default=0.0)
reason: Mapped[str] = mapped_column(String(60), default="")
emotion: Mapped[str] = mapped_column(String(20), default="")
created_at: Mapped[dt.datetime] = mapped_column(DateTime, server_default=func.now())
class AlertRule(Base):
"""预警规则。"""
__tablename__ = "alert_rules"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
code: Mapped[str] = mapped_column(String(12), index=True)
name: Mapped[str] = mapped_column(String(40), default="")
kind: Mapped[str] = mapped_column(String(20)) # price_above/price_below/pct_above/pct_below
threshold: Mapped[float] = mapped_column(Float)
channel: Mapped[str] = mapped_column(String(20), default="站内")
note: Mapped[str] = mapped_column(String(80), default="")
status: Mapped[str] = mapped_column(String(12), default="active") # active/triggered
last_value: Mapped[float] = mapped_column(Float, default=0.0)
created_at: Mapped[dt.datetime] = mapped_column(DateTime, server_default=func.now())
triggered_at: Mapped[dt.datetime | None] = mapped_column(DateTime, nullable=True)
class AlertEvent(Base):
"""预警触发事件(站内通知)。"""
__tablename__ = "alert_events"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
rule_id: Mapped[int] = mapped_column(Integer, index=True)
code: Mapped[str] = mapped_column(String(12))
name: Mapped[str] = mapped_column(String(40), default="")
message: Mapped[str] = mapped_column(String(160))
value: Mapped[float] = mapped_column(Float, default=0.0)
read: Mapped[bool] = mapped_column(default=False)
created_at: Mapped[dt.datetime] = mapped_column(DateTime, server_default=func.now())
class DailyReport(Base):
"""AI 自动复盘日报(收盘后生成,可推送)。"""
__tablename__ = "daily_reports"
date: Mapped[dt.date] = mapped_column(Date, primary_key=True)
source: Mapped[str] = mapped_column(String(8), default="rule") # llm / rule
title: Mapped[str] = mapped_column(String(80), default="")
content: Mapped[str] = mapped_column(Text, default="") # markdown 正文
pushed: Mapped[bool] = mapped_column(default=False)
created_at: Mapped[dt.datetime] = mapped_column(DateTime, server_default=func.now())
class SignalStat(Base):
"""信号历史胜率(基于全市场历史日线回测的统计,支撑 AI 证据链的『历史命中率』)。"""
__tablename__ = "signal_stats"
__table_args__ = (UniqueConstraint("signal", "horizon", name="uq_signal_horizon"),)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
signal: Mapped[str] = mapped_column(String(24), index=True)
horizon: Mapped[int] = mapped_column(Integer, default=5) # 向后 N 个交易日
samples: Mapped[int] = mapped_column(Integer, default=0)
win_rate: Mapped[float] = mapped_column(Float, default=0.0) # 上涨占比 %
avg_ret: Mapped[float] = mapped_column(Float, default=0.0) # 平均收益 %
updated_at: Mapped[dt.datetime] = mapped_column(DateTime, server_default=func.now())
class Prediction(Base):
"""AI 诊断/预测留痕N 日后核验真实涨跌,形成可回溯的『实测准确率』。"""
__tablename__ = "predictions"
__table_args__ = (UniqueConstraint("code", "date", "kind", name="uq_pred"),)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
date: Mapped[dt.date] = mapped_column(Date, index=True)
code: Mapped[str] = mapped_column(String(12), index=True)
name: Mapped[str] = mapped_column(String(40), default="")
kind: Mapped[str] = mapped_column(String(16), default="diagnose")
score: Mapped[float] = mapped_column(Float, default=0.0)
confidence: Mapped[float] = mapped_column(Float, default=0.0)
direction: Mapped[str] = mapped_column(String(6), default="flat") # up/down/flat
horizon: Mapped[int] = mapped_column(Integer, default=5)
base_close: Mapped[float] = mapped_column(Float, default=0.0)
actual_ret: Mapped[float] = mapped_column(Float, default=0.0)
status: Mapped[str] = mapped_column(String(8), default="open") # open/closed
hit: Mapped[bool | None] = mapped_column(nullable=True)
created_at: Mapped[dt.datetime] = mapped_column(DateTime, server_default=func.now())
class JobRun(Base):
"""定时/手动任务执行日志。"""
__tablename__ = "job_runs"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
job: Mapped[str] = mapped_column(String(40))
status: Mapped[str] = mapped_column(String(16)) # running/success/error
started_at: Mapped[dt.datetime] = mapped_column(DateTime, server_default=func.now())
finished_at: Mapped[dt.datetime | None] = mapped_column(DateTime, nullable=True)
message: Mapped[str] = mapped_column(Text, default="")