Files
signal-platform/alembic/versions/011_add_regime_snapshots.py
T
dennisthiessen ebff19940b
Deploy / lint (push) Successful in 7s
Deploy / test (push) Successful in 46s
Deploy / deploy (push) Successful in 27s
feat: add standalone AI/Tech regime-change monitor tab
A new /regime tab scoring how far the AI/Tech bull regime has deteriorated
toward a re-rating as a single 0-100 index with per-signal breakdown and a
7/30-day trend. Intentionally decoupled: nothing reads its output to gate or
score trades — the daily-pipeline membership is scheduling only.

- regime_monitor_service: price sub-scores (P1-P6 via Alpaca, like
  market_regime), VIX + HY credit spreads via a small FRED helper, weighted
  aggregation over available signals (missing source -> n/a, dropped from the
  denominator), one snapshot row/day, and a ~90-day history backfill by
  replaying the already-fetched series as-of each past day.
- F1/F3 fundamentals proposed by the configured grounded LLM (reuses
  sentiment_provider_service config resolution), with a manual override + lock.
- regime_snapshots table (migration 011); endpoints on the existing market
  router; admin-editable weights/threshold; standalone /regime page.

Data needs: prices via Alpaca, VIX/credit via FRED (optional key — signals show
n/a without it). No LLM needed for history.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 11:51:45 +02:00

44 lines
1.3 KiB
Python

"""add regime_snapshots table
Stores the daily AI/Tech regime-change index (one row per date) so the monitor
tab can show a 7/30-day trend. Standalone, observational feature: no other table
or job reads this.
Revision ID: 011
Revises: 010
Create Date: 2026-06-26 00:00:00.000000
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = "011"
down_revision: Union[str, None] = "010"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.create_table(
"regime_snapshots",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("date", sa.Date(), nullable=False),
sa.Column("total_score", sa.Float(), nullable=False),
sa.Column("band", sa.String(length=20), nullable=False),
sa.Column("breakdown_json", sa.Text(), nullable=False),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
"uq_regime_snapshots_date", "regime_snapshots", ["date"], unique=True
)
def downgrade() -> None:
op.drop_index("uq_regime_snapshots_date", table_name="regime_snapshots")
op.drop_table("regime_snapshots")