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
- Ein Linux-Server oder Mac mit mindestens 8 GB RAM (16 GB empfohlen)
- Docker installiert (Download: docker.com/get-docker)
- Python 3.10 oder neuer
- Ein Tardis-Account (tardis.dev) – die ersten 30 Tage sind kostenlos
- 30 Minuten Zeit und ein bisschen Geduld
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