S’abonner au carnet d’ordres Hyperliquid en temps réel

6 mai 2026
  • hyperliquid orderbook websocket

  • real time hyperliquid api

  • carnet d’ordres Hyperliquid en temps réel

  • abonnement websocket Hyperliquid

  • hyperliquid l2 book

Le carnet d’ordres est l’une des structures de données les plus importantes d’une plateforme de trading. Il montre en temps réel la répartition des ordres d’achat et de vente non exécutés, avec leurs prix et leurs tailles. Pour un bot quantitatif, un système d’arbitrage ou un tableau d’analyse de marché, recevoir l’état du carnet avec une latence de l’ordre de la milliseconde peut faire une vraie différence.

Hyperliquid propose une API WebSocket complète qui permet de recevoir les snapshots et les mises à jour incrémentales du carnet L2. Dans cet article, on va voir comment s’abonner, comprendre le format des messages, maintenir un carnet local fiable et gérer les reconnexions en conditions de production.

Si ton objectif est surtout de trader des contrats perpétuels sans construire toute l’infrastructure toi-même, OneKey Perps intègre déjà l’affichage de marché en temps réel et un workflow de trading prêt à l’emploi.

WebSocket ou polling REST : pourquoi choisir WebSocket ?

Avant d’entrer dans le code, il faut comprendre pourquoi WebSocket est généralement préférable au polling REST pour un carnet d’ordres en temps réel.

Avec REST, tu dois envoyer des requêtes répétées pour récupérer l’état du marché. Cela crée plus de latence, consomme davantage de ressources et risque de manquer des changements rapides entre deux appels. WebSocket, lui, garde une connexion ouverte : le serveur pousse les nouvelles données dès qu’elles sont disponibles.

Pour un carnet d’ordres temps réel, le polling REST ne remplace donc pas vraiment WebSocket. Pour les détails les plus récents sur les paramètres et limites, consulte toujours la documentation officielle d’Hyperliquid.

Établir une connexion WebSocket

Endpoint

L’endpoint WebSocket d’Hyperliquid est, selon la documentation officielle au moment de référence :

wss://api.hyperliquid.xyz/ws

Exemple de connexion de base

import asyncio
import json
import websockets

WS_URL = "wss://api.hyperliquid.xyz/ws"

async def connect_and_subscribe():
    async with websockets.connect(WS_URL) as ws:
        # Envoyer le message d’abonnement
        subscribe_msg = {
            "method": "subscribe",
            "subscription": {
                "type": "l2Book",
                "coin": "BTC"
            }
        }

        await ws.send(json.dumps(subscribe_msg))

        # Recevoir les messages en continu
        async for raw_msg in ws:
            msg = json.loads(raw_msg)
            handle_message(msg)

asyncio.run(connect_and_subscribe())

Format du message d’abonnement

S’abonner au carnet L2

Exemple pour s’abonner au carnet L2 de BTC :

{
  "method": "subscribe",
  "subscription": {
    "type": "l2Book",
    "coin": "BTC"
  }
}

Hyperliquid permet de s’abonner à plusieurs marchés en envoyant plusieurs messages d’abonnement. Chaque marché pousse ensuite ses propres mises à jour.

Se désabonner

{
  "method": "unsubscribe",
  "subscription": {
    "type": "l2Book",
    "coin": "BTC"
  }
}

Types de messages : snapshot et mises à jour incrémentales

Snapshot initial

Après l’abonnement, le serveur envoie d’abord un snapshot complet du carnet. Il contient les niveaux de prix actuellement disponibles côté achat et côté vente :

{
  "channel": "l2Book",
  "data": {
    "coin": "BTC",
    "time": 1714500000000,
    "levels": [
      [
        [{"px": "64000.0", "sz": "0.5", "n": 3}],
        [{"px": "64010.0", "sz": "0.3", "n": 2}]
      ]
    ]
  }
}
  • px : prix du niveau
  • sz : taille totale disponible à ce prix ; si la taille vaut 0, le niveau est vide
  • n : nombre d’ordres à ce niveau

Dans la structure levels, les bids sont généralement triés du prix le plus haut au plus bas, tandis que les asks sont triés du prix le plus bas au plus haut.

Mise à jour incrémentale

Après le snapshot, le serveur pousse uniquement les niveaux qui ont changé :

{
  "channel": "l2Book",
  "data": {
    "coin": "BTC",
    "time": 1714500000100,
    "levels": [
      [
        [{"px": "63990.0", "sz": "0.0", "n": 0}],
        [{"px": "64010.0", "sz": "0.8", "n": 4}]
      ]
    ]
  }
}

Quand sz vaut "0", "0.0" ou 0, cela signifie que le niveau de prix a été entièrement exécuté ou annulé. Tu dois donc le supprimer de ton carnet local.

Maintenir un carnet d’ordres local

La difficulté principale d’un flux WebSocket n’est pas seulement de recevoir les messages, mais de maintenir un état local cohérent.

Voici une structure simple en Python :

from sortedcontainers import SortedDict

class LocalOrderBook:
    def __init__(self, coin):
        self.coin = coin
        self.bids = SortedDict(lambda x: -float(x))  # bids : prix décroissant
        self.asks = SortedDict(lambda x: float(x))   # asks : prix croissant
        self.last_time = None

    def apply_snapshot(self, data):
        self.bids.clear()
        self.asks.clear()

        levels = data["levels"][0]

        for bid in levels[0]:
            if float(bid["sz"]) > 0:
                self.bids[bid["px"]] = float(bid["sz"])

        for ask in levels[1]:
            if float(ask["sz"]) > 0:
                self.asks[ask["px"]] = float(ask["sz"])

        self.last_time = data["time"]

    def apply_delta(self, data):
        levels = data["levels"][0]

        for bid in levels[0]:
            px, sz = bid["px"], float(bid["sz"])
            if sz == 0:
                self.bids.pop(px, None)
            else:
                self.bids[px] = sz

        for ask in levels[1]:
            px, sz = ask["px"], float(ask["sz"])
            if sz == 0:
                self.asks.pop(px, None)
            else:
                self.asks[px] = sz

        self.last_time = data["time"]

    @property
    def best_bid(self):
        return next(iter(self.bids.items()), None)

    @property
    def best_ask(self):
        return next(iter(self.asks.items()), None)

    @property
    def mid_price(self):
        bid = self.best_bid
        ask = self.best_ask
        if bid and ask:
            return (float(bid[0]) + float(ask[0])) / 2
        return None

    @property
    def spread(self):
        bid = self.best_bid
        ask = self.best_ask
        if bid and ask:
            return float(ask[0]) - float(bid[0])
        return None

Logique de traitement des messages

Tu dois distinguer le snapshot initial des mises à jour suivantes, puis appliquer chaque message au carnet local :

order_book = LocalOrderBook("BTC")
is_initialized = False

def handle_message(msg):
    global is_initialized

    if msg.get("channel") != "l2Book":
        return

    data = msg["data"]

    if not is_initialized:
        order_book.apply_snapshot(data)
        is_initialized = True
        print(
            f"Carnet initialisé : {len(order_book.bids)} niveaux bid, "
            f"{len(order_book.asks)} niveaux ask"
        )
    else:
        order_book.apply_delta(data)

    print(
        f"Best bid: {order_book.best_bid}, "
        f"best ask: {order_book.best_ask}, "
        f"spread: {order_book.spread}"
    )

Gérer les déconnexions et reconnexions

Une connexion WebSocket peut se couper à cause du réseau, d’un timeout ou d’une fermeture côté serveur. En production, tu dois prévoir une reconnexion automatique.

import asyncio
import json
import websockets

