|
|
"""
|
|
|
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
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
|
|
|
|
|
|
|
|
|
router = APIRouter(prefix="/api/hub", tags=["Data Hub"])
|
|
|
|
|
|
|
|
|
hub_service = DataHubService()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@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"
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
__all__ = ['router']
|
|
|
|