Files
IBKRTrader/docs/IBKR-Integration.md
RichardandClaude Opus 5 b96a20788c R10: Lesender Bestandsabgleich (IBrokerPortfolioReader) + Datenlage-Konzepte
Eigener Seam neben IBrokerClient: Wer handelt, braucht ihn nicht; wer die
eigene Buchfuehrung gegen den Broker abstimmt, braucht nur ihn. Zuteilung
und Verfall aendern Positionen ohne Order von uns - ohne Abgleich laeuft
das Managementbuch zwangslaeufig auseinander.

- IBrokerPortfolioReader mit GetPositionsAsync/GetExecutionsAsync;
  implementiert von IbkrBrokerClient und NullBrokerClient (DI registriert
  beide Rollen auf derselben Instanz).
- IbkrConnection: reqAccountUpdates statt reqPositions (nur dieser Weg
  liefert Marktwert und unrealisierten G/V), reqExecutions inkl. Zuordnung
  der verspaetet eintreffenden commissionReport-Callbacks ueber die ExecId.
- BrokerPosition/BrokerExecution als Broker-Wahrheit neben Position;
  IbkrMapping: ParseSide, ParseExecutionTime, FormatExecutionFilterTime
  (UTC wegen TWS-Warnung 2174) - mit Unit-Tests.
- Verifiziert gegen Paper-Konto DUR371528: 2 Positionen, 2 Ausfuehrungen
  inkl. Kommissionen.

Doku: Kapital- und Buchmodell (drei Wahrheiten, Kapitalzuteilung),
KONZEPT-Datenlage-und-Strategien (gemessen, was die API auf diesem Konto
liefert). Options-Wheel: Greeks bei verzoegerten Daten funktionieren
(Feld 83); Earnings-Termine sind ueber die TWS API nicht erreichbar
(Fehler 10358) - Behelf ueber IV-Filter statt Fremddatenquelle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 10:51:51 +02:00

8.5 KiB
Raw Permalink Blame History

IBKR-Anbindung (TWS API via IB Gateway)

Entscheidung: Der IbkrBrokerClient (Alternative zum NullBrokerClient) nutzt die TWS API über das IB Gateway native C#-Lib, robusteste Order-Ausführung, region-agnostisch.

Stand 2026-07-31: Der Adapter ist implementiert (src/IBKRTrader.Core/Trading/Ibkr/) und wird über IBKRSettings.UseTwsApi aktiviert. Gegen das Paper-Konto DUR371528 verifiziert sind Verbindung, GetAccountStateAsync und GetQuoteAsync (verzögerte Kurse, siehe unten) sowie der Fehlerpfad bei unbekanntem Symbol und nicht erreichbarer TWS. Noch nicht verifiziert: PlaceOrderAsync dafür ist eine echte Order auf dem Paper-Konto nötig.

Regionen (US ↔ IE)

Gleiche API, gleiche Gateway-Software, eine Codebasis. Unterschied nur: Login/Entity (Paper: IBKR Ireland, Live später: IBKR LLC US), Marktdaten-Abos, Reports kein Code-Fork. Paper vs. Live = Konto + Port, kein Code-Unterschied.

Betrieb (operativ)

  • Setup auf neuem System: alle nötigen TWS-/Gateway-Einstellungen Schritt für Schritt in der TWS-Setup-Checkliste.
  • IB Gateway (schlank, statt TWS) muss laufen und eingeloggt sein.
  • Ports: Paper 4002, Live 4001 (Auswahl über TradingSettings.Mode). → passt exakt zu den bestehenden IBKRSettings (Host 127.0.0.1, Port, ClientId).
  • 2FA / Dauerbetrieb: IBKR erzwingt 2FA und täglichen Neustart. Für unbeaufsichtigten Server-Betrieb IBC/IBController (Auto-Login + geplanter Neustart).

Bibliothek

Offizielle C#-API als NuGet-Mirror IB.TWS.CSharpApi 9.76.1, referenziert im Core und in der NuGet-Allowlist (NuGet.config) freigegeben. Das Paket zielt auf .NET Framework, ist aber reiner managed Code und läuft auf net10 NU1701 ist in der .csproj bewusst unterdrückt.

