Der offene Stand lag ueber sieben Konzepte, zwei Referenzdokumente und die
Phasen-Checkliste der Architektur verteilt. Dieselbe Aufgabe stand teils
doppelt unter zwei Namen - die asynchrone Fill-Verfolgung etwa als "bekannte
Grenze" in IBKR-Integration.md und zugleich als W-2 im OptionsWheel-Konzept.
Wer wissen wollte, was als Naechstes ansteht, musste alles neun lesen.
docs/ROADMAP.md fuehrt das zusammen:
- Fuenf Stufen in Abhaengigkeitsreihenfolge, von "Fundament schliessen" bis
zum OptionsWheel, dazu vier laufende Bahnen (Auslieferung, Accounting,
Supervisor, technische Schulden).
- Jede Zeile traegt ihre Herkunft (W-2, P5, Kapitalmodell 5, ...), damit die
Herleitung im Archiv auffindbar bleibt.
- Eigene Abschnitte fuer Zurueckgestelltes und Verworfenes. Zurueckgestellte
Ideen nennen ausdruecklich, WAS sie wieder aktuell macht; verworfene nennen
den Grund, damit sie nicht in sechs Monaten erneut vorgeschlagen werden.
- Erledigtes bleibt als Zeile mit Datum stehen statt zu verschwinden.
Archiv (git erkennt alle sieben als Umbenennung, Historie bleibt):
docs/konzepte/* -> docs/archiv/
docs/Kapital-und-Buchmodell.md -> docs/archiv/
Jedes archivierte Dokument bekommt oben einen Vermerk, warum es erhalten bleibt
und wo der lebende Stand steht. Inhaltlich ist keines veraendert.
Weiter gepflegt werden ARCHITECTURE.md (Aufbau + Phasen-Historie),
IBKR-Integration.md (Adapter-Design und Grenzen) und die TWS-Setup-Checkliste -
das sind Referenzen, keine Planung. Ihre eigenen Offen-Listen verweisen jetzt
mit Roadmap-Kennung dorthin, statt einen zweiten Stand zu fuehren.
Alle 63 relativen Markdown-Links geprueft, keiner tot. Fuenf Pfadverweise in
Code, csproj und systemd-Unit mitgezogen; die Unit zeigte auf die
Portierungsanalyse, die ausdruecklich den Stand VOR dem Umbau beschreibt - jetzt
auf ARCHITECTURE.md. Build 0 Warnungen, 198/198 Tests gruen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
142 lines
8.9 KiB
Markdown
142 lines
8.9 KiB
Markdown
# 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](TWS-Setup-Checkliste.md).
|
||
- **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**
|
||
- **`GetQuoteAsync`** → `reqContractDetails` (Ergebnis wird gecacht) → `reqMktData` als Snapshot →
|
||
`Quote`. Preis-Reihenfolge: letzter Handelspreis, sonst Bid/Ask-Mitte, sonst Schlusskurs.
|
||
- **`GetAccountStateAsync`** → `reqAccountSummary` (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 (5–600), 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:
|
||
[archiv/KONZEPT-Modul-OptionsWheel.md](archiv/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 [archiv/KONZEPT-Datenlage-und-Strategien.md](archiv/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](TWS-Setup-Checkliste.md), Abschnitt Verifikation.
|
||
|
||
## Offen
|
||
Die offenen Punkte dieses Adapters werden seit dem 2026-08-23 in der
|
||
[Roadmap](ROADMAP.md) gefuehrt, nicht mehr hier – sie haengen mit Aufgaben aus anderen Konzepten
|
||
zusammen und standen deshalb doppelt. Es sind:
|
||
|
||
| Roadmap | Punkt |
|
||
|---|---|
|
||
| **H1** | `PlaceOrderAsync` gegen das Paper-Konto verifizieren (Order → Fill → Buchung) |
|
||
| **H2** | Asynchrone Fill-Verfolgung, siehe „Bekannte Grenze" oben – zugleich Voraussetzung fuer OptionsWheel |
|
||
| **H4** | IBC fuer Auto-Login/Neustart einrichten (Server-Betrieb) |
|
||
| **T1** | Entscheiden, ob die Marktdaten-Historie von der CP Web API auf `reqHistoricalData` wandert |
|
||
|
||
Das **Design** und die **bekannten Grenzen** stehen weiterhin in diesem Dokument – es bleibt die
|
||
technische Referenz des Adapters.
|