@
Phase 0: Test-Fundament & Architektur-Doku - IBKRTrader.Tests (xUnit + NSubstitute + FluentAssertions), nur Unit-Tests - Repo-lokale NuGet.config: Test-Pakete in Allowlist ergaenzt - Hauptprojekt: Test-Unterordner aus SDK-Globbing ausgeschlossen - docs/ARCHITECTURE.md: Plan + Phasen-Checkliste - grundregeln.md: .NET 10, Launcher-Modell; DB-Passwort entfernt Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> @
This commit is contained in:
@@ -3,7 +3,8 @@ trigger: always_on
|
|||||||
---
|
---
|
||||||
|
|
||||||
Projektname: IBKRTrader
|
Projektname: IBKRTrader
|
||||||
Ziel: Modulares, hochperformantes C# Trading-Framework (.NET 8) für automatische Aktien-Strategien mit Interactive Brokers API.
|
Ziel: Modulares, hochperformantes C# Trading-Framework (.NET 10) für automatische Aktien-Strategien mit Interactive Brokers API.
|
||||||
|
Vorbild-Konzept: Polytrader (Core + unabhängige Module + Launcher, der die Fenster der einzelnen Module öffnet).
|
||||||
Strikte Architektur-Regeln (immer einhalten):
|
Strikte Architektur-Regeln (immer einhalten):
|
||||||
|
|
||||||
Harter Core + beliebig viele unabhängige Module
|
Harter Core + beliebig viele unabhängige Module
|
||||||
@@ -16,16 +17,21 @@ Keine gegenseitigen Blockierungen – alles thread-sicher und performant
|
|||||||
|
|
||||||
Technik (fest):
|
Technik (fest):
|
||||||
|
|
||||||
C# .NET 8 WinForms
|
C# .NET 10 WinForms
|
||||||
MySQL (bergisnu_db0 / bergisnu_0 / o5/A49+f}:Da / larx.your-database.de)
|
MySQL – Zugangsdaten NUR in settings.json (gitignored), NIE im Repo/Code/Doku hinterlegen
|
||||||
IBKR TWS/Gateway API
|
IBKR TWS/Gateway API (Paper: Port 4002, Live: Port 4001 – Umschaltung über TradingSettings.Mode)
|
||||||
Interne REST-API + lokaler Webserver (für späteres Web-UI)
|
Interne REST-API + lokaler Webserver (für späteres Web-UI)
|
||||||
Settings: settings.json + SettingsWorker.json
|
Settings: settings.json (Vorlage: settings.example.json)
|
||||||
Logging: RichTextBox (rtb_logs) + Dateien unter Logs\[Modul]\[Level]-dd-MM-yy.txt (Info/Warn/Error)
|
Logging: RichTextBox (rtb_logs) + Dateien unter Logs\[Modul]\[Level]-dd-MM-yy.txt (Info/Warn/Error)
|
||||||
|
Tests: eigenes Projekt IBKRTrader.Tests (xUnit + NSubstitute + FluentAssertions), NUR Unit-Tests,
|
||||||
|
alles Externe (DB/IBKR/Scraper) gemockt. DoD jeder Phase: `dotnet test` grün + Build sauber.
|
||||||
|
|
||||||
Bereits vorhandene UI-Elemente (müssen verwendet werden):
|
UI-Grundmodell (Launcher-Prinzip nach Polytrader):
|
||||||
|
|
||||||
TabControl mit Tabs: Dashboard, Trade History, Settings (PropertyGrid), Logs (rtb_logs), Workers/Services (dgv_workerlist), CongressTrading
|
LauncherForm = Basis-Fenster. Enthält: Core-Status/Steuerung ("Trading aktivieren", Paper/Live),
|
||||||
|
Workers/Services (dgv_workerlist), Logs (rtb_logs), Settings (PropertyGrid) und eine Modul-Liste.
|
||||||
|
Jedes Modul wird als EIGENSTÄNDIGES Fenster aus dem Launcher geöffnet (nicht als Tab).
|
||||||
|
Der Launcher trackt offene Fenster (Key → Form) und fokussiert bei erneutem Öffnen.
|
||||||
dgv_workerlist Spalten: Active | Type | Module | Workername | Last Runtime | Next Runtime | Run Every | Info
|
dgv_workerlist Spalten: Active | Type | Module | Workername | Last Runtime | Next Runtime | Run Every | Info
|
||||||
Type = "Worker" oder "Service" (Service = permanent laufend)
|
Type = "Worker" oder "Service" (Service = permanent laufend)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- net10.0-windows + WinForms, weil das Testprojekt die WinForms-Hauptassembly referenziert -->
|
||||||
|
<TargetFramework>net10.0-windows</TargetFramework>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||||
|
<PackageReference Include="xunit" Version="2.9.3" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
|
||||||
|
<PackageReference Include="NSubstitute" Version="5.3.0" />
|
||||||
|
<PackageReference Include="FluentAssertions" Version="7.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\IBKRTrader.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Xunit" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using IBKRTrader.Core.Settings;
|
||||||
|
using IBKRTrader.Core.Workers;
|
||||||
|
|
||||||
|
namespace IBKRTrader.Tests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Phase-0-Smoke-Test: bestätigt, dass die Test-Infrastruktur steht und die
|
||||||
|
/// Referenz auf die Hauptassembly (IBKRTrader) kompiliert und lädt.
|
||||||
|
/// </summary>
|
||||||
|
[Trait("cat", "unit")]
|
||||||
|
public class SmokeTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void MainAssembly_IsReferenced_AndDefaultsLoad()
|
||||||
|
{
|
||||||
|
var settings = new AppSettings();
|
||||||
|
|
||||||
|
settings.Should().NotBeNull();
|
||||||
|
settings.IBKR.Should().NotBeNull();
|
||||||
|
settings.Logging.Level.Should().Be("Info");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WorkerType_HasWorkerAndService()
|
||||||
|
{
|
||||||
|
Enum.GetNames<WorkerType>().Should().Contain(["Worker", "Service"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,9 @@
|
|||||||
<!-- Nur englische Satellitenassemblies – kein Sprachmüll im Build-Ordner -->
|
<!-- Nur englische Satellitenassemblies – kein Sprachmüll im Build-Ordner -->
|
||||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
|
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
|
||||||
|
<!-- Test-Projekt liegt in einem Unterordner: aus dem rekursiven SDK-Globbing des
|
||||||
|
Hauptprojekts ausschließen, sonst kompiliert IBKRTrader die Testdateien mit. -->
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);IBKRTrader.Tests\**</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
<Solution>
|
<Solution>
|
||||||
<Project Path="IBKRTrader.csproj" />
|
<Project Path="IBKRTrader.csproj" />
|
||||||
|
<Project Path="IBKRTrader.Tests/IBKRTrader.Tests.csproj" />
|
||||||
</Solution>
|
</Solution>
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Repo-lokale NuGet-Konfiguration.
|
||||||
|
Die globale NuGet.Config des Nutzers nutzt packageSourceMapping (Allowlist).
|
||||||
|
packageSourceMapping wird NICHT über Config-Dateien gemerged: die projektnächste
|
||||||
|
Datei ersetzt die Zuordnung vollständig. Deshalb hier die App-Pakete UND die
|
||||||
|
Test-Pakete gemeinsam auf nuget.org gemappt (Allowlist-Ansatz bleibt erhalten).
|
||||||
|
-->
|
||||||
|
<configuration>
|
||||||
|
<packageSources>
|
||||||
|
<clear />
|
||||||
|
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||||
|
</packageSources>
|
||||||
|
<packageSourceMapping>
|
||||||
|
<packageSource key="nuget.org">
|
||||||
|
<!-- App-Pakete -->
|
||||||
|
<package pattern="MySqlConnector" />
|
||||||
|
<package pattern="Dapper" />
|
||||||
|
<package pattern="HtmlAgilityPack" />
|
||||||
|
<package pattern="Newtonsoft.Json" />
|
||||||
|
<!-- Test-Pakete -->
|
||||||
|
<package pattern="xunit*" />
|
||||||
|
<package pattern="NSubstitute" />
|
||||||
|
<package pattern="Castle.Core" />
|
||||||
|
<package pattern="FluentAssertions" />
|
||||||
|
<package pattern="coverlet.*" />
|
||||||
|
<package pattern="Microsoft.CodeCoverage" />
|
||||||
|
<package pattern="Microsoft.TestPlatform.*" />
|
||||||
|
<!-- Framework / Extensions / Runtime -->
|
||||||
|
<package pattern="Microsoft.Extensions.*" />
|
||||||
|
<package pattern="Microsoft.NET.*" />
|
||||||
|
<package pattern="Microsoft.NETCore.*" />
|
||||||
|
<package pattern="Microsoft.WindowsDesktop.*" />
|
||||||
|
<package pattern="Microsoft.AspNetCore.*" />
|
||||||
|
<package pattern="Microsoft.Bcl.*" />
|
||||||
|
<package pattern="Microsoft.Win32.*" />
|
||||||
|
<package pattern="System.*" />
|
||||||
|
<package pattern="runtime.*" />
|
||||||
|
<package pattern="NETStandard.*" />
|
||||||
|
</packageSource>
|
||||||
|
</packageSourceMapping>
|
||||||
|
</configuration>
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
# IBKRTrader – Architektur & Implementierungsplan
|
||||||
|
|
||||||
|
Umbau von IBKRTrader auf das **Polytrader-Grundprinzip**:
|
||||||
|
**harter Core + beliebig viele unabhängige Module + ein Launcher, der die Fenster der
|
||||||
|
einzelnen Module öffnet.** Statt Polymarket wird über Interactive Brokers gehandelt.
|
||||||
|
|
||||||
|
> Polytrader dient als *konzeptionelle* Vorlage (Python/FastAPI + tkinter-Launcher + Web-UI),
|
||||||
|
> nicht als Code-Vorlage. IBKRTrader ist ein C#/.NET-10-WinForms-Framework.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Zielarchitektur
|
||||||
|
|
||||||
|
```
|
||||||
|
Program.cs (DI-Bootstrap)
|
||||||
|
│
|
||||||
|
├── CORE (harter Kern – kennt KEIN Modul)
|
||||||
|
│ ├── Settings AppSettings + settings.json
|
||||||
|
│ ├── Logging rtb + Logs/[Modul]/[Level]
|
||||||
|
│ ├── Database MySQL/Dapper + Migrationen (core_)
|
||||||
|
│ ├── IBKR Marktdaten [vorhanden] + Orders [neu]
|
||||||
|
│ ├── Portfolio Positionen/Balance/P&L (core_) [neu]
|
||||||
|
│ ├── Execution + Risk Signal → Prüfung → Order → Buchung [neu]
|
||||||
|
│ ├── Workers WorkerEngine + Core-Worker
|
||||||
|
│ └── Modules IModule-Vertrag + ModuleRegistry [neu]
|
||||||
|
│
|
||||||
|
├── MODULES (unabhängige Strategien – Abhängigkeit nur Modul → Core)
|
||||||
|
│ └── CongressTrading Scraper + Repo + Worker [vorhanden]
|
||||||
|
│ + Strategie + Fenster [neu]
|
||||||
|
│
|
||||||
|
└── UI
|
||||||
|
├── LauncherForm Basis: Core-Status, Worker-Grid, Logs, Settings,
|
||||||
|
│ Modul-Liste mit „Fenster öffnen"-Buttons
|
||||||
|
└── ModuleFormBase Basisklasse für eigenständige Modul-Fenster
|
||||||
|
```
|
||||||
|
|
||||||
|
### Kernregeln (siehe auch `.agents/rules/grundregeln.md`)
|
||||||
|
- Core kennt kein Modul. Module hängen sich über DI + `IModule` ein. Abhängigkeit nur Modul → Core.
|
||||||
|
- DB-Tabellen: `{ModulKürzel}_name` (Core = `core_`, CongressTrading = `ct_`).
|
||||||
|
- Jeder Worker ist unabhängig ein-/ausschaltbar, hat eigenen Zeitplan, ist manuell triggerbar.
|
||||||
|
- **Strategie lebt im Modul, nicht im Core.** Der Core stellt nur Primitive bereit
|
||||||
|
(Orders, Portfolio, Risiko); das Modul liefert nur ein `TradeSignal` an den `ExecutionService`.
|
||||||
|
|
||||||
|
### Festgelegte Entscheidungen
|
||||||
|
| Thema | Festlegung |
|
||||||
|
|---|---|
|
||||||
|
| Modul-Fenster | Eigenständige Top-Level-Fenster; Launcher trackt `Key → Form`, fokussiert bei Re-Open |
|
||||||
|
| Demo-Betrieb | IBKR **Paper-Account** (Port 4002); Umschaltung Paper/Live via `TradingSettings.Mode` |
|
||||||
|
| Tests | `IBKRTrader.Tests` (xUnit + NSubstitute + FluentAssertions), **nur Unit**, alles Externe gemockt |
|
||||||
|
| DoD je Phase | `dotnet test` (Unit) grün **und** Build sauber |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Abbildung Polytrader → IBKRTrader
|
||||||
|
|
||||||
|
| Polytrader | Rolle | IBKRTrader |
|
||||||
|
|---|---|---|
|
||||||
|
| `main.py` + `api/server.py` lifespan | Entry-Point, Orchestrierung, Background-Loops | `Program.cs` (DI) + `WorkerEngine` |
|
||||||
|
| `config.py` | zentrale Config | `SettingsService` / `AppSettings` |
|
||||||
|
| `database/` | Buchführung | `DatabaseService` + Migrationen + Repos |
|
||||||
|
| `polymarket_client.py` | Plattform-Anbindung | `IIbkrClient` (Marktdaten + Orders) |
|
||||||
|
| `trade_manager.py` | Positionen/Balance/P&L | `PortfolioService` |
|
||||||
|
| `trade_engine.py` | Signal → Risiko → Order | `ExecutionService` + `RiskService` |
|
||||||
|
| `trader_monitor.py` | Datenquelle pollen → Signal | Modul-Worker (z. B. `CT-ScrapeWorker`) |
|
||||||
|
| `demo_wallet.py` | Handel ohne echtes Geld | IBKR Paper-Account |
|
||||||
|
| `desktop_gui.py` | Launcher-Fenster | `LauncherForm` |
|
||||||
|
| `frontend/` (Sidebar → Pages) | Ansichten | Launcher-Panels + je Modul ein Fenster |
|
||||||
|
| `telegram_notifier.py` | Benachrichtigungen | `NotificationService` (später) |
|
||||||
|
| `module_checker.py` | Integritätscheck | Startup-Self-Check (später) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Teststrategie
|
||||||
|
|
||||||
|
- Eigenes Projekt **`IBKRTrader.Tests`** (`net10.0-windows`), im `.slnx`.
|
||||||
|
- **Nur Unit-Tests**, deterministisch, schnell, laufen bei jedem Build/Commit.
|
||||||
|
- Externe Abhängigkeiten hinter Interfaces (`IIbkrClient`, `IOrderService`, `IPortfolioService`,
|
||||||
|
`IRiskService`, `ICongressRepository` …) → in Tests via **NSubstitute** gemockt.
|
||||||
|
- Echtes MySQL/IBKR-Paper/Scraping wird **manuell** je Meilenstein geprüft (nicht automatisiert).
|
||||||
|
|
||||||
|
| Komponente | Beispiel-Testfall |
|
||||||
|
|---|---|
|
||||||
|
| `RiskService` | Sizing bei 5 % Budget; Ablehnung bei Slippage; globaler Pause-Schalter blockt |
|
||||||
|
| `ExecutionService` | Signal → gemockte Risk/Order/Portfolio; Buchung & Ablehnungsgründe |
|
||||||
|
| `CapitolTradesScraper` | Parser gegen Fixture `ct_raw.html` (deterministisch, kein Netz) |
|
||||||
|
| `ModuleRegistry` / `IModule` | Registrierung, Worker-Sammlung, `CreateWindow` liefert Fenster |
|
||||||
|
| `WorkerBase` | Interval-Loop, Trigger, Fehler → `Status=Error`, Cancellation |
|
||||||
|
| `AppSettings` / `SettingsService` | Laden/Serialisieren, Paper/Live-Port-Auswahl (4002/4001) |
|
||||||
|
| `WindowManager` | Fenster-Tracking, Re-Open fokussiert bestehendes Fenster |
|
||||||
|
|
||||||
|
WinForms selbst wird **nicht** unit-getestet – Logik in Services/Manager halten, Forms dünn.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Phasenplan (Checkliste)
|
||||||
|
|
||||||
|
### Phase 0 – Fundament & Doku ✅
|
||||||
|
- [x] `grundregeln.md` auf .NET 10 + Launcher-Modell aktualisiert (+ DB-Passwort entfernt)
|
||||||
|
- [x] `docs/ARCHITECTURE.md` angelegt
|
||||||
|
- [x] `IBKRTrader.Tests` (xUnit + NSubstitute + FluentAssertions) angelegt, im `.slnx`
|
||||||
|
- [x] Repo-lokale `NuGet.config` (Test-Pakete in Allowlist ergänzt)
|
||||||
|
- [x] Erster Smoke-Test grün (`dotnet test` → 2/2 bestanden)
|
||||||
|
|
||||||
|
### Phase 1 – Modul-System formalisieren (Refactoring, kein Verhaltensänderung)
|
||||||
|
- [ ] `Core/Modules/IModule.cs` (`Key`, `DisplayName`, `Description`, `Version`, `RegisterServices`, `InitializeAsync`, `GetWorkers`, `CreateWindow`)
|
||||||
|
- [ ] `Core/Modules/ModuleRegistry.cs`
|
||||||
|
- [ ] `CongressTradingModule` → `IModule`
|
||||||
|
- [ ] `Program.cs` iteriert über Registry statt CongressTrading hart zu nennen
|
||||||
|
- [ ] Tests: `ModuleRegistry`, `WorkerBase`, `CapitolTradesScraper` (gegen `ct_raw.html`)
|
||||||
|
|
||||||
|
### Phase 2 – Launcher-UI + Modul-Fenster
|
||||||
|
- [ ] `Form1` → `LauncherForm`; Kern-Panels behalten (Workers, Logs, Settings, Core-Status)
|
||||||
|
- [ ] Modul-Panel: Liste aus `ModuleRegistry`, je Modul „Fenster öffnen"
|
||||||
|
- [ ] `UI/ModuleFormBase.cs` + `UI/WindowManager.cs` (Fenster-Tracking)
|
||||||
|
- [ ] `Modules/CongressTrading/UI/CongressTradingForm.cs` (erstes Modul-Fenster)
|
||||||
|
- [ ] Tests: `WindowManager`
|
||||||
|
|
||||||
|
### Phase 3 – Trading-Kern (Core)
|
||||||
|
- [ ] `Core/Trading/IIbkrClient.cs` (+ Adapter auf `IBKRGatewayService`)
|
||||||
|
- [ ] `Core/Trading/IOrderService.cs` + Implementierung (Market/Limit, Paper+Live)
|
||||||
|
- [ ] `Core/Trading/PortfolioService.cs` + Migrationen `core_position`, `core_trade`, `core_account_snapshot`
|
||||||
|
- [ ] `Core/Trading/RiskService.cs` (Sizing, Limits, Slippage, Profit-Target, globaler Pause-Schalter)
|
||||||
|
- [ ] `Core/Trading/ExecutionService.cs` (`TradeSignal` → Risiko → Order → Buchung)
|
||||||
|
- [ ] `TradingSettings` in `AppSettings` (Mode Paper/Live, Risikoparameter)
|
||||||
|
- [ ] Tests: `RiskService`, `ExecutionService` (voll gemockt)
|
||||||
|
|
||||||
|
### Phase 4 – CongressTrading als vollständige Strategie
|
||||||
|
- [ ] `CongressTradingStrategy`: neue Scrape-Trades → `TradeSignal` an `ExecutionService`
|
||||||
|
- [ ] Modul-Fenster: offene/geschlossene Positionen, P&L, Strategie-Ein/Aus, Parameter
|
||||||
|
- [ ] Tests: Signal-Erzeugung
|
||||||
|
|
||||||
|
### Phase 5 – Feinschliff (optional)
|
||||||
|
- [ ] `NotificationService` (Telegram o. Ä.) + periodische Reports
|
||||||
|
- [ ] Startup-Self-Check (analog `module_checker`)
|
||||||
|
- [ ] Dashboard-Panel im Launcher (Gesamt-Balance/P&L über alle Module)
|
||||||
Reference in New Issue
Block a user