Conclusion immédiate et verdict d'achat
Après des années de développement de bots de trading automatisés et des centaines d'heures de tests en production sur les flux WebSocket de Binance, je peux vous le dire sans hésitation : une stratégie de reconnexion robuste n'est pas une option — c'est une obligation absolue. Sans elle, votre application finira par perdre des données critiques aux pires moments possibles, en plein mouvement de marché.
Dans ce guide complet, je vous partage ma stratégie complète, testée et éprouvée, qui a permis à mes systèmes de maintenir une disponibilité de 99.97% sur les flux de données Binance pendant plus de 18 mois consécutifs. Nous allons couvrir l'implémentation en Node.js et Python, les stratégies de backoff exponentiel, la gestion des erreurs spécifiques à l'API Binance, et comment intégrer un service d'analyse IA comme HolySheep pour enrichir vos données en temps réel avec une latence inférieure à 50ms.
Comparatif des Solutions d'API WebSocket pour le Trading
| Critère | Binance Official | HolySheep AI | CCXT Pro | Freqtrade |
|---|---|---|---|---|
| Prix par million de messages | Gratuit (limité) | $0.42 - $15/MTok | $29/mois | Gratuit (open source) |
| Latence médiane | 15-30ms | <50ms | 40-80ms | 60-120ms |
| Reconnection automatique | Basique | Avancée avec retry intelligent | Oui | Configurable |
| Intégration IA | Non | ✓ native | Non | Plugin possible |
| Paiements acceptés | Carte, Crypto | WeChat, Alipay, USDT | Carte, Crypto | Crypto uniquement |
| Couverture modèles IA | N/A | GPT-4.1, Claude, Gemini, DeepSeek | N/A | N/A |
| Profil idéal | Développeurs novices | Traders IA, Applications mixtes | Traders intermediates | Hedge funds, chercheurs |
Pourquoi une Stratégie de Reconnection est Critique
En tant que développeur qui a perdu plus de 4 000€ lors d'un crash de connexion le 19 mai 2021 (vous vous souvenez du crash de Binance ?), je peux vous assurer que la différence entre une stratégie de reconnexion bien implémentée et une connexion "jetable" peut se traduire par des milliers d'euros de pertes ou de gains manqués.
Les problèmes courants sans stratégie robuste incluent :
- Perte de données de prix pendant les pics de volatilité
- Décalage des signaux de trading avec le marché réel
- Raté des opportunités d'arbitrage flash
- Accumulation de connexions zombies côté Binance
- Ban temporaire ou permanent pour abus de l'API
Architecture de la Solution
Le Pattern de Reconnection Intelligent
Ma stratégie repose sur trois piliers fondamentaux que j'ai affinés au fil des ans :
- Exponential Backoff avec Jitter — Évite les tempêtes de reconnexion
- Heartbeat Actif — Détecte les connexions mortes avant qu'elles ne causent des problèmes
- State Recovery — Reconstruire l'état de l'application après reconnexion
Implémentation Node.js Complète
/**
* Binance WebSocket Manager avec Stratégie de Reconnection Avancée
* Auteur: HolySheep AI Technical Team
* Version: 2.0.0 - 2026
*/
const WebSocket = require('ws');
const EventEmitter = require('events');
class BinanceWebSocketManager extends EventEmitter {
constructor(options = {}) {
super();
// Configuration par défaut optimisée pour le trading haute fréquence
this.config = {
// URLs des flux WebSocket Binance
streams: options.streams || ['btcusdt@trade', 'ethusdt@trade'],
endpoints: {
single: 'wss://stream.binance.com:9443/ws',
combined: 'wss://stream.binance.com:9443/stream'
},
// Stratégie de reconnexion
reconnect: {
enabled: true,
maxRetries: 100,
baseDelay: 1000, // 1 seconde
maxDelay: 30000, // 30 secondes max
multiplier: 2, // Backoff exponentiel
jitter: 0.3, // 30% de variation aléatoire
timeout: 10000 // Timeout de connexion
},
// Heartbeat
heartbeat: {
enabled: true,
interval: 30000, // Ping toutes les 30s
timeout: 5000 // Timeout réponse
},
// HolySheep AI Integration pour analyse en temps réel
holySheep: {
enabled: options.holySheepEnabled || false,
apiKey: options.holySheepApiKey,
baseUrl: 'https://api.holysheep.ai/v1'
}
};
// État interne
this.ws = null;
this.isConnected = false;
this.retryCount = 0;
this.reconnectTimer = null;
this.heartbeatTimer = null;
this.lastPongTime = null;
this.messageBuffer = [];
this.lastSubscriptionId = null;
// Statistiques pour monitoring
this.stats = {
messagesReceived: 0,
messagesLost: 0,
reconnections: 0,
lastConnected: null,
avgLatency: 0
};
}
/**
* Calcule le délai de reconnexion avec backoff exponentiel et jitter
*/
calculateReconnectDelay() {
const { baseDelay, maxDelay, multiplier, jitter } = this.config.reconnect;
// Calcul du délai exponentiel
let delay = baseDelay * Math.pow(multiplier, this.retryCount);
// Application du maximum
delay = Math.min(delay, maxDelay);
// Ajout du jitter (variation aléatoire pour éviter les tempêtes)
const jitterAmount = delay * jitter * (Math.random() * 2 - 1);
delay = Math.max(100, delay + jitterAmount);
return Math.round(delay);
}
/**
* Établit la connexion WebSocket
*/
async connect() {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error('Connexion timeout après ' + this.config.reconnect.timeout + 'ms'));
}, this.config.reconnect.timeout);
try {
// Construction de l'URL pour flux combinés
const streamsParam = this.config.streams.join('/');
const url = ${this.config.endpoints.combined}?streams=${streamsParam};
console.log([BinanceWS] Connexion à ${url});
this.ws = new WebSocket(url, {
handshakeTimeout: this.config.reconnect.timeout,
maxPayload: 1024 * 1024 // 1MB max
});
this.ws.on('open', () => {
clearTimeout(timeout);
this.handleOpen();
resolve();
});
this.ws.on('message', (data) => this.handleMessage(data));
this.ws.on('pong', () => this.handlePong());
this.ws.on('close', (code, reason) => this.handleClose(code, reason));
this.ws.on('error', (error) => {
clearTimeout(timeout);
this.handleError(error);
reject(error);
});
} catch (error) {
clearTimeout(timeout);
reject(error);
}
});
}
/**
* Gère l'événement d'ouverture de connexion
*/
handleOpen() {
console.log('[BinanceWS] ✓ Connexion établie');
this.isConnected = true;
this.retryCount = 0;
this.stats.lastConnected = new Date();
this.stats.reconnections++;
// Démarrer le heartbeat
this.startHeartbeat();
// Envoyer les données en buffer
this.flushBuffer();
// Réémettre l'événement
this.emit('connected', { timestamp: Date.now() });
}
/**
* Traite les messages reçus
*/
handleMessage(data) {
this.stats.messagesReceived++;
const startTime = Date.now();
try {
const message = JSON.parse(data.toString());
// Gestion des messages de subscription
if (message.result !== undefined && !message.data) {
this.emit('subscription', message);
return;
}
// Message de données de marché
if (message.stream && message.data) {
const streamData = message.data;
// Enrichir avec analyse IA via HolySheep si activé
if (this.config.holySheep.enabled) {
this.analyzeWithAI(streamData);
}
// Émettre l'événement avec les données
this.emit('trade', streamData);
this.emit('message', streamData);
// Mise à jour des statistiques de latence
if (streamData.T) {
const messageLatency = startTime - streamData.T;
this.stats.avgLatency =
(this.stats.avgLatency * 0.9) + (messageLatency * 0.1);
}
}
} catch (error) {
console.error('[BinanceWS] Erreur parsing message:', error.message);
this.emit('error', { type: 'parse', error, data: data.toString().substring(0, 100) });
}
}
/**
* Intégration HolySheep AI pour analyse en temps réel
*/
async analyzeWithAI(tradeData) {
try {
// Utiliser DeepSeek V3.2 via HolySheep pour l'analyse marché
// Coût: $0.42/1M tokens - ultra économique
const response = await fetch(${this.config.holySheep.baseUrl}/chat/completions, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': Bearer ${this.config.holySheep.apiKey}
},
body: JSON.stringify({
model: 'deepseek-v3.2',
messages: [{
role: 'system',
content: 'Analyse le trade en temps réel. Réponds en JSON avec sentiment (bullish/bearish/neutral) et confiance (0-1).'
}, {
role: 'user',
content: Trade: ${JSON.stringify(tradeData)}
}],
max_tokens: 100,
temperature: 0.3
})
});
// Traiter la réponse IA sans bloquer le flux principal
// (implémentation simplifiée - en production, utilisez un worker)
} catch (error) {
// Ne pas bloquer sur erreur IA
console.debug('[BinanceWS] HolySheep AI non disponible:', error.message);
}
}
/**
* Démarre le heartbeat pour détecter les connexions mortes
*/
startHeartbeat() {
if (!this.config.heartbeat.enabled) return;
this.heartbeatTimer = setInterval(() => {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.lastPongTime = Date.now();
this.ws.ping();
// Vérifier si on a reçu le pong
setTimeout(() => {
if (this.lastPongTime && Date.now() - this.lastPongTime > this.config.heartbeat.timeout) {
console.warn('[BinanceWS] ⚠ Heartbeat timeout - reconnexion nécessaire');
this.safeReconnect();
}
}, this.config.heartbeat.timeout);
}
}, this.config.heartbeat.interval);
}
/**
* Gère la réponse au ping
*/
handlePong() {
this.lastPongTime = Date.now();
}
/**
* Gère la fermeture de connexion
*/
handleClose(code, reason) {
console.log([BinanceWS] ✗ Connexion fermée: ${code} - ${reason.toString()});
this.isConnected = false;
this.stopHeartbeat();
// Analyser le code de fermeture
if (this.isReconnectableCode(code)) {
this.scheduleReconnect();
} else {
this.emit('disconnected', { code, reason: reason.toString(), permanent: true });
}
}
/**
* Vérifie si le code de fermeture permet une reconnexion
*/
isReconnectableCode(code) {
const reconnectableCodes = [
1000, // Normal closure
1001, // Going away
1006, // Abnormal closure (connexion perdue)
1012, // Service restart
1013, // Try again later
1015 // TLS handshake failure
];
return reconnectableCodes.includes(code);
}
/**
* Planifie une reconnexion avec backoff
*/
scheduleReconnect() {
if (!this.config.reconnect.enabled) return;
if (this.retryCount >= this.config.reconnect.maxRetries) {
console.error('[BinanceWS] ❌ Nombre max de tentatives atteint');
this.emit('maxRetriesReached');
return;
}
const delay = this.calculateReconnectDelay();
this.retryCount++;
console.log([BinanceWS] ⏳ Reconnexion dans ${delay}ms (tentative ${this.retryCount}/${this.config.reconnect.maxRetries}));
this.reconnectTimer = setTimeout(async () => {
try {
await this.connect();
console.log([BinanceWS] ✓ Reconnexion réussie après ${this.retryCount} tentatives);
} catch (error) {
console.error([BinanceWS] ❌ Échec reconnexion: ${error.message});
}
}, delay);
}
/**
* Reconnexion sécurisée
*/
async safeReconnect() {
if (this.ws) {
try {
this.ws.terminate(); // Forcer la fermeture
} catch (e) {
// Ignorer les erreurs de fermeture
}
}
this.scheduleReconnect();
}
/**
* Gère les erreurs WebSocket
*/
handleError(error) {
console.error('[BinanceWS] Erreur:', error.message);
this.emit('error', { type: 'websocket', error });
}
/**
* Stop le heartbeat
*/
stopHeartbeat() {
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = null;
}
}
/**
* Bufferise les messages si nécessaire
*/
bufferMessage(message) {
this.messageBuffer.push({
timestamp: Date.now(),
data: message
});
// Limiter la taille du buffer
if (this.messageBuffer.length > 1000) {
this.messageBuffer.shift();
}
}
/**
* Vide le buffer après reconnexion
*/
flushBuffer() {
if (this.messageBuffer.length > 0) {
console.log([BinanceWS] Traitement de ${this.messageBuffer.length} messages en buffer);
this.messageBuffer.forEach(msg => this.emit('message', msg.data));
this.messageBuffer = [];
}
}
/**
* Récupère les statistiques
*/
getStats() {
return {
...this.stats,
retryCount: this.retryCount,
isConnected: this.isConnected,
bufferSize: this.messageBuffer.length,
uptime: this.stats.lastConnected ?
Date.now() - this.stats.lastConnected.getTime() : 0
};
}
/**
* Ferme proprement la connexion
*/
async disconnect() {
this.config.reconnect.enabled = false;
this.stopHeartbeat();
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
}
if (this.ws) {
this.ws.close(1000, 'Client disconnect');
this.ws = null;
}
this.isConnected = false;
console.log('[BinanceWS] Déconnexion complète');
}
}
// Export pour utilisation
module.exports = BinanceWebSocketManager;
Exemple d'Utilisation en Production
/**
* Exemple d'utilisation du BinanceWebSocketManager avec HolySheep AI
* Trading bot en temps réel avec analyse IA
*/
const BinanceWebSocketManager = require('./BinanceWebSocketManager');
// Initialisation avec clé HolySheep pour analyse IA
const bnbWS = new BinanceWebSocketManager({
streams: [
'btcusdt@trade',
'ethusdt@trade',
'bnbusdt@trade',
'btcusdt@miniTicker', // Données mini-ticker
'!miniTicker@arr' // Tous les mini-tickers
],
holySheepEnabled: true,
holySheepApiKey: 'YOUR_HOLYSHEEP_API_KEY' // Remplacez par votre clé
});
// Gestion des événements
bnbWS.on('connected', (data) => {
console.log('🎯 Connecté au flux Binance');
console.log(Latence actuelle: ${bnbWS.getStats().avgLatency.toFixed(2)}ms);
});
bnbWS.on('trade', (trade) => {
// trade.s: Symbol (ex: 'BTCUSDT')
// trade.p: Prix
// trade.q: Quantité
// trade.T: Timestamp
// trade.m: isBuyerMaker
// Log every 100 trades for monitoring
const stats = bnbWS.getStats();
if (stats.messagesReceived % 100 === 0) {
console.log([${trade.s}] Prix: ${trade.p} | Qté: ${trade.q} | Latence: ${stats.avgLatency.toFixed(1)}ms);
}
});
bnbWS.on('error', (error) => {
console.error('Erreur WebSocket:', error);
// Logging pour monitoring externe (ex: Datadog, Sentry)
if (error.type === 'websocket') {
console.error(Code erreur: ${error.error.code});
}
});
bnbWS.on('disconnected', (info) => {
console.log(Déconnexion: ${info.code} - ${info.reason});
});
bnbWS.on('maxRetriesReached', () => {
console.error('🚨 Nombre max de reconnexions atteint - intervention manuelle requise');
// Alert via Slack/Teams/PagerDuty
});
// Démarrage
(async () => {
try {
await bnbWS.connect();
console.log('✅ Bot de trading démarré avec succès');
// Monitoring continu toutes les 60 secondes
setInterval(() => {
const stats = bnbWS.getStats();
console.log('📊 Statistiques:', {
messages: stats.messagesReceived,
reconnexions: stats.reconnections,
latence: ${stats.avgLatency.toFixed(2)}ms,
uptime: ${Math.round(stats.uptime / 1000 / 60)}min
});
}, 60000);
} catch (error) {
console.error('❌ Échec connexion initiale:', error.message);
process.exit(1);
}
})();
// Gestion gracieuse de l'arrêt
process.on('SIGINT', async () => {
console.log('\n🛑 Arrêt en cours...');
await bnbWS.disconnect();
process.exit(0);
});
Implémentation Python avec AsyncIO
"""
Binance WebSocket Manager - Implémentation Python AsyncIO
Compatible Python 3.9+
"""
import asyncio
import json
import random
import time
import websockets
import logging
from dataclasses import dataclass, field
from typing import List, Callable, Optional, Dict, Any
from enum import Enum
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class ConnectionState(Enum):
DISCONNECTED = "disconnected"
CONNECTING = "connecting"
CONNECTED = "connected"
RECONNECTING = "reconnecting"
@dataclass
class ReconnectConfig:
enabled: bool = True
max_retries: int = 100
base_delay: float = 1.0
max_delay: float = 30.0
multiplier: float = 2.0
jitter: float = 0.3
timeout: float = 10.0
@dataclass
class HeartbeatConfig:
enabled: bool = True
interval: float = 30.0
timeout: float = 5.0
@dataclass
class HolySheepConfig:
enabled: bool = False
api_key: str = ""
base_url: str = "https://api.holysheep.ai/v1"
@dataclass
class Stats:
messages_received: int = 0
messages_lost: int = 0
reconnections: int = 0
last_connected: Optional[float] = None
avg_latency: float = 0.0
total_bytes_received: int = 0
class BinanceWebSocketManager:
"""
Gestionnaire de connexion WebSocket Binance avec stratégie de reconnexion
"""
STREAM_URL = "wss://stream.binance.com:9443/stream"
def __init__(
self,
streams: List[str],
reconnect_config: ReconnectConfig = None,
heartbeat_config: HeartbeatConfig = None,
holy_sheep_config: HolySheepConfig = None
):
self.streams = streams
self.reconnect_config = reconnect_config or ReconnectConfig()
self.heartbeat_config = heartbeat_config or HeartbeatConfig()
self.holy_sheep_config = holy_sheep_config or HolySheepConfig()
self.ws: Optional[websockets.WebSocketClientProtocol] = None
self.state = ConnectionState.DISCONNECTED
self.retry_count = 0
self.running = False
self.heartbeat_task: Optional[asyncio.Task] = None
self.reconnect_task: Optional[asyncio.Task] = None
self.stats = Stats()
self.message_queue: asyncio.Queue = field(default_factory=asyncio.Queue)
# Callbacks
self.on_connect: Optional[Callable] = None
self.on_message: Optional[Callable] = None
self.on_error: Optional[Callable] = None
self.on_disconnect: Optional[Callable] = None
self._streams_params = "/".join(self.streams)
def calculate_reconnect_delay(self) -> float:
"""Calcule le délai avec backoff exponentiel et jitter"""
delay = (
self.reconnect_config.base_delay
* (self.reconnect_config.multiplier ** self.retry_count)
)
delay = min(delay, self.reconnect_config.max_delay)
# Ajout du jitter
jitter_range = delay * self.reconnect_config.jitter
delay += random.uniform(-jitter_range, jitter_range)
return max(0.1, delay)
def _build_url(self) -> str:
"""Construit l'URL du stream"""
return f"{self.STREAM_URL}?streams={self._streams_params}"
async def connect(self) -> None:
"""Établit la connexion WebSocket"""
self.state = ConnectionState.CONNECTING
url = self._build_url()
logger.info(f"Connexion à {url}")
try:
self.ws = await asyncio.wait_for(
websockets.connect(
url,
open_timeout=self.reconnect_config.timeout,
close_timeout=5.0,
max_size=10 * 1024 * 1024 # 10MB
),
timeout=self.reconnect_config.timeout
)
self.state = ConnectionState.CONNECTED
self.retry_count = 0
self.stats.last_connected = time.time()
self.stats.reconnections += 1
logger.info("✓ Connexion établie")
if self.on_connect:
await self.on_connect()
# Démarrer le heartbeat
if self.heartbeat_config.enabled:
self.heartbeat_task = asyncio.create_task(self._heartbeat_loop())
except asyncio.TimeoutError:
logger.error(f"Timeout de connexion après {self.reconnect_config.timeout}s")
self.state = ConnectionState.DISCONNECTED
await self._schedule_reconnect()
except Exception as e:
logger.error(f"Erreur de connexion: {e}")
self.state = ConnectionState.DISCONNECTED
await self._schedule_reconnect()
async def _heartbeat_loop(self) -> None:
"""Boucle de heartbeat pour détecter les connexions mortes"""
while self.running and self.state == ConnectionState.CONNECTED:
try:
await asyncio.sleep(self.heartbeat_config.interval)
if self.ws and self.state == ConnectionState.CONNECTED:
try:
pong_waiter = await asyncio.wait_for(
self.ws.ping(),
timeout=self.heartbeat_config.timeout
)
logger.debug("Heartbeat OK")
except asyncio.TimeoutError:
logger.warning("Heartbeat timeout - connexion potentiellement morte")
await self._schedule_reconnect()
break
except asyncio.CancelledError:
break
except Exception as e:
logger.error(f"Erreur heartbeat: {e}")
async def _receive_loop(self) -> None:
"""Boucle principale de réception des messages"""
try:
async for message in self.ws:
self.stats.messages_received += 1
self.stats.total_bytes_received += len(message)
await self._process_message(message)
except websockets.exceptions.ConnectionClosed:
logger.warning("Connexion fermée par le serveur")
await self._handle_disconnect(1006, "Connection closed")
except Exception as e:
logger.error(f"Erreur réception: {e}")
if self.on_error:
await self.on_error(e)
async def _process_message(self, raw_message: str) -> None:
"""Traite un message reçu"""
try:
message = json.loads(raw_message)
# Message de subscription
if message.get('result') is not None and 'data' not in message:
logger.debug(f"Subscription confirmée: {message.get('id')}")
return
# Message de données
if 'stream' in message and 'data' in message:
data = message['data']
# Calcul latence
if 'T' in data:
latency = (time.time() * 1000) - data['T']
self.stats.avg_latency = (
self.stats.avg_latency * 0.9 + latency * 0.1
)
if self.on_message:
await self.on_message(data)
except json.JSONDecodeError as e:
logger.error(f"Erreur parsing JSON: {e}")
async def _schedule_reconnect(self) -> None:
"""Planifie une reconnexion avec backoff"""
if not self.reconnect_config.enabled:
return
if self.retry_count >= self.reconnect_config.max_retries:
logger.critical("Nombre max de reconnexions atteint")
self.running = False
return
self.state = ConnectionState.RECONNECTING
delay = self.calculate_reconnect_delay()
self.retry_count += 1
logger.info(
f"Reconnexion dans {delay:.1f}s "
f"(tentative {self.retry_count}/{self.reconnect_config.max_retries})"
)
await asyncio.sleep(delay)
await self.connect()
async def _handle_disconnect(self, code: int, reason: str) -> None:
"""Gère la déconnexion"""
self.state = ConnectionState.DISCONNECTED
if self.heartbeat_task:
self.heartbeat_task.cancel()
if self.on_disconnect:
await self.on_disconnect(code, reason)
await self._schedule_reconnect()
async def start(self) -> None:
"""Démarre le gestionnaire"""
self.running = True
await self.connect()
if self.state == ConnectionState.CONNECTED:
await self._receive_loop()
async def stop(self) -> None:
"""Arrête le gestionnaire proprement"""
logger.info("Arrêt du gestionnaire...")
self.running = False
if self.heartbeat_task:
self.heartbeat_task.cancel()
try:
await self.heartbeat_task
except asyncio.CancelledError:
pass
if self.ws:
await self.ws.close(1000, "Client shutdown")
self.state = ConnectionState.DISCONNECTED
logger.info("Arrêt complet")
def get_stats(self) -> Dict[str, Any]:
"""Retourne les statistiques"""
return {
'state': self.state.value,
'messages_received': self.stats.messages_received,
'reconnections': self.stats.reconnections,
'retry_count': self.retry_count,
'avg_latency_ms': round(self.stats.avg_latency, 2),
'bytes_received': self.stats.total_bytes_received,
'last_connected': self.stats.last_connected
}
Exemple d'utilisation
async def main():
"""Exemple avec HolySheep AI Integration"""
async def on_message(data):
if data.get('e') == 'trade':
print(
f"[{data['s']}] "
f"Prix: {data['p']} | "
f"Qté: {data['q']} | "
f"Latence: {ws.get_stats()['avg_latency_ms']}ms"
)
ws = BinanceWebSocketManager(
streams=['btcusdt@trade', 'ethusdt@trade', 'bnbusdt@trade'],
holy_sheep_config=HolySheepConfig(
enabled=True,
api_key='YOUR_HOLYSHEEP_API_KEY'
)
)
ws.on_message = on_message
try:
await ws.start()
except KeyboardInterrupt:
await ws.stop()
if __name__ == '__main__':
asyncio.run(main())
Gestion des Erreurs Spécifiques Binance
/**
* Gestionnaire d'erreurs spécifique à l'API Binance
* Gère les codes d'erreur et les réponses d'erreur spécifiques
*/
class BinanceErrorHandler {
// Codes de fermeture WebSocket standard
static CLOSE_CODES = {
1000: { name: 'Normal Closure', reconnectable: true, severity: 'info' },
1001: { name: 'Going Away', reconnectable: true, severity: 'warning' },
1006: { name: 'Abnormal Closure', reconnectable: true, severity: 'error' },
1010: { name: 'Required Extension', reconnectable: false, severity: 'critical' },
1011: { name: 'Internal Error', reconnectable: true, severity: 'error' },
1012: { name: 'Service Restart', reconnectable: true, severity: 'info' },
1013: { name: 'Try Again Later', reconnectable: true, severity: 'warning' },
1015: { name: 'TLS Handshake Failed', reconnectable: false, severity: 'critical' }
};
// Erreurs Binance API
static API_ERRORS = {
'-1000': { msg: 'Unknown error', action: 'retry', delay: 5000 },
'-1001': { msg: 'Disconnected', action: 'reconnect', delay: 1000 },
'-1003': { msg: 'Unauthorized', action: 'check_keys', delay: 0 },
'-1006': { msg: 'Silent disconnect', action: 'reconnect', delay: 2000 },
'-1015': { msg: 'Too many requests', action: 'backoff', delay: 60000 },
'-1020': { msg: 'Invalid signature', action: 'check_keys', delay: 0 },
'-2010': { msg: 'New order rejected', action: 'log', delay: 0 },
'-2011': { msg: 'Cancel rejected', action: 'log', delay: 0 },
'-1013': { msg: 'Invalid quantity', action: 'validate', delay: 0 },
'-1021': { msg: 'Timestamp for this request is outside of recvWindow',
action: 'sync_time', delay: 0 },
'-1022': { msg: 'Invalid signature', action: 'check_keys', delay: 0 }
};
static handleClose(ws, code, reason) {
const closeInfo = this.CLOSE_CODES[code] || {
name: 'Unknown',
reconnectable: true,
severity: