Really-amin's picture
Upload 325 files
b66240d verified
"""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 to CoinGecko ID mapping
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)
# CoinGecko OHLC endpoint provides limited data
# Days: 1, 7, 14, 30, 90, 180, 365, max
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)
# Parse CoinGecko OHLC format: [timestamp, open, high, low, close]
ohlcv_list = []
for candle in data[:limit]: # Limit results
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 # CoinGecko OHLC doesn't include volume
))
return ohlcv_list
async def fetch_prices(self, symbols: List[str]) -> List[Price]:
"""Fetch current prices from CoinGecko"""
# Convert symbols to coin IDs
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():
# Find original symbol
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