From 8a7dff97216fd301c7f3c4f20bebec917451d911 Mon Sep 17 00:00:00 2001 From: Tyler Hoang Date: Mon, 18 May 2026 01:21:40 -0700 Subject: feat: add DcfResult, MultipleResult, ValuationResponse schemas --- backend/app/schemas.py | 36 ++++++++++++++++++++++++++++++++++++ backend/tests/test_api.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/backend/app/schemas.py b/backend/app/schemas.py index 86f586c..87acd0d 100644 --- a/backend/app/schemas.py +++ b/backend/app/schemas.py @@ -128,6 +128,42 @@ class FinancialsResponse(BaseModel): cash_flow: FinancialStatement +class DcfResult(BaseModel): + available: bool = True + error: str | None = None + intrinsic_value_per_share: float | None = None + enterprise_value: float | None = None + equity_value: float | None = None + net_debt: float | None = None + cash_and_equivalents: float | None = None + total_debt: float | None = None + terminal_value_pv: float | None = None + fcf_pv_sum: float | None = None + growth_rate_used: float | None = None + base_fcf: float | None = None + wacc: float = 0.10 + terminal_growth: float = 0.03 + + +class MultipleResult(BaseModel): + available: bool = True + implied_price_per_share: float | None = None + implied_ev: float | None = None + equity_value: float | None = None + net_debt: float | None = None + multiple_used: float | None = None + + +class ValuationResponse(BaseModel): + symbol: str + current_price: float | None = None + shares_outstanding: float | None = None + dcf: DcfResult + ev_ebitda: MultipleResult + ev_revenue: MultipleResult + price_to_book: MultipleResult + + class WatchlistItem(BaseModel): symbol: str created_at: str diff --git a/backend/tests/test_api.py b/backend/tests/test_api.py index 0054c49..395bc12 100644 --- a/backend/tests/test_api.py +++ b/backend/tests/test_api.py @@ -598,3 +598,32 @@ def test_financials_route_period_param(monkeypatch) -> None: monkeypatch.setattr(main.data_service, "get_financials", mock_get_financials) main.ticker_financials("AAPL", period="quarterly") assert captured == ["quarterly"] + + +def test_valuation_schema_structure() -> None: + from app.schemas import DcfResult, MultipleResult, ValuationResponse + + dcf_unavail = DcfResult(available=False) + assert dcf_unavail.available is False + assert dcf_unavail.wacc == 0.10 + assert dcf_unavail.terminal_growth == 0.03 + assert dcf_unavail.error is None + assert dcf_unavail.intrinsic_value_per_share is None + + mult_unavail = MultipleResult(available=False) + assert mult_unavail.available is False + assert mult_unavail.implied_price_per_share is None + + resp = ValuationResponse( + symbol="AAPL", + current_price=150.0, + shares_outstanding=15_000_000_000.0, + dcf=DcfResult(available=True, intrinsic_value_per_share=182.0, growth_rate_used=0.082), + ev_ebitda=MultipleResult(available=True, implied_price_per_share=178.0, multiple_used=20.0), + ev_revenue=MultipleResult(available=False), + price_to_book=MultipleResult(available=False), + ) + assert resp.symbol == "AAPL" + assert resp.dcf.intrinsic_value_per_share == 182.0 + assert resp.ev_ebitda.multiple_used == 20.0 + assert resp.ev_revenue.available is False -- cgit v1.3-2-g0d8e