En tant que développeur qui a passé plus de trois ans à intégrer des APIs d'échanges de cryptomonnaies, je peux vous confirmer une vérité simple : les erreurs API sont inevitables, mais leur résolution ne doit pas être un cauchemar. Aujourd'hui, je vous partage mon guide complet des codes d'erreur que vous rencontrerez inévitablement lors de vos intégrations avec Binance, Coinbase, Kraken et autres plateformes.
Dans cet article, je vais vous montrer comment diagnostiquer rapidement chaque type d'erreur, avec des exemples de code concrets et des solutions testées en production. Que vous construisiez un bot de trading, un tableau de bord analytique ou un système de gestion de portefeuille, ce manuel deviendra votre référence.
Comprendre les codes d'erreur des exchanges
Chaque exchange majeurs utilise un système de codage propriétaire, mais certains patterns sont universels. Les erreurs se divisent généralement en quatre catégories : les erreurs d'authentification (401/403), les erreurs de limitation de débit (429), les erreurs de validation (400) et les erreurs serveur (500/503). La première étape de tout dépannage est d'identifier correctement la catégorie.
import requests
import json
import time
from datetime import datetime
class CryptoExchangeError(Exception):
"""Exception personnalisée pour les erreurs d'exchange."""
def __init__(self, exchange_name, error_code, error_message, response=None):
self.exchange_name = exchange_name
self.error_code = error_code
self.error_message = error_message
self.response = response
self.timestamp = datetime.now()
super().__init__(f"[{exchange_name}] Erreur {error_code}: {error_message}")
def to_dict(self):
return {
"exchange": self.exchange_name,
"code": self.error_code,
"message": self.error_message,
"timestamp": self.timestamp.isoformat(),
"retry_after": self.response.headers.get("Retry-After") if self.response else None
}
def make_request_with_error_handling(base_url, endpoint, api_key, secret_key=None,
max_retries=3, backoff_factor=2):
"""
Requête HTTP avec gestion complète des erreurs d'API crypto.
Args:
base_url: URL de base de l'API (ex: https://api.binance.com)
endpoint: Point de terminaison de l'API
api_key: Clé API publique
secret_key: Clé API secrète (pour les endpoints authentifiés)
max_retries: Nombre maximum de tentatives
backoff_factor: Facteur de temporisation exponentielle
Returns:
dict: Réponse JSON de l'API
"""
url = f"{base_url}{endpoint}"
headers = {
"X-MBX-APIKEY": api_key,
"Content-Type": "application/json"
}
for attempt in range(max_retries):
try:
response = requests.get(url, headers=headers, timeout=30)
# Analyse du code de réponse HTTP
if response.status_code == 200:
return response.json()
# Erreurs spécifiques aux APIs crypto
elif response.status_code == 401:
raise CryptoExchangeError(
base_url.split('//')[1].split('.')[0],
401,
"Clé API invalide ou expirée. Vérifiez vos identifiants.",
response
)
elif response.status_code == 403:
raise CryptoExchangeError(
base_url.split('//')[1].split('.')[0],
403,
"Accès refusé. Permissions insuffisantes ou IP non whitelistée.",
response
)
elif response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
wait_time = retry_after if retry_after > 0 else 60 * (attempt + 1)
print(f"⚠️ Rate limit atteint. Attente de {wait_time}s...")
time.sleep(wait_time)
continue
elif response.status_code == 418:
# IP bannie temporairement
ban_time = int(response.headers.get("X-Spot-Limit-Reset", 60))
raise CryptoExchangeError(
base_url.split('//')[1].split('.')[0],
418,
f"IP bannie temporairement. Réessayez dans {ban_time}s.",
response
)
else:
error_data = response.json() if response.text else {}
raise CryptoExchangeError(
base_url.split('//')[1].split('.')[0],
error_data.get("code", response.status_code),
error_data.get("msg", response.text),
response
)
except requests.exceptions.Timeout:
if attempt == max_retries - 1:
raise CryptoExchangeError(
base_url.split('//')[1].split('.')[0],
"TIMEOUT",
f"Délai d'attente dépassé après {max_retries} tentatives"
)
time.sleep(backoff_factor ** attempt)
except requests.exceptions.ConnectionError as e:
if attempt == max_retries - 1:
raise CryptoExchangeError(
base_url.split('//')[1].split('.')[0],
"CONNECTION_ERROR",
f"Impossible de se connecter: {str(e)}"
)
time.sleep(backoff_factor ** attempt)
raise CryptoExchangeError(base_url.split('//')[1].split('.')[0], "MAX_RETRIES",
f"Échec après {max_retries} tentatives")
Codes d'erreur Binance — Référence complète
Binance est l'exchange qui génère le plus d'appels API dans l'écosystème crypto. Leur système de codes d'erreur est particulièrement détaillé et mérite une attention particulière.
Erreurs d'authentification et de permission
- -2015 : Clé API invalide ou inactive. Vérifiez que votre clé n'a pas été révoquée.
- -1022 : Signature invalide. Problème de génération du hash HMAC.
- -1023 : Timestamp invalide. Décalage entre votre serveur et Binance supérieur à 5 secondes.
- -2010 : Account has been locked. Contactez le support pour débloquer.
Erreurs de limitation de débit
- -1003 : Too many requests. Réduisez la fréquence de vos appels.
- -1015 : Too many new orders. Limite de création d'ordres atteinte.
- -1121 : Invalid symbol. Le pair de trading n'existe pas.
Erreurs de trading
- -1010 : Unknown error. Réessayez avec un nouveau timestamp.
- -1021 : Timestamp for this request is outside of the recvWindow.
- -2019 : Margin is insufficient. Ajoutez des fonds ou réduisez la position.
- -2022 : Precision is beyond that permitted. Vérifiez les décimalesautorisées.
# Implémentation robuste du gestionnaire d'erreurs Binance
import hmac
import hashlib
import time
import urllib.parse
from typing import Dict, Optional
import requests
class BinanceAPIHandler:
"""
Gestionnaire d'API Binance avec retry automatique et gestion d'erreurs.
Inclut la gestion des signatures HMAC SHA256.
"""
RATE_LIMITS = {
"REQUEST_WEIGHT": {"limit": 1200, "window": 60000}, # 1200 req/min
"ORDERS": {"limit": 200, "window": 60000}, # 200 ordres/min
"ORDERS_PER_ASSET": {"limit": 10, "window": 1000}, # 10 req/sec par asset
}
def __init__(self, api_key: str, secret_key: str, testnet: bool = False):
self.api_key = api_key
self.secret_key = secret_key
self.base_url = "https://testnet.binance.vision/api" if testnet else "https://api.binance.com"
self.recv_window = 5000 # millisecondes
self.request_count = 0
self.last_reset = time.time() * 1000
def _generate_signature(self, query_string: str) -> str:
"""Génère la signature HMAC SHA256 pour les requêtes authentifiées."""
return hmac.new(
self.secret_key.encode('utf-8'),
query_string.encode('utf-8'),
hashlib.sha256
).hexdigest()
def _check_rate_limit(self, endpoint_type: str):
"""Vérifie et applique les limites de taux."""
current_time = time.time() * 1000
time_elapsed = current_time - self.last_reset
if time_elapsed > self.RATE_LIMITS[endpoint_type]["window"]:
self.request_count = 0
self.last_reset = current_time
if self.request_count >= self.RATE_LIMITS[endpoint_type]["limit"]:
wait_time = (self.RATE_LIMITS[endpoint_type]["window"] - time_elapsed) / 1000
print(f"⏳ Rate limit imminent. Pause de {wait_time:.1f}s...")
time.sleep(wait_time)
self.request_count = 0
self.last_reset = time.time() * 1000
self.request_count += 1
def _handle_binance_error(self, response_data: Dict) -> None:
"""Traitement des codes d'erreur spécifiques Binance."""
error_codes = {
-2015: ("INVALID_API_KEY", "Clé API invalide ou inactive. Vérifiez dans votre tableau de bord Binance."),
-1022: ("INVALID_SIGNATURE", "Signature invalide. Vérifiez votre clé secrète."),
-1023: ("INVALID_TIMESTAMP", "Timestamp invalide. Synchronisez votre horloge système."),
-1021: ("INVALID_TIMESTAMP", "Timestamp hors fenêtre recvWindow. Augmentez recvWindow ou syncronisez NTP."),
-2010: ("ACCOUNT_LOCKED", "Compte verrouillé. Contactez le support Binance."),
-1003: ("TOO_MANY_REQUESTS", "Trop de requêtes. Implémentez un backoff exponentiel."),
-1015: ("TOO_MANY_NEW_ORDERS", "Trop de nouveaux ordres. Limite de 10 ordres/seconde atteinte."),
-1010: ("UNKNOWN_ERROR", "Erreur inconnue. Réessayez avec un nouveau timestamp."),
-2019: ("MARGIN_INSUFFICIENT", "Marge insuffisante pour cette opération."),
-2022: ("PRECISION_ERROR", "Précision invalide. Vérifiez les décimales du pair."),
-1121: ("INVALID_SYMBOL", "Symbole invalide. Exemple: BTCUSDT pas BTC-USD."),
-1013: ("INVALID_QUANTITY", "Quantité invalide. Vérifiez les lots minimums."),
}
code = response_data.get("code")
msg = response_data.get("msg", "Erreur inconnue")
if code in error_codes:
error_name, solution = error_codes[code]
raise Exception(f"[{error_name}] {msg}\n💡 Solution: {solution}")
else:
raise Exception(f"[BINANCE ERROR {code}] {msg}")
def get_account_info(self) -> Dict:
"""Récupère les informations du compte avec gestion complète des erreurs."""
self._check_rate_limit("REQUEST_WEIGHT")
timestamp = int(time.time() * 1000)
params = f"timestamp={timestamp}&recvWindow={self.recv_window}"
signature = self._generate_signature(params)
url = f"{self.base_url}/v3/account?{params}&signature={signature}"
headers = {"X-MBX-APIKEY": self.api_key}
response = requests.get(url, headers=headers, timeout=30)
data = response.json()
# Vérification des erreurs Binance
if "code" in data and data["code"] != 0:
self._handle_binance_error(data)
return data
def place_order(self, symbol: str, side: str, order_type: str,
quantity: float, price: Optional[float] = None) -> Dict:
"""Place un ordre avec gestion des erreurs complète."""
self._check_rate_limit("ORDERS")
timestamp = int(time.time() * 1000)
# Construction des paramètres
params = {
"symbol": symbol.upper(),
"side": side.upper(),
"type": order_type.upper(),
"quantity": quantity,
"timestamp": timestamp,
"recvWindow": self.recv_window
}
if order_type.upper() == "LIMIT":
if not price:
raise ValueError("Prix requis pour les ordres LIMIT")
params["price"] = price
params["timeInForce"] = "GTC"
# Tri des paramètres par ordre alphabétique
sorted_params = sorted(params.items())
query_string = "&".join([f"{k}={v}" for k, v in sorted_params])
signature = self._generate_signature(query_string)
url = f"{self.base_url}/v3/order?{query_string}&signature={signature}"
headers = {"X-MBX-APIKEY": self.api_key}
response = requests.post(url, headers=headers, timeout=30)
data = response.json()
if "code" in data and data["code"] != 0:
self._handle_binance_error(data)
return data
def test_connection(self) -> Dict:
"""Teste la connexion à l'API Binance."""
url = f"{self.base_url}/v3/ping"
response = requests.get(url, timeout=10)
if response.status_code == 200:
return {"status": "OK", "latency_ms": response.elapsed.total_seconds() * 1000}
else:
raise Exception(f"Échec du test de connexion: HTTP {response.status_code}")
Utilisation
if __name__ == "__main__":
handler = BinanceAPIHandler(
api_key="VOTRE_API_KEY",
secret_key="VOTRE_SECRET_KEY"
)
# Test de connexion
try:
result = handler.test_connection()
print(f"✅ Connexion réussie - Latence: {result['latency_ms']:.2f}ms")
except Exception as e:
print(f"❌ Erreur: {e}")
Codes d'erreur Coinbase Advanced Trade
Coinbase a migré vers une nouvelle API Advanced Trade qui utilise des codes d'erreur RESTful standardisés. La documentation est plus散乱 que celle de Binance, donc j'ai compilé les codes les plus courants.
- 400 INVALID_ARGUMENT : Paramètres de requête invalides.
- 401 INVALID_CREDENTIALS : Clés API invalides ou malformées.
- 403 INVALID_PERMISSION : La clé API n'a pas les permissions requises.
- 429 RATE_LIMIT_EXCEEDED : Limite de requêtes dépassée.
- 500 INTERNAL_ERROR : Erreur serveur Coinbase.
Erreurs courantes et solutions
Après des années de debugging en production, voici les trois erreurs qui représentent 80% des problèmes que vous rencontrerez, avec leurs solutions complètes.
Cas 1 : Erreur de signature HMAC -2015
Cette erreur apparaît généralement是因为 la génération de la signature HMAC ne respecte pas l'ordre des paramètres ou utilise le mauvais algorithme de hashage.
# Solution complète pour l'erreur de signature
import hmac
import hashlib
import time
import requests
from typing import Dict, List, Tuple
def generate_binance_signature(secret_key: str, params: Dict) -> str:
"""
Génère une signature valide pour l'API Binance.
⚠️ ERREUR COURANTE: Ne pas trier les paramètres alphabétiquement.
⚠️ ERREUR COURANTE: Utiliser SHA512 au lieu de SHA256.
"""
# Étape 1: Convertir tous les paramètres en strings
string_params = []
for key, value in params.items():
if isinstance(value, bool):
value = "true" if value else "false"
string_params.append(f"{key}={value}")
# Étape 2: TRIER alphabétiquement par clé (OBLIGATOIRE)
string_params.sort()
# Étape 3: Joindre avec &
query_string = "&".join(string_params)
# Étape 4: Encoder en UTF-8 et signer avec HMAC-SHA256
signature = hmac.new(
secret_key.encode('UTF-8'),
query_string.encode('UTF-8'),
hashlib.sha256
).hexdigest()
return signature
def test_signature():
"""Test de validation de la génération de signature."""
api_secret = "your_secret_key_here"
# Paramètres de test
params = {
"symbol": "BTCUSDT",
"side": "BUY",
"type": "LIMIT",
"quantity": 0.001,
"price": 45000,
"timeInForce": "GTC",
"timestamp": 1677649400000,
"recvWindow": 5000
}
signature = generate_binance_signature(api_secret, params)
print(f"Signature générée: {signature}")
print(f"Longueur attendue: 64 caractères (SHA256 hex)")
# Validation
assert len(signature) == 64, "La signature doit faire 64 caractères"
assert all(c in '0123456789abcdef' for c in signature), "La signature doit être hexadécimale"
print("✅ Signature valide")
Exécuter le test
test_signature()
Cas 2 : Erreur 429 Rate Limit avec backoff exponentiel
L'erreur 429 est la plus fréquente en période de forte volatilité. Voici une implémentation robuste qui respecte les limites tout en maximisant le throughput.
import time
import requests
from functools import wraps
from datetime import datetime, timedelta
import threading
class RateLimitHandler:
"""Gestionnaire de rate limiting avec backoff exponentiel."""
def __init__(self, requests_per_second: int = 10, burst_limit: int = 20):
self.requests_per_second = requests_per_second
self.burst_limit = burst_limit
self.tokens = burst_limit
self.last_update = time.time()
self.lock = threading.Lock()
self.request_times = []
def acquire(self, endpoint: str = "default") -> float:
"""
Acquiert un token pour effectuer une requête.
Retourne le temps d'attente en secondes.
"""
with self.lock:
current_time = time.time()
# Régénération des tokens basée sur le temps écoulé
elapsed = current_time - self.last_update
self.tokens = min(
self.burst_limit,
self.tokens + elapsed * self.requests_per_second
)
self.last_update = current_time
# Nettoyage des timestamps anciens
cutoff = current_time - 1
self.request_times = [t for t in self.request_times if t > cutoff]
# Vérification du rate limit
if self.tokens < 1 or len(self.request_times) >= self.requests_per_second:
# Calcul du temps d'attente
if len(self.request_times) >= self.requests_per_second:
wait_time = 1 - (current_time - self.request_times[0])
else:
wait_time = (1 - self.tokens) / self.requests_per_second
wait_time = max(0, wait_time) + 0.01 # Marge de sécurité
time.sleep(wait_time)
return wait_time
# Consommer un token
self.tokens -= 1
self.request_times.append(current_time)
return 0
def get_retry_after(self, response: requests.Response) -> int:
"""Extrait le header Retry-After de la réponse."""
retry_after = response.headers.get("Retry-After")
if retry_after:
return int(retry_after)
# Calcul basé sur le code d'erreur Binance
try:
data = response.json()
if data.get("code") == -1003:
return 60 # Rate limit standard Binance
except:
pass
return 60 # Valeur par défaut
def exponential_backoff(attempt: int, base_delay: float = 1.0,
max_delay: float = 300.0,
jitter: bool = True) -> float:
"""
Calcule le délai pour le backoff exponentiel.
Args:
attempt: Numéro de la tentative (0-indexed)
base_delay: Délai de base en secondes
max_delay: Délai maximum en secondes
jitter: Ajouter du aléatoire pour éviter le thundering herd
Formule: min(max_delay, base_delay * (2 ** attempt))
"""
delay = min(max_delay, base_delay * (2 ** attempt))
if jitter:
import random
delay *= (0.5 + random.random() * 0.5) # Facteur aléatoire 0.5-1.0
return delay
class ResilientAPIClient:
"""Client API avec retry automatique et rate limiting."""
def __init__(self, api_key: str, secret_key: str,
requests_per_second: int = 10):
self.api_key = api_key
self.secret_key = secret_key
self.rate_limiter = RateLimitHandler(requests_per_second=requests_per_second)
self.session = requests.Session()
self.session.headers.update({"X-MBX-APIKEY": api_key})
def request_with_retry(self, method: str, url: str,
max_retries: int = 5,
**kwargs) -> requests.Response:
"""
Effectue une requête avec retry automatique.
"""
last_exception = None
for attempt in range(max_retries):
try:
# Attendre l'acquisition du token
wait_time = self.rate_limiter.acquire()
# Effectuer la requête
response = self.session.request(
method=method,
url=url,
timeout=30,
**kwargs
)
# Succès
if response.status_code == 200:
return response
# Rate limit
elif response.status_code == 429:
retry_after = self.rate_limiter.get_retry_after(response)
print(f"⚠️ Rate limit (tentative {attempt + 1}/{max_retries})")
print(f" Attente de {retry_after}s...")
time.sleep(retry_after)
continue
# Erreur temporaire (5xx)
elif 500 <= response.status_code < 600:
delay = exponential_backoff(attempt)
print(f"⚠️ Erreur serveur {response.status_code} (tentative {attempt + 1}/{max_retries})")
print(f" Retry dans {delay:.1f}s...")
time.sleep(delay)
continue
# Erreur permanente (4xx autre que 429)
else:
return response
except requests.exceptions.Timeout:
delay = exponential_backoff(attempt)
print(f"⏱️ Timeout (tentative {attempt + 1}/{max_retries})")
print(f" Retry dans {delay:.1f}s...")
time.sleep(delay)
last_exception = Exception("Timeout")
except requests.exceptions.ConnectionError as e:
delay = exponential_backoff(attempt)
print(f"🔌 Erreur de connexion (tentative {attempt + 1}/{max_retries})")
print(f" Retry dans {delay:.1f}s...")
time.sleep(delay)
last_exception = Exception(f"Connection error: {e}")
raise Exception(f"Échec après {max_retries} tentatives: {last_exception}")
Exemple d'utilisation
client = ResilientAPIClient(
api_key="VOTRE_API_KEY",
secret_key="VOTRE_SECRET_KEY",
requests_per_second=10
)
Test du rate limiter
print("Test du rate limiter:")
for i in range(15):
start = time.time()
wait = client.rate_limiter.acquire()
elapsed = time.time() - start
print(f"Requête {i+1:2d}: attendue {wait:.3f}s, réelle {elapsed:.3f}s")
Cas 3 : Erreur de timestamp hors fenêtre recvWindow
L'erreur -1021 ou "Timestamp for this request is outside of the recvWindow" est causée par un décalage entre l'horloge de votre serveur et celle de Binance. La solution nécessite une synchronisation NTP précise.
# Solution pour le problème de timestamp
import time
import requests
from datetime import datetime
import ntplib
import threading
class TimeSynchronizer:
"""Synchroniseur de temps avec les serveurs NTP et Binance."""
def __init__(self):
self.offset = 0
self.last_sync = None
self.servers = [
'pool.ntp.org',
'time.google.com',
'time.windows.com',
'api.binance.com' # Serveur de temps Binance
]
self.lock = threading.Lock()
def sync_with_ntp(self, server: str = 'pool.ntp.org') -> float:
"""Synchronise avec un serveur NTP et retourne l'offset."""
try:
client = ntplib.NTPClient()
response = client.request(server, timeout=5)
# Calculer l'offset entre le temps local et le serveur
self.offset = response.offset
self.last_sync = time.time()
print(f"✅ Sync NTP réussie avec {server}")
print(f" Offset: {self.offset:.3f}s")
print(f" Temps local: {datetime.now()}")
print(f" Temps serveur: {datetime.utcfromtimestamp(time.time() + self.offset)}")
return self.offset
except Exception as e:
print(f"❌ Échec sync NTP avec {server}: {e}")
return 0
def sync_with_binance(self) -> float:
"""Récupère le temps officiel Binance via API."""
try:
response = requests.get(
"https://api.binance.com/api/v3/time",
timeout=10
)
data = response.json()
server_time = data['serverTime']
local_time_ms = int(time.time() * 1000)
self.offset = (server_time - local_time_ms) / 1000
self.last_sync = time.time()
print(f"✅ Sync Binance réussie")
print(f" Offset: {self.offset:.3f}s")
print(f" Différence: {abs(self.offset):.3f}s")
return self.offset
except Exception as e:
print(f"❌ Échec sync Binance: {e}")
return self.sync_with_ntp()
def get_adjusted_time(self) -> int:
"""Retourne le timestamp ajusté en millisecondes."""
with self.lock:
return int((time.time() + self.offset) * 1000)
def get_recv_window(self) -> int:
"""Calcule une recvWindow appropriée basée sur l'offset."""
with self.lock:
# Si l'offset est important, augmenter recvWindow
abs_offset = abs(self.offset)
if abs_offset < 0.5:
return 5000 # Offset minime
elif abs_offset < 2:
return 10000 # Offset modéré
elif abs_offset < 10:
return 30000 # Offset important
else:
return 60000 # Offset très important
class TimestampSafeClient:
"""Client Binance avec synchronisation automatique du temps."""
def __init__(self, api_key: str, secret_key: str,
auto_sync_interval: int = 300):
self.api_key = api_key
self.secret_key = secret_key
self.time_syncer = TimeSynchronizer()
self.recv_window = 5000
self.auto_sync_interval = auto_sync_interval
self.last_sync_time = 0
# Synchronisation initiale
self.time_syncer.sync_with_binance()
def _ensure_sync(self):
"""S'assure que le temps est synchronisé."""
current_time = time.time()
# Resynchroniser si nécessaire
if current_time - self.last_sync_time > self.auto_sync_interval:
self.time_syncer.sync_with_binance()
self.recv_window = self.time_syncer.get_recv_window()
self.last_sync_time = current_time
def create_signed_params(self, params: dict) -> dict:
"""Crée les paramètres signés avec timestamp corrigé."""
self._ensure_sync()
# Ajouter timestamp ajusté
params['timestamp'] = self.time_syncer.get_adjusted_time()
params['recvWindow'] = self.recv_window
return params
def sign_request(self, params: dict) -> str:
"""Signe les paramètres avec la clé secrète."""
import hmac
import hashlib
# Trier et encoder les paramètres
sorted_params = sorted(params.items())
query_string = "&".join([f"{k}={v}" for k, v in sorted_params])
signature = hmac.new(
self.api_key.encode('utf-8'),
query_string.encode('utf-8'),
hashlib.sha256
).hexdigest()
return signature
def get_server_time(self) -> dict:
"""Récupère le temps serveur Binance avec diagnostic."""
self._ensure_sync()
server_time = self.time_syncer.get_adjusted_time()
local_time = int(time.time() * 1000)
return {
"server_time": server_time,
"local_time": local_time,
"difference_ms": local_time - server_time,
"offset_s": self.time_syncer.offset,
"recv_window": self.recv_window
}
Test du synchroniseur
if __name__ == "__main__":
print("=" * 50)
print("TEST DU SYNCHRONISEUR DE TEMPS")
print("=" * 50)
syncer = TimeSynchronizer()
# Test avec Binance
offset = syncer.sync_with_binance()
print("\n" + "=" * 50)
print("RÉSULTATS DU DIAGNOSTIC")
print("=" * 50)
if abs(offset) < 1:
print(f"✅ Offset acceptable: {offset:.3f}s")
elif abs(offset) < 5:
print(f"⚠️ Offset modéré: {offset:.3f}s (conseillé: sync NTP)")
else:
print(f"❌ Offset critique: {offset:.3f}s (URGENT: sync requise)")
print(f"\nTimestamp corrigé: {syncer.get_adjusted_time()}")
print(f"recvWindow recommandée: {syncer.get_recv_window()}ms")
Tableau comparatif des erreurs par exchange
| Code | Binance | Coinbase | Kraken | Solution rapide |
|---|---|---|---|---|
| 401 | -2015 Clé invalide | INVALID_CREDENTIALS | EAPI:Invalid key | Vérifier les clés API |
| 403 | Accès refusé | INVALID_PERMISSION | EGeneral:Permission denied | Vérifier les permissions |
| 429 | -1003 Too many requests | RATE_LIMIT_EXCEEDED | EGeneral:Too many requests | Backoff exponentiel |
| 400 | -1121 Symbole invalide | INVALID_ARGUMENT | EGeneral:Invalid arguments | Vérifier les paramètres |
| 500 | Erreur serveur | INTERNAL_ERROR | EGeneral:Internal error | Réessayer plus tard |
Comparatif de coûts pour l'analyse d'erreurs API
Pour construire un système robuste de gestion d'erreurs, vous aurez besoin de capacités de traitement de texte et d'analyse. Voici une comparaison des coûts pour处理的10 millions de tokens par mois, avec les prix vérifiés pour 2026.
| Modèle | Prix par million de tokens | Coût pour 10M tokens/mois | Latence moyenne | Score performance |
|---|---|---|---|---|
| GPT-4.1 (OpenAI) | 8,00 $ | 80,00 $ | ~150ms | ⭐⭐⭐⭐ |
| Claude Sonnet 4.5 | 15,00 $ | 150,00 $ | ~180ms | ⭐⭐⭐⭐⭐ |
| Gemini 2.5 Flash | 2,50 $ | 25,00 $ | ~80ms | ⭐⭐⭐⭐ |
| DeepSeek V3.2 | 0,42 $ | 4,20 $ | ~45ms | ⭐⭐⭐⭐⭐ |