|
|
|
|
|
"""
|
|
|
Whale Tracking Router
|
|
|
GET /api/whales/transactions, GET /api/whales/activity
|
|
|
"""
|
|
|
|
|
|
from fastapi import APIRouter, HTTPException, Query
|
|
|
from fastapi.responses import JSONResponse
|
|
|
from typing import Optional, List, Dict, Any
|
|
|
from datetime import datetime, timezone, timedelta
|
|
|
import logging
|
|
|
|
|
|
from backend.services.provider_fallback_manager import fallback_manager
|
|
|
from backend.services.data_resolver import get_data_resolver
|
|
|
from backend.services.persistence_service import PersistenceService
|
|
|
from database.db_manager import db_manager
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
router = APIRouter(
|
|
|
prefix="/api/whales",
|
|
|
tags=["Whale Tracking"]
|
|
|
)
|
|
|
|
|
|
persistence_service = PersistenceService()
|
|
|
|
|
|
|
|
|
def create_response(data: Any, source: str, attempted: List[str] = None) -> Dict[str, Any]:
|
|
|
"""Create standardized response"""
|
|
|
return {
|
|
|
"data": data,
|
|
|
"meta": {
|
|
|
"source": source,
|
|
|
"generated_at": datetime.now(timezone.utc).isoformat(),
|
|
|
"cache_ttl": 60,
|
|
|
"attempted": attempted or [source]
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
@router.get("/transactions")
|
|
|
async def get_whale_transactions(
|
|
|
limit: int = Query(50, description="Number of transactions"),
|
|
|
chain: Optional[str] = Query(None, description="Blockchain (ethereum, bsc, tron)"),
|
|
|
min_amount_usd: Optional[float] = Query(100000, description="Minimum amount in USD")
|
|
|
):
|
|
|
"""Get whale transactions"""
|
|
|
attempted = []
|
|
|
|
|
|
|
|
|
try:
|
|
|
transactions = await persistence_service.get_whale_transactions(
|
|
|
limit=limit,
|
|
|
chain=chain,
|
|
|
min_amount=min_amount_usd
|
|
|
)
|
|
|
if transactions:
|
|
|
attempted.append("database")
|
|
|
return create_response(transactions, "database", attempted)
|
|
|
except Exception as e:
|
|
|
logger.warning(f"Database query failed: {e}")
|
|
|
attempted.append("database")
|
|
|
|
|
|
|
|
|
try:
|
|
|
resolver = await get_data_resolver()
|
|
|
whale_data = await resolver.resolve_whale_transactions(limit=limit, chain=chain)
|
|
|
if whale_data:
|
|
|
attempted.append("hf")
|
|
|
|
|
|
await persistence_service.save_whale_transactions(whale_data)
|
|
|
return create_response(whale_data, "hf", attempted)
|
|
|
except Exception as e:
|
|
|
logger.warning(f"HF Space unavailable: {e}")
|
|
|
attempted.append("hf")
|
|
|
|
|
|
|
|
|
try:
|
|
|
result = await fallback_manager.fetch_with_fallback(
|
|
|
endpoint="/whale/transactions",
|
|
|
params={"limit": limit, "chain": chain or "ethereum"},
|
|
|
transform_func=lambda x: x if isinstance(x, list) else []
|
|
|
)
|
|
|
attempted.extend(result.attempted)
|
|
|
if result.success and result.data:
|
|
|
|
|
|
filtered = [
|
|
|
tx for tx in result.data
|
|
|
if tx.get("amount_usd", 0) >= min_amount_usd
|
|
|
]
|
|
|
await persistence_service.save_whale_transactions(filtered)
|
|
|
return create_response(filtered[:limit], result.source, attempted)
|
|
|
except Exception as e:
|
|
|
logger.error(f"External APIs failed: {e}")
|
|
|
attempted.append("external_apis")
|
|
|
|
|
|
|
|
|
return create_response([], "none", attempted)
|
|
|
|
|
|
|
|
|
@router.get("/activity")
|
|
|
async def get_whale_activity(
|
|
|
hours: int = Query(24, description="Hours to look back")
|
|
|
):
|
|
|
"""Get whale activity statistics"""
|
|
|
attempted = []
|
|
|
|
|
|
|
|
|
try:
|
|
|
since = datetime.now(timezone.utc) - timedelta(hours=hours)
|
|
|
activity = await persistence_service.get_whale_activity_stats(since)
|
|
|
if activity:
|
|
|
attempted.append("database")
|
|
|
return create_response(activity, "database", attempted)
|
|
|
except Exception as e:
|
|
|
logger.warning(f"Database query failed: {e}")
|
|
|
attempted.append("database")
|
|
|
|
|
|
|
|
|
try:
|
|
|
resolver = await get_data_resolver()
|
|
|
activity = await resolver.resolve_whale_activity(hours=hours)
|
|
|
if activity:
|
|
|
attempted.append("hf")
|
|
|
return create_response(activity, "hf", attempted)
|
|
|
except Exception as e:
|
|
|
logger.warning(f"HF Space unavailable: {e}")
|
|
|
attempted.append("hf")
|
|
|
|
|
|
|
|
|
try:
|
|
|
result = await fallback_manager.fetch_with_fallback(
|
|
|
endpoint="/whale/stats",
|
|
|
params={"hours": hours},
|
|
|
transform_func=lambda x: x if isinstance(x, dict) else {}
|
|
|
)
|
|
|
attempted.extend(result.attempted)
|
|
|
if result.success:
|
|
|
return create_response(result.data, result.source, attempted)
|
|
|
except Exception as e:
|
|
|
logger.error(f"External APIs failed: {e}")
|
|
|
attempted.append("external_apis")
|
|
|
|
|
|
|
|
|
default_stats = {
|
|
|
"total_transactions": 0,
|
|
|
"total_volume_usd": 0,
|
|
|
"top_chains": [],
|
|
|
"period_hours": hours
|
|
|
}
|
|
|
return create_response(default_stats, "default", attempted)
|
|
|
|
|
|
|