Umsetzung (src/IBKRTrader.Core/Trading/Ibkr/)

Die TWS API ist callback-basiert (EClientSocket sendet, EWrapper empfängt Events). Das ist hinter dem bestehenden async-Seam IBrokerClient gekapselt, aufgeteilt in drei Dateien:

Datei Aufgabe
IbkrMapping.cs Reine Abbildung Core ↔ TWS (Kontrakt, Order, Kurs, Port-/Statusregeln) unit-getestet
IbkrConnection.cs Socket-Lebenszyklus, Reader-Thread, reqId-Korrelation über TaskCompletionSource
IbkrBrokerClient.cs Implementiert IBrokerClient, übersetzt Fehler in leere Ergebnisse

Ablauf je Methode

  • GetQuoteAsyncreqContractDetails (Ergebnis wird gecacht) → reqMktData als Snapshot → Quote. Preis-Reihenfolge: letzter Handelspreis, sonst Bid/Ask-Mitte, sonst Schlusskurs.
  • GetAccountStateAsyncreqAccountSummary (NetLiquidation, AvailableFunds).
  • PlaceOrderAsync → Kontrakt auflösen → placeOrder; das Ergebnis kommt über orderStatus, die Order-IDs liefert nextValidId.

Bewusste Entscheidungen

  • Träges Verbinden mit Wiederholung statt Verbindungsaufbau beim Start. TWS ist nach einem Neustart minutenlang nicht bereit (erst abgelehnte Verbindungen, dann abgebrochene Handshakes); ein einmaliger Versuch beim Programmstart würde das nicht überleben.
  • Port-Prüfung gegen den Handelsmodus. Paper-Modus auf einem Live-Port (oder umgekehrt) wird abgelehnt, der Broker bleibt dann inaktiv sonst würde echtes Geld bewegt, wo ein Test erwartet wird.
  • Fehler werden nie geworfen, sondern zu leeren Ergebnissen. Konto 0 lässt die Risikoprüfung jedes Signal ablehnen die sichere Richtung bei nicht erreichbarem Broker.
  • MarketDataType standardmäßig 4 (verzögert + Frozen). Paper-Konten ohne Datenabo bekommen sonst überhaupt keine Kurse, und der ExecutionService überspringt jedes Signal mit „kein Kurs".
  • Zwei Sicherungen bleiben: UseTwsApi entscheidet über den Adapter, TradingEnabled über den Handel. Ohne den zweiten Schalter platziert der ExecutionService keine Order.

Bekannte Grenze: Orders ohne sofortige Ausführung

IBrokerClient.PlaceOrderAsync ist synchron gedacht (Ausführung oder Fehlschlag). Eine Order, die innerhalb von OrderTimeoutSeconds keinen Endstatus erreicht etwa eine Limit-Order im Orderbuch oder eine Market-Order außerhalb der Handelszeiten , wird als Fehlschlag zurückgegeben, kann bei IBKR aber weiterhin aktiv sein. Die Meldung enthält deshalb Order-ID und letzten Status. Sauber lösen ließe sich das nur mit asynchroner Fill-Verfolgung (Order-Zustand persistieren, orderStatus und execDetails dauerhaft mitschreiben) das ändert den Seam und ist eigene Arbeit.

Marktdaten

