Really-amin's picture
Upload 856 files
d115c85 verified
"""
═══════════════════════════════════════════════════════════════════
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']