← Alle Insights

Apache Kafka für Tick-Daten: Streaming-Architektur für Trading.

Solange ein Skript an einem WebSocket hängt, reicht ein WebSocket. Sobald drei Komponenten parallel auf denselben Tick-Stream zugreifen wollen — Live-Strategie, Backtest-Recorder, Monitoring — wird die Frage drängend, wo der Stream eigentlich wirklich lebt. Kafka beantwortet sie.

Was Kafka eigentlich ist.

Kafka ist eine verteilte, persistente Log-basierte Streaming-Plattform. Klingt sperrig, ist im Kern simpel: Producer schreiben Nachrichten in Topics, Consumer lesen sie. Anders als bei klassischen Message-Queues bleiben Nachrichten im Topic, auch nachdem sie gelesen wurden — über Tage oder Wochen. Mehrere Consumer können denselben Stream unabhängig voneinander lesen, jeder mit eigenem Offset.

Genau das ist für Trading interessant: Sie pumpen die Ticks einmal rein und haben dauerhaft die Möglichkeit, beliebig viele Consumer parallel anzuhängen — ohne die Datenquelle (IBKR, Binance, etc.) erneut zu belasten.

Die Kern-Konzepte.

Use-Case: WebSocket → Kafka → N Consumer.

Architektur, die ich in größeren Setups einsetze:

[IBKR WebSocket]   [Binance WebSocket]
       |                  |
       v                  v
  +-----------+      +-----------+
  | Producer  |      | Producer  |
  +-----------+      +-----------+
       \                  /
        v                v
       +---------------------+
       |       Kafka         |
       | ticks.equities.us   |
       | ticks.crypto.bin    |
       +---------------------+
        |        |        |
        v        v        v
  +---------+ +-------+ +----------+
  |Strategie| |Record-| |Monitoring|
  |  Live   | | er→DB | |  Grafana |
  +---------+ +-------+ +----------+

Drei unabhängige Consumer, ein einziger WebSocket pro Quelle. Wenn die Strategie crasht, bekommt der Recorder die Ticks trotzdem. Wenn ich eine vierte Strategie anhängen will, brauche ich keine zweite WebSocket-Connection — die Strategie wird einfach eine weitere Consumer-Group.

Producer in Python.

from confluent_kafka import Producer
import orjson, time

producer = Producer({
    'bootstrap.servers': 'kafka:9092',
    'linger.ms': 5,
    'compression.type': 'lz4',
    'acks': '1',
})

def on_tick(symbol, price, size, side, ts):
    msg = orjson.dumps({
        'symbol': symbol, 'price': price, 'size': size,
        'side': side, 'ts': ts,
    })
    producer.produce(
        topic='ticks.equities.us',
        key=symbol.encode(),   # Partition-Key: Ordering pro Symbol
        value=msg,
    )

# WebSocket-Loop ruft on_tick(...) auf
# Periodisch flushen:
while True:
    producer.poll(1.0)

Consumer in Python.

from confluent_kafka import Consumer
import orjson

consumer = Consumer({
    'bootstrap.servers': 'kafka:9092',
    'group.id': 'strategy.mean_reversion_v3',
    'auto.offset.reset': 'latest',
    'enable.auto.commit': True,
})
consumer.subscribe(['ticks.equities.us'])

while True:
    msg = consumer.poll(0.1)
    if msg is None or msg.error():
        continue
    tick = orjson.loads(msg.value())
    strategy.on_tick(tick)

Eine zweite Strategie bekommt schlicht eine andere group.idstrategy.momentum_v1 — und liest denselben Stream unabhängig. Der Recorder, der alle Ticks in TimescaleDB schreibt, ist eine dritte Group.

Das Ökosystem rundherum.

Performance.

Kafka ist auf Durchsatz optimiert. 1 Mio. Nachrichten pro Sekunde auf einem mittelgroßen Broker-Cluster sind alltäglich; mit getunter Konfiguration sind mehrere Millionen erreichbar. Für Trading-Tick-Daten ist das massive Overkill — ein einzelner Broker-Knoten reicht für die meisten Setups locker.

Latenz: Bei linger.ms=0 und acks=1 bewegt sich End-to-End (Producer → Broker → Consumer) im einstelligen Millisekunden-Bereich. Für Latenz-kritisches HFT ist das zu langsam — aber für Strategien mit Tick-bis-Order im Bereich 50–500 ms ist Kafka unproblematisch.

Alternative: Redis Streams.

Wenn Kafka zu viel Maschinerie ist, sind Redis Streams die schlanke Alternative. Ein einzelner Redis-Container, ähnliches Konzept (Consumer Groups, Offsets/IDs), aber deutlich weniger Operations-Overhead. Sweet-Spot: Solo-Trader mit 2–3 Strategien, die parallel auf denselben Stream zugreifen.

Grenze: Redis Streams persistiert in RAM (mit AOF-Backup), Kafka auf Disk. Bei Volumen über einigen GB pro Tag oder Retention > 24 h wird Kafka praktisch.

Docker-Compose-Setup.

services:
  zookeeper:
    image: confluentinc/cp-zookeeper:7.6.0
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000

  kafka:
    image: confluentinc/cp-kafka:7.6.0
    depends_on: [zookeeper]
    ports: ["9092:9092"]
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_LOG_RETENTION_HOURS: 168     # 7 Tage
      KAFKA_LOG_SEGMENT_BYTES: 1073741824
      KAFKA_COMPRESSION_TYPE: lz4

  schema-registry:
    image: confluentinc/cp-schema-registry:7.6.0
    depends_on: [kafka]
    environment:
      SCHEMA_REGISTRY_HOST_NAME: schema-registry
      SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS: kafka:9092
    ports: ["8081:8081"]

  tick-producer:
    build: ./producer
    depends_on: [kafka]
    environment:
      KAFKA_BROKERS: kafka:9092
      IBKR_API_KEY: ${IBKR_API_KEY}

Für Produktion: KRaft-Modus statt Zookeeper (ab Kafka 3.5 stabil), mindestens drei Broker für Replikation, separates Disk-Volume für die Log-Segments. Aber für den Einstieg reicht obiges Single-Node-Setup vollkommen.

Wann Kafka lohnt — und wann nicht.

Kafka lohnt, wenn:

Kafka lohnt nicht, wenn:

Meine Praxis.

In Solo-Setups: WebSocket → Strategie, direkt. Kein Kafka. In Multi-Strategie- und Mandanten-Setups: Kafka als zentrales Streaming-Backbone. Ein Producer pro Marktdaten-Quelle, Topics nach Asset-Class und Venue, jede Strategie eine eigene Consumer-Group. Recorder schreibt parallel alle Topics nach TimescaleDB für Backtest und Forensik.

Aufwand für das initiale Setup mit zwei Brokern und drei Consumern: rund eine Woche, inklusive Schema-Registry und Monitoring. Was Sie danach bekommen, ist eine Architektur, die mit jeder weiteren Strategie nicht teurer wird — sondern schlicht eine neue group.id bekommt. Genau das macht den Unterschied zwischen Bastelei und System.

Sie wollen aus einem WebSocket-Skript eine echte Streaming-Architektur machen? Erstgespräch buchen — wir entscheiden gemeinsam, ob Kafka, Redis Streams oder doch nur ein sauberer Direkt-Consumer der richtige Schritt ist.