diff options
| author | Tyler Hoang <tyler@tylerhoang.xyz> | 2026-05-18 02:37:26 -0700 |
|---|---|---|
| committer | Tyler Hoang <tyler@tylerhoang.xyz> | 2026-05-18 02:37:26 -0700 |
| commit | 37ac7be64d18bf1957e5400597abfb9d2d73c0c5 (patch) | |
| tree | 143126eb6993a031c95d7a41ce034f484aeb7abc /backend | |
| parent | 38bef98ab1964bc9365d17c4a5ca17cdbd32673b (diff) | |
feat: add GET /api/tickers/{symbol}/ratios route
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/app/main.py | 7 | ||||
| -rw-r--r-- | backend/tests/test_api.py | 27 |
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 |
