- 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 通过
63 lines
2.3 KiB
Python
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")
|