from __future__ import annotations import httpx from app.market.base import MarketData from app.schemas import Candle BASE_URL = "https://api.binance.com" def to_exchange_symbol(symbol: str) -> str: return symbol.replace("/", "").upper() class BinanceMarketData(MarketData): """Public Binance spot market data over REST (no API key required).""" def __init__(self, base_url: str = BASE_URL, timeout: float = 10.0) -> None: self._client = httpx.AsyncClient(base_url=base_url, timeout=timeout) async def fetch_candles(self, symbol: str, timeframe: str, limit: int) -> list[Candle]: response = await self._client.get( "/api/v3/klines", params={ "symbol": to_exchange_symbol(symbol), "interval": timeframe, "limit": limit, }, ) response.raise_for_status() return [ Candle( ts=int(row[0]), open=float(row[1]), high=float(row[2]), low=float(row[3]), close=float(row[4]), volume=float(row[5]), ) for row in response.json() ] async def fetch_price(self, symbol: str) -> float: response = await self._client.get( "/api/v3/ticker/price", params={"symbol": to_exchange_symbol(symbol)}, ) response.raise_for_status() return float(response.json()["price"]) async def close(self) -> None: await self._client.aclose()