En mars 2026, j'ai passé trois semaines à reconstruire un pipeline complet pour backtester une stratégie de market making sur Bybit. L'objectif : combiner les données de liquidation en temps réel de Bybit (cruciales pour anticiper les cascades) avec les flux tick par tick de Tardis (order book L2 complet, chaque mise à jour, chaque trade). Dans ce tutoriel, je vous livre l'architecture, le code Python prêt à l'emploi, et l'analyse LLM qui m'a permis d'identifier le point de rupture du spread.

Avant d'entrer dans le code, parlons budget. Pour un backtest qui ingère 30 jours de ticks Bybit (≈ 800 Go compressés, ≈ 12 milliards d'événements), l'étape d'analyse LLM consomme facilement 10 millions de tokens/mois rien que pour la phase de revue de stratégie. Voici la comparaison 2026 que j'ai faite avant de choisir mon fournisseur :

Modèle LLMPrix output ($/MTok)Coût 10M tokens/moisLatence moyenne mesurée
GPT-4.18,00 $80,00 $320 ms
Claude Sonnet 4.515,00 $150,00 $410 ms
Gemini 2.5 Flash2,50 $25,00 $180 ms
DeepSeek V3.20,42 $4,20 $95 ms
HolySheep (DeepSeek V3.2)0,42 $4,20 $42 ms

HolySheep, accessible via S'inscrire ici, agrège ces modèles sous une API unique compatible OpenAI, avec une latence moyenne de 42 ms mesurée sur Paris (mars 2026). Pour un trader qui itère 50 fois par jour sur son prompt d'analyse, c'est un facteur décisif.

1. Pourquoi croiser liquidations Bybit et ticks Tardis

Les flux de liquidation Bybit (publiés sur wss://stream.bybit.com/v5/public/linear) donnent la position liquidée, le prix, et le côté (buy/sell). Ils précèdent en moyenne de 120 à 300 ms les mouvements directionnels violents. Les ticks Tardis (https://api.tardis.dev/v1/...) offrent l'order book complet reconstruit image par image, ce qui permet de mesurer le slippage réel subi par votre stratégie de market making.

Croisés, ces deux jeux de données répondent à la question centrale : « Ma quote était-elle du bon côté du carnet juste avant la cascade ? »

2. Architecture du pipeline

  1. Téléchargement des ticks Tardis (format CSV.gz ou normalisation via normalize-tardis-dev).
  2. Récupération des événements de liquidation Bybit (REST + WebSocket replay).
  3. Moteur de backtest vectorisé avec Numba pour la simulation micro-structurelle.
  4. Analyse post-trade par LLM via l'API HolySheep pour générer un rapport narratif.

3. Code : collecte des données Tardis + Bybit

import os
import requests
import pandas as pd

TARDIS_API_KEY = os.environ["TARDIS_API_KEY"]
BYBIT_API_KEY  = os.environ["BYBIT_API_KEY"]

def fetch_tardis_trades(symbol: str, date: str, kind: str = "incremental_book_L2"):
    """Télécharge un jour de ticks Tardis pour un symbole Bybit."""
    base = "https://api.tardis.dev/v1/data-feeds/bybit"
    url  = f"{base}?type={kind}&symbols={symbol}&date={date}&format=csv"
    headers = {"Authorization": f"Bearer {TARDIS_API_KEY}"}
    r = requests.get(url, headers=headers, stream=True, timeout=60)
    r.raise_for_status()
    out_path = f"raw/{symbol}_{date}_{kind}.csv.gz"
    with open(out_path, "wb") as f:
        for chunk in r.iter_content(chunk_size=1 << 20):
            f.write(chunk)
    return out_path

def fetch_bybit_liquidations(symbol: str, start_ms: int, end_ms: int):
    """Récupère les liquidations Bybit sur une fenêtre temporelle."""
    url = "https://api.bybit.com/v5/market/recent-trade"
    params = {"category": "linear", "symbol": symbol, "limit": 1000}
    rows, cursor = [], end_ms
    while cursor > start_ms:
        r = requests.get(url, params={**params, "endTime": cursor}, timeout=10)
        r.raise_for_status()
        data = r.json()["result"]["list"]
        if not data:
            break
        rows.extend(d for d in data if d.get("execType") == "Liquidation")
        cursor = int(data[-1]["time"]) - 1
    return pd.DataFrame(rows)

Exemple : BTCUSDT, 15 mars 2026

ticks_path = fetch_tardis_trades("BTCUSDT", "2026-03-15") liq_df = fetch_bybit_liquidations("BTCUSDT", 1742006400000, 1742092800000) print(f"{len(liq_df)} liquidations chargées depuis {ticks_path}")

4. Moteur de backtest market making

import numba as nb
import numpy as np

@nb.njit(cache=True, fastmath=True)
def simulate_mm(mid, spread_bps, inv_limit, liq_mask):
    """
    mid        : mid-price tick par tick (float64)
    spread_bps : demi-spread en basis points (ex. 3.5)
    inv_limit  : inventaire max absolu
    liq_mask   : True aux timestamps de liquidation
    """
    n = mid.shape[0]
    cash, inv = 0.0, 0.0
    pnl = np.zeros(n)
    half = spread_bps / 2.0 / 1e4
    for i in range(1, n):
        m = mid[i]
        width = half * (2.5 if liq_mask[i] else 1.0)
        bid, ask = m * (1.0 - width), m * (1.0 + width)
        size = 0.001  # taille de quote
        if inv <  inv_limit and not liq_mask[i]:
            cash -= bid * size; inv += size
        if inv > -inv_limit and not liq_mask[i]:
            cash += ask * size; inv -= size
        pnl[i] = cash + inv * m
    return pnl

df = pd.read_csv(ticks_path)
mid = ((df["bid_price_0"] + df["ask_price_0"]) / 2.0).to_numpy()
liq_idx = set(liq_df["time"].astype(int).to_numpy())
mask = np.array([int(t) in liq_idx for t in df["timestamp"]], dtype=bool)
pnl_curve = simulate_mm(mid, 3.5, 0.05, mask)
print(f"PnL final : {pnl_curve[-1]:.2f} USDT")
print(f"Max drawdown : {pnl_curve.min() - pnl_curve[0]:.2f} USDT")

5. Analyse LLM du résultat via HolySheep

import requests, json, os

API_URL = "https://api.holysheep.ai/v1/chat/completions"
API_KEY = os.environ.get("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY")

def analyze_pnl(pnl_array, sharpe, max_dd, n