summaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorTyler Hoang <tyler@tylerhoang.xyz>2026-05-18 01:21:40 -0700
committerTyler Hoang <tyler@tylerhoang.xyz>2026-05-18 01:23:26 -0700
commit8a7dff97216fd301c7f3c4f20bebec917451d911 (patch)
treea035de96b5a34c433469e1a70c5d6a90bd0f959c /backend
parentdbd591e4e5eceb789cf2d841248632886fa9a2bd (diff)
feat: add DcfResult, MultipleResult, ValuationResponse schemas
Diffstat (limited to 'backend')
-rw-r--r--backend/app/schemas.py36
-rw-r--r--backend/tests/test_api.py29
2 files changed, 65 insertions, 0 deletions
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