summaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorTyler Hoang <tyler@tylerhoang.xyz>2026-05-18 02:37:26 -0700
committerTyler Hoang <tyler@tylerhoang.xyz>2026-05-18 02:37:26 -0700
commit37ac7be64d18bf1957e5400597abfb9d2d73c0c5 (patch)
tree143126eb6993a031c95d7a41ce034f484aeb7abc /backend
parent38bef98ab1964bc9365d17c4a5ca17cdbd32673b (diff)
feat: add GET /api/tickers/{symbol}/ratios route
Diffstat (limited to 'backend')
-rw-r--r--backend/app/main.py7
-rw-r--r--backend/tests/test_api.py27
2 files changed, 33 insertions, 1 deletions
diff --git a/backend/app/main.py b/backend/app/main.py
index 1cc127e..7e02cbe 100644
--- a/backend/app/main.py
+++ b/backend/app/main.py
@@ -9,7 +9,7 @@ from fastapi import FastAPI, HTTPException, Query, status
from fastapi.middleware.cors import CORSMiddleware
from app.db import watchlist
-from app.schemas import FinancialsResponse, HistoryPoint, MarketIndex, SearchResult, TickerOverview, ValuationResponse, WatchlistResponse
+from app.schemas import FinancialsResponse, HistoryPoint, MarketIndex, RatiosResponse, SearchResult, TickerOverview, ValuationResponse, WatchlistResponse
from app.services import data_service
load_dotenv()
@@ -75,6 +75,11 @@ def ticker_valuation(symbol: str) -> dict:
return data_service.get_valuation(symbol)
+@app.get("/api/tickers/{symbol}/ratios", response_model=RatiosResponse)
+def ticker_ratios(symbol: str) -> dict:
+ return data_service.get_ratios(symbol)
+
+
@app.get("/api/watchlist", response_model=WatchlistResponse)
def get_watchlist() -> dict:
items = []
diff --git a/backend/tests/test_api.py b/backend/tests/test_api.py
index d0aafa4..2ec4a08 100644
--- a/backend/tests/test_api.py
+++ b/backend/tests/test_api.py
@@ -1168,3 +1168,30 @@ def test_get_ratios_interest_coverage(monkeypatch) -> None:
assert result["interest_coverage"]["value"] == 8.5
assert result["interest_coverage"]["spark"] == []
+
+
+def test_ticker_ratios_route(monkeypatch) -> None:
+ """GET /api/tickers/{symbol}/ratios returns a valid RatiosResponse shape."""
+ clear_service_caches()
+
+ def _fake_ratios(sym: str) -> dict:
+ def _pt(v=None):
+ return {"value": v, "spark": [], "vs_sector": None}
+
+ return {
+ "pe_ttm": _pt(24.3), "ev_ebitda": _pt(16.1),
+ "gross_margin": _pt(0.46), "net_margin": _pt(0.14),
+ "price_to_book": _pt(5.8), "price_to_sales": _pt(6.2),
+ "ev_to_sales": _pt(6.5), "p_fcf": _pt(28.4), "forward_pe": _pt(22.0),
+ "operating_margin": _pt(0.19), "ebitda_margin": _pt(0.22), "fcf_margin": _pt(0.18),
+ "roe": _pt(0.38), "roa": _pt(0.12), "roic": _pt(0.22),
+ "debt_to_equity": _pt(1.4), "current_ratio": _pt(1.9),
+ "quick_ratio": _pt(1.5), "interest_coverage": _pt(8.5),
+ "dividend_yield": _pt(None), "dividend_payout": _pt(None),
+ }
+
+ monkeypatch.setattr(main.data_service, "get_ratios", _fake_ratios)
+ result = main.ticker_ratios("AAPL")
+ assert result["pe_ttm"]["value"] == pytest.approx(24.3)
+ assert result["gross_margin"]["spark"] == []
+ assert result["dividend_yield"]["vs_sector"] is None