Merge branch '2-news-api' into 3-market-api

This commit is contained in:
2025-09-30 17:30:01 +02:00
9 changed files with 226 additions and 755 deletions

View File

@@ -1,87 +1,30 @@
from .base import BaseWrapper
from app.markets.coinbase import CoinBaseWrapper
from app.markets.cryptocompare import CryptoCompareWrapper
from app.markets.binance import BinanceWrapper
from app.markets.binance_public import PublicBinanceAgent
from app.markets.error_handler import ProviderFallback, MarketAPIError, safe_execute
from .coinbase import CoinBaseWrapper
from .cryptocompare import CryptoCompareWrapper
from app.utils.wrapper_handler import WrapperHandler
from agno.utils.log import log_warning
import logging
__all__ = [ "MarketAPIs", "BaseWrapper", "CoinBaseWrapper", "CryptoCompareWrapper" ]
logger = logging.getLogger(__name__)
# TODO se si vuole usare un aggregatore di dati di mercato, si può aggiungere qui facendo una classe extra (simile a questa) che per ogni chiamata chiama tutti i wrapper e aggrega i risultati
class MarketAPIs(BaseWrapper):
"""
Classe per gestire le API di mercato disponibili.
Permette di ottenere un'istanza della prima API disponibile in base alla priorità specificata.
Supporta operazioni come ottenere informazioni su singoli prodotti, liste di prodotti e dati storici.
Usa un WrapperHandler per gestire più wrapper e tentare chiamate in modo resiliente.
"""
@staticmethod
def get_list_available_market_apis(currency: str = "USD") -> list[BaseWrapper]:
"""
Restituisce una lista di istanze delle API di mercato disponibili.
La priorità è data dall'ordine delle API nella lista wrappers.
1. CoinBase
2. CryptoCompare
:param currency: Valuta di riferimento (default "USD")
:return: Lista di istanze delle API di mercato disponibili
"""
wrapper_builders = [
CoinBaseWrapper,
CryptoCompareWrapper,
]
result = []
for wrapper in wrapper_builders:
try:
result.append(wrapper(currency=currency))
except Exception as e:
log_warning(f"{wrapper} cannot be initialized: {e}")
assert result, "No market API keys set in environment variables."
return result
def __init__(self, currency: str = "USD"):
"""
Inizializza la classe con la valuta di riferimento e la priorità dei provider.
Args:
currency: Valuta di riferimento (default "USD")
"""
self.currency = currency
self.wrappers = MarketAPIs.get_list_available_market_apis(currency=currency)
self.fallback_manager = ProviderFallback(self.wrappers)
# Metodi con fallback robusto tra provider multipli
def get_product(self, asset_id: str):
"""Ottiene informazioni su un prodotto con fallback automatico tra provider."""
try:
return self.fallback_manager.execute_with_fallback("get_product", asset_id)
except MarketAPIError as e:
logger.error(f"Failed to get product {asset_id}: {str(e)}")
raise
wrappers = [ CoinBaseWrapper, CryptoCompareWrapper ]
self.wrappers: WrapperHandler[BaseWrapper] = WrapperHandler.build_wrappers(wrappers)
def get_product(self, asset_id):
return self.wrappers.try_call(lambda w: w.get_product(asset_id))
def get_products(self, asset_ids: list):
"""Ottiene informazioni su più prodotti con fallback automatico tra provider."""
try:
return self.fallback_manager.execute_with_fallback("get_products", asset_ids)
except MarketAPIError as e:
logger.error(f"Failed to get products {asset_ids}: {str(e)}")
raise
return self.wrappers.try_call(lambda w: w.get_products(asset_ids))
def get_all_products(self):
"""Ottiene tutti i prodotti con fallback automatico tra provider."""
try:
return self.fallback_manager.execute_with_fallback("get_all_products")
except MarketAPIError as e:
logger.error(f"Failed to get all products: {str(e)}")
raise
def get_historical_prices(self, asset_id: str = "BTC"):
"""Ottiene prezzi storici con fallback automatico tra provider."""
try:
return self.fallback_manager.execute_with_fallback("get_historical_prices", asset_id)
except MarketAPIError as e:
logger.error(f"Failed to get historical prices for {asset_id}: {str(e)}")
raise
return self.wrappers.try_call(lambda w: w.get_all_products())
def get_historical_prices(self, asset_id = "BTC", limit: int = 100):
return self.wrappers.try_call(lambda w: w.get_historical_prices(asset_id, limit))