La reconstruction précise d'un order book de niveau 2 est essentielle pour tester des stratégies de trading algorithmique. Dans cet article, nous explorons comment utiliser Tardis.dev pour accéder aux données historiques de Binance et reconstruire un carnet d'ordres complet.

Comprendre les données du carnet d'ordres Binance

Binance propose plusieurs types de données pour son carnet d'ordres :

Configuration initiale avec l'API Tardis.dev

// Installation du client Tardis.market
npm install @tardis-dev/market-connector

// Configuration pour les données Binance spot
const config = {
  exchange: 'binance',
  symbol: 'BTCUSDT',
  startDate: new Date('2024-06-01'),
  endDate: new Date('2024-06-02'),
  dataTypes: ['book_snapshot', 'book_diff', 'trade']
};

console.log('Configuration chargée:', config);

Reconstruction de l'Order Book L2

class OrderBookBuilder {
  constructor(symbol) {
    this.symbol = symbol;
    this.bids = new Map(); // price -> quantity
    this.asks = new Map();
    this.lastUpdateId = 0;
  }

  // Applique un snapshot complet
  applySnapshot(snapshot) {
    this.bids.clear();
    this.asks.clear();
    
    for (const [price, qty] of snapshot.bids) {
      this.bids.set(parseFloat(price), parseFloat(qty));
    }
    for (const [price, qty] of snapshot.asks) {
      this.asks.set(parseFloat(price), parseFloat(qty));
    }
    
    this.lastUpdateId = snapshot.updateId;
    return this.getLevel2();
  }

  // Applique un diff (mise à jour incrémentale)
  applyDiff(diff) {
    // Vérification de la séquence
    if (diff.updateId <= this.lastUpdateId) {
      return null; // Diff ignoré (hors séquence)
    }

    for (const [price, qty] of diff.b) {
      const p = parseFloat(price);
      const q = parseFloat(qty);
      if (q === 0) {
        this.bids.delete(p);
      } else {
        this.bids.set(p, q);
      }
    }

    for (const [price, qty] of diff.a) {
      const p = parseFloat(price);
      const q = parseFloat(qty);
      if (q === 0) {
        this.asks.delete(p);
      } else {
        this.asks.set(p, q);
      }
    }

    this.lastUpdateId = diff.updateId;
    return this.getLevel2();
  }

  // Retourne les N meilleurs niveaux
  getLevel2(depth = 25) {
    const sortedBids = [...this.bids.entries()]
      .sort((a, b) => b[0] - a[0])
      .slice(0, depth);
    
    const sortedAsks = [...this.asks.entries()]
      .sort((a, b) => a[0] - b[0])
      .slice(0, depth);

    return {
      timestamp: Date.now(),
      symbol: this.symbol,
      bids: sortedBids,
      asks: sortedAsks,
      spread: sortedAsks[0] ? sortedAsks[0][0] - sortedBids[0][0] : 0,
      midPrice: sortedBids[0] && sortedAsks[0] 
        ? (sortedBids[0][0] + sortedAsks[0][0]) / 2 
        : null
    };
  }
}

// Utilisation
const ob = new OrderBookBuilder('BTCUSDT');
console.log('OrderBook initialisé');

Intégration avec le flux de données Tardis

import { createHistoricalDataset } from '@tardis-dev/market-connector';

async function replayOrderBook() {
  const ob = new OrderBookBuilder('BTCUSDT');
  const trades = [];
  
  const dataset = await createHistoricalDataset({
    exchange: 'binance',
    symbols: ['BTCUSDT'],
    startDate: new Date('2024-06-01T00:00:00Z'),
    endDate: new Date('2024-06-01T01:00:00Z'),
    dataType: ['book_snapshot', 'book_diff', 'trade'],
    onBookSnapshot: (snapshot) => {
      const level2 = ob.applySnapshot(snapshot);
      console.log(Snapshot reçu: ${snapshot.updateId});
    },
    onBookDiff: (diff) => {
      const level2 = ob.applyDiff(diff);
      if (level2) {
        // Stocker pour backtesting
        trades.push({
          time: diff.timestamp,
          ...level2
        });
      }
    },
    onTrade: (trade) => {
      // Capturer les transactions
      trades.push({
        time: trade.timestamp,
        price: parseFloat(trade.price),
        volume: parseFloat(trade.quantity),
        side: trade.side
      });
    }
  });

  await dataset.fill();
  return trades;
}