async def subscribe_with_reconnect(coin, handle_fn, max_retries=None):
    retries = 0

    while max_retries is None or retries < max_retries:
        try:
            async with websockets.connect(
                WS_URL,
                ping_interval=20,
                ping_timeout=10
            ) as ws:
                retries = 0
                is_initialized = False

                await ws.send(json.dumps({
                    "method": "subscribe",
                    "subscription": {
                        "type": "l2Book",
                        "coin": coin
                    }
                }))

                async for raw_msg in ws:
                    handle_fn(json.loads(raw_msg))

        except (websockets.ConnectionClosed, ConnectionError, OSError) as e:
            retries += 1
            wait = min(2 ** retries, 60)
            print(
                f"Connexion interrompue ({e}), nouvelle tentative dans "
                f"{wait} secondes, essai #{retries}"
            )

            is_initialized = False
            await asyncio.sleep(wait)

Lors d’une reconnexion, il faut réinitialiser l’état local. Le serveur renverra un nouveau snapshot complet après le nouvel abonnement ; il ne reprend pas nécessairement le flux exactement au point d’interruption.

Horodatage et ordre des messages

Les messages WebSocket d’Hyperliquid incluent un champ time. Tu peux l’utiliser pour détecter certains cas de messages obsolètes ou arrivés dans le mauvais ordre.

En production, il est recommandé de :

  • conserver le timestamp du dernier message traité ;
  • ignorer un message dont le timestamp est antérieur au dernier timestamp traité ;
  • reconnecter si aucun message n’est reçu pendant une durée anormale ;
  • suivre la latence ping/pong ;
  • envisager une infrastructure plus proche géographiquement si tu construis une stratégie très sensible à la latence.

S’abonner à plusieurs marchés en parallèle

Un seul WebSocket peut gérer plusieurs abonnements. C’est généralement préférable à l’ouverture de nombreuses connexions séparées.

coins = ["BTC", "ETH", "SOL"]
order_books = {coin: LocalOrderBook(coin) for coin in coins}
initialized = {coin: False for coin in coins}

async def multi_subscribe():
    async with websockets.connect(WS_URL) as ws:
        for coin in coins:
            await ws.send(json.dumps({
                "method": "subscribe",
                "subscription": {
                    "type": "l2Book",
                    "coin": coin
                }
            }))

        async for raw_msg in ws:
            msg = json.loads(raw_msg)

            if msg.get("channel") != "l2Book":
                continue

            data = msg["data"]
            coin = data["coin"]

            if coin not in order_books:
                continue

            if not initialized[coin]:
                order_books[coin].apply_snapshot(data)
                initialized[coin] = True
            else:
                order_books[coin].apply_delta(data)

Cette approche te permet de maintenir un carnet local par actif, tout en gardant une architecture asynchrone simple.

Cas d’usage concrets

Les données de carnet d’ordres en temps réel sont utiles pour plusieurs types de systèmes :

  • Bots de trading : ajuster dynamiquement les ordres limites selon le spread et la profondeur.
  • Arbitrage : surveiller les écarts de prix entre Hyperliquid et d’autres plateformes comme dYdX ou GMX.
  • Tableaux de bord marché : visualiser la profondeur, l’historique du spread et la distribution de liquidité.
  • Systèmes de risque : déclencher des alertes en cas d’élargissement brutal du spread ou de chute de liquidité.

OneKey Perps : trader sans construire toute l’infrastructure

Construire et maintenir un système de carnet d’ordres WebSocket demande du temps : gestion des snapshots, cohérence de l’état local, reconnexions, monitoring, stockage éventuel des données et tests en conditions réelles.

Si ton objectif principal est de trader des contrats perpétuels plutôt que de développer une infrastructure quant, OneKey Perps offre un workflow plus direct : affichage des marchés en temps réel, accès au trading et signature sécurisée avec l’écosystème OneKey.

Tu peux télécharger ou ouvrir OneKey, connecter ton portefeuille, puis utiliser OneKey Perps pour suivre les marchés et passer tes ordres avec une expérience pensée pour le trading on-chain. Ce n’est pas une garantie de performance, mais une manière plus simple de passer de l’analyse à l’exécution sans gérer toi-même toute la couche WebSocket.

Pour les utilisateurs qui veulent interagir avec des applications décentralisées via WalletConnect, la documentation WalletConnect fournit les principes d’intégration. OneKey prend en charge le protocole WalletConnect standard et peut être utilisé pour interagir avec des applications Web3 comme Hyperliquid de manière sécurisée.

