""" ═══════════════════════════════════════════════════════════════════ DATA HUB API ROUTER REST API endpoints for accessing collected crypto data ═══════════════════════════════════════════════════════════════════ This router provides REST API endpoints for the frontend to access: - Market prices (latest, top coins, bulk queries) - OHLCV candlestick data (for charts) - News articles (with filtering) - Sentiment indicators (Fear & Greed, etc.) - Whale transactions (large movements) - Provider health status - System statistics All data is served from the backend database via DataHubService. @version 1.0.0 @author Crypto Intelligence Hub """ from typing import List, Optional from fastapi import APIRouter, HTTPException, Query from pydantic import BaseModel from backend.services.data_hub_service import DataHubService # Initialize router router = APIRouter(prefix="/api/hub", tags=["Data Hub"]) # Initialize service hub_service = DataHubService() # ═══════════════════════════════════════════════════════════════════ # RESPONSE MODELS # ═══════════════════════════════════════════════════════════════════ class PriceResponse(BaseModel): """Response model for price data""" symbol: str price_usd: float change_1h: Optional[float] change_24h: Optional[float] change_7d: Optional[float] volume_24h: Optional[float] market_cap: Optional[float] circulating_supply: Optional[float] total_supply: Optional[float] sources_count: int sources: List[str] collected_at: str class FearGreedResponse(BaseModel): """Response model for Fear & Greed Index""" value: float classification: str source: str collected_at: str class NewsArticleResponse(BaseModel): """Response model for news articles""" title: str url: str content: Optional[str] summary: Optional[str] source: str author: Optional[str] published_at: str sentiment: Optional[str] sentiment_score: Optional[float] related_symbols: List[str] collected_at: str class WhaleTransactionResponse(BaseModel): """Response model for whale transactions""" tx_hash: str blockchain: str from_address: str to_address: str amount: float symbol: str usd_value: float tx_time: str block_number: Optional[int] source: str collected_at: str # ═══════════════════════════════════════════════════════════════════ # MARKET DATA ENDPOINTS # ═══════════════════════════════════════════════════════════════════ @router.get("/price/{symbol}", summary="Get latest price for a symbol") def get_price(symbol: str): """ Get the latest price data for a specific cryptocurrency Args: symbol: Cryptocurrency symbol (e.g., 'BTC', 'ETH') Returns: Price data from the most recent collection """ price = hub_service.get_latest_price(symbol) if not price: raise HTTPException( status_code=404, detail=f"No price data found for symbol: {symbol}" ) return price @router.get("/prices/top", summary="Get top cryptocurrencies by market cap") def get_top_coins(limit: int = Query(100, ge=1, le=500)): """ Get top cryptocurrencies ranked by market capitalization Args: limit: Maximum number of coins to return (1-500) Returns: List of top coins with price and market data """ coins = hub_service.get_top_coins(limit=limit) return {"count": len(coins), "coins": coins} @router.post("/prices/bulk", summary="Get prices for multiple symbols") def get_bulk_prices(symbols: List[str]): """ Get latest prices for multiple symbols in a single request Args: symbols: List of cryptocurrency symbols Returns: Dictionary mapping symbols to price data """ if not symbols: raise HTTPException(status_code=400, detail="Symbols list cannot be empty") if len(symbols) > 100: raise HTTPException(status_code=400, detail="Maximum 100 symbols per request") prices = hub_service.get_prices_bulk(symbols) return {"count": len(prices), "prices": prices} # ═══════════════════════════════════════════════════════════════════ # OHLCV DATA ENDPOINTS (for charts) # ═══════════════════════════════════════════════════════════════════ @router.get("/ohlcv/{symbol}", summary="Get OHLCV candlestick data for charting") def get_ohlcv( symbol: str, timeframe: str = Query("1h", regex="^(1m|5m|15m|1h|4h|1d|1w)$"), limit: int = Query(100, ge=1, le=1000), source: Optional[str] = None ): """ Get OHLCV (Open, High, Low, Close, Volume) candlestick data Args: symbol: Cryptocurrency symbol timeframe: Candle timeframe (1m, 5m, 15m, 1h, 4h, 1d, 1w) limit: Number of candles to return (1-1000) source: Specific data source (optional) Returns: List of OHLCV candles in chronological order """ candles = hub_service.get_ohlcv( symbol=symbol, timeframe=timeframe, limit=limit, source=source ) return {"count": len(candles), "candles": candles} # ═══════════════════════════════════════════════════════════════════ # SENTIMENT ENDPOINTS # ═══════════════════════════════════════════════════════════════════ @router.get("/fear-greed", summary="Get Fear & Greed Index") def get_fear_greed(): """ Get the latest Fear & Greed Index value The Fear & Greed Index is a market sentiment indicator that ranges from 0 (Extreme Fear) to 100 (Extreme Greed). Returns: Current Fear & Greed Index value and classification """ sentiment = hub_service.get_fear_greed() if not sentiment: raise HTTPException( status_code=404, detail="No Fear & Greed data available" ) return sentiment @router.get("/sentiment/history", summary="Get sentiment history") def get_sentiment_history( indicator: str = Query("fear_greed"), days: int = Query(30, ge=1, le=365) ): """ Get historical sentiment data for charting Args: indicator: Sentiment indicator name (default: fear_greed) days: Number of days of history (1-365) Returns: List of sentiment data points over time """ history = hub_service.get_sentiment_history( indicator=indicator, days=days ) return {"count": len(history), "data": history} # ═══════════════════════════════════════════════════════════════════ # NEWS ENDPOINTS # ═══════════════════════════════════════════════════════════════════ @router.get("/news", summary="Get latest news articles") def get_news( limit: int = Query(50, ge=1, le=200), source: Optional[str] = None, symbol: Optional[str] = None ): """ Get latest cryptocurrency news articles Args: limit: Maximum number of articles (1-200) source: Filter by news source (optional) symbol: Filter by related cryptocurrency (optional) Returns: List of news articles with sentiment analysis """ articles = hub_service.get_news( limit=limit, source=source, symbol=symbol ) return {"count": len(articles), "articles": articles} # ═══════════════════════════════════════════════════════════════════ # WHALE TRANSACTION ENDPOINTS # ═══════════════════════════════════════════════════════════════════ @router.get("/whales", summary="Get whale transaction alerts") def get_whale_alerts( min_usd: float = Query(1000000, ge=100000), limit: int = Query(50, ge=1, le=200), blockchain: Optional[str] = None ): """ Get recent large cryptocurrency transactions Args: min_usd: Minimum transaction value in USD (default: $1M) limit: Maximum number of transactions (1-200) blockchain: Filter by blockchain (optional) Returns: List of whale transactions """ transactions = hub_service.get_whale_alerts( min_usd=min_usd, limit=limit, blockchain=blockchain ) return {"count": len(transactions), "transactions": transactions} # ═══════════════════════════════════════════════════════════════════ # SYSTEM STATUS ENDPOINTS # ═══════════════════════════════════════════════════════════════════ @router.get("/sources/status", summary="Get data source health status") def get_provider_status(): """ Get health status of all data collection sources Returns: Health information for all API providers including: - Status (healthy/degraded/down) - Response times - Error counts - Last success/failure times """ return hub_service.get_provider_status() @router.get("/stats", summary="Get Data Hub statistics") def get_stats(): """ Get comprehensive Data Hub statistics Returns: Statistics including: - Total records by type - Last collection time - Total records across all tables """ return hub_service.get_stats() # ═══════════════════════════════════════════════════════════════════ # HEALTH CHECK # ═══════════════════════════════════════════════════════════════════ @router.get("/health", summary="API health check") def health_check(): """ Simple health check endpoint Returns: API status and version """ return { "status": "healthy", "service": "Data Hub API", "version": "1.0.0" } # Export router __all__ = ['router']