← Alle Insights

Interactive Brokers API mit Python: Praxis-Leitfaden.

Die IBKR-API ist mächtig — und gleichzeitig die unfreundlichste API, die ein Retail- oder Pro-Trader heute findet. Wer den Sprung schafft, bekommt Zugriff auf 150 Börsen, sämtliche Asset-Klassen und institutionelle Execution. Dieser Leitfaden zeigt, wie Sie ohne Frust an dieses Ziel kommen.

Die Architektur verstehen.

Anders als moderne REST-APIs liegt zwischen Ihrem Python-Code und den IBKR-Servern immer eine lokale Gateway-Applikation: entweder die Trader Workstation (TWS) oder das schlankere IB Gateway. Beide sprechen Socket-Protokoll auf Port 7497 (Paper) bzw. 7496 (Live) für TWS, 4002/4001 für das Gateway. Erst diese Gateway-Apps halten den authentifizierten Login zur IBKR-Infrastruktur.

Für produktive Setups ist das IB Gateway die richtige Wahl — geringer Speicherverbrauch, kein GUI-Overhead, läuft headless im Docker-Container oder auf einer VPS. TWS ist gut für Entwicklung und manuelles Eingreifen.

ibapi vs. ib_insync — die ehrliche Empfehlung.

Die offizielle Python-Library ibapi ist callback-basiert, threadlastig und für Anfänger ein Albtraum. Praktisch jeder produktive Python-Stack nutzt stattdessen ib_insync von Ewald de Wit — eine asyncio-basierte Wrapper-Bibliothek, die den Code um den Faktor 5 reduziert.

from ib_insync import IB, Stock, MarketOrder, util

ib = IB()
ib.connect('127.0.0.1', 7497, clientId=1)

# Kontrakt definieren
aapl = Stock('AAPL', 'SMART', 'USD')
ib.qualifyContracts(aapl)

# Marktdaten anfordern (Snapshot)
ticker = ib.reqMktData(aapl, '', False, False)
ib.sleep(2)
print(f"AAPL bid={ticker.bid} ask={ticker.ask} last={ticker.last}")

# Marktorder über 10 Aktien
order = MarketOrder('BUY', 10)
trade = ib.placeOrder(aapl, order)
ib.sleep(1)
print(f"Status: {trade.orderStatus.status}")

ib.disconnect()

Der gleiche Code in ibapi würde drei Klassen, einen eigenen Event-Loop und etwa 80 Zeilen Boilerplate benötigen. Die Entscheidung ist eindeutig: nutzen Sie ib_insync. Der einzige Grund gegen ib_insync wäre, wenn Sie das Original-Wrapping für einen anderen Client-Stil bauen wollen — aber das tut praktisch niemand.

Verbindung, Client-IDs und Reconnect-Logik.

Jede Verbindung zur Gateway-App braucht eine Client-ID — eine Integer zwischen 0 und 31. Die ID 0 ist reserviert für „Master" und sieht alle Orders aller Clients. Für jeden parallelen Prozess vergeben Sie eine eindeutige ID, ansonsten kickt Sie der Gateway sofort raus.

In Produktion brauchen Sie unbedingt Reconnect-Logik. Die Gateway-App führt täglich einen Auto-Logout durch (US-Default: 23:55 ET), und WLAN-Drops kommen vor. Ein Minimal-Wrapper:

import asyncio
from ib_insync import IB

async def ensure_connected(ib: IB, host='127.0.0.1', port=4002, client_id=42):
    while True:
        try:
            if not ib.isConnected():
                await ib.connectAsync(host, port, clientId=client_id, timeout=10)
                print("[ok] verbunden")
            await asyncio.sleep(5)
        except Exception as e:
            print(f"[warn] reconnect-versuch fehlgeschlagen: {e}")
            await asyncio.sleep(15)

ib = IB()
ib.errorEvent += lambda reqId, code, msg, _: print(f"err {code}: {msg}")
asyncio.run(ensure_connected(ib))

Wichtig: vor jeder kritischen Order prüfen Sie ib.isConnected() und cachen offene Orders lokal. Wenn der Gateway während eines Fills disconnected, müssen Sie nach Reconnect den Zustand abgleichen — IB sendet alte Events nicht erneut.

Marktdaten, Subscriptions und Limits.

Marktdaten kosten bei IBKR pro Exchange-Paket. Wer nur Paper-Trading macht, kommt mit den US-Securities-Snapshot-Bundles aus (kostenlos), für realistische Live-Daten sind Subscriptions fällig. Pro Konto-Session limitiert IBKR Streaming-Tickers auf 100 gleichzeitig (mehr nur mit speziellen Paketen).

