First reviewable slice of workstream A: schema only, no importers, no data. - data_import_runs: lean batch-import audit (source/revision/status, row_counts_json + validation_json as Text-holding-JSON per repo convention). - fundamental_snapshots: CIK-keyed, one immutable row per accession; stores per-period raw facts (duration = cumulative YTD/FY, balance-sheet = period-end) plus period_start/period_end/fiscal_year/fiscal_period so discrete quarters, Q4, TTM and YoY are derived at read time. - earnings_events: Dolt-sourced calendar + surprise history, unique (ticker_id, announce_date). - tickers: nullable cik/sic/sic_description — the ticker<->issuer join point. fundamental_data is left untouched (cutover gated separately at A5). Models registered in app/models/__init__.py; Ticker gains an earnings_events relationship. Verified: create_all builds the tables, mappers configure, and migration 026 renders valid Postgres DDL up and down. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
43 lines
1.9 KiB
Python
43 lines
1.9 KiB
Python
from datetime import date, datetime
|
|
|
|
from sqlalchemy import Date, DateTime, Float, ForeignKey, Index, String, UniqueConstraint
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.database import Base
|
|
|
|
|
|
class EarningsEvent(Base):
|
|
"""Earnings calendar + surprise history, sourced from the DoltHub earnings repo.
|
|
|
|
Forward rows (``announce_date`` > today) are the calendar; past rows are
|
|
results. Rescheduling is handled in the importer's promotion transaction:
|
|
this source's future-dated rows are deleted and re-inserted from the new
|
|
snapshot so moved/cancelled dates never linger; past rows are never deleted.
|
|
"""
|
|
|
|
__tablename__ = "earnings_events"
|
|
__table_args__ = (
|
|
UniqueConstraint("ticker_id", "announce_date", name="uq_earnings_ticker_announce"),
|
|
Index("ix_earnings_events_announce_date", "announce_date"),
|
|
)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
ticker_id: Mapped[int] = mapped_column(
|
|
ForeignKey("tickers.id", ondelete="CASCADE"), nullable=False
|
|
)
|
|
announce_date: Mapped[date] = mapped_column(Date, nullable=False)
|
|
# bmo | amc | unknown (source coverage is partial)
|
|
session: Mapped[str] = mapped_column(String(10), nullable=False, default="unknown")
|
|
period_end: Mapped[date | None] = mapped_column(Date, nullable=True)
|
|
eps_estimate: Mapped[float | None] = mapped_column(Float, nullable=True)
|
|
eps_actual: Mapped[float | None] = mapped_column(Float, nullable=True)
|
|
source: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
import_run_id: Mapped[int | None] = mapped_column(
|
|
ForeignKey("data_import_runs.id", ondelete="SET NULL"), nullable=True
|
|
)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), default=datetime.utcnow, nullable=False
|
|
)
|
|
|
|
ticker = relationship("Ticker", back_populates="earnings_events")
|