Files
qlib/backend/app/infrastructure/persistence/migrations/versions/d8e0b2f3c4d5_signal_tables.py
T
Simon ba52edc2d6 feat(signal): M8.1 交易信号引擎(规则 + signal_event 落库 + /api/signals)
- SignalRules(买入 rank 阈值/趋势 MA/动量 + 卖出区间/破位警示)+ SignalEvent
  (BUY/WATCH/SELL,score/price/trigger_reason 可解释)+ SignalResult/Meta
- quant/signal.generate_signals:与选股同一评分引擎取全市场 rank,按规则分类输出
- signal_snapshot/signal_event 表(migration d8e0b2f3c4d5,MySQL 已应用)+ Repo
- SignalService + POST /api/signals(同步+落库)、GET 详情/列表
- tests/test_signals.py(引擎分类/排序/破位不 BUY、service、API 提交读回);全量 pytest 通过
2026-09-09 00:35:37 +08:00

63 lines
2.3 KiB
Python

"""signal_snapshot / signal_event 表(M8.1 交易信号)
Revision ID: d8e0b2f3c4d5
Revises: c3e9a0d1f4b5
Create Date: 2026-09-09
"""
from __future__ import annotations
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
revision: str = "d8e0b2f3c4d5"
down_revision: str | None = "c3e9a0d1f4b5"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
op.create_table(
"signal_snapshot",
sa.Column("id", sa.String(length=32), nullable=False),
sa.Column("as_of", sa.Date(), nullable=False),
sa.Column("query_json", sa.Text(), nullable=False),
sa.Column("rules_json", sa.Text(), nullable=False),
sa.Column("statistics_json", sa.Text(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint("id"),
)
op.create_index("ix_signal_snapshot_as_of", "signal_snapshot", ["as_of"])
op.create_index("ix_signal_snapshot_created_at", "signal_snapshot", ["created_at"])
op.create_table(
"signal_event",
sa.Column(
"id",
sa.BigInteger().with_variant(sa.Integer(), "sqlite"),
autoincrement=True,
nullable=False,
),
sa.Column("signal_id", sa.String(length=32), nullable=False),
sa.Column("symbol", sa.String(length=12), nullable=False),
sa.Column("signal_date", sa.Date(), nullable=False),
sa.Column("signal_type", sa.String(length=8), nullable=False),
sa.Column("score", sa.Numeric(precision=14, scale=6), nullable=True),
sa.Column("price", sa.Numeric(precision=14, scale=4), nullable=True),
sa.Column("reason_json", sa.Text(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint("id"),
)
op.create_index("ix_signal_event_signal_id", "signal_event", ["signal_id"])
def downgrade() -> None:
op.drop_index("ix_signal_event_signal_id", table_name="signal_event")
op.drop_table("signal_event")
op.drop_index("ix_signal_snapshot_created_at", table_name="signal_snapshot")
op.drop_index("ix_signal_snapshot_as_of", table_name="signal_snapshot")
op.drop_table("signal_snapshot")