FAQ

Q1 : Existe-t-il une limite au nombre de connexions WebSocket ?

Oui, il faut se référer à la documentation officielle d’Hyperliquid pour connaître les limites de connexion à jour. En général, évite d’ouvrir trop de connexions depuis la même IP. Pour plusieurs marchés, privilégie un seul WebSocket avec plusieurs abonnements.

Q2 : Si je rate une mise à jour incrémentale, mon carnet local devient-il incorrect ?

Oui. Si une mise à jour est perdue à cause du réseau ou d’un problème côté client, ton état local peut diverger de l’état réel du serveur. Si tu suspectes une incohérence, par exemple un spread anormal ou un best bid/best ask incohérent, ferme la connexion et réabonne-toi pour recevoir un nouveau snapshot.

Q3 : Peut-on utiliser les données temps réel du carnet pour du backtesting ?

Pas directement. Le backtesting nécessite des données historiques, pas seulement un flux en direct. Une approche consiste à stocker les messages du carnet en tick data, puis à les utiliser une fois que tu as accumulé suffisamment d’historique. Tu peux aussi combiner cela avec les API de bougies historiques d’Hyperliquid pour des tests plus simples.

Q4 : Comment vérifier que ma connexion WebSocket est saine ?

Surveille au minimum :

  • le temps écoulé depuis le dernier message reçu ;
  • la latence ping/pong ;
  • le nombre de reconnexions ;
  • les anomalies de spread ou de profondeur ;
  • les timestamps de messages.

Si aucun message n’est reçu au-delà d’un seuil défini, par exemple 5 secondes selon ton cas d’usage, déclenche une reconnexion proactive.

Q5 : Un wallet OneKey peut-il augmenter la latence de trading ?

La signature via un hardware wallet OneKey prend généralement quelques centaines de millisecondes, ce qui reste acceptable pour la majorité des usages de trading. Pour des stratégies très haute fréquence, par exemple plusieurs dizaines d’ordres par seconde, une architecture séparant le capital principal et un sous-compte API Agent ou hot wallet peut être plus adaptée. L’idée est de protéger la gestion des fonds avec OneKey tout en gardant une couche d’exécution dédiée lorsque la fréquence l’exige.

Conclusion

L’abonnement au carnet d’ordres en temps réel est une brique essentielle pour construire un système de trading quantitatif sérieux. L’API WebSocket d’Hyperliquid est claire et permet de recevoir snapshots et mises à jour L2 afin de maintenir un carnet local utilisable pour le market making, l’arbitrage, l’analyse de liquidité ou le monitoring du risque.

Si tu veux développer ton propre moteur de données, les exemples ci-dessus te donnent une base solide. Si tu préfères trader des perpétuels on-chain sans gérer cette infrastructure, essaie OneKey et OneKey Perps : tu peux suivre les marchés, connecter ton wallet et exécuter tes transactions dans un environnement conçu pour associer expérience de trading et signature sécurisée.

Avertissement sur les risques : les données de carnet d’ordres ne représentent que l’état du marché à un instant donné et ne doivent pas être utilisées comme seul critère de décision. Les stratégies automatisées basées sur le carnet peuvent subir des pertes importantes en cas de volatilité, de panne technique, de latence ou d’erreur de conception. Le trading de contrats perpétuels comporte un risque élevé et peut entraîner la perte totale du capital engagé. Ce contenu est fourni à titre technique et informatif uniquement ; il ne constitue pas un conseil financier, juridique ou d’investissement.

Sécurisez votre parcours crypto avec OneKey

View details for Boutique OneKeyBoutique OneKey

Boutique OneKey

Le portefeuille matériel le plus avancé au monde.

View details for Télécharger l'applicationTélécharger l'application

Télécharger l'application

Alertes contre les arnaques. Toutes les pièces supportées.

View details for OneKey SifuOneKey Sifu

OneKey Sifu

Clarté Crypto—À un appel de distance.