"""SQLAlchemy 2.0 declarative models for ACE-F.""" from __future__ import annotations import datetime as dt import uuid from sqlalchemy import ( BigInteger, Boolean, Date, DateTime, ForeignKey, Index, Integer, Numeric, Text, UniqueConstraint, ) from sqlalchemy.dialects.postgresql import JSONB, UUID from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship # --------------------------------------------------------------------------- # Phase 3 imports (used below in new model definitions) # --------------------------------------------------------------------------- def _utcnow() -> dt.datetime: return dt.datetime.now(tz=dt.UTC) class Base(DeclarativeBase): pass class IssuerMaster(Base): __tablename__ = "issuer_master" issuer_id: Mapped[str] = mapped_column(Text, primary_key=True) cik: Mapped[str | None] = mapped_column(Text, unique=True, nullable=True) ticker: Mapped[str | None] = mapped_column(Text, nullable=True) issuer_name: Mapped[str] = mapped_column(Text, nullable=False) exchange: Mapped[str | None] = mapped_column(Text, nullable=True) country_code: Mapped[str | None] = mapped_column(Text, nullable=True) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) updated_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, onupdate=_utcnow, nullable=False ) symbols: Mapped[list[SymbolMaster]] = relationship(back_populates="issuer") class SymbolMaster(Base): __tablename__ = "symbol_master" symbol_id: Mapped[str] = mapped_column(Text, primary_key=True) issuer_id: Mapped[str | None] = mapped_column( Text, ForeignKey("issuer_master.issuer_id"), nullable=True ) ticker: Mapped[str] = mapped_column(Text, nullable=False) venue: Mapped[str | None] = mapped_column(Text, nullable=True) asset_type: Mapped[str | None] = mapped_column(Text, nullable=True) currency: Mapped[str | None] = mapped_column(Text, nullable=True) start_date: Mapped[dt.date | None] = mapped_column(Date, nullable=True) end_date: Mapped[dt.date | None] = mapped_column(Date, nullable=True) is_primary: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) updated_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, onupdate=_utcnow, nullable=False ) issuer: Mapped[IssuerMaster | None] = relationship(back_populates="symbols") class JobRun(Base): __tablename__ = "job_runs" __table_args__ = (Index("ix_job_runs_job_name_run_date", "job_name", "run_date"),) job_run_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) job_name: Mapped[str] = mapped_column(Text, nullable=False) source_name: Mapped[str | None] = mapped_column(Text, nullable=True) run_date: Mapped[dt.date | None] = mapped_column(Date, nullable=True) status: Mapped[str] = mapped_column(Text, nullable=False) started_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) finished_at_utc: Mapped[dt.datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) records_seen: Mapped[int] = mapped_column(Integer, default=0, nullable=False) records_written: Mapped[int] = mapped_column(Integer, default=0, nullable=False) records_skipped: Mapped[int] = mapped_column(Integer, default=0, nullable=False) error_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False) error_summary: Mapped[str | None] = mapped_column(Text, nullable=True) metadata_json: Mapped[dict] = mapped_column(JSONB, default=dict, nullable=False) class Document(Base): __tablename__ = "documents" __table_args__ = ( UniqueConstraint("accession_no", "form_type", name="uq_documents_accession_form"), Index("ix_documents_issuer_filing_date", "issuer_id", "filing_date"), Index("ix_documents_form_type_filing_date", "form_type", "filing_date"), ) document_id: Mapped[str] = mapped_column(Text, primary_key=True) source_name: Mapped[str] = mapped_column(Text, nullable=False) issuer_id: Mapped[str | None] = mapped_column( Text, ForeignKey("issuer_master.issuer_id"), nullable=True ) symbol_id: Mapped[str | None] = mapped_column( Text, ForeignKey("symbol_master.symbol_id"), nullable=True ) accession_no: Mapped[str | None] = mapped_column(Text, nullable=True) form_type: Mapped[str] = mapped_column(Text, nullable=False) filing_date: Mapped[dt.date] = mapped_column(Date, nullable=False) accepted_at_utc: Mapped[dt.datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) primary_document_name: Mapped[str | None] = mapped_column(Text, nullable=True) item_numbers: Mapped[list | None] = mapped_column(JSONB, nullable=True) parsed_status: Mapped[str] = mapped_column(Text, default="pending", nullable=False) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) updated_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, onupdate=_utcnow, nullable=False ) exhibits: Mapped[list[DocumentExhibit]] = relationship(back_populates="document") events: Mapped[list[Event]] = relationship(back_populates="primary_document") class DocumentExhibit(Base): __tablename__ = "document_exhibits" exhibit_id: Mapped[str] = mapped_column(Text, primary_key=True) document_id: Mapped[str] = mapped_column( Text, ForeignKey("documents.document_id"), nullable=False ) exhibit_code: Mapped[str] = mapped_column(Text, nullable=False) exhibit_name: Mapped[str | None] = mapped_column(Text, nullable=True) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) document: Mapped[Document] = relationship(back_populates="exhibits") class ExhibitCache(Base): __tablename__ = "exhibit_cache" __table_args__ = ( UniqueConstraint("accession_no", "exhibit_type", name="uq_exhibit_cache_accession_type"), ) id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) accession_no: Mapped[str] = mapped_column(Text, nullable=False) exhibit_type: Mapped[str] = mapped_column(Text, nullable=False) content_hash: Mapped[str] = mapped_column(Text, nullable=False) cache_path: Mapped[str] = mapped_column(Text, nullable=False) fetched_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) class Event(Base): __tablename__ = "events" __table_args__ = ( Index("ix_events_event_type_date", "event_type", "event_date"), Index("ix_events_primary_document_id", "primary_document_id"), ) event_id: Mapped[str] = mapped_column(Text, primary_key=True) issuer_id: Mapped[str | None] = mapped_column( Text, ForeignKey("issuer_master.issuer_id"), nullable=True ) symbol_id: Mapped[str | None] = mapped_column( Text, ForeignKey("symbol_master.symbol_id"), nullable=True ) primary_document_id: Mapped[str] = mapped_column( Text, ForeignKey("documents.document_id"), nullable=False ) event_type: Mapped[str] = mapped_column(Text, nullable=False) event_direction: Mapped[str] = mapped_column(Text, nullable=False) event_date: Mapped[dt.date] = mapped_column(Date, nullable=False) filed_at_utc: Mapped[dt.datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) parser_version: Mapped[str] = mapped_column(Text, nullable=False) parse_confidence: Mapped[float | None] = mapped_column(Numeric, nullable=True) status: Mapped[str] = mapped_column(Text, default="pending", nullable=False) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) updated_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, onupdate=_utcnow, nullable=False ) primary_document: Mapped[Document] = relationship(back_populates="events") parses: Mapped[list[EventParse]] = relationship(back_populates="event") feature_snapshots: Mapped[list[FeatureSnapshot]] = relationship(back_populates="event") class EventParse(Base): __tablename__ = "event_parses" event_parse_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) event_id: Mapped[str] = mapped_column( Text, ForeignKey("events.event_id"), nullable=False ) parser_kind: Mapped[str] = mapped_column(Text, nullable=False) parser_version: Mapped[str] = mapped_column(Text, nullable=False) schema_version: Mapped[str] = mapped_column(Text, nullable=False) output_json: Mapped[dict] = mapped_column(JSONB, nullable=False) validation_status: Mapped[str] = mapped_column(Text, nullable=False) validation_errors: Mapped[dict | None] = mapped_column(JSONB, nullable=True) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) event: Mapped[Event] = relationship(back_populates="parses") class MacroSeries(Base): __tablename__ = "macro_series" series_id: Mapped[str] = mapped_column(Text, primary_key=True) title: Mapped[str | None] = mapped_column(Text, nullable=True) frequency: Mapped[str | None] = mapped_column(Text, nullable=True) units: Mapped[str | None] = mapped_column(Text, nullable=True) source_name: Mapped[str] = mapped_column(Text, nullable=False) metadata_json: Mapped[dict] = mapped_column(JSONB, default=dict, nullable=False) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) observations: Mapped[list[MacroObservation]] = relationship(back_populates="series") class MacroObservation(Base): __tablename__ = "macro_observations" __table_args__ = ( UniqueConstraint("series_id", "observation_date", name="uq_macro_obs_series_date"), ) id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) series_id: Mapped[str] = mapped_column( Text, ForeignKey("macro_series.series_id"), nullable=False ) observation_date: Mapped[dt.date] = mapped_column(Date, nullable=False) value: Mapped[float | None] = mapped_column(Numeric, nullable=True) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) series: Mapped[MacroSeries] = relationship(back_populates="observations") class ShortSaleDaily(Base): __tablename__ = "short_sale_daily" __table_args__ = ( UniqueConstraint( "ticker_raw", "trade_date", "source_name", name="uq_short_sale_ticker_date_source" ), Index("ix_short_sale_ticker_date", "ticker_raw", "trade_date"), ) id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) symbol_id: Mapped[str | None] = mapped_column( Text, ForeignKey("symbol_master.symbol_id"), nullable=True ) ticker_raw: Mapped[str] = mapped_column(Text, nullable=False) trade_date: Mapped[dt.date] = mapped_column(Date, nullable=False) short_volume: Mapped[int] = mapped_column(BigInteger, nullable=False) short_exempt_volume: Mapped[int | None] = mapped_column(BigInteger, nullable=True) total_volume: Mapped[int | None] = mapped_column(BigInteger, nullable=True) source_name: Mapped[str] = mapped_column(Text, nullable=False) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) class FeatureSnapshot(Base): __tablename__ = "feature_snapshots" feature_snapshot_id: Mapped[int] = mapped_column( BigInteger, primary_key=True, autoincrement=True ) event_id: Mapped[str] = mapped_column( Text, ForeignKey("events.event_id"), nullable=False ) snapshot_name: Mapped[str] = mapped_column(Text, nullable=False) snapshot_version: Mapped[str] = mapped_column(Text, nullable=False) feature_json: Mapped[dict] = mapped_column(JSONB, nullable=False) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) event: Mapped[Event] = relationship(back_populates="feature_snapshots") class OrderPlan(Base): __tablename__ = "order_plans" order_plan_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) event_id: Mapped[str] = mapped_column( Text, ForeignKey("events.event_id"), nullable=False ) symbol_id: Mapped[str] = mapped_column( Text, ForeignKey("symbol_master.symbol_id"), nullable=False ) side: Mapped[str] = mapped_column(Text, nullable=False) planned_entry_date: Mapped[dt.date] = mapped_column(Date, nullable=False) planned_order_type: Mapped[str] = mapped_column(Text, nullable=False) planned_price: Mapped[float | None] = mapped_column(Numeric, nullable=True) stop_price: Mapped[float | None] = mapped_column(Numeric, nullable=True) take_profit_price: Mapped[float | None] = mapped_column(Numeric, nullable=True) quantity_plan: Mapped[float | None] = mapped_column(Numeric, nullable=True) status: Mapped[str] = mapped_column(Text, default="draft", nullable=False) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) class SyncCheckpoint(Base): __tablename__ = "sync_checkpoints" __table_args__ = (UniqueConstraint("domain", name="uq_sync_checkpoints_domain"),) id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) domain: Mapped[str] = mapped_column(Text, nullable=False) last_sync_at_utc: Mapped[dt.datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) last_sync_params: Mapped[dict] = mapped_column(JSONB, default=dict, nullable=False) status: Mapped[str] = mapped_column(Text, nullable=False) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) updated_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, onupdate=_utcnow, nullable=False ) # --------------------------------------------------------------------------- # Phase 3 models # --------------------------------------------------------------------------- class LLMCallCache(Base): """Cache of LLM API calls keyed by content hash.""" __tablename__ = "llm_call_cache" cache_key: Mapped[str] = mapped_column(Text, primary_key=True) document_id: Mapped[str | None] = mapped_column(Text, nullable=True) model_name: Mapped[str] = mapped_column(Text, nullable=False) prompt_version: Mapped[str] = mapped_column(Text, nullable=False) schema_version: Mapped[str] = mapped_column(Text, nullable=False) raw_prompt: Mapped[str] = mapped_column(Text, nullable=False) raw_response: Mapped[str] = mapped_column(Text, nullable=False) normalized_json: Mapped[dict] = mapped_column(JSONB, nullable=False) token_usage_json: Mapped[dict] = mapped_column(JSONB, nullable=False) elapsed_ms: Mapped[int] = mapped_column(Integer, nullable=False) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) class ReviewItem(Base): """Human-in-the-loop review queue item.""" __tablename__ = "review_items" __table_args__ = ( Index("ix_review_items_entity_open", "entity_type", "entity_id", "status"), Index("ix_review_items_status_priority", "status", "priority"), ) review_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) entity_type: Mapped[str] = mapped_column(Text, nullable=False) entity_id: Mapped[str] = mapped_column(Text, nullable=False) priority: Mapped[str] = mapped_column(Text, nullable=False) reason_codes: Mapped[list] = mapped_column(JSONB, nullable=False) status: Mapped[str] = mapped_column(Text, default="open", nullable=False) assigned_to: Mapped[str | None] = mapped_column(Text, nullable=True) snapshot_refs: Mapped[dict] = mapped_column(JSONB, nullable=False) suggested_overrides: Mapped[dict | None] = mapped_column(JSONB, nullable=True) reviewer_id: Mapped[str | None] = mapped_column(Text, nullable=True) resolution_type: Mapped[str | None] = mapped_column(Text, nullable=True) field_overrides: Mapped[dict | None] = mapped_column(JSONB, nullable=True) root_cause: Mapped[str | None] = mapped_column(Text, nullable=True) notes: Mapped[str | None] = mapped_column(Text, nullable=True) resolved_at: Mapped[dt.datetime | None] = mapped_column( DateTime(timezone=True), nullable=True ) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) updated_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, onupdate=_utcnow, nullable=False ) class EventLabel(Base): """Forward-return labels for a parsed event.""" __tablename__ = "event_labels" __table_args__ = ( UniqueConstraint( "event_id", "entry_convention", "label_version", name="uq_event_labels_event_convention_version", ), ) label_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) event_id: Mapped[str] = mapped_column( Text, ForeignKey("events.event_id"), nullable=False ) entry_convention: Mapped[str] = mapped_column(Text, nullable=False) reaction_date: Mapped[dt.date | None] = mapped_column(Date, nullable=True) entry_date: Mapped[dt.date | None] = mapped_column(Date, nullable=True) entry_price: Mapped[float | None] = mapped_column(Numeric, nullable=True) fwd_return_1d: Mapped[float | None] = mapped_column(Numeric, nullable=True) fwd_return_3d: Mapped[float | None] = mapped_column(Numeric, nullable=True) fwd_return_5d: Mapped[float | None] = mapped_column(Numeric, nullable=True) fwd_return_10d: Mapped[float | None] = mapped_column(Numeric, nullable=True) fwd_return_20d: Mapped[float | None] = mapped_column(Numeric, nullable=True) hit_pos_1r_within_3d: Mapped[bool | None] = mapped_column(Boolean, nullable=True) hit_neg_1r_within_3d: Mapped[bool | None] = mapped_column(Boolean, nullable=True) close_up_after_3d: Mapped[bool | None] = mapped_column(Boolean, nullable=True) close_up_after_5d: Mapped[bool | None] = mapped_column(Boolean, nullable=True) mfe_3d: Mapped[float | None] = mapped_column(Numeric, nullable=True) mae_3d: Mapped[float | None] = mapped_column(Numeric, nullable=True) mfe_5d: Mapped[float | None] = mapped_column(Numeric, nullable=True) mae_5d: Mapped[float | None] = mapped_column(Numeric, nullable=True) mfe_10d: Mapped[float | None] = mapped_column(Numeric, nullable=True) mae_10d: Mapped[float | None] = mapped_column(Numeric, nullable=True) mfe_20d: Mapped[float | None] = mapped_column(Numeric, nullable=True) mae_20d: Mapped[float | None] = mapped_column(Numeric, nullable=True) bars_to_mfe_3d: Mapped[int | None] = mapped_column(Integer, nullable=True) bars_to_mae_3d: Mapped[int | None] = mapped_column(Integer, nullable=True) days_to_peak_close_5d: Mapped[int | None] = mapped_column(Integer, nullable=True) label_status: Mapped[str] = mapped_column(Text, nullable=False) invalid_event_for_labeling: Mapped[bool] = mapped_column( Boolean, default=False, nullable=False ) risk_model_name: Mapped[str | None] = mapped_column(Text, nullable=True) initial_stop_price: Mapped[float | None] = mapped_column(Numeric, nullable=True) initial_r_value: Mapped[float | None] = mapped_column(Numeric, nullable=True) label_version: Mapped[str] = mapped_column(Text, nullable=False) created_at_utc: Mapped[dt.datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, nullable=False ) event: Mapped[Event] = relationship()