"""Screener Oracle service methods.""" from __future__ import annotations from libs.oracle_client.client import OracleClient from libs.oracle_client.models import ScreenerResponse, ScreenerStock _SCREENER_PATH = "/api/v1/screener/stocks" _DEFAULT_PAGE_SIZE = 250 class ScreenerService: def __init__(self, client: OracleClient) -> None: self._client = client async def search_stocks( self, market_cap_min: float | None = None, market_cap_max: float | None = None, min_avg_volume: int | None = None, exchange: str | None = None, exclude_types: str | None = None, price_min: float | None = None, page: int = 1, page_size: int = _DEFAULT_PAGE_SIZE, ) -> ScreenerResponse: """GET /api/v1/screener/stocks — single page.""" params: dict[str, str | int | float] = { "page": page, "page_size": page_size, } if market_cap_min is not None: params["market_cap_min"] = market_cap_min if market_cap_max is not None: params["market_cap_max"] = market_cap_max if min_avg_volume is not None: params["min_avg_volume"] = min_avg_volume if exchange is not None: params["exchange"] = exchange if exclude_types is not None: params["exclude_types"] = exclude_types if price_min is not None: params["price_min"] = price_min data = await self._client.get(_SCREENER_PATH, params=params) stocks = [ScreenerStock.model_validate(s) for s in data.get("stocks", [])] return ScreenerResponse( stocks=stocks, total=data.get("total", len(stocks)), page=page, page_size=page_size, ) async def search_all_stocks(self, **kwargs) -> list[ScreenerStock]: """Auto-paginate and return all matching stocks.""" all_stocks: list[ScreenerStock] = [] page = 1 page_size = kwargs.pop("page_size", _DEFAULT_PAGE_SIZE) while True: resp = await self.search_stocks(**kwargs, page=page, page_size=page_size) if not resp.stocks: break all_stocks.extend(resp.stocks) if len(resp.stocks) < page_size: break page += 1 return all_stocks