from datetime import date, datetime from decimal import Decimal from sqlalchemy import Boolean, Date, DateTime, Integer, Numeric, String, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column from app.core.database import Base from app.modules.business.models.common import TimestampMixin class MarketInstrument(Base, TimestampMixin): __tablename__ = "market_instruments" id: Mapped[int] = mapped_column(Integer, primary_key=True) symbol: Mapped[str] = mapped_column(String(32), unique=True, index=True) name: Mapped[str] = mapped_column(String(128), index=True) exchange: Mapped[str | None] = mapped_column(String(16), nullable=True, index=True) instrument_type: Mapped[str] = mapped_column(String(16), default="stock", index=True) industry: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True) list_date: Mapped[date | None] = mapped_column(Date, nullable=True) is_active: Mapped[bool] = mapped_column(Boolean, default=True, index=True) source_updated_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) class MarketDailyQuote(Base, TimestampMixin): __tablename__ = "market_daily_quotes" __table_args__ = (UniqueConstraint("symbol", "trade_date", name="uq_market_quote_day"),) id: Mapped[int] = mapped_column(Integer, primary_key=True) symbol: Mapped[str] = mapped_column(String(32), index=True) trade_date: Mapped[date] = mapped_column(Date, index=True) open_price: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True) high_price: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True) low_price: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True) close_price: Mapped[Decimal] = mapped_column(Numeric(18, 4)) pre_close: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True) pct_change: Mapped[Decimal | None] = mapped_column(Numeric(12, 4), nullable=True) volume: Mapped[Decimal | None] = mapped_column(Numeric(20, 2), nullable=True) amount_cny: Mapped[Decimal | None] = mapped_column(Numeric(20, 2), nullable=True) pe: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True) pb: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True) total_market_value: Mapped[Decimal | None] = mapped_column(Numeric(20, 2), nullable=True) class MarketFinancialMetric(Base, TimestampMixin): __tablename__ = "market_financial_metrics" __table_args__ = (UniqueConstraint("symbol", "period_end", name="uq_market_financial_period"),) id: Mapped[int] = mapped_column(Integer, primary_key=True) symbol: Mapped[str] = mapped_column(String(32), index=True) period_end: Mapped[date] = mapped_column(Date, index=True) revenue_yoy: Mapped[Decimal | None] = mapped_column(Numeric(12, 4), nullable=True) net_profit_yoy: Mapped[Decimal | None] = mapped_column(Numeric(12, 4), nullable=True) roe: Mapped[Decimal | None] = mapped_column(Numeric(12, 4), nullable=True) debt_to_assets: Mapped[Decimal | None] = mapped_column(Numeric(12, 4), nullable=True) operating_cashflow_yoy: Mapped[Decimal | None] = mapped_column(Numeric(12, 4), nullable=True) class MarketMacroIndicator(Base, TimestampMixin): __tablename__ = "market_macro_indicators" __table_args__ = (UniqueConstraint("code", "period_date", name="uq_market_macro_period"),) id: Mapped[int] = mapped_column(Integer, primary_key=True) code: Mapped[str] = mapped_column(String(64), index=True) name: Mapped[str] = mapped_column(String(128)) period_date: Mapped[date] = mapped_column(Date, index=True) value: Mapped[Decimal] = mapped_column(Numeric(20, 6)) unit: Mapped[str | None] = mapped_column(String(32), nullable=True) source: Mapped[str] = mapped_column(String(64), default="tushare") class MarketAnnouncement(Base, TimestampMixin): __tablename__ = "market_announcements" id: Mapped[int] = mapped_column(Integer, primary_key=True) source_key: Mapped[str] = mapped_column(String(64), unique=True, index=True) symbol: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True) announcement_date: Mapped[date] = mapped_column(Date, index=True) published_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) title: Mapped[str] = mapped_column(String(512)) category: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True) source_url: Mapped[str | None] = mapped_column(String(1024), nullable=True) source: Mapped[str] = mapped_column(String(64), default="tushare") class MarketWatchlist(Base, TimestampMixin): __tablename__ = "market_watchlists" __table_args__ = (UniqueConstraint("actor", "symbol", name="uq_market_watchlist_actor_symbol"),) id: Mapped[int] = mapped_column(Integer, primary_key=True) actor: Mapped[str] = mapped_column(String(128), index=True) symbol: Mapped[str] = mapped_column(String(32), index=True) enabled: Mapped[bool] = mapped_column(Boolean, default=True, index=True)