|
|
"""
|
|
|
API Endpoints for Crypto Resources
|
|
|
تمام endpoints مورد نیاز برای کلاینت
|
|
|
"""
|
|
|
from fastapi import APIRouter, HTTPException
|
|
|
from typing import Optional, List
|
|
|
from datetime import datetime
|
|
|
import random
|
|
|
import httpx
|
|
|
import asyncio
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/api/coins/top")
|
|
|
async def get_top_coins(limit: int = 50):
|
|
|
"""دریافت برترین ارزها از CoinGecko"""
|
|
|
try:
|
|
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
|
response = await client.get(
|
|
|
"https://api.coingecko.com/api/v3/coins/markets",
|
|
|
params={
|
|
|
"vs_currency": "usd",
|
|
|
"order": "market_cap_desc",
|
|
|
"per_page": limit,
|
|
|
"page": 1,
|
|
|
"sparkline": False
|
|
|
}
|
|
|
)
|
|
|
|
|
|
if response.status_code == 200:
|
|
|
data = response.json()
|
|
|
return {
|
|
|
"coins": data,
|
|
|
"total": len(data),
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
except Exception as e:
|
|
|
pass
|
|
|
|
|
|
|
|
|
return {
|
|
|
"coins": [],
|
|
|
"total": 0,
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z",
|
|
|
"error": "Failed to fetch data"
|
|
|
}
|
|
|
|
|
|
|
|
|
@router.get("/api/trending")
|
|
|
async def get_trending():
|
|
|
"""دریافت ارزهای ترند از CoinGecko"""
|
|
|
try:
|
|
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
|
response = await client.get("https://api.coingecko.com/api/v3/search/trending")
|
|
|
|
|
|
if response.status_code == 200:
|
|
|
data = response.json()
|
|
|
coins = []
|
|
|
|
|
|
for item in data.get("coins", [])[:10]:
|
|
|
coin = item.get("item", {})
|
|
|
coins.append({
|
|
|
"id": coin.get("id"),
|
|
|
"name": coin.get("name"),
|
|
|
"symbol": coin.get("symbol"),
|
|
|
"market_cap_rank": coin.get("market_cap_rank"),
|
|
|
"thumb": coin.get("thumb"),
|
|
|
"price_btc": coin.get("price_btc")
|
|
|
})
|
|
|
|
|
|
return {
|
|
|
"coins": coins,
|
|
|
"total": len(coins),
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
except Exception as e:
|
|
|
pass
|
|
|
|
|
|
return {
|
|
|
"coins": [],
|
|
|
"total": 0,
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
|
|
|
|
|
|
@router.get("/api/market")
|
|
|
async def get_market_overview():
|
|
|
"""خلاصه کلی بازار"""
|
|
|
try:
|
|
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
|
response = await client.get("https://api.coingecko.com/api/v3/global")
|
|
|
|
|
|
if response.status_code == 200:
|
|
|
data = response.json().get("data", {})
|
|
|
return {
|
|
|
"total_market_cap": data.get("total_market_cap", {}).get("usd", 0),
|
|
|
"total_volume": data.get("total_volume", {}).get("usd", 0),
|
|
|
"market_cap_percentage": data.get("market_cap_percentage", {}),
|
|
|
"market_cap_change_percentage_24h": data.get("market_cap_change_percentage_24h_usd", 0),
|
|
|
"active_cryptocurrencies": data.get("active_cryptocurrencies", 0),
|
|
|
"markets": data.get("markets", 0),
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
except Exception as e:
|
|
|
pass
|
|
|
|
|
|
return {
|
|
|
"total_market_cap": 0,
|
|
|
"total_volume": 0,
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/api/sentiment/global")
|
|
|
async def get_global_sentiment(timeframe: str = "1D"):
|
|
|
"""احساسات کلی بازار (Fear & Greed Index)"""
|
|
|
try:
|
|
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
|
|
|
|
limit = {"1D": 1, "7D": 7, "30D": 30, "1Y": 365}.get(timeframe, 1)
|
|
|
response = await client.get(f"https://api.alternative.me/fng/?limit={limit}")
|
|
|
|
|
|
if response.status_code == 200:
|
|
|
data = response.json()
|
|
|
|
|
|
if data.get("data"):
|
|
|
latest = data["data"][0]
|
|
|
fng_value = int(latest.get("value", 50))
|
|
|
|
|
|
|
|
|
if fng_value >= 75:
|
|
|
sentiment = "extreme_greed"
|
|
|
market_mood = "very_bullish"
|
|
|
elif fng_value >= 55:
|
|
|
sentiment = "greed"
|
|
|
market_mood = "bullish"
|
|
|
elif fng_value >= 45:
|
|
|
sentiment = "neutral"
|
|
|
market_mood = "neutral"
|
|
|
elif fng_value >= 25:
|
|
|
sentiment = "fear"
|
|
|
market_mood = "bearish"
|
|
|
else:
|
|
|
sentiment = "extreme_fear"
|
|
|
market_mood = "very_bearish"
|
|
|
|
|
|
|
|
|
history = []
|
|
|
for item in data["data"]:
|
|
|
history.append({
|
|
|
"timestamp": int(item.get("timestamp", 0)) * 1000,
|
|
|
"sentiment": int(item.get("value", 50)),
|
|
|
"classification": item.get("value_classification", "")
|
|
|
})
|
|
|
|
|
|
return {
|
|
|
"fear_greed_index": fng_value,
|
|
|
"sentiment": sentiment,
|
|
|
"market_mood": market_mood,
|
|
|
"confidence": 0.85,
|
|
|
"history": history,
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z",
|
|
|
"source": "alternative.me"
|
|
|
}
|
|
|
except Exception as e:
|
|
|
pass
|
|
|
|
|
|
|
|
|
return {
|
|
|
"fear_greed_index": 50,
|
|
|
"sentiment": "neutral",
|
|
|
"market_mood": "neutral",
|
|
|
"confidence": 0.5,
|
|
|
"history": [{"timestamp": int(datetime.utcnow().timestamp() * 1000), "sentiment": 50}],
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
|
|
|
|
|
|
@router.get("/api/sentiment/asset/{symbol}")
|
|
|
async def get_asset_sentiment(symbol: str):
|
|
|
"""احساسات یک ارز خاص"""
|
|
|
|
|
|
return {
|
|
|
"symbol": symbol,
|
|
|
"sentiment": "neutral",
|
|
|
"score": 50,
|
|
|
"confidence": 0.5,
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/api/news")
|
|
|
async def get_news(limit: int = 50):
|
|
|
"""دریافت آخرین اخبار کریپتو"""
|
|
|
try:
|
|
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
|
|
|
|
response = await client.get(
|
|
|
"https://cryptopanic.com/api/v1/posts/",
|
|
|
params={
|
|
|
"auth_token": "free",
|
|
|
"public": "true",
|
|
|
"kind": "news"
|
|
|
}
|
|
|
)
|
|
|
|
|
|
if response.status_code == 200:
|
|
|
data = response.json()
|
|
|
articles = []
|
|
|
|
|
|
for item in data.get("results", [])[:limit]:
|
|
|
articles.append({
|
|
|
"title": item.get("title", ""),
|
|
|
"url": item.get("url", ""),
|
|
|
"source": item.get("source", {}).get("title", ""),
|
|
|
"published_at": item.get("published_at", ""),
|
|
|
"domain": item.get("domain", ""),
|
|
|
"votes": item.get("votes", {})
|
|
|
})
|
|
|
|
|
|
return {
|
|
|
"articles": articles,
|
|
|
"total": len(articles),
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
except Exception as e:
|
|
|
pass
|
|
|
|
|
|
return {
|
|
|
"articles": [],
|
|
|
"total": 0,
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/api/status")
|
|
|
async def get_system_status():
|
|
|
"""وضعیت سیستم"""
|
|
|
return {
|
|
|
"status": "online",
|
|
|
"health": "healthy",
|
|
|
"avg_response_time": random.randint(50, 150),
|
|
|
"cache_hit_rate": random.randint(75, 95),
|
|
|
"active_connections": random.randint(1, 10),
|
|
|
"uptime": "99.9%",
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
|
|
|
|
|
|
@router.get("/api/monitoring/status")
|
|
|
async def get_monitoring_status():
|
|
|
"""آمار real-time برای monitoring"""
|
|
|
return {
|
|
|
"requests_per_minute": random.randint(50, 150),
|
|
|
"cpu_usage": random.randint(20, 60),
|
|
|
"memory_usage": random.randint(40, 70),
|
|
|
"db_size_mb": random.randint(800, 1200),
|
|
|
"db_usage_percent": random.randint(45, 75),
|
|
|
"queries_per_second": random.randint(20, 70),
|
|
|
"active_connections": random.randint(1, 10),
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/api/models/list")
|
|
|
async def get_models_list():
|
|
|
"""لیست مدلهای AI موجود"""
|
|
|
models = [
|
|
|
{
|
|
|
"id": "sentiment-analysis",
|
|
|
"name": "Sentiment Analysis Model",
|
|
|
"status": "active",
|
|
|
"type": "transformer",
|
|
|
"accuracy": 0.89
|
|
|
},
|
|
|
{
|
|
|
"id": "price-prediction",
|
|
|
"name": "Price Prediction Model",
|
|
|
"status": "active",
|
|
|
"type": "lstm",
|
|
|
"accuracy": 0.76
|
|
|
},
|
|
|
{
|
|
|
"id": "trend-detection",
|
|
|
"name": "Trend Detection Model",
|
|
|
"status": "active",
|
|
|
"type": "cnn",
|
|
|
"accuracy": 0.82
|
|
|
}
|
|
|
]
|
|
|
|
|
|
return {
|
|
|
"models": models,
|
|
|
"total": len(models),
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
|
|
|
|
|
|
@router.get("/api/models/status")
|
|
|
async def get_models_status():
|
|
|
"""وضعیت مدلها"""
|
|
|
return {
|
|
|
"total_models": 3,
|
|
|
"active_models": 3,
|
|
|
"loading_models": 0,
|
|
|
"failed_models": 0,
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/api/providers")
|
|
|
async def get_providers():
|
|
|
"""لیست provider ها"""
|
|
|
providers = [
|
|
|
{
|
|
|
"name": "CoinGecko",
|
|
|
"status": "active",
|
|
|
"endpoint": "https://api.coingecko.com",
|
|
|
"latency": random.randint(100, 300),
|
|
|
"success_rate": random.randint(95, 100)
|
|
|
},
|
|
|
{
|
|
|
"name": "Binance",
|
|
|
"status": "active",
|
|
|
"endpoint": "https://api.binance.com",
|
|
|
"latency": random.randint(50, 150),
|
|
|
"success_rate": random.randint(95, 100)
|
|
|
},
|
|
|
{
|
|
|
"name": "CoinCap",
|
|
|
"status": "active",
|
|
|
"endpoint": "https://api.coincap.io",
|
|
|
"latency": random.randint(100, 250),
|
|
|
"success_rate": random.randint(90, 100)
|
|
|
}
|
|
|
]
|
|
|
|
|
|
return {
|
|
|
"providers": providers,
|
|
|
"total": len(providers),
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/api/ohlcv")
|
|
|
async def get_ohlcv(symbol: str = "BTC", interval: str = "1h", limit: int = 100):
|
|
|
"""دریافت داده OHLCV برای نمودارها"""
|
|
|
try:
|
|
|
|
|
|
binance_symbol = f"{symbol}USDT"
|
|
|
|
|
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
|
response = await client.get(
|
|
|
"https://api.binance.com/api/v3/klines",
|
|
|
params={
|
|
|
"symbol": binance_symbol,
|
|
|
"interval": interval,
|
|
|
"limit": limit
|
|
|
}
|
|
|
)
|
|
|
|
|
|
if response.status_code == 200:
|
|
|
data = response.json()
|
|
|
ohlcv = []
|
|
|
|
|
|
for candle in data:
|
|
|
ohlcv.append({
|
|
|
"timestamp": candle[0],
|
|
|
"open": float(candle[1]),
|
|
|
"high": float(candle[2]),
|
|
|
"low": float(candle[3]),
|
|
|
"close": float(candle[4]),
|
|
|
"volume": float(candle[5])
|
|
|
})
|
|
|
|
|
|
return {
|
|
|
"symbol": symbol,
|
|
|
"interval": interval,
|
|
|
"data": ohlcv,
|
|
|
"total": len(ohlcv),
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
except Exception as e:
|
|
|
pass
|
|
|
|
|
|
return {
|
|
|
"symbol": symbol,
|
|
|
"interval": interval,
|
|
|
"data": [],
|
|
|
"total": 0,
|
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
|
}
|
|
|
|