# spot.py import logging import requests from typing import Union, List, Dict, Any from requests import HTTPError, Session from client import BaseClient logger = logging.getLogger(__name__) class SpotClient(BaseClient): """ Spot market endpoints for CCData (CryptoCompare / CoinDesk) Data API. - list_markets_instruments(market): all supported instrument codes for a spot market. - list_markets(market, groups): all spot markets, optionally filtered. - get_latest_tick(market, instruments): latest tick data for one or more instruments. """ def __init__(self, api_key: str, base_url: str = None, timeout: int = 10): super().__init__(api_key=api_key, base_url=base_url) self.timeout = timeout # Use a Session for connection pooling & retries self.session = Session() adapter = requests.adapters.HTTPAdapter(max_retries=3) self.session.mount("https://", adapter) def list_markets_instruments(self, market: str) -> Dict[str, Any]: """ GET /spot/v1/markets/instruments :param market: Exchange slug (e.g. "binance") :returns: {"Data": [ {instrument, ...}, … ]} """ params = {"market": market} return self._get("spot/v1/markets/instruments", params=params, timeout=self.timeout) def list_markets(self, market: str = None, groups: str = "BASIC") -> Dict[str, Any]: """ GET /spot/v1/markets :param market: optional exchange slug to filter by :param groups: filter group name (e.g. "BASIC", "ADVANCED") :returns: {"Data": [ {market info…}, … ]} """ params: Dict[str, Any] = {"groups": groups} if market: params["market"] = market return self._get("spot/v1/markets", params=params, timeout=self.timeout) def get_latest_tick( self, market: str, instruments: Union[str, List[str]] ) -> Dict[str, Any]: """ GET /spot/v1/latest/tick :param market: Exchange slug (e.g. "binance") :param instruments: Single ID or list (e.g. "BTC-USDT" or ["BTC-USDT","ETH-USDT"]) :returns: {"Data": [ { ...tick fields... }, … ]} """ # allow list-of-str or comma-string if isinstance(instruments, (list, tuple)): instr_param = ",".join(instruments) else: instr_param = instruments params = {"market": market, "instruments": instr_param} try: resp = self._get("spot/v1/latest/tick", params=params, timeout=self.timeout) except HTTPError as e: logger.warning( "Failed to fetch latest tick(%s) on %s: %s", instr_param, market, e ) return {"Data": []} data = resp.get("Data", []) # ensure we always return a list if isinstance(data, dict): data = [data] return {"Data": data}