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>
149 lines
12 KiB
Markdown
149 lines
12 KiB
Markdown
# IBKRTrader – Architektur & Implementierungsplan
|
||
|
||
> **KORRIGIERT (2026-07-27):** Vorbild ist **PolytraderSharp** (`J:\Softwareprojekte\PolytraderSharp`),
|
||
> die C#-Neuentwicklung – **nicht** die veraltete Python-Version. Die frühere Fassung dieses Plans
|
||
> basierte auf der Python-Vorlage und war konzeptionell falsch. Ziel ist eine **1:1-Neu-Fundamentierung**
|
||
> nach PolytraderSharp, im bestehenden IBKRTrader-Repo.
|
||
|
||
Ziel: modulares C#-Trading-Framework für Interactive-Brokers-Aktien, strukturell wie PolytraderSharp,
|
||
nur dass statt Polymarket über IBKR gehandelt wird.
|
||
|
||
---
|
||
|
||
## 1. Ziel-Architektur (nach PolytraderSharp)
|
||
|
||
```
|
||
IBKRTrader.App (WinExe, Root) – Generic Host + Shell (Launcher) + Core-Views
|
||
│ Program.cs: Host.CreateDefaultBuilder, IConfiguration, Module laden, ShellUiHost, Application.Run
|
||
│ Ui/: LauncherForm, ShellUiHost, Views/ (Dashboard, Terminal, Settings, Jobs)
|
||
│
|
||
├── src/IBKRTrader.Core (classlib, net10.0-windows, UseWindowsForms)
|
||
│ ├── Modularity/ IModule (Name, DbPrefix, RegisterServices, RegisterUi, Start/Stop, ActivationBlocker)
|
||
│ │ ModuleView, IModuleUiHost, WindowMenu ← UI-Contract liegt im Core
|
||
│ ├── Configuration/ DatabaseOptions, ServerVersion-Pinning
|
||
│ ├── DependencyInjection/ AddCorePersistence(...)
|
||
│ ├── Persistence/Ef/ CoreDbContext + Entities + EF-Repositories (hinter Interfaces)
|
||
│ ├── Trading/ Broker-Seam, Risk, Execution, Portfolio, Domänentypen
|
||
│ ├── Services/ TerminalLogger, JobManager, Hosted Services (Market-Sync etc.)
|
||
│ ├── Security/ SecretProtection (Master-Key, AES-256-GCM at-rest)
|
||
│ └── Hosting/ StartupHydrationService (IHostedService, hydriert State zuerst)
|
||
│
|
||
├── src/IBKRTrader.Modules.CongressTrading (classlib, referenziert NUR Core)
|
||
│ ├── CongressTradingModule : IModule
|
||
│ ├── Persistence/Ef/ eigener DbContext (ct_) + Repos
|
||
│ ├── Services/ Scraper + Jobs (IHostedService)
|
||
│ └── Ui/ CongressTradingMainForm (Tabs) via RegisterUi
|
||
│
|
||
└── tests/IBKRTrader.Tests (xUnit, referenziert Core + Module)
|
||
```
|
||
|
||
### Leitprinzipien (aus PolytraderSharp übernommen)
|
||
- **Multi-Projekt**: Core = eigenes Assembly; jedes Modul = eigenes Projekt, referenziert **nur** Core.
|
||
Module können einander physisch nicht referenzieren.
|
||
- **Generic Host**: `Host.CreateDefaultBuilder`, `IHostedService` für alle Hintergrund-Jobs,
|
||
`IOptions`/`IConfiguration`.
|
||
- **Config**: `appsettings.json` + `appsettings.Local.json` (gitignored, hält Connection-String/Secrets).
|
||
- **Modul-Vertrag** `IModule`: `Name`, `DbPrefix`, `RegisterServices(services, config)`,
|
||
`RegisterUi(host, sp)`, `StartAsync/StopAsync`, `GetActivationBlocker(config)`.
|
||
- **UI = Shell + Views**: Core und Module registrieren `ModuleView`s beim `IModuleUiHost`.
|
||
Der Launcher öffnet je View ein Fenster (Einzelinstanz, Re-Open fokussiert). Gemeinsames
|
||
„Fenster"-Menü (`WindowMenu`) auf jedem Form. Views sind designbare Forms mit `Initialize(sp)`.
|
||
- **Persistenz**: EF Core (Pomelo/MySQL), `AddDbContextFactory`, Repositories hinter Interfaces.
|
||
- **Sicherheit**: Master-Key + AES-256-GCM-Verschlüsselung von Credentials at-rest; TLS-Warnung.
|
||
- **Headless-Test**: `--smoke-ui` konstruiert jede View + Launcher ohne Message-Loop.
|
||
- **Module an/aus** über `ServerSettings.DisabledModules`.
|
||
|
||
---
|
||
|
||
## 2. Was aus dem bisherigen Stand übernommen wird
|
||
|
||
| Bestand (Phase 0–3, Python-basiert) | Schicksal |
|
||
|---|---|
|
||
| Testprojekt (xUnit) | bleibt, wandert nach `tests/` |
|
||
| `RiskService`, `ExecutionService`, Domänentypen | Logik bleibt → Core/Trading (Feinschliff) |
|
||
| CongressTrading Scraper/Repo | Inhalt bleibt → eigenes Modul-Projekt (auf EF/IHostedService umgestellt) |
|
||
| `IModule`/`ModuleRegistry`/`WindowManager` | ersetzt durch PolytraderSharp-Contract (`IModule` neu, `ModuleView`, `IModuleUiHost`, `WindowMenu`) |
|
||
| Manuelles `ServiceCollection` in Program.cs | ersetzt durch Generic Host |
|
||
| `settings.json`/`SettingsService` | ersetzt durch `IConfiguration` + `appsettings.Local.json` |
|
||
| Dapper + manuelle Migrationen | ersetzt durch EF Core |
|
||
| `WorkerEngine`/`IWorker` | ersetzt durch `IHostedService` |
|
||
|
||
---
|
||
|
||
## 3. Re-Fundamentierungs-Phasen (Checkliste)
|
||
|
||
### R1 – Solution-Skelett (Multi-Projekt, reiner Strukturumbau, Verhalten unverändert) ✅
|
||
- [x] `src/IBKRTrader.Core` (classlib, UseWindowsForms) – `Core/` + UI-Contract (`Ui/ModuleFormBase`, `Ui/WindowManager`)
|
||
- [x] `src/IBKRTrader.Modules.CongressTrading` (classlib, referenziert nur Core)
|
||
- [x] Root-Projekt → `IBKRTrader.App` (WinExe), referenziert Core + Modul; Program/LauncherForm/UI-Shell bleiben
|
||
- [x] `tests/IBKRTrader.Tests` – Referenzen auf Core + Modul; Fixture-Pfad angepasst
|
||
- [x] Neue `.slnx`; ungenutztes HtmlAgilityPack entfernt; Build + **38/38 Tests grün**; App startet
|
||
|
||
### R2 – Core-Contracts + Generic Host + Shell-UI ✅
|
||
- [x] `IModule` (PolytraderSharp-Stil) + `ModuleView` + `IModuleUiHost` + `WindowMenu` in Core
|
||
- [x] `Program.cs` → `Host.CreateDefaultBuilder`; `IConfiguration` (appsettings.json + appsettings.Local.json, gitignored)
|
||
- [x] `ShellUiHost` + `LauncherForm` (View-Buttons + gemeinsames Fenster-Menü); Core-Views (Workers/Logs/Settings) als eigene Fenster
|
||
- [x] CongressTrading auf neuen `IModule`-Vertrag; Modul-Worker als `IWorker` registriert
|
||
- [x] `--smoke-ui` Headless-Test (alle Views + Launcher konstruieren) → grün
|
||
- [ ] **Offen (R4/R5):** Worker von `WorkerEngine`/`IWorker` auf `IHostedService` umstellen (aktuell noch WorkerEngine)
|
||
|
||
### R3 – Persistenz auf EF Core
|
||
**Festgelegt:** EF-Migrationen **extern** (wie PolytraderSharp) – Schema per `dotnet ef database update`,
|
||
App legt keine Tabellen zur Laufzeit an. Server: **MariaDB 11.8.6** (via `--db-version` bestätigt) →
|
||
Pin `new MariaDbServerVersion(new Version(11, 8, 6))`. Verbindung aus `appsettings.Local.json`.
|
||
- [x] `--db-version`-Diagnose (Serverversion für den EF-Pin)
|
||
- [x] **Slice 1:** `Configuration/DatabaseOptions` + `DatabaseServerVersion`-Pin (MariaDB 11.8.6); `AddCorePersistence` (`AddDbContextFactory`) + `CoreDbContext` + Entities (core_position, core_trade_history, core_budget, core_worker_log, core_settings) + Design-Time-Factory; **EF-Migration `InitialCore` erzeugt**
|
||
- [x] **Slice 2:** `PortfolioService`, `BudgetService`, `TradeHistoryService` auf EF (`IDbContextFactory<CoreDbContext>`) umgestellt; **5 EF-InMemory-Unit-Tests** (Buchführung real verifiziert). WorkerBase-Log folgt in Slice 4.
|
||
- [x] **Slice 3:** Modul auf EF (`CongressTradingDbContext` ct_ + `CongressRepository`); `WorkerBase`-Log auf EF (core_worker_log); `CoreSettingsService` (core_settings); `CoreMigrations`/`CongressMigrations` (Dapper) entfernt; EF-Migration `InitialCongressTrading`; `appsettings.Local.json` (gitignored) als Connection-Quelle; Fallback für leeren Connection-String. **+4 EF-InMemory-Tests** (CongressRepository)
|
||
- [x] **Slice 4:** IBKR-Marktdaten (`core_ibkr_*`) auf EF (3 Entities im `CoreDbContext`, Cross-Modul-Query via Raw-SQL); Migration `AddIbkr`; **Dapper + `DatabaseService` + `IBKRMigrations` vollständig entfernt** – Persistenz ist jetzt **komplett EF Core**. +4 EF-InMemory-Tests.
|
||
|
||
**R3 abgeschlossen** ✅ – gesamte Persistenz auf EF Core (Migrationen: `InitialCore`, `AddIbkr`, `InitialCongressTrading`), extern via `dotnet ef database update` anzuwenden.
|
||
- Hinweis: nur build-verifizierbar (Unit-Tests ohne DB); Schema-Anwendung extern via `dotnet ef database update` (env `IBKRTRADER_MYSQL`)
|
||
|
||
### R4 – Worker auf `IHostedService` ✅
|
||
- [x] `WorkerBase` implementiert `IHostedService`; `IWorker` auf Metadaten+Trigger reduziert
|
||
- [x] Worker via `AddHostedService` registriert; Lebenszyklus über `AppHost.Start()`/`StopAsync()`
|
||
- [x] `WorkerEngine` auf leichte Registry reduziert (WorkerInfos für UI + `TriggerWorkerAsync`)
|
||
- [x] `LauncherForm` startet/stoppt keine Worker mehr; Build + 43/43 Tests + smoke-ui + App-Start grün
|
||
- Hinweis: Trading-Kern (Risk/Execution/Portfolio/Broker) wurde bereits in Phase 3 gebaut und in R3 auf EF gehoben
|
||
|
||
### R5 – CongressTrading als vollständige Strategie ✅
|
||
- [x] `CongressTradingStrategy`: neuer Scrape-Trade → `TradeSignal` (buy/sell-Mapping) → Core-`IExecutionService`
|
||
- [x] `CongressScrapeWorker` ruft die Strategie je neuem Trade auf (per try/catch isoliert)
|
||
- [x] Modul-Fenster zeigt offene Positionen (`IPortfolioService.GetPositionsAsync("CT")`)
|
||
- [x] **8 neue Tests** (Signal-Mapping/Ausführung, gemockter ExecutionService) → 51/51 grün
|
||
- Hinweis: Handel bleibt durch Trading-Gate (`TradingEnabled=false`) + `NullBrokerClient` sicher aus, bis echter Broker + Freigabe
|
||
|
||
### R6 – Sicherheit + Config-Härtung ✅
|
||
- [x] `SecretProtection` (Master-Key aus env `IBKRTRADER_MASTER_KEY`/`master.key`, AES-256-GCM at-rest, selbstheilendes `enc:v1:`-Format) + `EncryptedStringConverter` (bereit für künftige IBKR-Credentials)
|
||
- [x] `ConfigureSecretProtection` + TLS-Warnung (`SslMode`) beim Start; `master.key` gitignored
|
||
- [x] Connection-String in `appsettings.Local.json` (gitignored)
|
||
- [x] **5 SecretProtection-Tests** (Round-Trip, Idempotenz, Passthrough, Tamper/Key-Fehler) → 56/56 grün
|
||
- [ ] **Offen (Nutzer-Aktion):** geleaktes DB-Passwort rotieren (liegt in Git-Historie via `grundregeln.md`, Commit `ebeb035`); EF-Schema per `dotnet ef database update` auf die DB anwenden
|
||
|
||
### R7 – Feinschliff ✅
|
||
- [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
|
||
- [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**
|
||
- [x] **`IBrokerPortfolioReader`** (Bestand + Ausführungen beim Broker) – eigener Seam neben `IBrokerClient`, Grundlage für den Abgleich der eigenen Buchführung; gegen DUR371528 verifiziert (2 Positionen, 2 Ausführungen inkl. Kommissionen)
|
||
- [ ] **Offen:** `PlaceOrderAsync` mit echter Ausführung verifizieren (Fill → Buchung); asynchrone Fill-Verfolgung (Orders ohne sofortige Ausführung)
|
||
- [ ] IBKR-Account-Credentials mit `EncryptedStringConverter` speichern
|
||
|
||
---
|
||
|
||
## Kurskorrektur abgeschlossen (R1–R7)
|
||
IBKRTrader entspricht jetzt strukturell dem PolytraderSharp-Konzept: Multi-Projekt (Core + Modul + App + Tests),
|
||
Generic Host + `IHostedService`, `IConfiguration`, `IModule`/`ModuleView`/`ShellUiHost`, EF Core (extern migriert),
|
||
Trading-Kern (Risk/Execution/Portfolio, `NullBroker`-Default), CongressTrading-Strategie, Security (Master-Key/AES-GCM).
|
||
**Offen für später:** echte IBKR-Broker-Anbindung (Paper-Gateway), DB-Passwort-Rotation, EF-Schema anwenden.
|
||
|
||
---
|
||
|
||
## 4. Historie (bereits erledigt, teils zu ersetzen)
|
||
- Phase 0–3 (Python-basiert): Testfundament, IModule/ModuleRegistry, LauncherForm+WindowManager,
|
||
Trading-Kern (Risk/Execution/Portfolio, NullBroker). Logik brauchbar, Infrastruktur wird ersetzt.
|
||
- Commits bis `2ad4b55` auf Gitea.
|