"""Pydantic schemas for fundamental data endpoints.""" from __future__ import annotations from datetime import date, datetime from pydantic import BaseModel class MetricIndustry(BaseModel): label: str median: float favorable_percentile: int # 0-100, polarity-aware (higher = more favorable) peer_count: int class MetricHistoryPoint(BaseModel): period_end: str # YYYY-MM-DD value: float | None class MetricItem(BaseModel): key: str value: float | None = None history: list[MetricHistoryPoint] = [] industry: MetricIndustry | None = None period_end: str | None = None filed_date: str | None = None source: str = "sec" class EarningsNext(BaseModel): date: str session: str days_until: int class EarningsRecent(BaseModel): announce_date: str period_end: str | None = None eps_estimate: float | None = None eps_actual: float | None = None surprise_pct: float | None = None class EarningsObject(BaseModel): next: EarningsNext | None = None recent: list[EarningsRecent] = [] class Valuation(BaseModel): pe: float | None = None fcf_yield: float | None = None market_cap_est: float | None = None pe_industry: MetricIndustry | None = None fcf_yield_industry: MetricIndustry | None = None price_date: str | None = None class FundamentalsReads(BaseModel): """Deterministic text outputs, separate from the numeric metrics. ``by_key`` is a fixed map over every metric key plus ``pe`` and ``fcf_yield``, each a read string or null. ``header`` is null when there is no read at all.""" header: str | None = None by_key: dict[str, str | None] = {} class FundamentalResponse(BaseModel): """Envelope-ready fundamental data response. Legacy fields are preserved unchanged (they come from ``fundamental_data`` / the legacy providers). The additive v1 objects — earnings, metrics, valuation, reads — are SEC/Dolt-derived and independent; a null legacy field is never mapped onto the new SEC metrics and vice-versa. """ symbol: str pe_ratio: float | None = None revenue_growth: float | None = None earnings_surprise: float | None = None market_cap: float | None = None next_earnings_date: date | None = None fetched_at: datetime | None = None unavailable_fields: dict[str, str] = {} # --- additive v1 (always present; empty/null when unavailable) --- earnings: EarningsObject | None = None metrics: list[MetricItem] | None = None valuation: Valuation | None = None reads: FundamentalsReads | None = None