|
|
|
|
|
""" |
|
|
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"] |
|
|
|
|
|
|