Stell dir vor, du könntest jede einzelne Order, jeden Trade und jeden Tiefen-Book-Snapshot von Bitcoin, Ethereum und tausenden anderen Kryptowährungen speichern – und das über Jahre hinweg, ohne dass dein Server in die Knie geht. Genau das ermöglicht die Kombination aus Tardis (einem historischen Marktdaten-Service) und ClickHouse (einer ultraschnellen Spalten-Datenbank). In diesem Tutorial zeige ich dir, wie du als absoluter Anfänger ein solches Daten-Warehouse von Null auf aufbaust – ganz ohne Vorwissen.

Was sind Tardis und ClickHouse?

Tardis ist ein Marktdaten-Anbieter, der historische Order-Book- und Trade-Daten von über 30 Krypto-Börsen (Binance, Coinbase, Kraken, OKX, Bybit …) zu fairen Preisen anbietet. Die Daten reichen teilweise bis ins Jahr 2019 zurück und sind in Rohformat (Tick-für-Tick) verfügbar.

ClickHouse ist eine Open-Source-Datenbank, die für analytische Abfragen auf Milliarden von Zeilen optimiert ist. Sie komprimiert Daten hervorragend und liefert Antworten oft in unter 50 Millisekunden – egal ob du 1 Tag oder 5 Jahre Daten abfragst. Zusammen ergeben beide ein unschlagbares Gespann für eigene Backtests, Algo-Trading-Strategien oder Marktforschung.

Voraussetzungen

Schritt 1: ClickHouse via Docker starten

Öffne dein Terminal und führe folgenden Befehl aus. Docker lädt automatisch das offizielle Image und startet einen ClickHouse-Server auf Port 8123 (HTTP) bzw. 9000 (native Protokoll).

# ClickHouse-Server starten
docker run -d \
  --name clickhouse-server \
  -p 8123:8123 \
  -p 9000:9000 \
  --ulimit nofile=262144:262144 \
  -v clickhouse_data:/var/lib/clickhouse \
  clickhouse/clickhouse-server:24.3

Testen, ob der Server läuft

curl http://localhost:8123/

📸 Screenshot-Hinweis: Wenn du im Browser http://localhost:8123 aufrufst, solltest du "Ok." sehen – das bedeutet, alles funktioniert.

Schritt 2: ClickHouse-Datenbank und Tabelle anlegen

Wir verbinden uns jetzt mit dem ClickHouse-Client und erstellen eine Tabelle für Binance-Trades. ClickHouse nutzt eine eigene Engine namens MergeTree, die extrem schnell beim Schreiben und Komprimieren ist.

docker exec -it clickhouse-server clickhouse-client

CREATE DATABASE IF NOT EXISTS crypto;

CREATE TABLE IF NOT EXISTS crypto.binance_trades
(
    timestamp   DateTime64(6, 'UTC'),
    symbol      LowCardinality(String),
    price       Float64,
    quantity    Float64,
    side        Enum8('buy' = 1, 'sell' = 2),
    trade_id    UInt64,
    buyer_maker UInt8
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(timestamp)
ORDER BY (symbol, timestamp)
TTL timestamp + INTERVAL 3 YEAR;

📸 Screenshot-Hinweis: Im Terminal solltest du nach jeder Anweisung ein "Ok." als Bestätigung sehen. Damit ist die Tabelle einsatzbereit.

Schritt 3: Tardis-Daten herunterladen und in ClickHouse laden

Jetzt kommt das Herzstück: Wir holen uns historische Roh-Daten von Tardis und pipen sie direkt nach ClickHouse. Tardis bietet CSV-Dateien pro Stunde an, die wir zeilenweise einlesen und in 100.000er-Blöcken schreiben.

# Python-Umgebung vorbereiten
pip install tardis-client clickhouse-connect requests

daten_import.py

import os import gzip import csv import io import requests from datetime import datetime import clickhouse_connect

Konfiguration

TARDIS_API_KEY = os.environ.get("TARDIS_API_KEY", "dein_tardis_key_hier") CLICKHOUSE_HOST = "localhost" CLICKHOUSE_PORT = 8123 client = clickhouse_connect.get_client( host=CLICKHOUSE_HOST, port=CLICKHOUSE_PORT, database="crypto" ) def lade_tardis_stunde(symbol="binance-futures", market="trades", datum="2024-01-15", stunde=10): """Laedt eine Stunde Tardis-Daten und schreibt sie nach ClickHouse.""" url = f"https://datasets.tardis.dev/v1/{symbol}/{market}/{datum}/{stunde}.csv.gz" headers = {"Authorization": f"Bearer {TARDIS_API_KEY}"} print(f"Lade {url} ...") response = requests.get(url, headers=headers, timeout=60) if response.status_code != 200: raise RuntimeError(f"Tardis-Fehler: HTTP {response.status_code}") rohdaten = gzip.decompress(response.content).decode("utf-8") reader = csv.DictReader(io.StringIO(rohdaten)) chargen = [] zaehler = 0 for zeile in reader: chargen.append([ datetime.fromisoformat(zeile["timestamp"].replace("Z", "+00:00")), symbol.split("-")[0], float(zeile["price"]), float(zeile["amount"]), "buy" if zeile["side"] == "buy" else "sell", int