Das Paper-Konto hat kein Marktdaten-Abo. TWS meldet deshalb bei jeder Kursanfrage den Hinweis 10167 („nicht abonniert, es werden verzögerte Marktdaten angezeigt") und liefert danach ganz normal verzögerte Ticks. Das ist ein Statushinweis, kein Fehler wird er als Fehler behandelt, bricht die Kursanfrage ab, bevor die Ticks eintreffen, und jedes Symbol liefert „kein Kurs". IbkrMapping.IsInformational deckt den Code deshalb ausdrücklich ab (mit Test).

Verifiziert am 2026-07-31 gegen DUR371528: AAPL 302,94 / MSFT 476,88 / NVDA 209,81 (verzögert).

Optionen (Berechtigung verifiziert 2026-08-04)

Das Paper-Konto DUR371528 ist für den Optionshandel freigeschaltet. Geprüft ohne jede Ausführung über eine What-If-Order (Order.WhatIf = true): IBKR rechnet dabei Margin und Gebühren durch die komplette Prüfkette inklusive Handelsberechtigung und verwirft die Order anschließend.

Prüfung Ergebnis
reqSecDefOptParams AAPL 24 Verfallstermine, 127 Strikes (5600), Multiplier 100, TradingClass AAPL
Börsen SMART, CBOE, ISE, EMERALD, NASDAQBX, PHLX, AMEX, MEMX, PSE
Kontrakt AAPL 20260812 C302.5 aufgelöst, ConId 906106141, LocalSymbol AAPL 260812C00302500
What-If BUY 1 Kontrakt angenommen, Init-Margin 0 → 589,52
What-If BUY 1 AAPL (Aktie) angenommen, Init-Margin 0 → 87,61, Kommission 1,00 USD

Fehlte die Berechtigung, hätte IBKR die What-If-Order mit einem Berechtigungsfehler abgelehnt statt eine Margin zu liefern. Für Realtime-Optionskurse wäre zusätzlich ein OPRA-Abo nötig; ohne Abo kommen verzögerte Daten (siehe Marktdaten unten). Modul-Konzept: konzepte/KONZEPT-Modul-OptionsWheel.md.

What-If als Testwerkzeug: Damit lässt sich der gesamte Orderpfad bis zur Broker-Annahme prüfen, ohne eine Position zu eröffnen. Der Adapter nutzt es nicht produktiv für Vorabprüfungen (Margin-Deckung vor einer echten Order) wäre es aber ein naheliegender Ausbau. Welche Daten die API auf diesem Konto tatsächlich liefert und welche Strategien das trägt steht gemessen in konzepte/KONZEPT-Datenlage-und-Strategien.md. Kurz: Kurshistorie (30 Jahre), Volatilitätshistorie, Optionsketten und Griechen ja; Fundamentaldaten und Marktscanner nein (Abo nötig).

Historie: welcher Gateway?

Aktuell laufen die Marktdaten-Worker über die Client Portal Web API (IBKRGatewayService). Später zu entscheiden:

  • Broker (Quotes/Konto/Orders) → TWS API; Marktdaten-Historie vorerst auf CP Web API belassen, oder
  • Historie ebenfalls auf TWS (reqHistoricalData) migrieren → nur noch ein Gateway.

Konfiguration (settings.json, Abschnitt IBKR)

Schlüssel Default Bedeutung
UseTwsApi false Aktiviert den echten Adapter; sonst NullBrokerClient
Host / Port / ClientId 127.0.0.1 / 4002 / 1 Verbindung; Port muss zum Handelsmodus passen
MarketDataType 4 1 Realtime, 2 Frozen, 3 verzögert, 4 verzögert+Frozen
ConnectTimeoutSeconds 15 Socket-Verbindung und Handshake
RequestTimeoutSeconds 15 Kurs-, Kontrakt- und Kontoantworten
OrderTimeoutSeconds 60 Wartezeit auf den Endstatus einer Order

Testbarkeit

  • IbkrMapping ist vollständig unit-getestet (tests/.../IbkrMappingTests.cs): Port-/Modus-Regeln, Kontrakt- und Order-Aufbau, Kursableitung, Tick- und Statusklassifizierung.
  • Verbindung, Kurse und Orders bleiben manuelle Verifikation gegen das Paper-Gateway siehe TWS-Setup-Checkliste, Abschnitt Verifikation.

Offen

  1. PlaceOrderAsync gegen das Paper-Konto verifizieren (Order → Fill → Buchung).
  2. IBC für Auto-Login/Neustart einrichten (Server-Betrieb).
  3. Asynchrone Fill-Verfolgung, siehe „Bekannte Grenze" oben.
  4. Entscheiden, ob die Marktdaten-Historie von der CP Web API auf reqHistoricalData wandert.