Observability für Trading-Systeme: Logs, Metrics, Traces.
Ein Trading-System ohne Observability ist eine Blackbox mit Echtgeld-Risiko. Wenn der Bot um 03:14 Uhr keine Order mehr abschickt, wollen Sie nicht raten — Sie wollen die Zeile sehen, in der es passiert ist.
Die drei Säulen.
- Logs beantworten was passiert ist: textuelle Ereignisse mit Zeitstempel und Kontext. Order eingereicht, Fill empfangen, API-Fehler aufgetreten.
- Metrics beantworten was passiert: numerische Zeitreihen, aggregiert. P&L pro Strategie, Order-Latenz P95, offene Positionen, CPU-Last.
- Traces beantworten warum es passiert: verkettete Spans über Service-Grenzen hinweg. Signal-Generierung → Risk-Check → Order-Submit → Fill — als ein zusammenhängender Pfad mit Latenzen pro Schritt.
Die drei sind komplementär. Logs allein reichen, bis Ihr System ein einzelnes Skript ist. Sobald mehrere Services beteiligt sind, brauchen Sie Metrics für Trends und Traces für Korrelation.
Metrics: Prometheus + Grafana.
Prometheus ist der De-facto-Standard für Metrics im Open-Source-Umfeld: Pull-basiert, Time-Series-Datenbank, einfache Client-Libraries in allen relevanten Sprachen. Grafana ist das Frontend, das man mit Tabs aufrufen will.
from prometheus_client import Counter, Histogram, Gauge
orders_submitted = Counter(
'orders_submitted_total', 'Anzahl eingereichter Orders',
['strategy', 'symbol', 'side'])
order_latency = Histogram(
'order_latency_seconds', 'Latenz Order-Submit bis Acknowledgement',
['venue'],
buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5))
open_position = Gauge(
'open_position_qty', 'Aktuelle Position pro Symbol',
['strategy', 'symbol'])
Diese drei Primitive — Counter, Histogram, Gauge — decken 90 % der Bedürfnisse ab. Für Trading-Systeme empfehle ich mindestens: P&L pro Strategie (Gauge), Anzahl Orders pro Stunde (Counter), Order-Latenz (Histogram), Anzahl offener Positionen (Gauge), API-Fehler nach Typ (Counter).
Logs: Loki oder Elasticsearch.
Loki von Grafana Labs ist das schlanke Pendant zu Elasticsearch: indiziert nur Labels, nicht den vollen Text, deutlich günstiger im Betrieb. Für Setups bis ~50 GB Logs/Tag ist Loki meine Standard-Wahl. Ab da wird Elasticsearch durch volle Volltextsuche relevant.
Wichtig: strukturierte Logs, nicht print. JSON pro Zeile, mit Feldern
wie strategy, symbol, order_id,
trace_id. Das macht die Korrelation mit Traces und das Filtern in
Grafana erst möglich.
import structlog
log = structlog.get_logger()
log.info("order.submit",
strategy="mean_reversion_v3",
symbol="AAPL",
side="buy",
qty=120,
limit=187.42,
trace_id=current_trace_id())
Traces: OpenTelemetry.
OpenTelemetry (OTel) ist der Standard für Distributed-Tracing. Sie instrumentieren Ihre Services einmal mit dem OTel-SDK, der Collector schickt die Traces an Tempo, Jaeger oder einen Cloud-Provider. Für Trading-Systeme besonders wertvoll: End-to-End-Latenz von Marktdatum bis Order ist nur über Traces sauber messbar.
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("strategy.evaluate") as span:
span.set_attribute("strategy", "mean_reversion_v3")
signal = strategy.evaluate(bar)
with tracer.start_as_current_span("risk.check"):
ok = risk.allow(signal)
if ok:
with tracer.start_as_current_span("order.submit"):
broker.submit(signal.to_order())
Was Sie unbedingt loggen sollten.
- Jeder Order-Submit: Strategy, Symbol, Side, Qty, Limit, Time. Mit Trace-ID.
- Jeder Fill: Order-ID, Fill-Price, Fill-Qty, Venue, Commission. Mit Trace-ID.
- Jeder Reject / Cancel: Order-ID, Reason-Code, Original-Params.
- Jedes Strategie-Signal: Auch wenn es nicht zur Order führt. Inklusive der Indikator-Werte zum Zeitpunkt der Entscheidung — sonst können Sie post mortem nicht rekonstruieren, warum der Trade ausgelöst (oder eben nicht) wurde.
- Jeder Fehler: API-Fehler, Connection-Drop, Parsing-Fehler. Stack-Trace plus Kontext.
Alerts: PagerDuty oder Opsgenie.
Alertmanager (Teil des Prometheus-Stacks) routet Alerts an PagerDuty oder Opsgenie. Drei Tiers, die ich konsequent unterscheide:
- Critical: Bot ist down, Position ohne Stop, API-Connection seit > 60 s tot. Phone-Call, jederzeit.
- Warning: P&L heute > 2× ATR negativ, Order-Latenz P95 > 500 ms, Disk > 80 %. Push/Slack, nur Tagsüber.
- Info: Tagesreport, Backtest fertig, Re-Training abgeschlossen. E-Mail oder Slack-Kanal.
Wichtigste Regel: Jeder Critical-Alert muss eine Runbook-Verlinkung haben. Wenn der Pager um 04:00 Uhr klingelt, wollen Sie nicht erst überlegen, was zu tun ist.
SLOs für Trading-Systeme.
Service-Level-Objectives sind das Bindeglied zwischen Metrics und Geschäft. Für ein Live-Trading-System sinnvolle SLOs:
- 99,9 % der Order-Acknowledgements in < 100 ms — gemessen über 30-Tage-Fenster.
- 99,95 % Uptime des Strategie-Workers während Handelszeiten.
- 0 Critical-Incidents pro Monat mit Geld-Verlust durch Software-Bug (nicht: Markt-Verlust).
- P95-Latenz Signal-zu-Order < 250 ms für Intraday-Strategien.
Wer keine SLOs definiert, kann auch nicht entscheiden, ob ein Incident relevant war oder Rauschen.
Konkretes Docker-Compose-Setup.
services:
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prom_data:/prometheus
ports: ["9090:9090"]
grafana:
image: grafana/grafana:latest
environment:
- GF_SECURITY_ADMIN_PASSWORD=__changeme__
volumes:
- grafana_data:/var/lib/grafana
ports: ["3000:3000"]
loki:
image: grafana/loki:latest
ports: ["3100:3100"]
tempo:
image: grafana/tempo:latest
command: -config.file=/etc/tempo.yml
volumes:
- ./tempo.yml:/etc/tempo.yml:ro
ports: ["3200:3200", "4317:4317"] # OTLP gRPC
alertmanager:
image: prom/alertmanager:latest
volumes:
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
ports: ["9093:9093"]
volumes:
prom_data:
grafana_data:
Dieses Setup läuft bei mir auf einem dedizierten Monitoring-VPS — getrennt vom Trading-VPS, damit ein Crash der Trading-Maschine nicht den Monitoring-Stack mitnimmt.
Meine Praxis.
Für die Mandanten, mit denen ich arbeite, läuft der komplette Observability-Stack (Prometheus, Grafana, Loki, Tempo, Alertmanager) auf einem zentralen VPS. Jeder Mandant bekommt einen eigenen Grafana-Tenant mit Read-Only-Dashboards: P&L, offene Positionen, Strategie-Status, Order-Latenz. Alerts werden zentral kuratiert, der Mandant bekommt nur die Critical-Eskalationen.
Aufwand für das Initial-Setup: 1–2 Tage. Aufwand für das Instrumentieren der Trading-Codebasis: weitere 1–3 Tage je nach Größe. Ergebnis: Sie sehen ein Problem, bevor der Mandant es sieht — und das ist die einzige Position, in der Sie sein wollen.
Sie wollen Ihr Trading-System aus dem Blindflug holen? Erstgespräch buchen — wir bauen einen schlanken Observability-Stack, der zu Ihrem Setup passt.