|
|
import logging |
|
|
import aiohttp |
|
|
import os |
|
|
import asyncio |
|
|
from typing import Dict, List, Optional, Any |
|
|
from datetime import datetime |
|
|
from backend.orchestration.provider_manager import provider_manager, ProviderConfig |
|
|
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def fetch_coingecko_market(config: ProviderConfig, **kwargs) -> Any: |
|
|
ids = kwargs.get("ids", "bitcoin,ethereum") |
|
|
vs_currency = kwargs.get("vs_currency", "usd") |
|
|
|
|
|
url = f"{config.base_url}/coins/markets" |
|
|
params = { |
|
|
"vs_currency": vs_currency, |
|
|
"ids": ids, |
|
|
"order": "market_cap_desc", |
|
|
"per_page": 100, |
|
|
"page": 1, |
|
|
"sparkline": "false", |
|
|
"price_change_percentage": "24h" |
|
|
} |
|
|
|
|
|
|
|
|
if config.api_key: |
|
|
params["x_cg_pro_api_key"] = config.api_key |
|
|
|
|
|
async with aiohttp.ClientSession() as session: |
|
|
async with session.get(url, params=params, timeout=config.timeout) as response: |
|
|
if response.status == 429: |
|
|
raise Exception("Rate limit exceeded (429)") |
|
|
response.raise_for_status() |
|
|
return await response.json() |
|
|
|
|
|
async def fetch_coingecko_price(config: ProviderConfig, **kwargs) -> Any: |
|
|
coin_id = kwargs.get("coin_id", "bitcoin") |
|
|
vs_currencies = kwargs.get("vs_currencies", "usd") |
|
|
|
|
|
url = f"{config.base_url}/simple/price" |
|
|
params = {"ids": coin_id, "vs_currencies": vs_currencies} |
|
|
|
|
|
if config.api_key: |
|
|
params["x_cg_pro_api_key"] = config.api_key |
|
|
|
|
|
async with aiohttp.ClientSession() as session: |
|
|
async with session.get(url, params=params, timeout=config.timeout) as response: |
|
|
response.raise_for_status() |
|
|
return await response.json() |
|
|
|
|
|
async def fetch_binance_ticker(config: ProviderConfig, **kwargs) -> Any: |
|
|
symbol = kwargs.get("symbol", "BTCUSDT").upper() |
|
|
url = f"{config.base_url}/ticker/price" |
|
|
params = {"symbol": symbol} |
|
|
|
|
|
async with aiohttp.ClientSession() as session: |
|
|
async with session.get(url, params=params, timeout=config.timeout) as response: |
|
|
if response.status == 451: |
|
|
raise Exception("Geo-blocked (451)") |
|
|
response.raise_for_status() |
|
|
data = await response.json() |
|
|
|
|
|
return {"price": float(data.get("price", 0)), "symbol": data.get("symbol")} |
|
|
|
|
|
async def fetch_binance_klines(config: ProviderConfig, **kwargs) -> Any: |
|
|
symbol = kwargs.get("symbol", "BTCUSDT").upper() |
|
|
interval = kwargs.get("interval", "1h") |
|
|
limit = kwargs.get("limit", 100) |
|
|
|
|
|
url = f"{config.base_url}/klines" |
|
|
params = { |
|
|
"symbol": symbol, |
|
|
"interval": interval, |
|
|
"limit": limit |
|
|
} |
|
|
|
|
|
async with aiohttp.ClientSession() as session: |
|
|
async with session.get(url, params=params, timeout=config.timeout) as response: |
|
|
if response.status == 451: |
|
|
raise Exception("Geo-blocked (451)") |
|
|
response.raise_for_status() |
|
|
return await response.json() |
|
|
|
|
|
async def fetch_cryptopanic_news(config: ProviderConfig, **kwargs) -> Any: |
|
|
filter_type = kwargs.get("filter", "hot") |
|
|
url = f"{config.base_url}/posts/" |
|
|
|
|
|
params = { |
|
|
"auth_token": config.api_key, |
|
|
"filter": filter_type, |
|
|
"public": "true" |
|
|
} |
|
|
|
|
|
async with aiohttp.ClientSession() as session: |
|
|
async with session.get(url, params=params, timeout=config.timeout) as response: |
|
|
response.raise_for_status() |
|
|
return await response.json() |
|
|
|
|
|
async def fetch_newsapi(config: ProviderConfig, **kwargs) -> Any: |
|
|
query = kwargs.get("query", "crypto") |
|
|
url = f"{config.base_url}/everything" |
|
|
|
|
|
params = { |
|
|
"q": query, |
|
|
"apiKey": config.api_key, |
|
|
"sortBy": "publishedAt", |
|
|
"language": "en" |
|
|
} |
|
|
|
|
|
async with aiohttp.ClientSession() as session: |
|
|
async with session.get(url, params=params, timeout=config.timeout) as response: |
|
|
response.raise_for_status() |
|
|
return await response.json() |
|
|
|
|
|
async def fetch_alternative_me_fng(config: ProviderConfig, **kwargs) -> Any: |
|
|
limit = kwargs.get("limit", 1) |
|
|
url = f"{config.base_url}/fng/" |
|
|
params = {"limit": limit} |
|
|
|
|
|
async with aiohttp.ClientSession() as session: |
|
|
async with session.get(url, params=params, timeout=config.timeout) as response: |
|
|
response.raise_for_status() |
|
|
return await response.json() |
|
|
|
|
|
async def fetch_etherscan_gas(config: ProviderConfig, **kwargs) -> Any: |
|
|
url = config.base_url |
|
|
params = { |
|
|
"module": "gastracker", |
|
|
"action": "gasoracle", |
|
|
"apikey": config.api_key |
|
|
} |
|
|
|
|
|
async with aiohttp.ClientSession() as session: |
|
|
async with session.get(url, params=params, timeout=config.timeout) as response: |
|
|
response.raise_for_status() |
|
|
return await response.json() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def initialize_providers(): |
|
|
|
|
|
provider_manager.register_provider( |
|
|
"market", |
|
|
ProviderConfig( |
|
|
name="coingecko_free", |
|
|
category="market", |
|
|
base_url="https://api.coingecko.com/api/v3", |
|
|
rate_limit_per_min=30, |
|
|
weight=100 |
|
|
), |
|
|
fetch_coingecko_market |
|
|
) |
|
|
|
|
|
provider_manager.register_provider( |
|
|
"market_pro", |
|
|
ProviderConfig( |
|
|
name="coingecko_pro", |
|
|
category="market", |
|
|
base_url="https://pro-api.coingecko.com/api/v3", |
|
|
api_key=os.getenv("COINGECKO_PRO_API_KEY", "04cf4b5b-9868-465c-8ba0-9f2e78c92eb1"), |
|
|
rate_limit_per_min=500, |
|
|
weight=200 |
|
|
), |
|
|
fetch_coingecko_market |
|
|
) |
|
|
|
|
|
provider_manager.register_provider( |
|
|
"market", |
|
|
ProviderConfig( |
|
|
name="binance", |
|
|
category="market", |
|
|
base_url="https://api.binance.com/api/v3", |
|
|
rate_limit_per_min=1200, |
|
|
weight=90 |
|
|
), |
|
|
fetch_binance_ticker |
|
|
) |
|
|
|
|
|
|
|
|
provider_manager.register_provider( |
|
|
"ohlc", |
|
|
ProviderConfig( |
|
|
name="binance_ohlc", |
|
|
category="ohlc", |
|
|
base_url="https://api.binance.com/api/v3", |
|
|
rate_limit_per_min=1200, |
|
|
weight=100 |
|
|
), |
|
|
fetch_binance_klines |
|
|
) |
|
|
|
|
|
|
|
|
provider_manager.register_provider( |
|
|
"news", |
|
|
ProviderConfig( |
|
|
name="cryptopanic", |
|
|
category="news", |
|
|
base_url="https://cryptopanic.com/api/v1", |
|
|
api_key=os.getenv("CRYPTOPANIC_API_KEY", "7832690f05026639556837583758"), |
|
|
rate_limit_per_min=60, |
|
|
weight=100 |
|
|
), |
|
|
fetch_cryptopanic_news |
|
|
) |
|
|
|
|
|
provider_manager.register_provider( |
|
|
"news", |
|
|
ProviderConfig( |
|
|
name="newsapi", |
|
|
category="news", |
|
|
base_url="https://newsapi.org/v2", |
|
|
api_key=os.getenv("NEWS_API_KEY", "968a5e25552b4cb5ba3280361d8444ab"), |
|
|
rate_limit_per_min=100, |
|
|
weight=90 |
|
|
), |
|
|
fetch_newsapi |
|
|
) |
|
|
|
|
|
|
|
|
provider_manager.register_provider( |
|
|
"sentiment", |
|
|
ProviderConfig( |
|
|
name="alternative_me", |
|
|
category="sentiment", |
|
|
base_url="https://api.alternative.me", |
|
|
rate_limit_per_min=60, |
|
|
weight=100 |
|
|
), |
|
|
fetch_alternative_me_fng |
|
|
) |
|
|
|
|
|
|
|
|
provider_manager.register_provider( |
|
|
"onchain", |
|
|
ProviderConfig( |
|
|
name="etherscan", |
|
|
category="onchain", |
|
|
base_url="https://api.etherscan.io/api", |
|
|
api_key=os.getenv("ETHERSCAN_API_KEY", "SZHYFZK2RR8H9TIMJBVW54V4H81K2Z2KR2"), |
|
|
rate_limit_per_min=5, |
|
|
weight=100 |
|
|
), |
|
|
fetch_etherscan_gas |
|
|
) |
|
|
|
|
|
provider_manager.register_provider( |
|
|
"onchain", |
|
|
ProviderConfig( |
|
|
name="etherscan_backup", |
|
|
category="onchain", |
|
|
base_url="https://api.etherscan.io/api", |
|
|
api_key=os.getenv("ETHERSCAN_API_KEY_2", "T6IR8VJHX2NE6ZJW2S3FDVN1TYG4PYYI45"), |
|
|
rate_limit_per_min=5, |
|
|
weight=90 |
|
|
), |
|
|
fetch_etherscan_gas |
|
|
) |
|
|
|
|
|
|
|
|
initialize_providers() |
|
|
|