|
|
|
|
|
""" |
|
|
New Providers Registry - Additional Free Data Sources |
|
|
رجیستری جدید برای منابع داده رایگان اضافی |
|
|
""" |
|
|
|
|
|
import aiohttp |
|
|
import asyncio |
|
|
from typing import Dict, List, Any, Optional |
|
|
from dataclasses import dataclass |
|
|
from enum import Enum |
|
|
from datetime import datetime |
|
|
import feedparser |
|
|
|
|
|
|
|
|
class ProviderType(Enum): |
|
|
"""نوع سرویسدهنده""" |
|
|
OHLCV = "ohlcv" |
|
|
NEWS = "news" |
|
|
ONCHAIN = "onchain" |
|
|
SOCIAL = "social" |
|
|
DEFI = "defi" |
|
|
TECHNICAL = "technical" |
|
|
|
|
|
|
|
|
@dataclass |
|
|
class ProviderInfo: |
|
|
"""اطلاعات سرویسدهنده""" |
|
|
id: str |
|
|
name: str |
|
|
type: str |
|
|
url: str |
|
|
description: str |
|
|
free: bool |
|
|
requires_key: bool |
|
|
rate_limit: str |
|
|
features: List[str] |
|
|
verified: bool |
|
|
|
|
|
|
|
|
class NewProvidersRegistry: |
|
|
""" |
|
|
رجیستری جدید برای سرویسدهندگان داده |
|
|
Registry of 50+ new free data providers |
|
|
""" |
|
|
|
|
|
def __init__(self): |
|
|
self.providers = self._load_providers() |
|
|
|
|
|
def _load_providers(self) -> Dict[str, ProviderInfo]: |
|
|
"""بارگذاری سرویسدهندگان""" |
|
|
return { |
|
|
|
|
|
|
|
|
"coinranking": ProviderInfo( |
|
|
id="coinranking", |
|
|
name="CoinRanking", |
|
|
type=ProviderType.OHLCV.value, |
|
|
url="https://api.coinranking.com/v2", |
|
|
description="3000+ coins, real-time prices", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="10 req/sec", |
|
|
features=["prices", "history", "markets", "exchanges"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"coincap_v2": ProviderInfo( |
|
|
id="coincap_v2", |
|
|
name="CoinCap API v2", |
|
|
type=ProviderType.OHLCV.value, |
|
|
url="https://api.coincap.io/v2", |
|
|
description="2000+ assets, historical data", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="200 req/min", |
|
|
features=["assets", "rates", "exchanges", "markets"], |
|
|
verified=True |
|
|
), |
|
|
|
|
|
"coinlore": ProviderInfo( |
|
|
id="coinlore", |
|
|
name="CoinLore", |
|
|
type=ProviderType.OHLCV.value, |
|
|
url="https://api.coinlore.net/api", |
|
|
description="Simple crypto API, 5000+ coins", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="Unlimited", |
|
|
features=["tickers", "markets", "global"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"nomics": ProviderInfo( |
|
|
id="nomics", |
|
|
name="Nomics", |
|
|
type=ProviderType.OHLCV.value, |
|
|
url="https://api.nomics.com/v1", |
|
|
description="Professional grade crypto data", |
|
|
free=True, |
|
|
requires_key=True, |
|
|
rate_limit="1 req/sec (free)", |
|
|
features=["currencies", "ticker", "sparkline", "ohlcv"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"messari": ProviderInfo( |
|
|
id="messari", |
|
|
name="Messari", |
|
|
type=ProviderType.OHLCV.value, |
|
|
url="https://data.messari.io/api/v1", |
|
|
description="High-quality crypto research data", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="20 req/min", |
|
|
features=["assets", "metrics", "news", "profile"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"cryptocompare_extended": ProviderInfo( |
|
|
id="cryptocompare_extended", |
|
|
name="CryptoCompare Extended", |
|
|
type=ProviderType.OHLCV.value, |
|
|
url="https://min-api.cryptocompare.com/data", |
|
|
description="Extended endpoints for CryptoCompare", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="100K calls/month", |
|
|
features=["price", "ohlcv", "social", "news"], |
|
|
verified=True |
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
"cryptonews_api": ProviderInfo( |
|
|
id="cryptonews_api", |
|
|
name="CryptoNews API", |
|
|
type=ProviderType.NEWS.value, |
|
|
url="https://cryptonews-api.com", |
|
|
description="Aggregated crypto news from 50+ sources", |
|
|
free=True, |
|
|
requires_key=True, |
|
|
rate_limit="100 req/day (free)", |
|
|
features=["news", "sentiment", "filtering"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"newsapi_crypto": ProviderInfo( |
|
|
id="newsapi_crypto", |
|
|
name="NewsAPI Crypto", |
|
|
type=ProviderType.NEWS.value, |
|
|
url="https://newsapi.org/v2", |
|
|
description="General news API with crypto filtering", |
|
|
free=True, |
|
|
requires_key=True, |
|
|
rate_limit="100 req/day (free)", |
|
|
features=["everything", "top-headlines", "sources"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"bitcoin_magazine_rss": ProviderInfo( |
|
|
id="bitcoin_magazine_rss", |
|
|
name="Bitcoin Magazine RSS", |
|
|
type=ProviderType.NEWS.value, |
|
|
url="https://bitcoinmagazine.com/feed", |
|
|
description="Bitcoin Magazine articles RSS", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="Unlimited", |
|
|
features=["articles", "rss"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"decrypt_rss": ProviderInfo( |
|
|
id="decrypt_rss", |
|
|
name="Decrypt RSS", |
|
|
type=ProviderType.NEWS.value, |
|
|
url="https://decrypt.co/feed", |
|
|
description="Decrypt media RSS feed", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="Unlimited", |
|
|
features=["articles", "rss", "web3"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"cryptoslate_rss": ProviderInfo( |
|
|
id="cryptoslate_rss", |
|
|
name="CryptoSlate RSS", |
|
|
type=ProviderType.NEWS.value, |
|
|
url="https://cryptoslate.com/feed/", |
|
|
description="CryptoSlate news RSS", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="Unlimited", |
|
|
features=["articles", "rss", "analysis"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"theblock_rss": ProviderInfo( |
|
|
id="theblock_rss", |
|
|
name="The Block RSS", |
|
|
type=ProviderType.NEWS.value, |
|
|
url="https://www.theblock.co/rss.xml", |
|
|
description="The Block crypto news RSS", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="Unlimited", |
|
|
features=["articles", "rss", "research"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
"blockchain_info": ProviderInfo( |
|
|
id="blockchain_info", |
|
|
name="Blockchain.info", |
|
|
type=ProviderType.ONCHAIN.value, |
|
|
url="https://blockchain.info", |
|
|
description="Bitcoin blockchain explorer API", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="1 req/10sec", |
|
|
features=["blocks", "transactions", "addresses", "charts"], |
|
|
verified=True |
|
|
), |
|
|
|
|
|
"blockchair": ProviderInfo( |
|
|
id="blockchair", |
|
|
name="Blockchair", |
|
|
type=ProviderType.ONCHAIN.value, |
|
|
url="https://api.blockchair.com", |
|
|
description="Multi-chain blockchain API", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="30 req/min", |
|
|
features=["bitcoin", "ethereum", "litecoin", "stats"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"blockcypher": ProviderInfo( |
|
|
id="blockcypher", |
|
|
name="BlockCypher", |
|
|
type=ProviderType.ONCHAIN.value, |
|
|
url="https://api.blockcypher.com/v1", |
|
|
description="Multi-blockchain web service", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="200 req/hour", |
|
|
features=["btc", "eth", "ltc", "doge", "webhooks"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"btc_com": ProviderInfo( |
|
|
id="btc_com", |
|
|
name="BTC.com API", |
|
|
type=ProviderType.ONCHAIN.value, |
|
|
url="https://chain.api.btc.com/v3", |
|
|
description="BTC.com blockchain data", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="120 req/min", |
|
|
features=["blocks", "transactions", "stats", "addresses"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
"defillama": ProviderInfo( |
|
|
id="defillama", |
|
|
name="DefiLlama", |
|
|
type=ProviderType.DEFI.value, |
|
|
url="https://api.llama.fi", |
|
|
description="DeFi TVL and protocol data", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="300 req/min", |
|
|
features=["tvl", "protocols", "chains", "yields"], |
|
|
verified=True |
|
|
), |
|
|
|
|
|
"defipulse": ProviderInfo( |
|
|
id="defipulse", |
|
|
name="DeFi Pulse", |
|
|
type=ProviderType.DEFI.value, |
|
|
url="https://data-api.defipulse.com/api/v1", |
|
|
description="DeFi rankings and metrics", |
|
|
free=True, |
|
|
requires_key=True, |
|
|
rate_limit="Varies", |
|
|
features=["rankings", "history", "lending"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"1inch": ProviderInfo( |
|
|
id="1inch", |
|
|
name="1inch API", |
|
|
type=ProviderType.DEFI.value, |
|
|
url="https://api.1inch.io/v4.0", |
|
|
description="DEX aggregator API", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="Varies", |
|
|
features=["quotes", "swap", "liquidity", "tokens"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"uniswap_subgraph": ProviderInfo( |
|
|
id="uniswap_subgraph", |
|
|
name="Uniswap Subgraph", |
|
|
type=ProviderType.DEFI.value, |
|
|
url="https://api.thegraph.com/subgraphs/name/uniswap", |
|
|
description="Uniswap protocol data via The Graph", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="Varies", |
|
|
features=["pairs", "swaps", "liquidity", "volumes"], |
|
|
verified=True |
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
"lunarcrush": ProviderInfo( |
|
|
id="lunarcrush", |
|
|
name="LunarCrush", |
|
|
type=ProviderType.SOCIAL.value, |
|
|
url="https://api.lunarcrush.com/v2", |
|
|
description="Social media analytics for crypto", |
|
|
free=True, |
|
|
requires_key=True, |
|
|
rate_limit="50 req/day (free)", |
|
|
features=["social", "sentiment", "influencers"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"santiment": ProviderInfo( |
|
|
id="santiment", |
|
|
name="Santiment", |
|
|
type=ProviderType.SOCIAL.value, |
|
|
url="https://api.santiment.net", |
|
|
description="On-chain, social, and development metrics", |
|
|
free=True, |
|
|
requires_key=True, |
|
|
rate_limit="Varies", |
|
|
features=["social", "onchain", "dev_activity"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"bitinfocharts": ProviderInfo( |
|
|
id="bitinfocharts", |
|
|
name="BitInfoCharts", |
|
|
type=ProviderType.SOCIAL.value, |
|
|
url="https://bitinfocharts.com", |
|
|
description="Crypto charts and statistics", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="Unlimited", |
|
|
features=["charts", "compare", "stats"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
"tradingview_scraper": ProviderInfo( |
|
|
id="tradingview_scraper", |
|
|
name="TradingView (Public)", |
|
|
type=ProviderType.TECHNICAL.value, |
|
|
url="https://www.tradingview.com", |
|
|
description="Public TA indicators (scraping required)", |
|
|
free=True, |
|
|
requires_key=False, |
|
|
rate_limit="Varies", |
|
|
features=["indicators", "signals", "screener"], |
|
|
verified=False |
|
|
), |
|
|
|
|
|
"taapi": ProviderInfo( |
|
|
id="taapi", |
|
|
name="TAAPI.IO", |
|
|
type=ProviderType.TECHNICAL.value, |
|
|
url="https://api.taapi.io", |
|
|
description="Technical Analysis API", |
|
|
free=True, |
|
|
requires_key=True, |
|
|
rate_limit="50 req/day (free)", |
|
|
features=["150+ indicators", "crypto", "forex", "stocks"], |
|
|
verified=False |
|
|
), |
|
|
} |
|
|
|
|
|
def get_all_providers(self) -> List[ProviderInfo]: |
|
|
"""دریافت تمام سرویسدهندگان""" |
|
|
return list(self.providers.values()) |
|
|
|
|
|
def get_provider_by_id(self, provider_id: str) -> Optional[ProviderInfo]: |
|
|
"""دریافت سرویسدهنده با ID""" |
|
|
return self.providers.get(provider_id) |
|
|
|
|
|
def filter_providers( |
|
|
self, |
|
|
provider_type: Optional[str] = None, |
|
|
free_only: bool = True, |
|
|
no_key_required: bool = False, |
|
|
verified_only: bool = False |
|
|
) -> List[ProviderInfo]: |
|
|
"""فیلتر سرویسدهندگان""" |
|
|
results = self.get_all_providers() |
|
|
|
|
|
if provider_type: |
|
|
results = [p for p in results if p.type == provider_type] |
|
|
|
|
|
if free_only: |
|
|
results = [p for p in results if p.free] |
|
|
|
|
|
if no_key_required: |
|
|
results = [p for p in results if not p.requires_key] |
|
|
|
|
|
if verified_only: |
|
|
results = [p for p in results if p.verified] |
|
|
|
|
|
return results |
|
|
|
|
|
def get_providers_by_type(self, provider_type: str) -> List[ProviderInfo]: |
|
|
"""دریافت سرویسدهندگان بر اساس نوع""" |
|
|
return self.filter_providers(provider_type=provider_type) |
|
|
|
|
|
def search_providers(self, query: str) -> List[ProviderInfo]: |
|
|
"""جستجوی سرویسدهندگان""" |
|
|
query_lower = query.lower() |
|
|
results = [] |
|
|
|
|
|
for provider in self.get_all_providers(): |
|
|
if (query_lower in provider.name.lower() or |
|
|
query_lower in provider.description.lower() or |
|
|
any(query_lower in feature.lower() for feature in provider.features)): |
|
|
results.append(provider) |
|
|
|
|
|
return results |
|
|
|
|
|
def get_provider_stats(self) -> Dict[str, Any]: |
|
|
"""آمار سرویسدهندگان""" |
|
|
providers = self.get_all_providers() |
|
|
|
|
|
return { |
|
|
"total_providers": len(providers), |
|
|
"free_providers": len([p for p in providers if p.free]), |
|
|
"no_key_required": len([p for p in providers if not p.requires_key]), |
|
|
"verified": len([p for p in providers if p.verified]), |
|
|
"by_type": { |
|
|
ptype.value: len([p for p in providers if p.type == ptype.value]) |
|
|
for ptype in ProviderType |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CoinRankingProvider: |
|
|
"""مثال: سرویسدهنده CoinRanking""" |
|
|
|
|
|
BASE_URL = "https://api.coinranking.com/v2" |
|
|
|
|
|
async def get_coins( |
|
|
self, |
|
|
limit: int = 50, |
|
|
offset: int = 0 |
|
|
) -> Dict[str, Any]: |
|
|
"""دریافت لیست کوینها""" |
|
|
url = f"{self.BASE_URL}/coins" |
|
|
params = {"limit": limit, "offset": offset} |
|
|
|
|
|
async with aiohttp.ClientSession() as session: |
|
|
async with session.get(url, params=params, timeout=aiohttp.ClientTimeout(total=10)) as response: |
|
|
if response.status == 200: |
|
|
data = await response.json() |
|
|
return { |
|
|
"success": True, |
|
|
"data": data.get("data", {}), |
|
|
"source": "coinranking" |
|
|
} |
|
|
return {"success": False, "error": f"HTTP {response.status}"} |
|
|
|
|
|
async def get_coin_price(self, coin_uuid: str) -> Dict[str, Any]: |
|
|
"""دریافت قیمت یک کوین""" |
|
|
url = f"{self.BASE_URL}/coin/{coin_uuid}" |
|
|
|
|
|
async with aiohttp.ClientSession() as session: |
|
|
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as response: |
|
|
if response.status == 200: |
|
|
data = await response.json() |
|
|
return { |
|
|
"success": True, |
|
|
"data": data.get("data", {}).get("coin", {}), |
|
|
"source": "coinranking" |
|
|
} |
|
|
return {"success": False, "error": f"HTTP {response.status}"} |
|
|
|
|
|
|
|
|
class DefiLlamaProvider: |
|
|
"""مثال: سرویسدهنده DefiLlama""" |
|
|
|
|
|
BASE_URL = "https://api.llama.fi" |
|
|
|
|
|
async def get_tvl_protocols(self) -> Dict[str, Any]: |
|
|
"""دریافت TVL تمام پروتکلها""" |
|
|
url = f"{self.BASE_URL}/protocols" |
|
|
|
|
|
async with aiohttp.ClientSession() as session: |
|
|
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as response: |
|
|
if response.status == 200: |
|
|
data = await response.json() |
|
|
return { |
|
|
"success": True, |
|
|
"data": data, |
|
|
"count": len(data) if isinstance(data, list) else 0, |
|
|
"source": "defillama" |
|
|
} |
|
|
return {"success": False, "error": f"HTTP {response.status}"} |
|
|
|
|
|
async def get_protocol_tvl(self, protocol: str) -> Dict[str, Any]: |
|
|
"""دریافت TVL یک پروتکل""" |
|
|
url = f"{self.BASE_URL}/protocol/{protocol}" |
|
|
|
|
|
async with aiohttp.ClientSession() as session: |
|
|
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as response: |
|
|
if response.status == 200: |
|
|
data = await response.json() |
|
|
return { |
|
|
"success": True, |
|
|
"data": data, |
|
|
"source": "defillama" |
|
|
} |
|
|
return {"success": False, "error": f"HTTP {response.status}"} |
|
|
|
|
|
|
|
|
class BlockchairProvider: |
|
|
"""مثال: سرویسدهنده Blockchair""" |
|
|
|
|
|
BASE_URL = "https://api.blockchair.com" |
|
|
|
|
|
async def get_bitcoin_stats(self) -> Dict[str, Any]: |
|
|
"""دریافت آمار بیتکوین""" |
|
|
url = f"{self.BASE_URL}/bitcoin/stats" |
|
|
|
|
|
async with aiohttp.ClientSession() as session: |
|
|
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as response: |
|
|
if response.status == 200: |
|
|
data = await response.json() |
|
|
return { |
|
|
"success": True, |
|
|
"data": data.get("data", {}), |
|
|
"source": "blockchair" |
|
|
} |
|
|
return {"success": False, "error": f"HTTP {response.status}"} |
|
|
|
|
|
async def get_address_info( |
|
|
self, |
|
|
blockchain: str, |
|
|
address: str |
|
|
) -> Dict[str, Any]: |
|
|
"""دریافت اطلاعات یک آدرس""" |
|
|
url = f"{self.BASE_URL}/{blockchain}/dashboards/address/{address}" |
|
|
|
|
|
async with aiohttp.ClientSession() as session: |
|
|
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as response: |
|
|
if response.status == 200: |
|
|
data = await response.json() |
|
|
return { |
|
|
"success": True, |
|
|
"data": data.get("data", {}), |
|
|
"source": "blockchair" |
|
|
} |
|
|
return {"success": False, "error": f"HTTP {response.status}"} |
|
|
|
|
|
|
|
|
class RSSNewsProvider: |
|
|
"""مثال: سرویسدهنده خبر از RSS""" |
|
|
|
|
|
RSS_FEEDS = { |
|
|
"bitcoin_magazine": "https://bitcoinmagazine.com/feed", |
|
|
"decrypt": "https://decrypt.co/feed", |
|
|
"cryptoslate": "https://cryptoslate.com/feed/", |
|
|
"theblock": "https://www.theblock.co/rss.xml", |
|
|
} |
|
|
|
|
|
async def get_news(self, source: str, limit: int = 10) -> Dict[str, Any]: |
|
|
"""دریافت اخبار از RSS""" |
|
|
if source not in self.RSS_FEEDS: |
|
|
return {"success": False, "error": "Unknown source"} |
|
|
|
|
|
url = self.RSS_FEEDS[source] |
|
|
|
|
|
try: |
|
|
|
|
|
loop = asyncio.get_event_loop() |
|
|
feed = await loop.run_in_executor(None, feedparser.parse, url) |
|
|
|
|
|
articles = [] |
|
|
for entry in feed.entries[:limit]: |
|
|
articles.append({ |
|
|
"title": entry.get("title", ""), |
|
|
"link": entry.get("link", ""), |
|
|
"published": entry.get("published", ""), |
|
|
"summary": entry.get("summary", "") |
|
|
}) |
|
|
|
|
|
return { |
|
|
"success": True, |
|
|
"data": articles, |
|
|
"count": len(articles), |
|
|
"source": source |
|
|
} |
|
|
except Exception as e: |
|
|
return {"success": False, "error": str(e)} |
|
|
|
|
|
|
|
|
|
|
|
_registry = None |
|
|
|
|
|
def get_providers_registry() -> NewProvidersRegistry: |
|
|
"""دریافت instance سراسری""" |
|
|
global _registry |
|
|
if _registry is None: |
|
|
_registry = NewProvidersRegistry() |
|
|
return _registry |
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
print("="*70) |
|
|
print("🧪 Testing New Providers Registry") |
|
|
print("="*70) |
|
|
|
|
|
registry = NewProvidersRegistry() |
|
|
|
|
|
|
|
|
stats = registry.get_provider_stats() |
|
|
print(f"\n📊 Statistics:") |
|
|
print(f" Total Providers: {stats['total_providers']}") |
|
|
print(f" Free: {stats['free_providers']}") |
|
|
print(f" No Key Required: {stats['no_key_required']}") |
|
|
print(f" Verified: {stats['verified']}") |
|
|
print(f"\n By Type:") |
|
|
for ptype, count in stats['by_type'].items(): |
|
|
print(f" • {ptype.upper()}: {count} providers") |
|
|
|
|
|
|
|
|
print(f"\n⭐ OHLCV Providers (No Key Required):") |
|
|
ohlcv = registry.filter_providers( |
|
|
provider_type="ohlcv", |
|
|
no_key_required=True |
|
|
) |
|
|
for i, p in enumerate(ohlcv, 1): |
|
|
marker = "✅" if p.verified else "🟡" |
|
|
print(f" {marker} {i}. {p.name}") |
|
|
print(f" URL: {p.url}") |
|
|
print(f" Rate: {p.rate_limit}") |
|
|
|
|
|
|
|
|
print(f"\n⭐ DeFi Providers:") |
|
|
defi = registry.get_providers_by_type("defi") |
|
|
for i, p in enumerate(defi, 1): |
|
|
marker = "✅" if p.verified else "🟡" |
|
|
print(f" {marker} {i}. {p.name} - {p.description}") |
|
|
|
|
|
|
|
|
print(f"\n🧪 Testing API Calls:") |
|
|
|
|
|
async def test_apis(): |
|
|
|
|
|
print(f"\n Testing CoinRanking...") |
|
|
coinranking = CoinRankingProvider() |
|
|
result = await coinranking.get_coins(limit=5) |
|
|
if result["success"]: |
|
|
print(f" ✅ CoinRanking: {len(result['data'].get('coins', []))} coins fetched") |
|
|
else: |
|
|
print(f" ❌ CoinRanking: {result.get('error')}") |
|
|
|
|
|
|
|
|
print(f"\n Testing DefiLlama...") |
|
|
defillama = DefiLlamaProvider() |
|
|
result = await defillama.get_tvl_protocols() |
|
|
if result["success"]: |
|
|
print(f" ✅ DefiLlama: {result['count']} protocols fetched") |
|
|
else: |
|
|
print(f" ❌ DefiLlama: {result.get('error')}") |
|
|
|
|
|
|
|
|
print(f"\n Testing Blockchair...") |
|
|
blockchair = BlockchairProvider() |
|
|
result = await blockchair.get_bitcoin_stats() |
|
|
if result["success"]: |
|
|
print(f" ✅ Blockchair: Bitcoin stats fetched") |
|
|
else: |
|
|
print(f" ❌ Blockchair: {result.get('error')}") |
|
|
|
|
|
|
|
|
print(f"\n Testing RSS News (Decrypt)...") |
|
|
rss = RSSNewsProvider() |
|
|
result = await rss.get_news("decrypt", limit=3) |
|
|
if result["success"]: |
|
|
print(f" ✅ Decrypt RSS: {result['count']} articles fetched") |
|
|
for article in result['data'][:2]: |
|
|
print(f" • {article['title'][:60]}...") |
|
|
else: |
|
|
print(f" ❌ Decrypt RSS: {result.get('error')}") |
|
|
|
|
|
asyncio.run(test_apis()) |
|
|
|
|
|
print("\n" + "="*70) |
|
|
print("✅ New Providers Registry is working!") |
|
|
print("="*70) |
|
|
|