|
|
|
|
|
"""
|
|
|
Binance Secure Client with Rotating DNS/Proxy
|
|
|
کلاینت امن Binance با DNS و Proxy چرخشی
|
|
|
"""
|
|
|
|
|
|
import httpx
|
|
|
import logging
|
|
|
from typing import Optional, Dict, List
|
|
|
from datetime import datetime
|
|
|
|
|
|
from backend.services.rotating_access_manager import rotating_access_manager
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
class BinanceSecureClient:
|
|
|
"""
|
|
|
Binance API Client با امنیت بالا
|
|
|
|
|
|
همیشه از Rotating DNS/Proxy استفاده میکنه
|
|
|
هیچ وقت مشکل دسترسی نداریم!
|
|
|
"""
|
|
|
|
|
|
def __init__(self):
|
|
|
self.base_url = "https://api.binance.com"
|
|
|
self.api_urls = [
|
|
|
"https://api.binance.com",
|
|
|
"https://api1.binance.com",
|
|
|
"https://api2.binance.com",
|
|
|
"https://api3.binance.com"
|
|
|
]
|
|
|
self.current_api_index = 0
|
|
|
|
|
|
def get_next_api_url(self) -> str:
|
|
|
"""چرخش بین URLهای مختلف Binance"""
|
|
|
url = self.api_urls[self.current_api_index]
|
|
|
self.current_api_index = (self.current_api_index + 1) % len(self.api_urls)
|
|
|
return url
|
|
|
|
|
|
async def get_24h_ticker(self, symbol: str = "BTCUSDT") -> Optional[Dict]:
|
|
|
"""
|
|
|
دریافت قیمت 24 ساعته با Rotating Access
|
|
|
|
|
|
Args:
|
|
|
symbol: نماد ارز (مثلاً BTCUSDT)
|
|
|
|
|
|
Returns:
|
|
|
{
|
|
|
"symbol": "BTCUSDT",
|
|
|
"lastPrice": "50000.00",
|
|
|
"priceChange": "500.00",
|
|
|
"priceChangePercent": "1.01",
|
|
|
...
|
|
|
}
|
|
|
"""
|
|
|
|
|
|
base_url = self.get_next_api_url()
|
|
|
url = f"{base_url}/api/v3/ticker/24hr"
|
|
|
|
|
|
logger.info(f"📊 Getting Binance ticker for {symbol} (Secure)")
|
|
|
|
|
|
response = await rotating_access_manager.secure_fetch(
|
|
|
url,
|
|
|
params={"symbol": symbol},
|
|
|
use_rotating_dns=True,
|
|
|
use_rotating_proxy=True
|
|
|
)
|
|
|
|
|
|
if response and response.status_code == 200:
|
|
|
data = response.json()
|
|
|
logger.info(f"✅ Binance ticker retrieved: ${data.get('lastPrice')}")
|
|
|
return data
|
|
|
|
|
|
return None
|
|
|
|
|
|
async def get_price(self, symbol: str = "BTCUSDT") -> Optional[float]:
|
|
|
"""
|
|
|
دریافت قیمت فعلی (ساده)
|
|
|
|
|
|
Returns:
|
|
|
float: قیمت (مثلاً 50000.5)
|
|
|
"""
|
|
|
base_url = self.get_next_api_url()
|
|
|
url = f"{base_url}/api/v3/ticker/price"
|
|
|
|
|
|
response = await rotating_access_manager.secure_fetch(
|
|
|
url,
|
|
|
params={"symbol": symbol},
|
|
|
use_rotating_dns=True,
|
|
|
use_rotating_proxy=True
|
|
|
)
|
|
|
|
|
|
if response and response.status_code == 200:
|
|
|
data = response.json()
|
|
|
price = float(data.get("price", 0))
|
|
|
logger.info(f"✅ Binance price: {symbol} = ${price}")
|
|
|
return price
|
|
|
|
|
|
return None
|
|
|
|
|
|
async def get_ohlcv(
|
|
|
self,
|
|
|
symbol: str = "BTCUSDT",
|
|
|
interval: str = "1h",
|
|
|
limit: int = 100
|
|
|
) -> Optional[List[Dict]]:
|
|
|
"""
|
|
|
دریافت کندلها (OHLCV)
|
|
|
|
|
|
Args:
|
|
|
symbol: نماد ارز
|
|
|
interval: بازه زمانی (1m, 5m, 15m, 1h, 4h, 1d)
|
|
|
limit: تعداد کندل
|
|
|
|
|
|
Returns:
|
|
|
[
|
|
|
{
|
|
|
"timestamp": 1234567890,
|
|
|
"open": 50000,
|
|
|
"high": 51000,
|
|
|
"low": 49000,
|
|
|
"close": 50500,
|
|
|
"volume": 12345
|
|
|
},
|
|
|
...
|
|
|
]
|
|
|
"""
|
|
|
base_url = self.get_next_api_url()
|
|
|
url = f"{base_url}/api/v3/klines"
|
|
|
|
|
|
logger.info(f"📈 Getting Binance OHLCV for {symbol} ({interval})")
|
|
|
|
|
|
response = await rotating_access_manager.secure_fetch(
|
|
|
url,
|
|
|
params={
|
|
|
"symbol": symbol,
|
|
|
"interval": interval,
|
|
|
"limit": limit
|
|
|
},
|
|
|
use_rotating_dns=True,
|
|
|
use_rotating_proxy=True
|
|
|
)
|
|
|
|
|
|
if response and 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])
|
|
|
})
|
|
|
|
|
|
logger.info(f"✅ Got {len(ohlcv)} candles")
|
|
|
return ohlcv
|
|
|
|
|
|
return None
|
|
|
|
|
|
async def get_orderbook(self, symbol: str = "BTCUSDT", limit: int = 20) -> Optional[Dict]:
|
|
|
"""
|
|
|
دریافت Order Book
|
|
|
|
|
|
Returns:
|
|
|
{
|
|
|
"bids": [[price, quantity], ...],
|
|
|
"asks": [[price, quantity], ...],
|
|
|
...
|
|
|
}
|
|
|
"""
|
|
|
base_url = self.get_next_api_url()
|
|
|
url = f"{base_url}/api/v3/depth"
|
|
|
|
|
|
response = await rotating_access_manager.secure_fetch(
|
|
|
url,
|
|
|
params={"symbol": symbol, "limit": limit},
|
|
|
use_rotating_dns=True,
|
|
|
use_rotating_proxy=True
|
|
|
)
|
|
|
|
|
|
if response and response.status_code == 200:
|
|
|
data = response.json()
|
|
|
logger.info(f"✅ Binance orderbook retrieved")
|
|
|
return data
|
|
|
|
|
|
return None
|
|
|
|
|
|
async def get_exchange_info(self, symbol: Optional[str] = None) -> Optional[Dict]:
|
|
|
"""
|
|
|
دریافت اطلاعات صرافی
|
|
|
|
|
|
Args:
|
|
|
symbol: نماد ارز (اختیاری)
|
|
|
"""
|
|
|
base_url = self.get_next_api_url()
|
|
|
url = f"{base_url}/api/v3/exchangeInfo"
|
|
|
|
|
|
params = {}
|
|
|
if symbol:
|
|
|
params["symbol"] = symbol
|
|
|
|
|
|
response = await rotating_access_manager.secure_fetch(
|
|
|
url,
|
|
|
params=params if params else None,
|
|
|
use_rotating_dns=True,
|
|
|
use_rotating_proxy=True
|
|
|
)
|
|
|
|
|
|
if response and response.status_code == 200:
|
|
|
data = response.json()
|
|
|
logger.info(f"✅ Binance exchange info retrieved")
|
|
|
return data
|
|
|
|
|
|
return None
|
|
|
|
|
|
async def health_check(self) -> bool:
|
|
|
"""
|
|
|
بررسی سلامت API
|
|
|
|
|
|
Returns:
|
|
|
True اگر Binance در دسترس باشه
|
|
|
"""
|
|
|
base_url = self.get_next_api_url()
|
|
|
url = f"{base_url}/api/v3/ping"
|
|
|
|
|
|
try:
|
|
|
response = await rotating_access_manager.secure_fetch(
|
|
|
url,
|
|
|
use_rotating_dns=True,
|
|
|
use_rotating_proxy=True
|
|
|
)
|
|
|
|
|
|
if response and response.status_code == 200:
|
|
|
logger.info(f"💚 Binance health check: OK")
|
|
|
return True
|
|
|
|
|
|
return False
|
|
|
|
|
|
except:
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
binance_secure_client = BinanceSecureClient()
|
|
|
|
|
|
|
|
|
__all__ = ["BinanceSecureClient", "binance_secure_client"]
|
|
|
|
|
|
|