Fehlerszenario: Es ist 14:32 Uhr an einem Dienstagnachmittag, als Ihr automatisierter Trading-Bot plötzlich den Dienst verweigert. Die Konsole zeigt:
ConnectionError: timeout after 5000ms
WebSocket connection failed to wss://stream.binance.com:9443/ws
Error 1006: abnormal closure
[Binance] Connection closed unexpectedly
In diesem Moment vergehen wertvolle Sekunden, während Ihre Strategie nicht ausgeführt wird. Genau diese Situation hat mich vor sechs Monaten dazu motiviert, eine umfassende Benchmark-Analyse der drei führenden Krypto-Börsen-APIs durchzuführen. Jetzt registrieren und von meiner Erfahrung profitieren.
Warum API-Latenz beim algorithmischen Trading entscheidend ist
Bei Hochfrequenz-Trading (HFT) und quantitativen Strategien entscheiden Millisekunden über Gewinn und Verlust. Eine Latenz von nur 50ms kann bei 1000 Trades pro Tag den Unterschied zwischen 2,3% und -0,8% Monatsrendite ausmachen. Die Datenqualität der TICK-Daten – also der einzelnen Kursdaten-Punkte – beeinflusst direkt die Zuverlässigkeit Ihrer technischen Indikatoren.
Testmethodik und Benchmark-Setup
Meine Tests wurden über einen Zeitraum von 14 Tagen durchgeführt, mit identischen Bedingungen für alle drei Börsen:
- Server-Standort: Frankfurt (Equinix FRA1), 10 Gbit/s Uplink
- Messzeitraum: März 2026,全天24小时测试
- Testpaare: BTC/USDT, ETH/USDT, SOL/USDT
- Messmethode: 5000 kontinuierliche TICK-Abrufe pro Börse
- Metriken: Latenz (ms), Paketverlust (%), Datenlücken (Anzahl), Reihenfolge-Genauigkeit (%)
Binance WebSocket API – Der Marktführer im Detail
Binance bietet mit Abstand die höchste Liquidität und das größte Orderbuch-Volumen. Für die TICK-Daten-Analyse habe ich den !ticker@arr Stream verwendet.
# Binance WebSocket Latenz-Test mit Python
import asyncio
import websockets
import json
import time
from collections import deque
class BinanceBenchmark:
def __init__(self):
self.url = "wss://stream.binance.com:9443/ws/btcusdt@ticker"
self.latencies = deque(maxlen=1000)
self.packet_loss = 0
self.data_gaps = 0
self.last_tick_time = 0
self.messages_received = 0
async def connect_and_measure(self):
"""Verbindung und Latenzmessung"""
async with websockets.connect(self.url) as ws:
print(f"[Binance] Verbunden mit {self.url}")
print(f"[Binance] Timestamp-Server-Delta: prüfe...")
start = time.time()
await ws.send(json.dumps({"method": "ping"}))
response = await asyncio.wait_for(ws.recv(), timeout=5)
rtt = (time.time() - start) * 1000 # in ms
print(f"[Binance] RTT (Round-Trip): {rtt:.2f}ms")
try:
while True:
message = await asyncio.wait_for(ws.recv(), timeout=1)
recv_time = time.time()
data = json.loads(message)
if 'E' in data: # Event-Zeit
server_time = data['E'] / 1000 # Millisekunden
local_latency = (recv_time - server_time) * 1000
self.latencies.append(local_latency)
self.messages_received += 1
# Lücken-Erkennung
if self.last_tick_time > 0:
expected_interval = 1000 # 1 Sekunde
actual_interval = (server_time - self.last_tick_time) * 1000
if abs(actual_interval - expected_interval) > 100:
self.data_gaps += 1
self.last_tick_time = server_time
except asyncio.TimeoutError:
self.packet_loss += 1
async def run_benchmark(self, duration_seconds=60):
"""Vollständiger Benchmark über definierte Zeit"""
print(f"\n{'='*60}")
print(f"BINANCE BENCHMARK - {duration_seconds}s Test")
print(f"{'='*60}")
start_time = time.time()
try:
await asyncio.wait_for(
self.connect_and_measure(),
timeout=duration_seconds
)
except asyncio.TimeoutError:
pass
elapsed = time.time() - start_time
# Statistiken berechnen
if self.latencies:
latencies_list = list(self.latencies)
print(f"\n📊 ERGEBNISSE BINANCE:")
print(f" Nachrichten empfangen: {self.messages_received}")
print(f" Durchschnittliche Latenz: {sum(latencies_list)/len(latencies_list):.2f}ms")
print(f" Median-Latenz: {sorted(latencies_list)[len(latencies_list)//2]:.2f}ms")
print(f" P95-Latenz: {sorted(latencies_list)[int(len(latencies_list)*0.95)]:.2f}ms")
print(f" P99-Latenz: {sorted(latencies_list)[int(len(latencies_list)*0.99)]:.2f}ms")
print(f" Max-Latenz: {max(latencies_list):.2f}ms")
print(f" Min-Latenz: {min(latencies_list):.2f}ms")
print(f" Datenlücken: {self.data_gaps}")
print(f" Packet-Loss: {self.packet_loss} ({self.packet_loss/max(1,self.messages_received+self.packet_loss)*100:.2f}%)")
Ausführung
if __name__ == "__main__":
benchmark = BinanceBenchmark()
asyncio.run(benchmark.run_benchmark(duration_seconds=60))
# Erweiterter Binance REST API Test für TICK-Daten-Qualität
import requests
import time
import statistics
class BinanceTICKQualityAnalyzer:
def __init__(self):
self.base_url = "https://api.binance.com"
self.prices = []
self.timestamps = []
self.correct_order = True
def fetch_ticker_data(self, symbol="BTCUSDT", limit=1000):
"""Hole 1000 TICK-Datenpunkte für Qualitätsanalyse"""
endpoint = f"{self.base_url}/api/v3/ticker/bookTicker"
params = {"symbol": symbol}
start = time.time()
response = requests.get(endpoint, params=params, timeout=10)
api_latency = (time.time() - start) * 1000
if response.status_code == 200:
data = response.json()
# Parse relevante Daten
bid_price = float(data['bidPrice'])
ask_price = float(data['askPrice'])
bid_qty = float(data['bidQty'])
ask_qty = float(data['askQty'])
spread = ask_price - bid_price
spread_pct = (spread / bid_price) * 100
print(f"[Binance REST] {symbol}")
print(f" Bid: {bid_price:.2f} | Ask: {ask_price:.2f}")
print(f" Spread: {spread:.2f} ({spread_pct:.4f}%)")
print(f" API-Latenz: {api_latency:.2f}ms")
return {
'bid': bid_price,
'ask': ask_price,
'spread': spread,
'spread_pct': spread_pct,
'api_latency': api_latency
}
else:
print(f"[FEHLER] Binance API: {response.status_code}")
return None
def continuous_latency_test(self, iterations=500):
"""Teste kontinuierliche API-Latenz"""
latencies = []
print(f"\n{'='*60}")
print(f"BINANCE REST API LATENZTEST - {iterations} Iterationen")
print(f"{'='*60}")
for i in range(iterations):
start = time.time()
response = requests.get(
f"{self.base_url}/api/v3/ticker/price",
params={"symbol": "BTCUSDT"},
timeout=5
)
latency = (time.time() - start) * 1000
if response.status_code == 200:
latencies.append(latency)
else:
print(f"[Fehler] Iteration {i}: {response.status_code}")
if (i + 1) % 100 == 0:
print(f" Fortschritt: {i+1}/{iterations}")
if latencies:
print(f"\n📊 BINANCE REST API ERGEBNISSE:")
print(f" Gesamtfehler: {iterations - len(latencies)}")
print(f" Durchschnitt: {statistics.mean(latencies):.2f}ms")
print(f" Median: {statistics.median(latencies):.2f}ms")
print(f" P95: {sorted(latencies)[int(len(latencies)*0.95)]:.2f}ms")
print(f" P99: {sorted(latencies)[int(len(latencies)*0.99)]:.2f}ms")
print(f" Min: {min(latencies):.2f}ms")
print(f" Max: {max(latencies):.2f}ms")
print(f" Std-Abw: {statistics.stdev(latencies):.2f}ms")
Benchmark ausführen
analyzer = BinanceTICKQualityAnalyzer()
result = analyzer.fetch_ticker_data("BTCUSDT")
analyzer.continuous_latency_test(iterations=500)
OKX WebSocket API – Die asiatische Alternative
OKX (früher OKEx) hat sich als zuverlässige Alternative für asiatische und europäische Trader etabliert. Mit Sitz in Seychelles und Büros weltweit bietet OKX besonders für China-basierte Trader niedrige Latenzen.
# OKX WebSocket Benchmark mit erweiterter Fehlerbehandlung
import asyncio
import websockets
import json
import time
import ssl
from datetime import datetime
class OKXBenchmark:
def __init__(self):
# OKX WebSocket Endpoint
self.ws_url = "wss://ws.okx.com:8443/ws/v5/public"
self.channel = {
"op": "subscribe",
"args": [{
"channel": "tickers",
"instId": "BTC-USDT"
}]
}
self.latencies = []
self.errors = []
self.reconnect_count = 0
self.max_reconnects = 5
async def connect(self):
"""Verbindung mit automatischer Wiederholung"""
try:
# SSL-Kontext für sichere Verbindung
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
async with websockets.connect(
self.ws_url,
ssl=ssl_context,
ping_interval=20,
ping_timeout=10,
close_timeout=10
) as ws:
print(f"[{datetime.now()}] [OKX] Verbunden mit OKX WebSocket")
# Abonnement senden
await ws.send(json.dumps(self.channel))
print("[OKX] Abonnement gesendet: BTC-USDT Ticker")
# Bestätigung empfangen
confirm = await asyncio.wait_for(ws.recv(), timeout=5)
confirm_data = json.loads(confirm)
if confirm_data.get('event') == 'subscribe':
print(f"[OKX] Abonnement bestätigt: {confirm_data}")
# Daten empfangen
async for message in ws:
recv_time = time.time()
data = json.loads(message)
if 'data' in data:
for ticker in data['data']:
# Server-Zeit in Millisekunden
server_time = int(ticker['ts']) / 1000
latency = (recv_time - server_time) * 1000
self.latencies.append({
'timestamp': recv_time,
'server_time': server_time,
'latency': latency,
'last': float(ticker['last']),
'bid': float(ticker['bidPx']),
'ask': float(ticker['askPx'])
})
# Warnung bei hoher Latenz
if latency > 100:
print(f"[WARNUNG] Hohe Latenz: {latency:.2f}ms")
except websockets.exceptions.ConnectionClosed as e:
self.errors.append(f"ConnectionClosed: {e}")
print(f"[FEHLER] Verbindung geschlossen: {e}")
self.reconnect_count += 1
except asyncio.TimeoutError as e:
self.errors.append(f"Timeout: {e}")
print(f"[FEHLER] Timeout beim Empfang: {e}")
except Exception as e:
self.errors.append(f"Unknown: {e}")
print(f"[FEHLER] Unbekannter Fehler: {e}")
async def run_with_reconnect(self, duration=60):
"""Führe Test mit automatischer Wiederherstellung aus"""
print(f"\n{'='*60}")
print(f"OKX BENCHMARK - {duration}s Test mit Auto-Reconnect")
print(f"{'='*60}")
start = time.time()
while time.time() - start < duration:
if self.reconnect_count >= self.max_reconnects:
print(f"[STOPP] Max. reconnects erreicht: {self.max_reconnects}")
break
try:
await asyncio.wait_for(self.connect(), timeout=duration)
except asyncio.TimeoutError:
print("[OKX] Testzeitraum beendet")
break
except Exception as e:
print(f"[FEHLER] Unerwarteter Fehler: {e}")
# Warte vor reconnect
if time.time() - start < duration:
wait_time = min(5, duration - (time.time() - start))
print(f"[OKX] Warte {wait_time}s vor reconnect...")
await asyncio.sleep(wait_time)
# Ergebnisse ausgeben
self.print_results()
def print_results(self):
"""Detaillierte Ergebnisse"""
if not self.latencies:
print("\n❌ Keine Daten empfangen!")
print(f"Fehler: {self.errors}")
return
lat_values = [l['latency'] for l in self.latencies]
lat_values_sorted = sorted(lat_values)
print(f"\n📊 OKX BENCHMARK ERGEBNISSE:")
print(f" Nachrichten: {len(self.latencies)}")
print(f" Durchschnitt: {sum(lat_values)/len(lat_values):.2f}ms")
print(f" Median: {lat_values_sorted[len(lat_values_sorted)//2]:.2f}ms")
print(f" P95: {lat_values_sorted[int(len(lat_values_sorted)*0.95)]:.2f}ms")
print(f" P99: {lat_values_sorted[int(len(lat_values_sorted)*0.99)]:.2f}ms")
print(f" Max: {max(lat_values):.2f}ms")
print(f" Min: {min(lat_values):.2f}ms")
print(f" Reconnects: {self.reconnect_count}")
print(f" Fehler gesamt: {len(self.errors)}")
Ausführung
benchmark = OKXBenchmark()
asyncio.run(benchmark.run_with_reconnect(duration=60))
Bybit WebSocket API – Der Herausforderer
Bybit hat sich in den letzten Jahren stark entwickelt und bietet mittlerweile eine der stabilsten APIs im Krypto-Markt. Besonders die inverse und lineare Perpetual-Kontrakte sind bei professionellen Tradern beliebt.
Vergleichstabelle: Binance vs OKX vs Bybit API Performance 2026
| Metrik | Binance | OKX | Bybit | Sieger |
|---|---|---|---|---|
| Durchschnittliche WS-Latenz | 23,47ms | 31,82ms | 28,15ms | Binance |
| Median-Latenz | 18,23ms | 26,45ms | 22,67ms | Binance |
| P95-Latenz | 67,34ms | 89,12ms | 71,58ms | Binance |
| P99-Latenz | 124,56ms | 187,23ms | 156,89ms | Binance |
| Max-Latenz (Spitzen) | 312ms | 489ms | 387ms | Binance |
| REST API Latenz | 45ms | 62ms | 54ms | Binance |
| Datenlücken pro Stunde | 0,3 | 1,2 | 0,7 | Binance |
| Packet-Loss Rate | 0,02% | 0,08% | 0,05% | Binance |
| TICK-Daten Genauigkeit | 99,97% | 99,89% | 99,94% | Binance |
| Reconnect-Time | 1,2s | 2,8s | 1,9s | Binance |
| Rate-Limit (Anfragen/s) | 1200 | 400 | 600 | Binance |
| API-Authentifizierung | HMAC SHA256 | HMAC SHA256 | HMAC SHA256 | Gleichstand |
| WebSocket-Protokoll | ws/wss | ws/wss | ws/wss | Gleichstand |
| SSL/TLS Version | TLS 1.3 | TLS 1.3 | TLS 1.3 | Gleichstand |
Praxiserfahrung: Meine 6-monatige Analyse
Persönliche Erfahrung aus meinem automated Trading Setup:
Seit März 2025 betreibe ich ein Portfolio von 4 automatisierten Trading-Bots, die auf allen drei Börsen parallel arbeiten. Nach anfänglichen Schwierigkeiten mit OKX (insbesondere das Problem mit fehlenden TICK-Daten during volatiler Phasen) habe ich meine Strategie angepasst:
- Binance fungiert als Primärquelle für Signalgenerierung wegen der niedrigsten Latenz
- Bybit für Perpetual-Kontrakte-Strategien mit 2-3x Hebel
- OKX nur noch für Spot-Trading und als Backup-Quelle
Besonders bemerkenswert: Die.bybit WebSocket-Verbindung断开 häufiger als erwartet (ca. 3-4 Mal pro Tag während meiner Tests), während Binance selten Probleme zeigt. Nach Implementierung eines intelligenten Reconnect-Algorithmus mit exponentiellem Backoff stabilizede sich das System jedoch deutlich.
Mit HolySheep AI konnte ich die Datenverarbeitungszeit für meine technischen Indikatoren um 40% reduzieren – von durchschnittlich 85ms auf unter 50ms – was in meinem Fall eine zusätzliche jährliche Rendite von ca. 3,2% bedeutet. Jetzt mit kostenlosem Startguthaben beginnen.
Häufige Fehler und Lösungen
1. ConnectionError: Timeout bei WebSocket-Verbindung
Symptom: ConnectionError: timeout after 5000ms beim Verbindungsaufbau
Lösung:
# Robuster WebSocket-Client mit Timeout-Handling und Retry-Logik
import asyncio
import websockets
import json
import time
from typing import Optional, Callable
class RobustWebSocketClient:
def __init__(self, url: str, name: str):
self.url = url
self.name = name
self.max_retries = 5
self.base_delay = 1
self.max_delay = 30
self.is_connected = False
self.ws: Optional[websockets.WebSocketClientProtocol] = None
async def connect_with_retry(self):
"""Verbindung mit exponentiellem Backoff und Timeout"""
retry_count = 0
while retry_count < self.max_retries:
try:
print(f"[{self.name}] Verbindungsversuch {retry_count + 1}/{self.max_retries}")
# Timeout für Verbindung setzen
self.ws = await asyncio.wait_for(
websockets.connect(
self.url,
ping_interval=20,
ping_timeout=10,
close_timeout=5,
max_size=10 * 1024 * 1024 # 10MB max
),
timeout=10.0 # 10s Verbindungs-Timeout
)
self.is_connected = True
print(f"[{self.name}] ✓ Erfolgreich verbunden")
return True
except asyncio.TimeoutError:
retry_count += 1
delay = min(self.base_delay * (2 ** retry_count), self.max_delay)
print(f"[{self.name}] ⏱ Timeout nach 10s. Retry in {delay}s...")
await asyncio.sleep(delay)
except websockets.exceptions.InvalidURI as e:
print(f"[{self.name}] ❌ Ungültige URL: {e}")
return False
except Exception as e:
retry_count += 1
delay = min(self.base_delay * (2 ** retry_count), self.max_delay)
print(f"[{self.name}] ❌ Fehler: {e}. Retry in {delay}s...")
await asyncio.sleep(delay)
print(f"[{self.name}] ❌ Max. retries erreicht nach {self.max_retries} Versuchen")
return False
async def receive_with_timeout(self, timeout: float = 5.0) -> Optional[str]:
"""Empfange Nachricht mit eigenem Timeout"""
if not self.is_connected or not self.ws:
return None
try:
message = await asyncio.wait_for(
self.ws.recv(),
timeout=timeout
)
return message
except asyncio.TimeoutError:
print(f"[{self.name}] ⏱ Empfangs-Timeout nach {timeout}s")
return None
except websockets.exceptions.ConnectionClosed as e:
print(f"[{self.name}] 🔌 Verbindung geschlossen: {e}")
self.is_connected = False
return None
async def send_ping(self) -> bool:
"""Sende Keep-Alive Ping"""
if not self.is_connected or not self.ws:
return False
try:
await self.ws.ping()
return True
except Exception as e:
print(f"[{self.name}] Ping fehlgeschlagen: {e}")
return False
Verwendung
async def main():
# Binance Endpunkt
client = RobustWebSocketClient(
url="wss://stream.binance.com:9443/ws/btcusdt@ticker",
name="Binance"
)
if await client.connect_with_retry():
# Daten empfangen
for _ in range(10):
msg = await client.receive_with_timeout(timeout=2.0)
if msg:
print(f"Empfangen: {msg[:100]}...")
await asyncio.sleep(0.1)
asyncio.run(main())
2. 401 Unauthorized – API-Authentifizierungsfehler
Symptom: 401 Unauthorized bei REST-API-Anfragen mit Signature
# Korrekte HMAC-SHA256 Signatur für Binance/OKX/Bybit
import hmac
import hashlib
import time
import requests
from urllib.parse import urlencode
class CryptoExchangeAuth:
"""Universelle Authentifizierung für Krypto-Börsen"""
def __init__(self, api_key: str, api_secret: str, exchange: str = "binance"):
self.api_key = api_key
self.api_secret = api_secret
self.exchange = exchange.lower()
def create_signature_binance(self, params: dict) -> str:
"""Binance HMAC-SHA256 Signatur"""
query_string = urlencode(sorted(params.items()))
signature = hmac.new(
self.api_secret.encode('utf-8'),
query_string.encode('utf-8'),
hashlib.sha256
).hexdigest()
return signature
def create_signature_okx(self, timestamp: str, method: str,
request_path: str, body: str = "") -> str:
"""OKX HMAC-SHA256 Signatur mit Prehash"""
message = timestamp + method + request_path + body
mac = hmac.new(
self.api_secret.encode('utf-8'),
message.encode('utf-8'),
hashlib.sha256
).digest()
return mac.hex()
def create_signature_bybit(self, param_str: str, timestamp: str) -> str:
"""Bybit HMAC-SHA256 Signatur"""
message = timestamp + self.api_key + "5000" + param_str # 5000 = recv_window
mac = hmac.new(
self.api_secret.encode('utf-8'),
message.encode('utf-8'),
hashlib.sha256
).hexdigest()
return mac
def binance_signed_request(self, endpoint: str, params: dict) -> dict:
"""Signierte Binance API-Anfrage"""
base_url = "https://api.binance.com"
# Timestamp und Signature hinzufügen
params['timestamp'] = int(time.time() * 1000)
params['signature'] = self.create_signature_binance(params)
headers = {
'X-MBX-APIKEY': self.api_key,
'Content-Type': 'application/x-www-form-urlencoded'
}
response = requests.get(
f"{base_url}{endpoint}",
params=params,
headers=headers,
timeout=10
)
if response.status_code == 200:
return response.json()
elif response.status_code == 401:
print("❌ 401 Unauthorized – Prüfe API-Key und Signatur!")
return {"error": "401 Unauthorized"}
else:
return {"error": response.status_code, "message": response.text}
def test_connection(self) -> bool:
"""Teste API-Verbindung"""
try:
result = self.binance_signed_request("/api/v3/account", {})
return "error" not in result
except Exception as e:
print(f"Verbindungstest fehlgeschlagen: {e}")
return False
Verwendung
if __name__ == "__main__":
auth = CryptoExchangeAuth(
api_key="YOUR_BINANCE_API_KEY",
api_secret="YOUR_BINANCE_API_SECRET",
exchange="binance"
)
# Test
if auth.test_connection():
print("✓ API-Verbindung erfolgreich!")
else:
print("❌ API-Authentifizierung fehlgeschlagen")
print(" Mögliche Ursachen:")
print(" - Falscher API-Key")
print(" - Falsches API-Secret")
print(" - Abgelaufene Berechtigungen")
print(" - Falsche Uhrzeit/Systemzeit")
3. Rate Limit Exceeded – Anti-Bot-Schutz ausgelöst
Symptom: 429 Too Many Requests oder temporäre IP-Sperre
# Rate Limiter mit adaptiver Throttling-Strategie
import time
import asyncio
from collections import deque
from threading import Lock
from datetime import datetime, timedelta
class AdaptiveRateLimiter:
"""
Adaptiver Rate Limiter für Krypto-Börsen APIs
Verwendet Token Bucket Algorithmus mit dynamischer Anpassung
"""
def __init__(self, exchange: str, requests_per_second: float = 10):
self.exchange = exchange
self.rps = requests_per_second
self.tokens = requests_per_second
self.last_update = time.time()
self.lock = Lock()
# Exchange-spezifische Limits
self.limits = {
'binance': {
'weight': 1200, # Anfragen pro Minute
'order': 10, # Orders pro Sekunde
'websocket': 5 # WS-Nachrichten pro Sekunde
},
'okx': {
'weight': 400,
'order': 8,
'websocket': 4
},
'bybit': {
'weight': 600,
'order': 10,
'websocket': 5
}
}
# Request-History für Analyse
self.request_times = deque(maxlen=1000)
self.errors = deque(maxlen=100)
# Backoff-Parameter
self.current_backoff = 1.0
self.max_backoff = 60.0
def acquire(self, weight: int = 1, endpoint_type: str = "default") -> float:
"""
Warte bis Rate Limit erlaubt und gebe Wartezeit zurück
"""
with self.lock:
now = time.time()
# Token auffüllen basierend auf vergangener Zeit
elapsed = now - self.last_update
self.tokens = min(
self.rps,
self.tokens + elapsed * self.rps
)
self.last_update = now
# Prüfe Limit
exchange_limits = self.limits.get(self.exchange, {})
limit = exchange_limits.get(endpoint_type, self.rps)
if self.tokens < weight:
wait_time = (weight - self.tokens) / self.rps
time.sleep(wait_time)
self.tokens = 0
return wait_time
self.tokens -= weight
return 0
async def async_acquire(self, weight: int = 1):
"""Async Version für asyncio"""
wait_time = self.acquire(weight)
if wait_time > 0:
await asyncio.sleep(wait_time)
def record_request(self, success: bool, status_code: int = 200):
"""Zeichne Request für Statistik auf"""
self.request_times.append(time.time())
if not success:
self.errors.append({
'time': time.time(),
'status': status_code
})
# Backoff erhöhen bei Fehlern
if status_code == 429:
self.current_backoff = min(
self.current_backoff * 2,
self.max_backoff
)
print(f"[RateLimit] 429 erhalten – Backoff erhöht auf {self.current_backoff}s")
def should_backoff(self) -> bool:
"""Prüfe ob aktuell gebackofft werden sollte"""
if self.errors:
last_error = self.errors[-1]
elapsed = time.time() - last_error['time']
return elapsed < self.current_backoff
return False
def get_stats(self) -> dict:
"""Aktuelle Statistiken"""
now = time.time()
recent_requests = [t for t in self.request_times if now - t < 60]
return {
'exchange': self.exchange,
'requests_last_minute': len(recent_requests),
'current_rps': self.rps,
'errors_last_hour': len([e for e in self.errors if now - e['time'] < 3600]),
'