| """CoinGecko provider implementation""" |
| from __future__ import annotations |
| from typing import List |
| from datetime import datetime |
| import sys |
| import os |
| sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) |
|
|
| from core.base_provider import BaseProvider |
| from core.models import OHLCV, Price |
|
|
|
|
| class CoinGeckoProvider(BaseProvider): |
| """CoinGecko public API provider""" |
|
|
| |
| SYMBOL_MAP = { |
| "BTC": "bitcoin", |
| "ETH": "ethereum", |
| "SOL": "solana", |
| "XRP": "ripple", |
| "BNB": "binancecoin", |
| "ADA": "cardano", |
| "DOT": "polkadot", |
| "LINK": "chainlink", |
| "LTC": "litecoin", |
| "BCH": "bitcoin-cash", |
| "MATIC": "matic-network", |
| "AVAX": "avalanche-2", |
| "XLM": "stellar", |
| "TRX": "tron", |
| } |
|
|
| def __init__(self, api_key: str = None): |
| super().__init__( |
| name="coingecko", |
| base_url="https://api.coingecko.com/api/v3", |
| timeout=15 |
| ) |
| self.api_key = api_key |
|
|
| def _get_coin_id(self, symbol: str) -> str: |
| """Convert symbol to CoinGecko coin ID""" |
| symbol = symbol.upper().replace("USDT", "").replace("/USDT", "") |
| return self.SYMBOL_MAP.get(symbol, symbol.lower()) |
|
|
| async def fetch_ohlcv(self, symbol: str, interval: str, limit: int) -> List[OHLCV]: |
| """Fetch OHLCV data from CoinGecko""" |
| coin_id = self._get_coin_id(symbol) |
|
|
| |
| |
| days_map = { |
| "1m": 1, |
| "5m": 1, |
| "15m": 1, |
| "1h": 7, |
| "4h": 30, |
| "1d": 90, |
| "1w": 365, |
| } |
| days = days_map.get(interval, 7) |
|
|
| url = f"{self.base_url}/coins/{coin_id}/ohlc" |
| params = { |
| "vs_currency": "usd", |
| "days": days |
| } |
|
|
| if self.api_key: |
| params["x_cg_pro_api_key"] = self.api_key |
|
|
| data = await self._make_request(url, params) |
|
|
| |
| ohlcv_list = [] |
| for candle in data[:limit]: |
| ohlcv_list.append(OHLCV( |
| timestamp=int(candle[0]), |
| open=float(candle[1]), |
| high=float(candle[2]), |
| low=float(candle[3]), |
| close=float(candle[4]), |
| volume=0.0 |
| )) |
|
|
| return ohlcv_list |
|
|
| async def fetch_prices(self, symbols: List[str]) -> List[Price]: |
| """Fetch current prices from CoinGecko""" |
| |
| coin_ids = [self._get_coin_id(s) for s in symbols] |
|
|
| url = f"{self.base_url}/simple/price" |
| params = { |
| "ids": ",".join(coin_ids), |
| "vs_currencies": "usd", |
| "include_24hr_change": "true", |
| "include_24hr_vol": "true", |
| "include_market_cap": "true" |
| } |
|
|
| if self.api_key: |
| params["x_cg_pro_api_key"] = self.api_key |
|
|
| data = await self._make_request(url, params) |
|
|
| prices = [] |
| for coin_id, coin_data in data.items(): |
| |
| symbol = next( |
| (s for s, cid in self.SYMBOL_MAP.items() if cid == coin_id), |
| coin_id.upper() |
| ) |
|
|
| prices.append(Price( |
| symbol=symbol, |
| name=coin_id.replace("-", " ").title(), |
| price=coin_data.get("usd", 0), |
| priceUsd=coin_data.get("usd", 0), |
| change24h=coin_data.get("usd_24h_change"), |
| volume24h=coin_data.get("usd_24h_vol"), |
| marketCap=coin_data.get("usd_market_cap"), |
| lastUpdate=datetime.now().isoformat() |
| )) |
|
|
| return prices |
|
|
| async def fetch_market_data(self) -> dict: |
| """Fetch global market data""" |
| url = f"{self.base_url}/global" |
|
|
| if self.api_key: |
| params = {"x_cg_pro_api_key": self.api_key} |
| else: |
| params = None |
|
|
| data = await self._make_request(url, params) |
|
|
| if "data" in data: |
| return data["data"] |
| return data |
|
|