R9: Echter IbkrBrokerClient über die TWS API
Broker-Adapter gegen TWS/IB Gateway, aktivierbar über IBKRSettings.UseTwsApi;
NullBrokerClient bleibt Default. TradingEnabled bleibt als zweite, unabhängige
Sicherung bestehen – ohne ihn platziert der ExecutionService keine Order.
Aufteilung (src/IBKRTrader.Core/Trading/Ibkr/):
- IbkrMapping – reine Abbildung Core <-> TWS (Kontrakt, Order, Kurs, Port-
und Statusregeln), vollständig unit-getestet
- IbkrConnection – Socket-Lebenszyklus, Reader-Thread, reqId-Korrelation über
TaskCompletionSource
- IbkrBrokerClient – implementiert IBrokerClient, übersetzt Fehler in leere
Ergebnisse (Konto 0 lässt die Risikoprüfung alles ablehnen)
Bewusste Entscheidungen:
- Träges Verbinden mit Wiederholung statt Verbindungsaufbau beim Start: TWS ist
nach einem Neustart minutenlang nicht bereit.
- Port wird gegen den Handelsmodus geprüft; Paper-Modus auf Live-Port (oder
umgekehrt) lässt den Broker inaktiv, statt auf dem falschen Konto zu handeln.
- MarketDataType Default 4: Paper-Konten ohne Datenabo bekommen sonst keine Kurse.
- Fehlercode 10167 ist ein Statushinweis (verzögerte Daten folgen), kein Fehler.
Als Fehler behandelt scheiterte jede einzelne Kursabfrage.
Verifiziert gegen Paper-Konto DUR371528: Verbindung, Konto (100.105,50 EUR),
Kurse (AAPL/MSFT/NVDA, verzögert), Fehlerpfade. Orderpfad bis zur Broker-Annahme
per What-If-Order geprüft (Aktie + Option, ohne Ausführung); dabei zugleich die
Optionsberechtigung des Kontos bestätigt. Offen: echte Ausführung (Fill ->
Buchung) und asynchrone Fill-Verfolgung – beides in IBKR-Integration.md notiert.
Doku: TWS-Setup-Checkliste.md (Einstellungen für Neuinstallation) neu,
IBKR-Integration.md / ARCHITECTURE.md / README.md nachgezogen.
154/154 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -125,7 +125,10 @@ Pin `new MariaDbServerVersion(new Version(11, 8, 6))`. Verbindung aus `appsettin
|
||||
- [x] Core-**Dashboard-View** (Gesamtüberblick: Trading-Modus, aggregierte Kennzahlen, geladene Module) + Icon
|
||||
- [x] `DashboardService` (aggregiert Positionen/Exposure/Trades via EF) + **2 InMemory-Tests** → 58/58 grün
|
||||
- [x] Tests durchgehend portiert; `--smoke-ui` deckt alle Views ab
|
||||
- [ ] **Nächster Meilenstein (blockiert bis Paper-Zugang):** echter `IbkrBrokerClient` über die **TWS API / IB Gateway** (entschieden 2026-07-29). Setup + Design: siehe [IBKR-Integration.md](IBKR-Integration.md). Ports Paper 4002 / Live 4001, region-agnostisch (US↔IE), `NullBroker` bleibt Default bis verifiziert.
|
||||
- [x] **Echter `IbkrBrokerClient` über die TWS API** (2026-07-31): `src/IBKRTrader.Core/Trading/Ibkr/` – `IbkrMapping` (rein, unit-getestet), `IbkrConnection` (Socket + reqId-Korrelation), `IbkrBrokerClient` (`IBrokerClient`). Aktivierung über `IBKRSettings.UseTwsApi`; `NullBrokerClient` bleibt Default. Design und Grenzen: [IBKR-Integration.md](IBKR-Integration.md), Einstellungen: [TWS-Setup-Checkliste.md](TWS-Setup-Checkliste.md).
|
||||
- [x] Gegen Paper-Konto DUR371528 verifiziert: Verbindung, Konto (NetLiquidation 100.105,50 EUR), Kurse (AAPL/MSFT/NVDA, verzögert) und Fehlerpfade
|
||||
- [x] Orderpfad bis zur Broker-Annahme per **What-If-Order** verifiziert (Aktie + Option, keine Ausführung); **Optionsberechtigung im Paper-Konto bestätigt**
|
||||
- [ ] **Offen:** `PlaceOrderAsync` mit echter Ausführung verifizieren (Fill → Buchung); asynchrone Fill-Verfolgung (Orders ohne sofortige Ausführung)
|
||||
- [ ] IBKR-Account-Credentials mit `EncryptedStringConverter` speichern
|
||||
|
||||
---
|
||||
|
||||
+103
-33
@@ -1,11 +1,13 @@
|
||||
# IBKR-Anbindung – Plan (TWS API via IB Gateway)
|
||||
# IBKR-Anbindung (TWS API via IB Gateway)
|
||||
|
||||
**Entscheidung:** Der `IbkrBrokerClient` (ersetzt `NullBrokerClient`) nutzt die **TWS API** über das
|
||||
**IB Gateway** – native C#-Lib, robusteste Order-Ausführung, region-agnostisch.
|
||||
**Entscheidung:** Der `IbkrBrokerClient` (Alternative zum `NullBrokerClient`) nutzt die **TWS API**
|
||||
über das **IB Gateway** – native C#-Lib, robusteste Order-Ausführung, region-agnostisch.
|
||||
|
||||
> Umsetzung ist **blockiert**, bis der Paper-Zugang + ein laufendes IB Gateway verfügbar sind
|
||||
> (echte Verifikation von Quotes/Konto/Orders nur gegen den Gateway möglich). Dieses Dokument hält
|
||||
> Setup und Design fest, damit die Umsetzung dann schnell und korrekt läuft.
|
||||
> **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
|
||||
@@ -13,6 +15,8 @@ Gleiche API, gleiche Gateway-Software, **eine Codebasis**. Unterschied nur: Logi
|
||||
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`).
|
||||
@@ -20,38 +24,104 @@ Paper vs. Live = Konto + Port, kein Code-Unterschied.
|
||||
Server-Betrieb **IBC/IBController** (Auto-Login + geplanter Neustart).
|
||||
|
||||
## Bibliothek
|
||||
- Empfohlen: offizielle C#-API als NuGet-Mirror **`IB.TWS.CSharpApi`** (keine Abhängigkeiten),
|
||||
ggf. der vereinfachte Wrapper **`IB.CSharpApiClient`** (mathpaquette) für weniger Callback-Boilerplate.
|
||||
- NuGet-Allowlist (`NuGet.config`) muss um das Paket ergänzt werden.
|
||||
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.
|
||||
|
||||
## Design `IbkrBrokerClient : IBrokerClient`
|
||||
Die TWS API ist **callback-basiert** (`EClientSocket` sendet, `EWrapper` empfängt Events). Wir kapseln
|
||||
das hinter unserem bestehenden async-Seam `IBrokerClient`:
|
||||
- **Verbindung:** `EClientSocket.eConnect(host, port, clientId)` + Reader-Thread; Reconnect-Logik.
|
||||
- **Korrelation:** je Request eine `reqId`; Antworten via `TaskCompletionSource` in einem
|
||||
`ConcurrentDictionary<int, TCS>` auflösen. Timeout je Request.
|
||||
- **`GetQuoteAsync(symbol)`** → Kontrakt (`reqContractDetails`/`reqMatchingSymbols`) → Snapshot-Kurs
|
||||
(`reqMktData` snapshot bzw. `reqTickByTickData`) → `Quote(Last, Bid, Ask)`.
|
||||
- **`GetAccountStateAsync()`** → `reqAccountSummary` (NetLiquidation, AvailableFunds).
|
||||
- **`PlaceOrderAsync(OrderRequest)`** → `Order` bauen (MKT/LMT, Menge, Side) → `placeOrder(orderId, contract, order)`;
|
||||
Ergebnis über `orderStatus`/`openOrder`/`execDetails`-Callbacks einsammeln → `OrderResult`.
|
||||
`nextValidId` liefert die Order-IDs.
|
||||
- **Sicherheit bleibt:** `NullBrokerClient` bleibt Default; `IbkrBrokerClient` wird erst registriert
|
||||
(via Config-Schalter), wenn verifiziert. Handel zusätzlich weiter durch `TradingEnabled`-Gate geschützt.
|
||||
## 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:
|
||||
[konzepte/KONZEPT-Modul-OptionsWheel.md](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.
|
||||
### Historie: welcher Gateway?
|
||||
Aktuell laufen die Marktdaten-Worker über die **Client Portal Web API** (`IBKRGatewayService`).
|
||||
Optionen (später entscheiden):
|
||||
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.
|
||||
|
||||
## Testbarkeit
|
||||
- Reine Logik (Order-/Kontrakt-Mapping, Response-Parsing) → Unit-Tests möglich.
|
||||
- Verbindung/Quotes/Orders → **manuell gegen das Paper-Gateway**, sobald verfügbar.
|
||||
## Konfiguration (`settings.json`, Abschnitt `IBKR`)
|
||||
|
||||
## To-do bei Gateway-Zugang
|
||||
1. `IB.TWS.CSharpApi` (+ NuGet-Allowlist) hinzufügen.
|
||||
2. `IbkrBrokerClient` implementieren (Design oben), hinter Config-Schalter registrieren.
|
||||
3. `TradingSettings.Mode` → Port 4002/4001; `IBKRSettings.ClientId` nutzen.
|
||||
4. Gegen Paper verifizieren: Verbindung → Quote → Konto → Test-Order (Paper) → Buchung.
|
||||
5. IBC für Auto-Login/Neustart einrichten.
|
||||
| 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
|
||||
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.
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
# TWS / IB-Gateway – Setup-Checkliste (Neuinstallation)
|
||||
|
||||
Ziel: Auf einem frischen System alle Einstellungen so setzen, dass IBKRTrader **ohne manuelle
|
||||
Eingriffe** (Popups, Bestätigungen, nächtliche Abbrüche) gegen die TWS API arbeiten kann.
|
||||
Stand: 2026-07-31. **Verifiziert**: TWS Paper (Konto DUR371528), Verbindung über
|
||||
`127.0.0.1:4002` erfolgreich, ServerVersion 151, Kontodaten + Positionen werden geliefert.
|
||||
|
||||
## 1. Voraussetzungen (einmalig, im IBKR Client Portal)
|
||||
|
||||
- [ ] Paper-Trading-Konto aktiv (Konto-ID beginnt mit `DU…`).
|
||||
- [ ] Paper-**Benutzername** und Passwort bekannt: Client Portal → **Einstellungen →
|
||||
Konto-Einstellungen → Paper-Trading-Konto**. (Login erfolgt mit dem Paper-Username,
|
||||
nicht mit der Konto-ID!)
|
||||
- [ ] Optional: **Marktdaten-Freigabe** Live → Paper aktivieren (sonst nur verzögerte Kurse):
|
||||
ebenfalls unter Einstellungen → Paper-Trading-Konto.
|
||||
- [ ] Software installieren: **TWS** (Desktop/Entwicklung) oder **IB Gateway** (Server, schlanker).
|
||||
Version „Stable“ genügt.
|
||||
|
||||
## 2. Login
|
||||
|
||||
- [ ] Beim Start Modus **„Paper Trading“** wählen (nicht „Live Trading“).
|
||||
- [ ] Mit Paper-Benutzername anmelden. Paper verlangt **kein 2FA** → automatisierbar.
|
||||
|
||||
## 3. API-Einstellungen
|
||||
|
||||
TWS: **File → Global Configuration → API → Einstellungen** (Gateway: Configure → Settings → API):
|
||||
|
||||
- [ ] **„ActiveX- und Socket-Clients aktivieren“** ☑
|
||||
- [ ] **„Schreibgeschützte API“** ☐ (deaktiviert lassen, sonst sind keine Orders möglich)
|
||||
- [ ] **Socket-Port:** Paper **4002**, Live **4001** (TWS-Default wäre 7497/7496 → umstellen,
|
||||
damit es zur App-Konfiguration passt)
|
||||
- [ ] **„Nur Verbindungen vom lokalen Host zulassen“** ☑ (App läuft auf derselben Maschine)
|
||||
- [ ] **„Vertrauenswürdige IPs“: `127.0.0.1` eintragen** (Erstellen → IP → Übernehmen).
|
||||
**Kritisch für den Automatikbetrieb:** Ohne Eintrag verlangt TWS für jede API-Verbindung
|
||||
eine Popup-Bestätigung; ein übersehenes Popup = tote Verbindung.
|
||||
- [ ] Optional fürs Debugging: „API-Nachrichten-Logdatei erstellen“ ☑
|
||||
- [ ] **Master-API-Client-ID:** leer lassen (App nutzt `IBKRSettings.ClientId`, Default 1;
|
||||
Test-Tools nutzen andere IDs, z. B. 99 — jede parallele Verbindung braucht eine eigene ID)
|
||||
|
||||
## 4. Vorsichtseinstellungen (API → Vorsichtseinstellungen / Precautions)
|
||||
|
||||
- [ ] **„Bypass Order Precautions for API Orders“** ☑ — sonst hält TWS automatische Orders mit
|
||||
Bestätigungsdialogen an (Preis-/Größen-Warnungen). Die Risiko-Limits übernimmt stattdessen
|
||||
unsere App (`TradingSettings`: MaxTradePercent, MaxSlippagePercent, …).
|
||||
|
||||
## 5. Dauerbetrieb (kein nächtlicher Ausfall)
|
||||
|
||||
- [ ] **Sperren und schließen** (Lock and Exit): **„Automatischer Neustart“** statt „Beenden“
|
||||
wählen; Neustartzeit außerhalb der Handelszeiten legen (z. B. 03:00).
|
||||
→ TWS läuft dann bis zu ~1 Woche ohne neuen Login durch.
|
||||
- [ ] Wöchentlicher Neuanmelde-Zwang bleibt: beim Paper-Konto ohne 2FA unkritisch,
|
||||
fürs Live-Konto später **IB Key mit „Weekly Re-Authentication“**.
|
||||
- [ ] Server-Zielbild (siehe [IBKR-Integration.md](IBKR-Integration.md)): **IB Gateway + IBC**
|
||||
(IBController) für Auto-Login und geplante Neustarts, als Autostart/geplanter Task.
|
||||
|
||||
## 6. App-Konfiguration (`settings.json`, lokal / gitignored)
|
||||
|
||||
- [ ] `IBKR.Host` = `127.0.0.1`
|
||||
- [ ] `IBKR.Port` = **4002** (Paper) bzw. **4001** (Live)
|
||||
- [ ] `IBKR.ClientId` = `1` (jede parallele API-Verbindung braucht eine eigene ID)
|
||||
- [ ] `IBKR.UseTwsApi` = `true` → echter Broker; `false` → `NullBrokerClient` (handelt nie)
|
||||
- [ ] `IBKR.MarketDataType` = `4` (verzögert + Frozen) – ohne Datenabo liefert `1` keine Kurse
|
||||
- [ ] `Trading.Mode` = `Paper`
|
||||
- [ ] `Trading.TradingEnabled` = `false`, bis die Verbindung verifiziert ist
|
||||
|
||||
Port und Handelsmodus müssen zusammenpassen: Paper-Modus auf einem Live-Port (und umgekehrt) lehnt
|
||||
der Adapter ab und bleibt inaktiv, statt auf dem falschen Konto zu handeln.
|
||||
|
||||
## 7. Verifikation
|
||||
|
||||
- [ ] Port erreichbar? `Test-NetConnection 127.0.0.1 -Port 4002` → `TcpTestSucceeded: True`
|
||||
- [ ] API-Verbindung: Verbindungstest ausführen (Konto-ID, NetLiquidation, Positionen müssen
|
||||
kommen). Hängt der Handshake > 10 s → Trusted IP fehlt (Punkt 3) oder Popup offen.
|
||||
|
||||
Erfolgreiche Ausgabe sieht so aus (Referenz vom 2026-07-31):
|
||||
|
||||
```
|
||||
VERBUNDEN. ServerVersion=151, Konten: DUR371528
|
||||
[2104] Verbindung zum Marktdatenzentrum ist OK: usfarm, eufarm, …
|
||||
[2106] Verbindung zum HMDS-Datenzentrum ist OK: ushmds, euhmds, …
|
||||
DUR371528 AccountType INDIVIDUAL
|
||||
DUR371528 NetLiquidation 100047.93 EUR
|
||||
DUR371528 TotalCashValue 100000.00 EUR
|
||||
```
|
||||
|
||||
Die Meldungen 2104/2106/2158 sind **keine Fehler**, sondern Status-Infos („Datenzentrum OK”).
|
||||
Dasselbe gilt für **10167** („nicht abonniert, verzögerte Marktdaten”) – ohne Marktdaten-Abo ist das
|
||||
bei jeder Kursanfrage der Normalfall, die Kurse kommen danach trotzdem.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **TCP-Verbindung wird angenommen, aber der API-Handshake bleibt ohne Antwort** (Client hängt
|
||||
beim Verbinden): TWS wartet intern auf die Bestätigung eines Verbindungs-Popups — auch wenn
|
||||
keines (mehr) sichtbar ist. Passiert, wenn die Trusted IP fehlte, das Popup unbemerkt verfiel
|
||||
oder der Konfigurationsdialog offen war (blockiert als modaler Dialog die Popups).
|
||||
**Lösung (am 2026-07-31 so verifiziert):** Konfigurationsdialog mit OK schließen, Trusted IP
|
||||
`127.0.0.1` prüfen (Punkt 3), dann **TWS komplett neu starten** — das räumt hängengebliebene,
|
||||
unbeantwortete Verbindungsanfragen ab. Danach verbindet sich der Client ohne Rückfrage.
|
||||
Wichtig: Die Trusted IP allein reichte **nicht**, solange TWS noch die alten Anfragen hielt —
|
||||
der Neustart war zwingend.
|
||||
- **Nach dem TWS-Start kurz warten:** Direkt nach dem Login lehnt der Port die Verbindung noch ab
|
||||
(„Verbindung verweigert“), danach folgt eine Phase mit abgebrochenem Handshake
|
||||
(„Unable to read beyond the end of the stream“). Erst wenn TWS vollständig hochgefahren ist,
|
||||
klappt der Login. Ein Client sollte deshalb **Reconnect mit Retry** machen statt einmalig zu
|
||||
scheitern — relevant für `IbkrBrokerClient`.
|
||||
- **`ClientId` muss je Verbindung eindeutig sein.** Eine zweite Verbindung mit derselben ID
|
||||
verdrängt die erste. App nutzt `IBKRSettings.ClientId` (Default 1), Diagnose-Tools eine andere.
|
||||
- Einstellungsänderungen im API-Dialog immer mit **Übernehmen/OK** abschließen; solange der
|
||||
Dialog offen ist, gelten sie nicht.
|
||||
|
||||
## Unterschiede Live-Betrieb (später)
|
||||
|
||||
| Punkt | Paper | Live |
|
||||
|--------------|------------------------|-----------------------------------------|
|
||||
| Login-Modus | Paper Trading | Live Trading |
|
||||
| Port | 4002 | 4001 |
|
||||
| 2FA | nein | ja → IB Key, Weekly Re-Authentication |
|
||||
| Marktdaten | geteilt vom Live-Konto | eigene Abos |
|
||||
| App | `Trading.Mode=Paper` | `Trading.Mode=Live` + Port umstellen |
|
||||
@@ -0,0 +1,241 @@
|
||||
# Konzept: Modul „OptionsWheel" (Covered Call / Cash-Secured Put)
|
||||
|
||||
> Stand: 2026-08-03
|
||||
> Ziel: Auf einer kleinen Watchlist von Tickern, an deren langfristigen Erfolg wir glauben,
|
||||
> **systematisch Optionsprämien vereinnahmen** – Cash-Secured Put → (Zuteilung) → Aktienbestand →
|
||||
> Covered Call → (Abruf) → wieder Cash. Vollautomatisch, delta-basierte Strike-Wahl, aktives Rollen.
|
||||
>
|
||||
> **Festlegungen (2026-08-03, mit dem Betreiber abgestimmt):**
|
||||
> 1. Put-Seite ist **Cash-Secured Put**, nicht Covered Put (kein Leerverkauf der Aktie).
|
||||
> 2. **Vollautomatisch** von Anfang an – Sicherungen sind Schalter und Limits, keine Klick-Freigabe.
|
||||
> 3. Strike-Wahl **delta-basiert** (Zielband 0,15–0,30).
|
||||
> 4. Bei drohender Zuteilung wird **gerollt**, solange das per Netto-Kredit möglich ist.
|
||||
|
||||
## 0. Leitprinzipien
|
||||
1. **Niemals nackt.** Ein Short Call ist nur zulässig mit 100 freien Aktien je Kontrakt, ein Short Put
|
||||
nur mit reserviertem Cash über Strike × 100 je Kontrakt. Diese Deckungsprüfung gehört in den
|
||||
**Core-`RiskService`**, nicht ins Modul – ein Modulfehler darf keine ungedeckte Option schreiben können.
|
||||
2. **Der Broker ist die Wahrheit.** Zuteilung und Verfall ändern Positionen **ohne** eine Order von uns.
|
||||
Ohne regelmäßigen Positionsabgleich gegen IBKR läuft die eigene Buchführung zwangsläufig auseinander.
|
||||
3. **Nur Watchlist.** Das Modul handelt ausschließlich explizit eingetragene Ticker. Keine Entdeckung,
|
||||
kein Screening, keine Ausweitung zur Laufzeit.
|
||||
4. **Jede Entscheidung ist nachlesbar.** Kandidatenbewertung, Zustandsübergang und Order gehen über
|
||||
`core_decision_journal` / `core_order_events` mit gemeinsamer `SignalId` – dieselbe Forensik-Grundlage,
|
||||
die der Supervisor bereits nutzt.
|
||||
|
||||
---
|
||||
|
||||
## 1. Warum das nicht additiv geht: der Core ist heute aktienbasiert
|
||||
|
||||
| Stelle | Heutiger Stand | Konsequenz |
|
||||
|---|---|---|
|
||||
| `IbkrMapping.Stock()` | „der einzige Instrumententyp, den die Module handeln" | Kein Options-Kontrakt (Expiry/Strike/Right/Multiplier) baubar |
|
||||
| `TradeSignal` / `OrderRequest` | nur `Symbol` + `Side` + `Quantity` | Ein Signal kann keine Option benennen |
|
||||
| `Position.Notional` | `Quantity × AvgPrice` | Bei Optionen um Faktor 100 falsch → Risikolimits wirkungslos |
|
||||
| `RiskService.EvaluateSell` | „Verkauf schließt Position", lehnt ohne Bestand ab | **Sell-to-open wird grundsätzlich abgelehnt** – die Kernoperation des Moduls |
|
||||
| `IBrokerClient.PlaceOrderAsync` | Fill-oder-Fehlschlag innerhalb `OrderTimeoutSeconds` | Limitorder am Mid liegt im Buch → gilt als Fehlschlag, ist aber aktiv (bekannte Grenze, [IBKR-Integration.md](../IBKR-Integration.md)) |
|
||||
| `IBrokerClient` | kein `reqPositions`, keine Optionskette, keine Greeks | Zuteilung/Verfall unsichtbar, Strike-Wahl unmöglich |
|
||||
|
||||
Das Modul setzt also auf einem **Core-Options-Fundament** auf, das zuerst gebaut wird. Der Aktienpfad
|
||||
bleibt dabei unverändert (neue Felder sind optional, `Kind = Stock` ist der Default) – CongressTrading
|
||||
darf nicht regressieren.
|
||||
|
||||
---
|
||||
|
||||
## 2. Core-Erweiterungen
|
||||
|
||||
### 2.1 Instrumententyp
|
||||
```csharp
|
||||
public enum InstrumentKind { Stock, Option }
|
||||
public enum OptionRight { Call, Put }
|
||||
|
||||
public sealed record OptionSpec(
|
||||
string Underlying,
|
||||
DateOnly Expiry,
|
||||
decimal Strike,
|
||||
OptionRight Right,
|
||||
int Multiplier = 100);
|
||||
```
|
||||
`TradeSignal` und `OrderRequest` bekommen je ein **optionales** `OptionSpec? Option`. Ist es null,
|
||||
verhält sich alles exakt wie heute.
|
||||
|
||||
### 2.2 Positionen mit Instrument-Identität
|
||||
`core_position` erhält `Kind`, `Expiry`, `Strike`, `Right`, `Multiplier`; der fachliche Schlüssel wird
|
||||
`(Module, Symbol, Kind, Expiry, Strike, Right)`. Bestandszeilen sind `Kind = Stock` mit leeren
|
||||
Optionsfeldern – Migration ohne Datenumzug. `Notional` rechnet ab jetzt mit dem Multiplikator.
|
||||
`IPortfolioService` bekommt entsprechend überladene Abfragen; die bestehenden Aktien-Signaturen bleiben.
|
||||
|
||||
### 2.3 Optionskette + Greeks
|
||||
Neuer Seam am `IBrokerClient`:
|
||||
```csharp
|
||||
Task<OptionChain?> GetOptionChainAsync(string underlying, DateOnly from, DateOnly to, CancellationToken ct);
|
||||
Task<OptionQuote?> GetOptionQuoteAsync(OptionSpec spec, CancellationToken ct); // + Delta, IV, OpenInterest
|
||||
Task<IReadOnlyList<BrokerPosition>> GetPositionsAsync(CancellationToken ct);
|
||||
```
|
||||
Umsetzung in `IbkrConnection`:
|
||||
- **Kette** über `reqSecDefOptParams` – liefert Expiries und Strikes je Underlying **ohne** Marktdaten
|
||||
und ohne Abo. Das ist der einzige gangbare Einstieg: eine volle Kette hat hunderte Kontrakte,
|
||||
TWS erlaubt aber nur ~100 gleichzeitige Marktdatenzeilen.
|
||||
- **Vorfilter, dann Quotes:** Expiry-Fenster aus dem DTE-Ziel, Strike-Fenster um den Spot (± x %) –
|
||||
erst für diese Handvoll Kontrakte `reqMktData` mit Greeks (`tickOptionComputation`).
|
||||
- `IbkrMapping.Option(spec)` → `SecType="OPT"`, `Exchange="SMART"`, `LastTradeDateOrContractMonth`
|
||||
als `yyyyMMdd`, `Strike`, `Right="C"/"P"`, `Multiplier="100"`, plus `TradingClass` (nötig, sobald ein
|
||||
Underlying mehrere Klassen führt, z. B. nach Splits oder bei Mini-Optionen). Rein, unit-getestet –
|
||||
wie das bestehende `IbkrMapping`.
|
||||
|
||||
### 2.4 Asynchrone Order- und Fill-Verfolgung
|
||||
Das ist der **teuerste, aber unumgängliche** Teil: eine Optionsorder wird limitiert am Mid platziert und
|
||||
füllt oft erst Minuten später oder gar nicht.
|
||||
- Neue Tabelle `core_order_state`: Order-ID, `SignalId`, Kontrakt, Menge, Limit, Status, gefüllte Menge,
|
||||
Zeitstempel – überlebt einen App-Neustart.
|
||||
- `IBrokerClient.SubmitOrderAsync(...)` gibt die Order-ID **ohne Warten** zurück; `PlaceOrderAsync`
|
||||
bleibt für den Aktienpfad erhalten (intern: submit + warten).
|
||||
- Dauerabo auf `orderStatus` / `openOrder` / `execDetails` statt Slot-je-Order; ein
|
||||
`OrderTrackingService` (`IHostedService`) trägt Endstatus nach, ruft dann `RecordFillAsync` und
|
||||
schreibt `core_order_events`. Nicht gefüllte Orders werden nach einer Frist neu bepreist oder storniert.
|
||||
- **Nebennutzen:** löst die in [IBKR-Integration.md](../IBKR-Integration.md) dokumentierte Grenze auch
|
||||
für CongressTrading.
|
||||
|
||||
### 2.5 Positionsabgleich (Zuteilung & Verfall)
|
||||
`ReconcilePositionsWorker` (`IHostedService`, z. B. stündlich und nach Marktschluss) vergleicht
|
||||
`reqPositions` mit `core_position`:
|
||||
- Aktien tauchen auf / Short Put verschwindet → **Zuteilung**.
|
||||
- Short Call verschwindet, Aktien weg → **Abruf (called away)**.
|
||||
- Option verschwindet am Verfallstag ohne Gegenbuchung → **wertlos verfallen**.
|
||||
Jede Abweichung wird gebucht **und** ins Entscheidungsjournal geschrieben. Unerklärbare Differenzen
|
||||
(manueller Eingriff in TWS) setzen den betroffenen Ticker auf `Halted`.
|
||||
|
||||
### 2.6 Risiko: sell-to-open + Deckung
|
||||
`RiskContext` bekommt `FreeShares` (nicht bereits durch andere Short Calls gebunden) und
|
||||
`AvailableCashForReservation`. Neue Regeln im `RiskService`:
|
||||
|
||||
| Fall | Regel |
|
||||
|---|---|
|
||||
| Sell-to-open Call | `FreeShares ≥ 100 × Kontrakte`, sonst Ablehnung „ungedeckt" |
|
||||
| Sell-to-open Put | `AvailableCashForReservation ≥ Strike × 100 × Kontrakte`, sonst Ablehnung |
|
||||
| Buy-to-close | zulässig bis zur offenen Short-Menge |
|
||||
| Limits | `MaxTradePercent` / `MaxPositionPercentPerModule` rechnen mit dem **Multiplikator** |
|
||||
|
||||
---
|
||||
|
||||
## 3. Modul `IBKRTrader.Modules.OptionsWheel`
|
||||
|
||||
`IModule` mit `Name = "OptionsWheel"`, `DbPrefix = "ow_"`, referenziert nur den Core, eigener DbContext,
|
||||
eigenes Fenster, eigene Settings-Sektion – analog Accounting/CongressTrading.
|
||||
|
||||
### 3.1 Zustandsautomat je Ticker
|
||||
```
|
||||
Idle ──sell put──► ShortPut ──ITM/DTE──► Rolling ──► ShortPut
|
||||
▲ │ │
|
||||
│ │ Zuteilung └─ kein Netto-Kredit ─► (Zuteilung zulassen)
|
||||
│ ▼
|
||||
└── called away ── Stock ──sell call──► ShortCall ──ITM/DTE──► Rolling ──► ShortCall
|
||||
▲ │
|
||||
└─ verfallen ─────────┘
|
||||
```
|
||||
Zusätzlich `PendingOrder` (Order im Buch) und `Halted` (Sperre nach Fehler/Abweichung, nur manuell lösbar).
|
||||
Der Automat ist **rein und unit-getestet** – er kennt weder Broker noch Datenbank.
|
||||
|
||||
### 3.2 Persistenz (`ow_`)
|
||||
| Tabelle | Inhalt |
|
||||
|---|---|
|
||||
| `ow_underlyings` | Watchlist: Ticker, aktiv, Parameter-Überschreibungen, aktueller Zustand |
|
||||
| `ow_cycles` | Ein Wheel-Durchlauf (Start, Ende, vereinnahmte Prämie brutto/netto, Ergebnis, Aktien-Einstand) |
|
||||
| `ow_legs` | Jede verkaufte/geschlossene Option: Kontrakt, Prämie, Delta+IV bei Eröffnung, DTE, Status, Roll-Kette |
|
||||
| `ow_candidates` | Bewertete Strike-Kandidaten je Scan (auch die verworfenen, mit Grund) – Nachvollziehbarkeit |
|
||||
| `ow_events` | Zustandsübergänge mit Auslöser |
|
||||
|
||||
`ow_candidates` ist bewusst dabei: bei Vollautomatik ist die **nicht** getroffene Wahl die wichtigste
|
||||
Information für die spätere Fehlersuche und für den Supervisor.
|
||||
|
||||
### 3.3 Reine Logik (`Logic/`, vollständig unit-getestet)
|
||||
- **`StrikeSelector`** – filtert die Kette: DTE-Fenster, Delta-Zielband, Mindestprämie (absolut und als
|
||||
annualisierte Rendite), maximaler Bid/Ask-Spread, Mindest-Open-Interest. Bewertet die Verbleibenden
|
||||
und begründet jede Verwerfung.
|
||||
- **`RollDecider`** – rollen ja/nein: Trigger, Zielkontrakt, Netto-Kredit-Bedingung.
|
||||
- **`CoverageCalculator`** – welche Aktien/welches Cash sind frei, welche durch offene Shorts gebunden.
|
||||
- **`PremiumMath`** – annualisierte Rendite, Break-even, effektiver Einstand nach Prämien.
|
||||
- **`WheelStateMachine`** – zulässige Übergänge, Ableitung des Zustands aus Positionen.
|
||||
|
||||
### 3.4 Worker
|
||||
- `WheelScanWorker` – im Handelszeitfenster: Zustand je Ticker prüfen, ggf. neues Leg eröffnen.
|
||||
- `WheelManageWorker` – offene Legs überwachen: rollen, schließen, Orders nachbepreisen.
|
||||
|
||||
### 3.5 UI (ein Fenster, Tabs)
|
||||
Übersicht (je Ticker: Zustand, offenes Leg, DTE, aktuelles Delta, Prämie vereinnahmt/annualisiert),
|
||||
Watchlist (Ticker + Parameter, Not-Aus je Ticker), Kandidaten (letzter Scan inkl. Verwerfungsgründe),
|
||||
Zyklen/Historie, Log. DB-Zugriff nur auf Interaktion (Smoke-UI-sicher).
|
||||
|
||||
---
|
||||
|
||||
## 4. Regelwerk (Defaults, je Ticker überschreibbar)
|
||||
|
||||
| Parameter | Default | Begründung |
|
||||
|---|---|---|
|
||||
| DTE beim Öffnen | 30–45 | Bestes Verhältnis Zeitwertverfall/Handelskosten |
|
||||
| Ziel-Delta | 0,20 (Band 0,15–0,30) | ≈ 20 % Zuteilungswahrscheinlichkeit |
|
||||
| Roll-Trigger | DTE ≤ 21 **und** (Delta > 0,50 oder ITM) | Gamma-Risiko steigt in der letzten Woche stark |
|
||||
| Roll-Bedingung | nur bei **Netto-Kredit** | Ein Debit-Roll kauft nur Zeit und kostet Geld |
|
||||
| Covered-Call-Strike | **≥ effektiver Einstand** der Aktien | Verhindert, dass der Wheel systematisch Verluste realisiert |
|
||||
| Max. Kontrakte je Ticker | 1 | Bewusst klein starten |
|
||||
| Max. gebundenes Cash gesamt | Anteil des Kontowerts | Zweite Grenze über die Core-Limits hinaus |
|
||||
| Vorzeitiges Schließen bei Gewinnziel | **aus** | Nicht gewählt – siehe Hinweis unten |
|
||||
|
||||
> **Hinweis zum Gewinnziel:** Der übliche Begleiter der Roll-Politik ist, ein Leg bei ~50 % vereinnahmter
|
||||
> Prämie zurückzukaufen; das nimmt Gamma-Risiko aus der letzten Woche und ist der Grund, warum viele
|
||||
> Roll-Trigger nie greifen. Der Parameter ist vorgesehen (`ProfitTargetPercent` existiert bereits in
|
||||
> `TradingSettings`), steht per Vorgabe auf „aus" und lässt sich ohne Codeänderung zuschalten.
|
||||
|
||||
> **Zuteilung ist nicht abwählbar.** Auch bei konsequentem Rollen teilt IBKR zu – amerikanische Optionen
|
||||
> können jederzeit ausgeübt werden, beim Call besonders vor dem Ex-Dividenden-Tag, und ein Roll ist nicht
|
||||
> immer per Netto-Kredit möglich. Zuteilung ist deshalb ein **regulärer Pfad** des Automaten, kein Fehler.
|
||||
> Genau dafür ist der Positionsabgleich (2.5) Pflicht.
|
||||
|
||||
---
|
||||
|
||||
## 5. Sicherungen
|
||||
Zu den bestehenden zwei Schaltern (`IBKR.UseTwsApi`, `Trading.TradingEnabled`) kommen:
|
||||
1. `OptionsWheel.Enabled` – Modulschalter.
|
||||
2. **Watchlist als Whitelist** – kein Ticker außerhalb.
|
||||
3. **Naked-Sperre im Core-`RiskService`** (2.6) – wirkt auch, wenn die Modullogik falsch liegt.
|
||||
4. `Halted` je Ticker bei unerklärter Positionsabweichung; Neueröffnungen stoppen, bestehende Legs
|
||||
werden weiter verwaltet.
|
||||
5. Kill-Switch „keine Neueröffnungen" – laufende Positionen bleiben handhabbar.
|
||||
|
||||
---
|
||||
|
||||
## 6. Phasen
|
||||
|
||||
| Phase | Inhalt | Abschlusskriterium |
|
||||
|---|---|---|
|
||||
| **W-0** | Core: `InstrumentKind`/`OptionSpec`, `IbkrMapping.Option`, Positionen mit Multiplikator | Build + Tests grün, Aktienpfad unverändert |
|
||||
| **W-1** | Core: Optionskette + Greeks (`reqSecDefOptParams`, `tickOptionComputation`) | Kette eines Watchlist-Tickers gegen das Paper-Gateway abrufbar |
|
||||
| **W-2** | Core: asynchrone Order-/Fill-Verfolgung (`core_order_state`, `OrderTrackingService`) | Limitorder überlebt Timeout und App-Neustart, Fill wird nachgebucht |
|
||||
| **W-3** | Core: Positionsabgleich + `RiskService` sell-to-open/Deckung | Zuteilung im Paper erkannt und gebucht; ungedeckte Order wird abgelehnt |
|
||||
| **W-4** | Modul-Gerüst: `IModule`, `ow_`-DbContext + Migration, UI-Tabs, Watchlist | App startet, `--smoke-ui` grün, kein Handel |
|
||||
| **W-5** | Reine Strategie-Logik + Tests (StrikeSelector, StateMachine, RollDecider, PremiumMath) | Hohe Testabdeckung ohne Broker |
|
||||
| **W-6** | Verdrahtung + vollautomatischer Paper-Betrieb, Beobachtung über mehrere Verfallszyklen | Mindestens ein vollständiger Wheel-Durchlauf im Paper |
|
||||
| **W-7** | Live-Freigabe | Eigene Entscheidung nach W-6 |
|
||||
|
||||
W-0 bis W-3 sind Core-Arbeit und nützen auch den anderen Modulen; erst ab W-4 entsteht das Modul selbst.
|
||||
|
||||
---
|
||||
|
||||
## 7. Bewusst offen / zu klären
|
||||
1. ~~**Optionsberechtigung im Paper-Konto DUR371528 prüfen**~~ → **erledigt am 2026-08-04, vorhanden.**
|
||||
Verifiziert gegen das laufende Gateway (Details siehe [IBKR-Integration.md](../IBKR-Integration.md),
|
||||
Abschnitt „Optionen"): `reqSecDefOptParams` für AAPL liefert 24 Verfallstermine, 127 Strikes,
|
||||
Multiplier 100 über SMART; eine **What-If-Order** auf `AAPL 20260812 C302.5` wurde von IBKR
|
||||
angenommen (Init-Margin 589,52) statt mit einem Berechtigungsfehler abgelehnt.
|
||||
Damit ist die Grundvoraussetzung für dieses Modul gegeben.
|
||||
2. **Greeks bei verzögerten Daten.** `MarketDataType = 4` liefert Optionsberechnungen als verzögerte
|
||||
Tick-Variante; ob Delta zuverlässig ankommt, muss gegen das laufende Gateway verifiziert werden.
|
||||
Fällt es aus, greift ersatzweise eine Strike-Wahl über Abstand in % + Mindestprämie – der
|
||||
`StrikeSelector` wird von vornherein so geschnitten, dass beide Kriterien einsetzbar sind.
|
||||
3. **Marktdatenabo (OPRA)** für Realtime-Optionskurse – Kosten/Notwendigkeit später entscheiden.
|
||||
4. **Earnings-Sperre**: keine neuen Legs über Quartalszahlen hinweg. Sinnvoll, aber es fehlt eine
|
||||
Datenquelle für Earnings-Termine – Punkt bewusst offen.
|
||||
5. **Accounting-Anschluss**: Optionsprämien, Zuteilungen und Abrufe müssen im `AccountingClassifier`
|
||||
eigene Buchungskategorien bekommen; der `RealizedPnlEngine` (FIFO) kennt weder Multiplikator noch
|
||||
die Einstandsverschiebung durch Zuteilung. Eigene Arbeit im Accounting-Modul.
|
||||
6. **Steuer** bleibt wie im Accounting-Konzept unberührt und offen. Keine Steuerberatung.
|
||||
Reference in New Issue
Block a user