Es ist verlockend, einen Trading-Bot als ein großes Skript zu schreiben: Kurs abrufen, Bedingung prüfen, Order platzieren, wiederholen. Das funktioniert im Demo und scheitert in der Produktion, meist im ungünstigsten Moment. Ein robuster Bot trennt Verantwortlichkeiten in eigene Schichten, sodass ein einzelner Fehler eingedämmt statt katastrophal ist.
Die geschichtete Architektur
- 1.Datenschicht — nimmt Marktdaten auf und validiert sie, stellt eine saubere Schnittstelle bereit, isoliert von der Strategie-Logik.
- 2.Signalschicht — reine Funktionen, die validierte Daten in ein Handelssignal verwandeln (Kaufen/Verkaufen/Halten + Konfidenz).
- 3.Risikoschicht — bemisst die Position, prüft Exposure-Limits und kann jedes Signal unabhängig von der Konfidenz ablehnen.
- 4.Ausführungsschicht — übersetzt eine genehmigte Order in Broker-API-Aufrufe, handhabt Retries und Idempotenz.
- 5.Monitoring-Schicht — protokolliert alles, verfolgt Live- vs. erwartete Performance, löst Alarme und Kill-Switches aus.
Selbst wenn deine Signal-Logik heute fehlerfrei ist, könnte eine zukünftige Code-Änderung oder ein schlechter Daten-Tick ein absurdes Signal erzeugen (z. B. Größe = 10.000 Lots). Die Aufgabe der Risikoschicht ist es, eine harte, unabhängige Obergrenze zu sein — max. Positionsgröße, max. Tagesverlust, max. Orderrate —, die kein Upstream-Bug umgehen kann.
State-Management
Ein Bot muss immer genau wissen, in welchem Zustand er ist: flach, Order ausstehend, in Position, schließend. Modelliere dies explizit als Zustandsmaschine, statt Boolean-Flags über die Codebasis zu verstreuen. Mehrdeutiger Zustand ist der Grund, warum Bots am Ende Positionen doppelt eröffnen oder verwaiste Orders nach einem Absturz im Buch hinterlassen.
enum BotStatus { FLACH, ORDER_AUSSTEHEND, IN_POSITION, SCHLIESSEND }
function beiFillEreignis(status: BotStatus, fill: Fill): BotStatus {
if (status === BotStatus.ORDER_AUSSTEHEND && fill.side === 'entry') return BotStatus.IN_POSITION;
if (status === BotStatus.SCHLIESSEND && fill.side === 'exit') return BotStatus.FLACH;
return status; // unerwarteter Fill -> loggen und alarmieren, nicht still übergehen
}Idempotenz und Crash-Recovery
Bots starten neu — durch Deployments, Abstürze oder Cloud-Instanz-Recycling. Beim Start muss der Bot seinen angenommenen Zustand gegen den tatsächlichen Kontostatus des Brokers (offene Orders, Positionen) abgleichen, bevor irgendetwas anderes passiert. Nimm nie an, dass die lokale State-Datei die Wahrheit ist — die Broker-API ist die einzige Quelle der Wahrheit.
Teststrategie
- ▸Teste Signal- und Risikoschicht vollständig isoliert mit gemockten Daten — keine Netzwerkaufrufe.
- ▸Integrationstest gegen die Sandbox-/Paper-Umgebung des Brokers vor jedem Live-Deployment.
- ▸Chaos-Test — den Prozess absichtlich mitten in einer Order beenden und verifizieren, dass die Abgleichslogik sauber wiederherstellt.
Das Fazit
Das ausgeklügeltste Signal der Welt ist wertlos, wenn es an einen fragilen Bot angeflanscht wird. Architekturdisziplin — saubere Schichtentrennung, expliziter Zustand, idempotente Ausführung — verwandelt ein Wochenend-Skript in etwas, dem man tatsächlich Kapital anvertrauen kann.