// Exécution
replayOrderBook()
  .then(data => console.log(Données collectées: ${data.length} entrées))
  .catch(err => console.error('Erreur:', err));

Stratégie de backtesting simple

class MarketMaker {
  constructor(spreadPercent = 0.001) {
    this.spreadPercent = spreadPercent;
    this.position = 0;
    this.pnl = 0;
    this.trades = [];
  }

  evaluate(marketData) {
    if (!marketData.midPrice) return;

    const { midPrice, bids, asks, time } = marketData;
    
    // Prix limites pour notre market making
    const bidPrice = midPrice * (1 - this.spreadPercent);
    const askPrice = midPrice * (1 + this.spreadPercent);
    
    // Vérifier si notre ordre est exécuté
    // Simulation simplifiée
    for (const [price, qty] of asks) {
      if (price <= askPrice && qty > 0) {
        // Ordre d'achat exécuté
        this.position += qty;
        this.pnl -= price * qty;
        this.recordTrade(time, 'buy', price, qty);
      }
    }
    
    for (const [price, qty] of bids) {
      if (price >= bidPrice && qty > 0) {
        // Ordre de vente exécuté
        this.position -= qty;
        this.pnl += price * qty;
        this.recordTrade(time, 'sell', price, qty);
      }
    }
  }

  recordTrade(time, side, price, qty) {
    this.trades.push({ time, side, price, qty, position: this.position });
  }

  getStats() {
    const buyVolume = this.trades
      .filter(t => t.side === 'buy')
      .reduce((sum, t) => sum + t.qty * t.price, 0);
      
    const sellVolume = this.trades
      .filter(t => t.side === 'sell')
      .reduce((sum, t) => sum + t.qty * t.price, 0);

    return {
      totalPnl: this.pnl,
      netPosition: this.position,
      buyVolume,
      sellVolume,
      tradeCount: this.trades.length,
      avgSpread: this.spreadPercent * 100
    };
  }
}

Optimisation des performances

Pour gérer de grands volumes de données, plusieurs techniques sont recommandées :

Considérations pour les frais et la latence

Lorsque vous travaillez avec des données historiques pour le backtesting, gardez à l'esprit :

Pour qui / pour qui ce n'est pas fait

Idéal pour Moins adapté pour
Stratégies market making Trading haute fréquence (HFT) pur
Analyse de liquidité Données tick-by-tick en temps réel
Backtesting de stratégies等候 Exécution automatisée ( nécessite un autre layer)
Recherche académique Production sans supervision humaine

Tarification et ROI

Plan Tardis.dev Prix approximatif Cas d'usage
Free 0$ (limité) Tests et prototypes
Start ~99$/mois Développement单人策略
Pro ~499$/mois Équipes et production

Conclusion

La reconstruction du carnet d'ordres L2 avec Tardis.dev offre une base solide pour développer et tester des stratégies de trading algorithmique. La clé est de bien gérer la séquentialité des données et de simuler fidèlement les conditions réelles de marché.

N'hésitez pas à explorer la documentation officielle de Tardis.dev pour des fonctionnalités avancées comme la reconstruction multi-symbole et l'optimisation de la mémoire.


Cet article a été publié sur HolySheep AI Blog. Pour accéder à des ressources supplémentaires sur les APIs de données financières, consultez notre section guides techniques.

👉 Inscrivez-vous sur HolySheep AI — crédits offerts

```