diff options
| -rw-r--r-- | backend/app/schemas.py | 81 |
1 files changed, 79 insertions, 2 deletions
diff --git a/backend/app/schemas.py b/backend/app/schemas.py index 351de06..27e56b4 100644 --- a/backend/app/schemas.py +++ b/backend/app/schemas.py @@ -1,7 +1,7 @@ """Pydantic response schemas for the Prism v2 Overview API.""" -from typing import Literal +from typing import ClassVar, Literal -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, model_validator class SearchResult(BaseModel): @@ -96,6 +96,8 @@ class TickerOverview(BaseModel): range_52w: Range52Week short_interest: ShortInterest meta: OverviewMeta + currency: str = "USD" + currency_warning: str | None = None class HistoryPoint(BaseModel): @@ -126,6 +128,54 @@ class FinancialsResponse(BaseModel): income: FinancialStatement balance: FinancialStatement cash_flow: FinancialStatement + currency: str = "USD" + currency_warning: str | None = None + + +class AdvancedDcfInputs(BaseModel): + _projection_arrays: ClassVar[tuple[str, ...]] = ( + "revenue_growth", + "ebitda_margin", + "dna_pct_revenue", + "capex_pct_revenue", + "nwc_chg_pct_delta_rev", + "tax_rate", + ) + + base_revenue: float = Field(gt=0) + revenue_growth: list[float] = Field(min_length=1) + ebitda_margin: list[float] = Field(min_length=1) + dna_pct_revenue: list[float] = Field(min_length=1) + capex_pct_revenue: list[float] = Field(min_length=1) + nwc_chg_pct_delta_rev: list[float] = Field(min_length=1) + tax_rate: list[float] = Field(min_length=1) + wacc: float + terminal_growth: float + projection_years: int = Field(default=5, ge=1) + + @model_validator(mode="after") + def projection_arrays_cover_horizon(self) -> "AdvancedDcfInputs": + short_fields = [ + field_name + for field_name in self._projection_arrays + if len(getattr(self, field_name)) < self.projection_years + ] + if short_fields: + fields = ", ".join(short_fields) + raise ValueError(f"projection_years requires assumptions for every year: {fields}") + return self + + +class SensitivityMatrix(BaseModel): + wacc: list[float] = Field(min_length=5, max_length=5) + terminal_growth: list[float] = Field(min_length=5, max_length=5) + implied_prices: list[list[float | None]] = Field(min_length=5, max_length=5) + + @model_validator(mode="after") + def implied_prices_are_five_by_five(self) -> "SensitivityMatrix": + if any(len(row) != 5 for row in self.implied_prices): + raise ValueError("implied_prices must contain five WACC rows with five terminal-growth columns") + return self class DcfResult(BaseModel): @@ -144,6 +194,8 @@ class DcfResult(BaseModel): wacc: float = 0.10 terminal_growth: float = 0.03 projection_years: int = 5 + sensitivity: SensitivityMatrix | None = None + advanced_inputs: AdvancedDcfInputs | None = None class MultipleResult(BaseModel): @@ -163,6 +215,29 @@ class ValuationResponse(BaseModel): ev_ebitda: MultipleResult ev_revenue: MultipleResult price_to_book: MultipleResult + currency: str = "USD" + currency_warning: str | None = None + + +class WaccResponse(BaseModel): + symbol: str + available: bool = True + wacc: float | None = None + cost_of_equity: float | None = None + after_tax_cost_of_debt: float | None = None + risk_free_rate: float = 0.044 + beta: float = 1.0 + equity_risk_premium: float = 0.055 + cost_of_debt: float = 0.05 + tax_rate: float = 0.21 + market_cap: float | None = None + total_debt: float | None = None + cash: float | None = None + net_debt: float | None = None + equity_weight: float | None = None + debt_weight: float | None = None + currency: str = "USD" + currency_warning: str | None = None class WatchlistItem(BaseModel): @@ -204,6 +279,8 @@ class RatiosResponse(BaseModel): interest_coverage: RatioPoint dividend_yield: RatioPoint dividend_payout: RatioPoint + currency: str = "USD" + currency_warning: str | None = None class InsiderTransaction(BaseModel): |