Historische Bars werden über ib.reqHistoricalData() abgerufen. Limits: etwa 60 simultane Requests pro 10 Minuten, je Symbol und Bar-Size eigene Begrenzungen. Für Backtest-Datensätze besser einmal pullen und lokal in Parquet ablegen, statt jedes Mal abzufragen.

Wer Tick-Daten braucht (Trades und Quotes auf höchster Granularität), nutzt reqTickByTickData() — limitiert auf 5 simultane Symbole pro Account. Das ist die wichtigste Einschränkung für HFT-artige Setups: für mehr als eine Handvoll Live-Symbole müssen Sie aggregieren oder einen anderen Datenfeed dazuziehen.

Order-Typen, die Sie wirklich nutzen werden.

Multi-Currency und Cross-Border.

Hier wird es interessant — und unangenehm. IBKR rechnet jede Order in die jeweilige Settlement-Währung ab. Kaufen Sie an der LSE eine GBP-denominated Aktie mit einem EUR-Konto, entsteht ein negativer GBP-Cash-Saldo, den IBKR per Margin-Kredit ausgleicht. Sie zahlen Zinsen darauf, solange Sie nicht konvertieren.

Konvertieren geht über das Cash-Forex-Paar:

from ib_insync import IB, Forex, MarketOrder

ib = IB()
ib.connect('127.0.0.1', 4002, clientId=7)

# 5000 GBP von EUR-Cash kaufen — settled in IBKR Cash-Forex
gbpeur = Forex('GBPEUR')
ib.qualifyContracts(gbpeur)
order = MarketOrder('BUY', 5000)
trade = ib.placeOrder(gbpeur, order)
ib.sleep(2)
print(trade.orderStatus.status, trade.orderStatus.avgFillPrice)
ib.disconnect()

Faustregel für die Praxis: konvertieren Sie nur, wenn Sie wirklich in der Zielwährung cash sein wollen — etwa für Ausschüttungen oder Auszahlungen. Für die meisten Trading-Strategien ist der IBKR-Margin-Kredit günstiger und flexibler als ständig FX-Konvertierungen zu fahren.

Typische Fehler und ihre Ursachen.

  1. Error 502: „Couldn't connect to TWS" — die Gateway-App läuft nicht oder API-Verbindungen sind deaktiviert. In TWS unter Configure → API → Settings die Checkbox „Enable ActiveX and Socket Clients" prüfen.
  2. Error 200: „No security definition" — der Contract ist falsch spezifiziert. Vor jeder Order ib.qualifyContracts() aufrufen.
  3. Error 354: „Requested market data is not subscribed" — Sie brauchen entweder ein Subscription-Paket oder müssen mit Delayed-Daten arbeiten (ib.reqMarketDataType(3)).
  4. Error 10197: „No market data during competing live session" — Sie haben TWS auf einem anderen Rechner offen. IBKR erlaubt nur eine Live- Marktdaten-Session pro Konto.
  5. Stiller Order-Reject: prüfen Sie immer trade.log — manche Rejects kommen als Log-Event statt als Exception.

Produktiv-Setup, das funktioniert.

Mein empfohlener Stack für IBKR-Live-Trading:

  1. IB Gateway im Docker-Container, automatischer Restart vor dem Daily-Logout via IBC (Interactive Brokers Controller).
  2. Python-Service mit ib_insync, asyncio-Eventloop, zentralem State-Store (Redis oder Postgres) für Order-Tracking.
  3. Heartbeat-Monitor: separater Prozess, der alle 30 Sekunden den Connection-State prüft und bei mehrfacher Fehlmeldung Alerts schickt.
  4. Order-Reconciliation: täglich nach Settlement Soll/Ist-Abgleich zwischen internem State und IBKR-Account-Statements.
  5. Paper-Mirror: parallel zur Live-Engine eine Paper-Instanz mit gleichem Code laufen lassen, Divergenzen automatisch protokollieren.

Mit dieser Infrastruktur sind 12 Monate stabilen Live-Betriebs realistisch — auch für Multi-Asset-Strategien über mehrere Kontinente. Die initialen 2–4 Wochen Aufwand, das Setup sauber aufzubauen, sind die beste Investition im gesamten Quant-Stack.

Sie planen einen IBKR-Live-Betrieb oder kämpfen mit Reconnect- und Order-State- Problemen? Erstgespräch buchen — wir setzen den Stack auf, der auch um 3 Uhr morgens noch läuft.