"""ORM mappings for additive advisory product reference tables. The immutable ``fin_product`` catalogue remains mapped by ``FundProduct`` in ``app.model.fund``. This module only maps the new advisory evidence tables. """ from datetime import date, datetime from decimal import Decimal from typing import Any from sqlalchemy import JSON, BigInteger, Date, DateTime, Numeric, String, Text from sqlalchemy.orm import Mapped, mapped_column from app.model.base import Base class AdvisorProductIndustryExposure(Base): __tablename__ = "advisor_product_industry_exposure" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) product_id: Mapped[int] = mapped_column(BigInteger, nullable=False) industry_code: Mapped[str] = mapped_column(String(32), nullable=False) industry_name: Mapped[str] = mapped_column(String(128), nullable=False) exposure_weight_pct: Mapped[Decimal] = mapped_column(Numeric(7, 4), nullable=False) as_of_date: Mapped[date] = mapped_column(Date, nullable=False) source: Mapped[str] = mapped_column(String(64), nullable=False) status: Mapped[str] = mapped_column(String(16), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) updated_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) class AdvisorProductReferenceSnapshot(Base): __tablename__ = "advisor_product_reference_snapshot" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) product_id: Mapped[int] = mapped_column(BigInteger, nullable=False) as_of_date: Mapped[date] = mapped_column(Date, nullable=False) fund_type: Mapped[str] = mapped_column(String(64), nullable=False) fund_asset_scale_billion: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False) source: Mapped[str] = mapped_column(String(64), nullable=False) risk_mapping_version: Mapped[str] = mapped_column(String(32), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) updated_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) class AdvisorProductPriceHistory(Base): __tablename__ = "advisor_product_price_history" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) product_id: Mapped[int] = mapped_column(BigInteger, nullable=False) trade_date: Mapped[date] = mapped_column(Date, nullable=False) price_kind: Mapped[str] = mapped_column(String(16), nullable=False) close_price: Mapped[Decimal] = mapped_column(Numeric(18, 6), nullable=False) turnover_amount: Mapped[Decimal | None] = mapped_column(Numeric(24, 2)) source: Mapped[str] = mapped_column(String(64), nullable=False) source_updated_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) updated_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) class AdvisorProductMetricSnapshot(Base): __tablename__ = "advisor_product_metric_snapshot" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) product_id: Mapped[int] = mapped_column(BigInteger, nullable=False) as_of_date: Mapped[date] = mapped_column(Date, nullable=False) trailing_20d_return_pct: Mapped[Decimal | None] = mapped_column(Numeric(10, 4)) trailing_120d_return_pct: Mapped[Decimal | None] = mapped_column(Numeric(10, 4)) annualized_volatility_pct: Mapped[Decimal | None] = mapped_column(Numeric(10, 4)) max_drawdown_pct: Mapped[Decimal | None] = mapped_column(Numeric(10, 4)) average_daily_turnover_amount: Mapped[Decimal | None] = mapped_column(Numeric(24, 2)) observation_count: Mapped[int] = mapped_column(BigInteger, nullable=False) source: Mapped[str] = mapped_column(String(64), nullable=False) calculation_version: Mapped[str] = mapped_column(String(16), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) class AdvisorProductAssetClassification(Base): __tablename__ = "advisor_product_asset_classification" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) product_id: Mapped[int] = mapped_column(BigInteger, nullable=False) as_of_date: Mapped[date] = mapped_column(Date, nullable=False) asset_class: Mapped[str] = mapped_column(String(32), nullable=False) source: Mapped[str] = mapped_column(String(64), nullable=False) status: Mapped[str] = mapped_column(String(16), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) updated_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) class AdvisorProductDataQualitySnapshot(Base): __tablename__ = "advisor_product_data_quality_snapshot" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) product_id: Mapped[int] = mapped_column(BigInteger, nullable=False) as_of_date: Mapped[date] = mapped_column(Date, nullable=False) observation_count: Mapped[int] = mapped_column(BigInteger, nullable=False) expected_trading_days: Mapped[int] = mapped_column(BigInteger, nullable=False) price_coverage_pct: Mapped[Decimal] = mapped_column(Numeric(7, 4), nullable=False) turnover_coverage_pct: Mapped[Decimal] = mapped_column(Numeric(7, 4), nullable=False) max_abs_daily_return_pct: Mapped[Decimal | None] = mapped_column(Numeric(10, 4)) status: Mapped[str] = mapped_column(String(16), nullable=False) reason_codes: Mapped[list[str]] = mapped_column(JSON, nullable=False) rule_version: Mapped[str] = mapped_column(String(16), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) class AdvisorAllocationBacktestRun(Base): __tablename__ = "advisor_allocation_backtest_run" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) backtest_no: Mapped[str] = mapped_column(String(36), unique=True, nullable=False) started_on: Mapped[date] = mapped_column(Date, nullable=False) ended_on: Mapped[date] = mapped_column(Date, nullable=False) profile_risk_level: Mapped[str] = mapped_column(String(8), nullable=False) return_target_lower_pct: Mapped[Decimal] = mapped_column(Numeric(7, 4), nullable=False) max_drawdown_pct: Mapped[Decimal] = mapped_column(Numeric(7, 4), nullable=False) liquidity_requirement: Mapped[str] = mapped_column(String(32), nullable=False) status: Mapped[str] = mapped_column(String(32), nullable=False) observation_count: Mapped[int] = mapped_column(BigInteger, nullable=False) static_total_return_pct: Mapped[Decimal | None] = mapped_column(Numeric(12, 4)) dynamic_total_return_pct: Mapped[Decimal | None] = mapped_column(Numeric(12, 4)) static_max_drawdown_pct: Mapped[Decimal | None] = mapped_column(Numeric(12, 4)) dynamic_max_drawdown_pct: Mapped[Decimal | None] = mapped_column(Numeric(12, 4)) dynamic_rebalance_count: Mapped[int] = mapped_column(BigInteger, nullable=False) liquidity_history_coverage_pct: Mapped[Decimal] = mapped_column(Numeric(7, 4), nullable=False) limitations: Mapped[list[str]] = mapped_column(JSON, nullable=False) strategy_version: Mapped[str] = mapped_column(String(32), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) class AdvisorProductSuitabilityReference(Base): __tablename__ = "advisor_product_suitability_reference" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) product_id: Mapped[int] = mapped_column(BigInteger, nullable=False) sales_institution: Mapped[str] = mapped_column(String(128), nullable=False) risk_level: Mapped[str] = mapped_column(String(8), nullable=False) effective_from: Mapped[date] = mapped_column(Date, nullable=False) effective_until: Mapped[date | None] = mapped_column(Date) source_url: Mapped[str] = mapped_column(String(1024), nullable=False) document_title: Mapped[str] = mapped_column(String(256), nullable=False) document_published_at: Mapped[date | None] = mapped_column(Date) document_sha256: Mapped[str] = mapped_column(String(64), nullable=False) source: Mapped[str] = mapped_column(String(64), nullable=False) review_status: Mapped[str] = mapped_column(String(16), nullable=False) verified_by: Mapped[str | None] = mapped_column(String(128)) verified_at: Mapped[datetime | None] = mapped_column(DateTime) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) updated_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) class AdvisorProductContractSnapshot(Base): __tablename__ = "advisor_product_contract_snapshot" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) product_id: Mapped[int] = mapped_column(BigInteger, nullable=False) effective_from: Mapped[date] = mapped_column(Date, nullable=False) effective_until: Mapped[date | None] = mapped_column(Date) fund_type: Mapped[str] = mapped_column(String(64), nullable=False) investment_scope: Mapped[str] = mapped_column(Text, nullable=False) performance_benchmark: Mapped[str | None] = mapped_column(String(256)) risk_return_characteristics: Mapped[str] = mapped_column(Text, nullable=False) custodian_name: Mapped[str | None] = mapped_column(String(128)) management_fee_rate_pct: Mapped[Decimal | None] = mapped_column(Numeric(9, 6)) custodian_fee_rate_pct: Mapped[Decimal | None] = mapped_column(Numeric(9, 6)) inception_date: Mapped[date | None] = mapped_column(Date) source_url: Mapped[str] = mapped_column(String(1024), nullable=False) document_title: Mapped[str] = mapped_column(String(256), nullable=False) document_published_at: Mapped[date | None] = mapped_column(Date) document_sha256: Mapped[str] = mapped_column(String(64), nullable=False) source: Mapped[str] = mapped_column(String(64), nullable=False) review_status: Mapped[str] = mapped_column(String(16), nullable=False) verified_by: Mapped[str | None] = mapped_column(String(128)) verified_at: Mapped[datetime | None] = mapped_column(DateTime) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) updated_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) class AdvisorProductGovernanceCandidate(Base): __tablename__ = "advisor_product_governance_candidate_snapshot" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) product_id: Mapped[int] = mapped_column(BigInteger, nullable=False) data_kind: Mapped[str] = mapped_column(String(16), nullable=False) sales_institution: Mapped[str | None] = mapped_column(String(128)) observed_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) effective_from: Mapped[date] = mapped_column(Date, nullable=False) risk_level: Mapped[str | None] = mapped_column(String(8)) payload: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False) source_url: Mapped[str] = mapped_column(String(1024), nullable=False) document_title: Mapped[str] = mapped_column(String(256), nullable=False) document_published_at: Mapped[date | None] = mapped_column(Date) document_sha256: Mapped[str] = mapped_column(String(64), nullable=False) source: Mapped[str] = mapped_column(String(64), nullable=False) review_status: Mapped[str] = mapped_column(String(16), nullable=False) reviewed_by: Mapped[int | None] = mapped_column(BigInteger) reviewed_at: Mapped[datetime | None] = mapped_column(DateTime) review_comment: Mapped[str | None] = mapped_column(String(1000)) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) updated_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) class AdvisorProductGovernanceSyncRun(Base): __tablename__ = "advisor_product_governance_sync_run" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) run_no: Mapped[str] = mapped_column(String(36), nullable=False, unique=True) source: Mapped[str] = mapped_column(String(64), nullable=False) status: Mapped[str] = mapped_column(String(16), nullable=False) product_count: Mapped[int] = mapped_column(BigInteger, nullable=False) change_count: Mapped[int] = mapped_column(BigInteger, nullable=False) error_count: Mapped[int] = mapped_column(BigInteger, nullable=False) detail: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False) started_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) completed_at: Mapped[datetime | None] = mapped_column(DateTime) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) updated_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) class AdvisorProductMarketQuoteSnapshot(Base): __tablename__ = "advisor_product_market_quote_snapshot" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) product_id: Mapped[int] = mapped_column(BigInteger, nullable=False) observed_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) last_price: Mapped[Decimal] = mapped_column(Numeric(18, 6), nullable=False) previous_close: Mapped[Decimal | None] = mapped_column(Numeric(18, 6)) change_pct: Mapped[Decimal | None] = mapped_column(Numeric(10, 4)) volume: Mapped[Decimal | None] = mapped_column(Numeric(24, 4)) turnover_amount: Mapped[Decimal | None] = mapped_column(Numeric(24, 2)) quote_status: Mapped[str] = mapped_column(String(16), nullable=False) source: Mapped[str] = mapped_column(String(64), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) class AdvisorMarketQuoteSourceRun(Base): __tablename__ = "advisor_market_quote_source_run" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) sync_run_no: Mapped[str] = mapped_column(String(36), nullable=False) source: Mapped[str] = mapped_column(String(64), nullable=False) priority_order: Mapped[int] = mapped_column(BigInteger, nullable=False) status: Mapped[str] = mapped_column(String(16), nullable=False) requested_count: Mapped[int] = mapped_column(BigInteger, nullable=False) quote_count: Mapped[int] = mapped_column(BigInteger, nullable=False) error_type: Mapped[str | None] = mapped_column(String(128)) started_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) completed_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) class AdvisorMarketQuoteSourceHealth(Base): __tablename__ = "advisor_market_quote_source_health" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) source: Mapped[str] = mapped_column(String(64), nullable=False, unique=True) status: Mapped[str] = mapped_column(String(16), nullable=False) consecutive_failure_count: Mapped[int] = mapped_column(BigInteger, nullable=False) last_success_at: Mapped[datetime | None] = mapped_column(DateTime) last_failure_at: Mapped[datetime | None] = mapped_column(DateTime) last_error_type: Mapped[str | None] = mapped_column(String(128)) last_requested_count: Mapped[int] = mapped_column(BigInteger, nullable=False) last_quote_count: Mapped[int] = mapped_column(BigInteger, nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) updated_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) class AdvisorMarketQuoteAlert(Base): __tablename__ = "advisor_market_quote_alert" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) alert_no: Mapped[str] = mapped_column(String(36), nullable=False, unique=True) source: Mapped[str] = mapped_column(String(64), nullable=False) alert_type: Mapped[str] = mapped_column(String(64), nullable=False) severity: Mapped[str] = mapped_column(String(16), nullable=False) status: Mapped[str] = mapped_column(String(16), nullable=False) occurrence_count: Mapped[int] = mapped_column(BigInteger, nullable=False) detail: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False) first_observed_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) last_observed_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) resolved_at: Mapped[datetime | None] = mapped_column(DateTime) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False) updated_at: Mapped[datetime] = mapped_column(DateTime, nullable=False)