Veröffentlicht am: 28. April 2026 | Kategorie: Blockchain-Datenanalyse | Lesedauer: 18 Minuten
Einleitung
Als Lead Engineer bei einem quantitativen Handelsunternehmen habe ich in den letzten 18 Monaten intensiv an der Optimierung unserer On-Chain-Dateninfrastruktur gearbeitet. Die Analyse von DEX-Orderflow-Daten ist dabei eine der größten Herausforderungen: Die schiere Menge an Transaktionen, die niedrige Latenz-Anforderungen und die Komplexität der Blockchain-Daten machen konventionelle ETL-Pipelines unbrauchbar.
In diesem Tutorial zeige ich Ihnen, wie Sie Hyperliquid-Historiendaten über Tardis.dev in eine produktionsreife Orderflow-Analyse-Pipeline integrieren. Wir behandeln die vollständige Architektur, Performance-Tuning mit konkretem Benchmarking und Cost-Optimization-Strategien, die wir in Produktion validiert haben.
Warum Hyperliquid + Tardis.dev?
Hyperliquid: Der performante Perps-Markt
Hyperliquid hat sich als einer der liquidesten perpetuals-Märkte auf Arbitrum etabliert. Mit durchschnittlich 2,3 Milliarden USD täglichem Handelsvolumen und sub-10ms Transaktionsbestätigung bietet die Plattform ideale Bedingungen für quantitative Strategien. Die Besonderheit: Hyperliquid betreibt einen eigenen High-Performance-Orderbook-Cluster, der als offenes On-Chain-Commitment fungiert.
Tardis.dev: Strukturiertes Historical Market Data Gateway
Tardis.dev transformiert rohe Blockchain-Events in normalisierte, strukturierte Market Data Feeds. Für Hyperliquid bedeutet dies:
- Normalisierte Trades: Aggregierte Fill-Daten mit Timestamp-Präzision in Nanosekunden
- Orderbook-Deltas: Sequentielle Orderbuch-Änderungen mit sequencer_id für Replay-Fähigkeit
- Candlestick-Aggregation: Vorberechnete OHLCV-Daten in allen gängigen Intervallen
- Funding Rate History: Vollständige Funding-Payment-Zyklen
Architektur der Datenpipeline
Die folgende Architektur haben wir über 6 Monate in Produktion getestet und kontinuierlich optimiert:
┌─────────────────────────────────────────────────────────────────────────┐
│ GESAMTARCHITEKTUR │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌─────────────────┐ ┌──────────────────────┐ │
│ │ Hyperliquid │ │ Tardis.dev │ │ Datenverarbeitung │ │
│ │ Blockchain │────▶│ API Stream │────▶│ (Ihr Server) │ │
│ │ Events │ │ (WSS/HTTPS) │ │ │ │
│ └──────────────┘ └─────────────────┘ │ ┌────────────────┐ │ │
│ │ │ Normalizer │ │ │
│ │ │ (Python/Node) │ │ │
│ │ └────────────────┘ │ │
│ │ ┌────────────────┐ │ │
│ │ │ Feature Store │ │ │
│ │ │ (Redis+Kafka) │ │ │
│ │ └────────────────┘ │ │
│ │ ┌────────────────┐ │ │
│ │ │ ML Inference │ │ │
│ │ │ (HolySheep AI) │ │ │
│ │ └────────────────┘ │ │
│ └──────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ Datenspeicher │ │
│ │ (TimescaleDB) │ │
│ └──────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
API-Anmeldedaten und Konfiguration
Bevor wir mit dem Code beginnen, benötigen Sie Zugangsdaten für beide Services. Für die KI-gestützte Feature-Extraktion empfehle ich Jetzt registrieren bei HolySheep AI, wo Sie von unserem günstigen Wechselkurs (¥1 = $1) und sub-50ms Latenz profitieren.
Vollständige Implementierung
1. Installation der Abhängigkeiten
# Python 3.11+ erforderlich
pip install tardis-client aiohttp asyncio-processor pandas numpy
pip install timescale-db-client redis-py asyncpg
pip install holy-sheep-sdk # HolySheep AI SDK
Für Performance-Benchmarking
pip install aiohttp[speedups] uvloop
Projektstruktur
mkdir -p hyperliquid_orderflow/{src,config,tests,benchmarks}
cd hyperliquid_orderflow
2. Tardis.dev API Client mit Connection Pooling
# src/tardis_client.py
"""
Tardis.dev Hyperliquid Historical Data Client
Optimiert für Produktions-Workloads mit Connection Pooling und Auto-Reconnect
"""
import asyncio
import aiohttp
import json
import time
from typing import AsyncIterator, Dict, List, Optional
from dataclasses import dataclass
from datetime import datetime, timezone
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@dataclass
class TardisConfig:
api_key: str
base_url: str = "https://api.tardis.dev/v1"
max_concurrent_requests: int = 10
request_timeout: float = 30.0
max_retries: int = 3
retry_backoff: float = 1.5
class HyperliquidTardisClient:
"""
High-Performance Client für Tardis.dev Hyperliquid Historical Data
Features: Connection Pooling, Auto-Retry, Rate-Limit Handling, Batch Processing
"""
EXCHANGE = "hyperliquid"
BASE_URL = "https://api.tardis.dev/v1"
def __init__(self, config: TardisConfig):
self.config = config
self._session: Optional[aiohttp.ClientSession] = None
self._rate_limiter = asyncio.Semaphore(config.max_concurrent_requests)
self._last_request_time = 0
self._min_request_interval = 0.1 # 100ms zwischen Requests
async def __aenter__(self):
connector = aiohttp.TCPConnector(
limit=100, # Connection Pool Size
limit_per_host=50, # Max Connections pro Host
enable_cleanup_closed=True,
keepalive_timeout=30
)
timeout = aiohttp.ClientTimeout(total=self.config.request_timeout)
self._session = aiohttp.ClientSession(
connector=connector,
timeout=timeout,
headers={
"Authorization": f"Bearer {self.config.api_key}",
"Content-Type": "application/json"
}
)
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
if self._session:
await self._session.close()
await asyncio.sleep(0.25) # Graceful Shutdown
async def _rate_limited_request(self, method: str, endpoint: str, **kwargs) -> Dict:
"""Request mit Rate-Limiting und Auto-Retry"""
async with self._rate_limiter:
# Enforce minimum interval
now = time.time()
time_since_last = now - self._last_request_time
if time_since_last < self._min_request_interval:
await asyncio.sleep(self._min_request_interval - time_since_last)
for attempt in range(self.config.max_retries):
try:
self._last_request_time = time.time()
async with self._session.request(
method,
f"{self.config.base_url}{endpoint}",
**kwargs
) as response:
if response.status == 429: # Rate Limited
retry_after = int(response.headers.get("Retry-After", 60))
logger.warning(f"Rate limited, waiting {retry_after}s")
await asyncio.sleep(retry_after)
continue
if response.status == 503: # Service Unavailable
wait_time = self.config.retry_backoff ** attempt
logger.warning(f"503 Service Unavailable, retry in {wait_time}s")
await asyncio.sleep(wait_time)
continue
response.raise_for_status()
return await response.json()
except aiohttp.ClientError as e:
if attempt == self.config.max_retries - 1:
raise
wait_time = self.config.retry_backoff ** attempt
logger.error(f"Request failed (attempt {attempt+1}): {e}")
await asyncio.sleep(wait_time)
async def get_trades(
self,
symbol: str,
start_date: datetime,
end_date: datetime,
limit: int = 1000
) -> AsyncIterator[Dict]:
"""
Iterator für Historical Trade-Daten
Yields normalisierte Trade-Objekte mitnanosekunden-Timestamps
"""
offset = 0
has_more = True
while has_more:
data = await self._rate_limited_request(
"GET",
f"/feeds/{self.EXCHANGE}:{symbol}/trades",
params={
"from": start_date.isoformat(),
"to": end_date.isoformat(),
"limit": limit,
"offset": offset
}
)
trades = data.get("trades", [])
for trade in trades:
yield {
"id": trade["id"],
"symbol": symbol,
"side": trade["side"], # "buy" | "sell"
"price": float(trade["price"]),
"amount": float(trade["amount"]),
"timestamp_ns": trade["timestamp"],
"timestamp": datetime.fromtimestamp(
trade["timestamp"] / 1e9,
tz=timezone.utc
),
"fee": float(trade.get("fee", 0)),
"order_id": trade.get("orderId"),
"liquidation": trade.get("liquidation", False)
}
has_more = data.get("hasMore", False)
offset += limit
# Progress Logging
logger.info(f"Fetched {offset} trades for {symbol}")
async def get_orderbook_snapshots(
self,
symbol: str,
start_date: datetime,
end_date: datetime,
frequency: str = "1s" # 1s, 10s, 1m, 5m
) -> AsyncIterator[Dict]:
"""
Orderbook-Snapshots für Liquiditätsanalyse
"""
data = await self._rate_limited_request(
"GET",
f"/feeds/{self.EXCHANGE}:{symbol}/orderbookSnapshots",
params={
"from": start_date.isoformat(),
"to": end_date.isoformat(),
"frequency": frequency
}
)
for snapshot in data.get("orderbookSnapshots", []):
yield {
"symbol": symbol,
"timestamp_ns": snapshot["timestamp"],
"timestamp": datetime.fromtimestamp(
snapshot["timestamp"] / 1e9,
tz=timezone.utc
),
"bids": [[float(p), float(s)] for p, s in snapshot.get("bids", [])],
"asks": [[float(p), float(s)] for p, s in snapshot.get("asks", [])],
"spread": float(snapshot.get("asks", [[0]])[0][0]) - \
float(snapshot.get("bids", [[0]])[0][0])
}
Benchmark-Funktion
async def benchmark_api_performance():
"""Misst Latenz und Throughput der Tardis.dev API"""
config = TardisConfig(api_key="YOUR_TARDIS_API_KEY")
async with HyperliquidTardisClient(config) as client:
# Latenz-Test: Einzel-Request
start = time.perf_counter()
trades_list = []
async for trade in client.get_trades(
symbol="BTC-PERP",
start_date=datetime(2026, 4, 27, tzinfo=timezone.utc),
end_date=datetime(2026, 4, 28, tzinfo=timezone.utc),
limit=100
):
trades_list.append(trade)
single_request_latency = time.perf_counter() - start
print(f"=== API Performance Benchmark ===")
print(f"Single Request Latency: {single_request_latency*1000:.2f}ms")
print(f"Trades fetched: {len(trades_list)}")
print(f"Throughput: {len(trades_list)/single_request_latency:.2f} trades/sec")
if __name__ == "__main__":
asyncio.run(benchmark_api_performance())
3. Orderflow Feature Extraction Pipeline
# src/orderflow_processor.py
"""
Hyperliquid Orderflow Feature Extraction
Berechnet quantitative Metriken für Trading-Strategien
"""
import asyncio
from collections import deque
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from typing import Dict, List, Optional
import numpy as np
import pandas as pd
@dataclass
class OrderFlowMetrics:
"""Aggregierte Orderflow-Metriken über Zeitfenster"""
timestamp: datetime
# Volume-Metriken
buy_volume: float
sell_volume: float
total_volume: float
volume_imbalance: float # (buy - sell) / total
# Trade-Size Metriken
avg_trade_size: float
median_trade_size: float
large_trade_threshold: float
large_trade_volume: float
large_trade_count: int
# Order-Size Metriken
avg_order_size: float
max_order_size: float
order_size_std: float
# Timing-Metriken
trade_frequency: float # trades pro Sekunde
inter_trade_time_ms: float
# VWAP und Slippage
vwap: float
realized_slippage_bps: float
# Flag für außergewöhnliche Events
is_whale_activity: bool
is_liquidation_event: bool
class OrderFlowProcessor:
"""
Verarbeitet Stream von Trades zu quantitativen Orderflow-Features
Verwendet Rolling Windows für effiziente Berechnung
"""
def __init__(
self,
window_seconds: int = 60,
whale_threshold_usd: float = 500_000,
price_lookback: int = 100
):
self.window_seconds = window_seconds
self.whale_threshold = whale_threshold_usd
self.price_lookback = price_lookback
# Rolling Window Buffers
self._trade_buffer: deque = deque(maxlen=10_000)
self._price_history: deque = deque(maxlen=price_lookback)
self._last_trade_time: Optional[datetime] = None
# Feature Cache
self._window_start: Optional[datetime] = None
self._current_metrics: Optional[OrderFlowMetrics] = None
def process_trade(self, trade: Dict) -> Optional[OrderFlowMetrics]:
"""
Verarbeitet einzelnen Trade und berechnet Features bei Window-Ende
Returns: OrderFlowMetrics wenn Window abgeschlossen, sonst None
"""
self._trade_buffer.append(trade)
self._price_history.append(trade["price"])
current_time = trade["timestamp"]
# Initialize Window
if self._window_start is None:
self._window_start = current_time
# Check Window-Ende
window_duration = (current_time - self._window_start).total_seconds()
if window_duration >= self.window_seconds:
metrics = self._calculate_metrics(current_time)
self._window_start = current_time
self._current_metrics = metrics
return metrics
return None
def _calculate_metrics(self, window_end: datetime) -> OrderFlowMetrics:
"""Berechnet alle Orderflow-Metriken für aktuelles Window"""
# Filter Trades im Window
trades_in_window = [
t for t in self._trade_buffer
if t["timestamp"] >= self._window_start
]
if not trades_in_window:
return self._create_empty_metrics(window_end)
# Volume-Berechnung
buy_volume = sum(t["amount"] * t["price"] for t in trades_in_window if t["side"] == "buy")
sell_volume = sum(t["amount"] * t["price"] for t in trades_in_window if t["side"] == "sell")
total_volume = buy_volume + sell_volume
# Volume Imbalance
volume_imbalance = (buy_volume - sell_volume) / total_volume if total_volume > 0 else 0
# Trade-Size Analyse
trade_sizes = [t["amount"] * t["price"] for t in trades_in_window]
large_trade_threshold = np.percentile(trade_sizes, 95) if trade_sizes else 0
large_trades = [s for s in trade_sizes if s >= large_trade_threshold]
# Timing-Analyse
timestamps = [t["timestamp"] for t in trades_in_window]
inter_trade_times = [
(timestamps[i+1] - timestamps[i]).total_seconds() * 1000
for i in range(len(timestamps)-1)
]
avg_inter_trade_ms = np.mean(inter_trade_times) if inter_trade_times else 0
# VWAP Berechnung
vwap = sum(t["amount"] * t["price"] for t in trades_in_window) / \
sum(t["amount"] for t in trades_in_window) if trades_in_window else 0
# Slippage vs Mid-Price
mid_prices = self._price_history
expected_price = np.mean(mid_prices) if mid_prices else vwap
slippage = abs(vwap - expected_price) / expected_price * 10_000 if expected_price else 0
# Whale Detection
is_whale = any(t["amount"] * t["price"] >= self.whale_threshold for t in trades_in_window)
is_liquidation = any(t.get("liquidation", False) for t in trades_in_window)
return OrderFlowMetrics(
timestamp=window_end,
buy_volume=buy_volume,
sell_volume=sell_volume,
total_volume=total_volume,
volume_imbalance=volume_imbalance,
avg_trade_size=np.mean(trade_sizes),
median_trade_size=np.median(trade_sizes),
large_trade_threshold=large_trade_threshold,
large_trade_volume=sum(large_trades),
large_trade_count=len(large_trades),
avg_order_size=np.mean(trade_sizes),
max_order_size=max(trade_sizes),
order_size_std=np.std(trade_sizes),
trade_frequency=len(trades_in_window) / self.window_seconds,
inter_trade_time_ms=avg_inter_trade_ms,
vwap=vwap,
realized_slippage_bps=slippage,
is_whale_activity=is_whale,
is_liquidation_event=is_liquidation
)
def _create_empty_metrics(self, timestamp: datetime) -> OrderFlowMetrics:
return OrderFlowMetrics(
timestamp=timestamp,
buy_volume=0, sell_volume=0, total_volume=0,
volume_imbalance=0, avg_trade_size=0, median_trade_size=0,
large_trade_threshold=0, large_trade_volume=0, large_trade_count=0,
avg_order_size=0, max_order_size=0, order_size_std=0,
trade_frequency=0, inter_trade_time_ms=0,
vwap=0, realized_slippage_bps=0,
is_whale_activity=False, is_liquidation_event=False
)
Integration mit HolySheep AI für Feature Enrichment
async def enrich_features_with_ai(
metrics: OrderFlowMetrics,
market_context: Dict
) -> Dict:
"""
Verwendet HolySheep AI für erweiterte Orderflow-Analyse
Kostengünstige Inference mit DeepSeek V3.2 ($0.42/MTok)
"""
import aiohttp
base_url = "https://api.holysheep.ai/v1"
api_key = "YOUR_HOLYSHEEP_API_KEY" # Via https://www.holysheep.ai/register
prompt = f"""
Analysiere folgende Hyperliquid Orderflow-Daten:
Volume Imbalance: {metrics.volume_imbalance:.4f}
Buy Volume: ${metrics.buy_volume:,.2f}
Sell Volume: ${metrics.sell_volume:,.2f}
VWAP: ${metrics.vwap:.4f}
Large Trade Count: {metrics.large_trade_count}
Whale Activity: {metrics.is_whale_activity}
Liquidation Event: {metrics.is_liquidation_event}
Marktkontext:
{market_context}
Erkläre in 2-3 Sätzen die wahrscheinliche Marktdynamik.
"""
async with aiohttp.ClientSession() as session:
async with session.post(
f"{base_url}/chat/completions",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
},
json={
"model": "deepseek-v3.2",
"messages": [{"role": "user", "content": prompt}],
"max_tokens": 150,
"temperature": 0.3
}
) as response:
result = await response.json()
return {
"metrics": metrics.__dict__,
"ai_insight": result["choices"][0]["message"]["content"],
"model_used": "deepseek-v3.2",
"cost_usd": result["usage"]["total_tokens"] * 0.00042 # $0.42/MTok
}
Performance Test
async def test_feature_pipeline():
"""Benchmark der Orderflow-Feature-Berechnung"""
import time
processor = OrderFlowProcessor(window_seconds=1, whale_threshold_usd=100_000)
# Simuliere 10.000 Trades
trades = [
{
"timestamp": datetime(2026, 4, 28, 12, 0, i // 100),
"price": 65_000 + np.random.randn() * 100,
"amount": np.random.exponential(0.5),
"side": np.random.choice(["buy", "sell"]),
"liquidation": np.random.random() < 0.01
}
for i in range(10_000)
]
start = time.perf_counter()
for trade in trades:
processor.process_trade(trade)
elapsed = time.perf_counter() - start
print(f"=== Feature Pipeline Benchmark ===")
print(f"Trades processed: {len(trades)}")
print(f"Total time: {elapsed*1000:.2f}ms")
print(f"Throughput: {len(trades)/elapsed:.0f} trades/sec")
if __name__ == "__main__":
asyncio.run(test_feature_pipeline())
4. Produktions-Ready Data Loader mit Batch-Processing
# src/production_loader.py
"""
Produktionsreifer Data Loader für Hyperliquid Historical Data
Features: Batch-Processing, Checkpointing, Dead Letter Queue
"""
import asyncio
import json
import os
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import AsyncIterator, Dict, List, Optional
from dataclasses import dataclass, asdict
import asyncpg
from redis.asyncio import Redis
from kafka import AsyncProducer
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@dataclass
class LoaderConfig:
"""Konfiguration für Production Data Loader"""
# Tardis.dev Settings
tardis_api_key: str
symbols: List[str] = None # z.B. ["BTC-PERP", "ETH-PERP"]
# Database Settings (TimescaleDB)
db_host: str = "localhost"
db_port: int = 5432
db_user: str = "postgres"
db_password: str = ""
db_name: str = "hyperliquid"
# Redis Settings (Checkpointing)
redis_url: str = "redis://localhost:6379"
# Kafka Settings (Event Streaming)
kafka_bootstrap_servers: str = "localhost:9092"
kafka_topic: str = "hyperliquid-orderflow"
# Processing Settings
batch_size: int = 1000
checkpoint_interval: int = 10_000
max_concurrent_streams: int = 5
class HyperliquidProductionLoader:
"""
Produktionsreifer Data Loader mit:
- Batch-Insert in TimescaleDB
- Checkpointing via Redis
- Event-Streaming via Kafka
- Dead Letter Queue für Fehlerbehandlung
"""
def __init__(self, config: LoaderConfig):
self.config = config
self._pool: Optional[asyncpg.Pool] = None
self._redis: Optional[Redis] = None
self._kafka: Optional[AsyncProducer] = None
self._checkpoint_key = "hyperliquid:checkpoint"
async def initialize(self):
"""Initialisiert alle Connections"""
# PostgreSQL Pool
self._pool = await asyncpg.create_pool(
host=self.config.db_host,
port=self.config.db_port,
user=self.config.db_user,
password=self.config.db_password,
database=self.config.db_name,
min_size=10,
max_size=20
)
# Redis für Checkpointing
self._redis = Redis.from_url(
self.config.redis_url,
encoding="utf-8",
decode_responses=True
)
# Kafka Producer
self._kafka = AsyncProducer(
bootstrap_servers=self.config.kafka_bootstrap_servers,
value_serializer=lambda v: json.dumps(v).encode("utf-8")
)
# Initialisiere Database Schema
await self._init_schema()
logger.info("All connections initialized successfully")
async def _init_schema(self):
"""Erstellt TimescaleDB Hypertables und Continuous Aggregates"""
async with self._pool.acquire() as conn:
await conn.execute("""
CREATE TABLE IF NOT EXISTS hyperliquid_trades (
id BIGSERIAL,
trade_id VARCHAR(64) NOT NULL,
symbol VARCHAR(32) NOT NULL,
side VARCHAR(4) NOT NULL,
price DOUBLE PRECISION NOT NULL,
amount DOUBLE PRECISION NOT NULL,
fee DOUBLE PRECISION DEFAULT 0,
order_id VARCHAR(64),
liquidation BOOLEAN DEFAULT FALSE,
timestamp TIMESTAMPTZ NOT NULL,
inserted_at TIMESTAMPTZ DEFAULT NOW(),
PRIMARY KEY (timestamp, trade_id)
);
SELECT create_hypertable(
'hyperliquid_trades',
'timestamp',
if_not_exists => TRUE,
migrate_data => TRUE
);
CREATE INDEX IF NOT EXISTS idx_trades_symbol_time
ON hyperliquid_trades (symbol, timestamp DESC);
""")
# Continuous Aggregate für 1-Minute OHLCV
await conn.execute("""
CREATE MATERIALIZED VIEW IF NOT EXISTS
hyperliquid_trades_1m_agg
WITH (timescaledb.continuous) AS
SELECT
symbol,
time_bucket('1 minute', timestamp) AS bucket,
COUNT(*) AS trade_count,
AVG(price) AS avg_price,
SUM(CASE WHEN side = 'buy' THEN amount ELSE 0 END) AS buy_volume,
SUM(CASE WHEN side = 'sell' THEN amount ELSE 0 END) AS sell_volume,
MIN(price) AS low,
MAX(price) AS high,
FIRST(price, timestamp) AS open,
LAST(price, timestamp) AS close
FROM hyperliquid_trades
GROUP BY symbol, bucket;
""")
async def load_historical_data(
self,
start_date: datetime,
end_date: datetime
):
"""
Lädt Historical Data mit Checkpointing und Error Recovery
"""
from src.tardis_client import HyperliquidTardisClient, TardisConfig
tardis_config = TardisConfig(api_key=self.config.tardis_api_key)
async with HyperliquidTardisClient(tardis_config) as tardis:
tasks = []
for symbol in self.config.symbols:
task = self._stream_and_process(
tardis, symbol, start_date, end_date
)
tasks.append(task)
await asyncio.gather(*tasks, return_exceptions=True)
async def _stream_and_process(
self,
tardis: HyperliquidTardisClient,
symbol: str,
start_date: datetime,
end_date: datetime
):
"""Streamt Trades, verarbeitet in Batches, speichert"""
batch = []
processed_count = 0
checkpoint = await self._get_checkpoint(symbol)
# Resume from checkpoint
current_start = checkpoint if checkpoint else start_date
logger.info(f"Starting stream for {symbol} from {current_start}")
async for trade in tardis.get_trades(
symbol=symbol,
start_date=current_start,
end_date=end_date
):
batch.append(trade)
processed_count += 1
if len(batch) >= self.config.batch_size:
await self._batch_insert(batch)
batch = []
# Checkpointing
if processed_count % self.config.checkpoint_interval == 0:
await self._save_checkpoint(symbol, trade["timestamp"])
await self._send_to_kafka(symbol, batch)
logger.info(f"{symbol}: Processed {processed_count} trades")
# Final batch
if batch:
await self._batch_insert(batch)
await self._save_checkpoint(symbol, batch[-1]["timestamp"])
async def _batch_insert(self, trades: List[Dict]):
"""Batch-Insert mit Retry-Logic"""
if not trades:
return
values = [
(
t["id"],
t["symbol"],
t["side"],
t["price"],
t["amount"],
t.get("fee", 0),
t.get("order_id"),
t.get("liquidation", False),
t["timestamp"]
)
for t in trades
]
async with self._pool.acquire() as conn:
await conn.executemany("""
INSERT INTO hyperliquid_trades
(trade_id, symbol, side, price, amount, fee, order_id, liquidation, timestamp)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
ON CONFLICT (timestamp, trade_id) DO NOTHING
""", values)
async def _get_checkpoint(self, symbol: str) -> Optional[datetime]:
"""Liest letzten Checkpoint aus Redis"""
checkpoint = await self._redis.get(f"{self._checkpoint_key}:{symbol}")
return datetime.fromisoformat(checkpoint) if checkpoint else None
async def _save_checkpoint(self, symbol: str, timestamp: datetime):
"""Speichert Checkpoint in Redis mit TTL"""
await self._redis.set(
f"{self._checkpoint_key}:{symbol}",
timestamp.isoformat(),
ex=86400 * 7 # 7 days TTL
)
async def _send_to_kafka(self, symbol: str, trades: List[Dict]):
"""Sendet Batch an Kafka Topic"""
for trade in trades:
await self._kafka.send(
self.config.kafka_topic,
value={
"symbol": symbol,
"event_type": "trade",
"data": trade
}
)
async def shutdown(self):
"""Graceful Shutdown aller Connections"""
if self._pool:
await self._pool.close()
if self._redis:
await self._redis.close()
if self._kafka:
await self._kafka.flush()
Usage Example
async def main():
config = LoaderConfig(
tardis_api_key="YOUR_TARDIS_API_KEY",
symbols=["BTC-PERP", "ETH-PERP", "SOL-PERP"],
db_host="timescaledb.internal",
db_password=os.environ["DB_PASSWORD"],
redis_url=os.environ["REDIS_URL"],
kafka_bootstrap_servers="kafka.internal:9092"
)
loader = HyperliquidProductionLoader(config)
try:
await loader.initialize()
await loader.load_historical_data(
start_date=datetime(2026, 4, 1, tzinfo=timezone.utc),
end_date=datetime(2026, 4, 28, tzinfo=timezone.utc)
)
finally:
await loader.shutdown()
if __name__ == "__main__":
asyncio.run(main())
Benchmark-Ergebnisse und Performance-Analyse
Wir haben die Pipeline unter Produktionsbedingungen getestet. Die folgenden Zahlen wurden auf einem c6i.4xlarge AWS Instance (16 vCPU, 32 GB RAM) gemessen:
| Metrik | Wert | Bemerkung |
|---|---|---|
Tardis.dev API Latenz (p50)Verwandte RessourcenVerwandte Artikel
🔥 HolySheep AI ausprobierenDirektes KI-API-Gateway. Claude, GPT-5, Gemini, DeepSeek — ein Schlüssel, kein VPN. |