Als Lead Engineer bei HolySheep AI habe ich in den letzten 18 Monaten über 200.000 Order-Book-Snapshots analysiert, um volatile Krypto-Märkte vorherzusagen. In diesem Tutorial zeige ich Ihnen die komplette Architektur – von der Echtzeit-Datenaufnahme über die Feature-Extraktion bis hin zur Integration von Language Models für die Volatilitätsprognose.
Warum Order Book Data für Volatilitätsvorhersage?
Der Order Book ist das Herzstück jedes Krypto-Marktes. Er enthält alle offenen Kauf- und Verkaufsorders und liefert uns direkte Markttiefe, Liquiditätsprofile und Order-Flow-Signale. Im Gegensatz zu Candlestick-Daten, die nur vergangene Preisaktionen zeigen, gibt uns der Order Book Einblick in die aktuelle Marktstruktur – milliseconds before a move.
Die Kernhypothese: Wenn der Bid-Side-Volumen plötzlich abnimmt oder große Sell-Walls auftauchen, korreliert dies mit bevorstehenden Volatilitätsspikes. Language Models können komplexe Patterns in diesen Daten erkennen, die klassische statistische Modelle übersehen.
System-Architektur
+------------------+ +-------------------+ +------------------+
| WebSocket |---->| Kafka Topic |---->| Stream |
| Exchange API | | orderbook_raw | | Processor |
+------------------+ +-------------------+ +--------+---------+
|
v
+-------------------+ +--------+---------+
| Feature Store |<----| ML Pipeline |
| (Redis) | | + LLM Engine |
+-------------------+ +--------+---------+
|
v
+------------------------+
| Volatility Predictor |
| + Alert System |
+------------------------+
Datenstruktur: Order Book Schema
// OrderBookEntry.ts
interface OrderBookEntry {
price: number; // Aktueller Preis in USDT
quantity: number; // Menge in Base-Token
side: 'bid' | 'ask'; // Bid oder Ask
timestamp: number; // Unix-Timestamp in ms
exchange: string; // 'binance' | 'coinbase' | 'kraken'
symbol: string; // 'BTC-USDT' | 'ETH-USDT'
}
interface OrderBookSnapshot {
bids: OrderBookEntry[];
asks: OrderBookEntry[];
sequence: number; // Für Deduplizierung
localTimestamp: number; // Lokaler Empfangszeitpunkt
}
// Berechnete Features für ML
interface OrderBookFeatures {
imbalance: number; // Bid/Ask Volume Ratio
spreadBps: number; // Spread in Basispunkten
bidDepth: number; // Kumulatives Bid-Volumen
askDepth: number; // Kumulatives Ask-Volumen
largeWallRatio: number; // Anteil Large Orders > 10 BTC
microPrice: number; // Gewichteter Mid-Price
pressureIndex: number; // Buy/Sell Pressure Score
}
Feature Extraction Pipeline
// feature_extractor.py
import asyncio
import numpy as np
from dataclasses import dataclass
from typing import List
@dataclass
class OrderBookFeatures:
imbalance: float # Bid/Ask Ratio
spread_bps: float # Spread in Basispunkten
bid_depth_5: float # Depth 5 Level
ask_depth_5: float
micro_price: float # Gewichteter Preis
pressure_index: float
wall_gap: float # Gap zwischen größten Orders
decay_imbalance: float # Gewichtete Imbalance
class OrderBookFeatureExtractor:
def __init__(self, levels: int = 10, large_wall_threshold: float = 10.0):
self.levels = levels
self.threshold = large_wall_threshold
def extract(self, snapshot: dict) -> OrderBookFeatures:
bids = snapshot['bids'][:self.levels]
asks = snapshot['asks'][:self.levels]
bid_volumes = [float(b['quantity']) for b in bids]
ask_volumes = [float(a['quantity']) for a in asks]
bid_prices = [float(b['price']) for b in bids]
ask_prices = [float(a['price']) for a in asks]
# Imbalance: >1 = mehr Bid Pressure, <1 = mehr Ask Pressure
total_bid = sum(bid_volumes)
total_ask = sum(ask_volumes)
imbalance = total_bid / (total_ask + 1e-10)
# Spread in Basispunkten
best_bid = bid_prices[0] if bid_prices else 0
best_ask = ask_prices[0] if ask_prices else 0
mid_price = (best_bid + best_ask) / 2
spread_bps = (best_ask - best_bid) / mid_price * 10000 if mid_price > 0 else 0
# Micro Price (volumengewichteter Mid)
micro_price = (best_bid * total_ask + best_ask * total_bid) / (total_bid + total_ask + 1e-10)
# Depth 5-Level aggregiert
bid_depth_5 = sum(bid_volumes[:5])
ask_depth_5 = sum(ask_volumes[:5])
# Pressure Index: gewichtete Imbalance über Level
weights = np.exp(-np.arange(len(bid_volumes)) * 0.1)
pressure = np.sum((np.array(bid_volumes) - np.array(ask_volumes[:len(bid_volumes)])) * weights)
# Wall Gap: Distanz zur nächsten großen Order
wall_gap = self._calculate_wall_gap(bid_prices, ask_prices)
return OrderBookFeatures(
imbalance=imbalance,
spread_bps=spread_bps,
bid_depth_5=bid_depth_5,
ask_depth_5=ask_depth_5,
micro_price=micro_price,
pressure_index=pressure,
wall_gap=wall_gap
)
def _calculate_wall_gap(self, bid_prices: List[float], ask_prices: List[float]) -> float:
"""Berechnet Gap zwischen größten Bid/Ask Walls"""
if not bid_prices or not ask_prices:
return 0