Fruehjahrsputz: toter Code, ungenutzte Symbole, Dokumentenstand

Alles Entfernte war nachweislich ohne Aufrufer. Build, 198/198 Tests, Smoke-UI
und Daemon-Prueflauf sind vor und nach jedem Schritt gruen.

Code:
  - AIModelService: Platzhalter, der immer 0.5 lieferte. Im DI registriert,
    aber nie irgendwo injiziert. Ordner Core/AI faellt mit weg.
  - CtApiWrapper + CtMeta: JSON-Modelle fuer einen {data,meta}-Umschlag, den
    CapitolTrades nicht mehr liefert. Der Scraper deserialisiert seit laengerem
    direkt List<CtTrade>.
  - IBKRGatewayService: DisconnectAsync, InitBrokerageSessionAsync und
    SearchStocksBySymbolAsync. Der Dienst selbst bleibt - er versorgt
    Instrument-Sync, Kurshistorie und den Watchdog-Heartbeat.
  - Je eine Methode ohne Aufrufer: BudgetService.GetAvailableBudgetAsync,
    TradeHistoryService.GetRecentTradesAsync, CongressRepository.
    GetAllTradeIdsAsync und .ResetHistoryImportAsync, IbkrMapping.DefaultPortFor,
    SecretProtection.IsEncrypted.
  - CongressRepository bekam damit einen LoggingService injiziert, den es nicht
    mehr benutzt - Abhaengigkeit samt Konstruktorparameter raus.

Ressourcen:
  - 17 Symbole der WinForms-Oberflaeche entfernt. Das Wildcard-Muster im csproj
    nahm sie in die Binaerdatei auf, ViewIcons.cs bildet aber nur sieben
    Schluessel ab. Resources/ enthaelt jetzt genau die sieben.

NuGet-Allowlist:
  - Dapper und HtmlAgilityPack sind seit R3 bzw. R1 aus dem Projekt raus,
    Microsoft.WindowsDesktop.* seit L5. Muster entfernt.
  - MySqlConnector und Newtonsoft.Json stehen NUR transitiv in den
    Projektdateien und wurden zuerst mitentfernt - ein Restore in einen leeren
    Paket-Ordner scheiterte darauf mit NU1100. Beide wieder aufgenommen, jetzt
    mit Begruendung, damit der naechste Aufraeumlauf nicht dieselbe Falle tritt.

Dokumente an den tatsaechlichen Stand angeglichen:
  - ARCHITECTURE: R2 fuehrte die Umstellung auf IHostedService als offen, obwohl
    R4 sie erledigt hat. L6 und die Deploymentcenter-Phase fehlten ganz.
  - DC-Konzept: Schritte 0-8 standen auf "dieser Durchlauf", sind aber umgesetzt.
    Jetzt je Schritt der wirkliche Stand - inklusive der beiden Halbfertigen:
    Update-PRUEFUNG laeuft, das Anwenden hat keinen Aufrufer; die
    Release-Pipeline steht, ist aber nie gelaufen. P5 ist eingetreten.
  - Accounting und Supervisor trugen keinen Umsetzungsvermerk, obwohl beide
    Module gebaut sind. Vermerk nach dem Muster des Linux-Konzepts ergaenzt,
    mit dem, was jeweils offen bleibt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-08-23 12:25:03 +02:00
co-authored by Claude Opus 5
parent 0a72ea7e28
commit e1546bd1b1
33 changed files with 78 additions and 163 deletions
+5 -4
View File
@@ -13,10 +13,12 @@
</packageSources> </packageSources>
<packageSourceMapping> <packageSourceMapping>
<packageSource key="nuget.org"> <packageSource key="nuget.org">
<!-- App-Pakete --> <!-- App-Pakete. Beide stehen NUR transitiv in den Projektdateien: MySqlConnector kommt ueber
Pomelo, Newtonsoft.Json ueber die Testplattform. Ohne Eintrag scheitert ein Restore aus
leerem Cache mit NU1100 - auf einem Entwicklungsrechner unsichtbar, weil dort gecacht.
Am 2026-08-23 geprueft, indem beide entfernt und der Restore in einen leeren
Paket-Ordner wiederholt wurde; er schlug fehl. Nicht entfernen. -->
<package pattern="MySqlConnector" /> <package pattern="MySqlConnector" />
<package pattern="Dapper" />
<package pattern="HtmlAgilityPack" />
<package pattern="Newtonsoft.Json" /> <package pattern="Newtonsoft.Json" />
<!-- Offizielle TWS-C#-API (NuGet-Mirror) für den IBKR-Broker-Adapter --> <!-- Offizielle TWS-C#-API (NuGet-Mirror) für den IBKR-Broker-Adapter -->
<package pattern="IB.TWS.CSharpApi" /> <package pattern="IB.TWS.CSharpApi" />
@@ -55,7 +57,6 @@
<package pattern="Microsoft.Extensions.*" /> <package pattern="Microsoft.Extensions.*" />
<package pattern="Microsoft.NET.*" /> <package pattern="Microsoft.NET.*" />
<package pattern="Microsoft.NETCore.*" /> <package pattern="Microsoft.NETCore.*" />
<package pattern="Microsoft.WindowsDesktop.*" />
<package pattern="Microsoft.AspNetCore.*" /> <package pattern="Microsoft.AspNetCore.*" />
<package pattern="Microsoft.Bcl.*" /> <package pattern="Microsoft.Bcl.*" />
<package pattern="Microsoft.Win32.*" /> <package pattern="Microsoft.Win32.*" />
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

+29 -1
View File
@@ -97,7 +97,7 @@ src/IBKRTrader.Hosting (classlib, net10.0) AppHostBuilder + RunStartu
- [x] `ShellUiHost` + `LauncherForm` (View-Buttons + gemeinsames Fenster-Menü); Core-Views (Workers/Logs/Settings) als eigene Fenster - [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] CongressTrading auf neuen `IModule`-Vertrag; Modul-Worker als `IWorker` registriert
- [x] `--smoke-ui` Headless-Test (alle Views + Launcher konstruieren) → grün - [x] `--smoke-ui` Headless-Test (alle Views + Launcher konstruieren) → grün
- [ ] **Offen (R4/R5):** Worker von `WorkerEngine`/`IWorker` auf `IHostedService` umstellen (aktuell noch WorkerEngine) - [x] Worker von `WorkerEngine`/`IWorker` auf `IHostedService` umgestellt — **in R4 erledigt**, die Zeile stand hier bis zum 2026-08-23 faelschlich noch offen
### R3 Persistenz auf EF Core ### R3 Persistenz auf EF Core
**Festgelegt:** EF-Migrationen **extern** (wie PolytraderSharp) Schema per `dotnet ef database update`, **Festgelegt:** EF-Migrationen **extern** (wie PolytraderSharp) Schema per `dotnet ef database update`,
@@ -163,6 +163,34 @@ Anzeigegerät mehr und ist damit erstmals Teil der CI.
**Offen:** IB Gateway kopflos betreiben (IBC + Xvfb) eigene Baustelle, unabhängig vom Code; **Offen:** IB Gateway kopflos betreiben (IBC + Xvfb) eigene Baustelle, unabhängig vom Code;
LiveCharts2 kommt mit den neuen Modulen (Avalonia deshalb auf der 11er-Linie gepinnt). LiveCharts2 kommt mit den neuen Modulen (Avalonia deshalb auf der 11er-Linie gepinnt).
### L6 Namensgebung bereinigt ✅ (2026-08-07)
- [x] `IBKRTrader.App.Avalonia`**`IBKRTrader.App`**. Das Suffix gab es nur, solange daneben eine
WinForms-`IBKRTrader.App` stand; seit L5 ist die weg. Assembly, Wurzel-Namensraum und die
`avares://`-Ressourcen-URI sind mitgezogen, Git erkennt alles als Umbenennung.
- [x] Die `global::Avalonia`-Qualifizierungen entfallen sie waren nur nötig, weil der Namensraum
`IBKRTrader.App.Avalonia` das gleichnamige Paket verdeckte.
- [x] **Inhaltlich falsch gewordene Aussagen berichtigt** das waren die eigentlichen Überbleibsel,
nicht die Kommentare: `.agents/rules/grundregeln.md` schrieb weiterhin „C# .NET 10 WinForms",
RichTextBox-Logging, `LauncherForm` und `PropertyGrid` vor und hätte die Portierung Stück für
Stück rückgängig gemacht. Dazu Core-Kommentare (`LogEntry`, `IWorker`, `ModuleView`) und Doku.
### DC Deploymentcenter-Integration ✅ (2026-08-23)
Konzept und Begründung: [konzepte/KONZEPT-Deploymentcenter-Integration.md](konzepte/KONZEPT-Deploymentcenter-Integration.md).
Schritte 08 der dortigen Reihenfolge sind umgesetzt; der Stand je Schritt steht in §9 dieses Konzepts.
- [x] Lizenz (Sperrbetrieb statt Abbruch), Watchdog-Heartbeat, Fehler-Stream inkl. globaler
Ausnahmebehandler, Update-Prüfung mit `ReleaseCredentials`, `setup.json` + Release-Pipeline.
Einbauort ist `IBKRTrader.Hosting/Deploymentcenter/` den Host teilen sich Shell und Daemon.
- [x] Vier Projekt-Befunde vorab bereinigt: Zugangsdaten aus `AppSettings` (P1), `AppPaths`-Rückfall
unter Windows (P2), globale Handler (P3), Version zentral in `Directory.Build.props` (P4).
- [ ] **Offen (P5):** Die Gitea-CI checkt das Schwester-Repo `Deploymentcenter` nicht aus. Solange
das SDK als Cross-Repo-`ProjectReference` hängt, ist der CI-Lauf rot. Behebt sich mit
Schritt 10 (SDK als NuGet-Paket in der Gitea-Registry).
- [ ] **Offen (Schritt 9):** Bugtracker-Baustein setzt voraus, dass das Projekt `ibkrtrader` im
DC-WebUI angelegt ist und ein Token mit `bugtracker:report` vorliegt (serverseitige Handarbeit).
- [ ] **Offen:** Das Anwenden eines gefundenen Updates ist nicht verdrahtet. `DcUpdateService.LaunchAgent`
ist fertig und dokumentiert, es fehlt der Aufrufer, der danach geordnet herunterfährt.
--- ---
## Kurskorrektur abgeschlossen (R1R7) ## Kurskorrektur abgeschlossen (R1R7)
@@ -523,6 +523,9 @@ Packager, der genau das abfängt — kein Fehlschlag, sondern die Absicherung, d
## 8. Befunde und offene Punkte ## 8. Befunde und offene Punkte
> **Status 2026-08-23:** P1P4 sind umgesetzt (Einzelheiten in §9). **P5 ist eingetreten**,
> P6 entscheidet sich erst beim ersten Release. Der ursprüngliche Vermerk von 2026-08-14:
>
> **Status 2026-08-14:** Alle sieben ursprünglich an den Deploymentcenter-Entwickler > **Status 2026-08-14:** Alle sieben ursprünglich an den Deploymentcenter-Entwickler
> gemeldeten Befunde (D1D7) sind mit den Versionen 2.5.0/2.5.1 behoben — bestätigt über > gemeldeten Befunde (D1D7) sind mit den Versionen 2.5.0/2.5.1 behoben — bestätigt über
> `GET /api/updateservice/v1/changelog?since=2.4`. Der Abschnitt bleibt als Nachweis > `GET /api/updateservice/v1/changelog?since=2.4`. Der Abschnitt bleibt als Nachweis
@@ -567,6 +570,13 @@ ersten Release ab — zu Recht.
nur IBKRTrader aus. Eine `ProjectReference` nach `..\..\..\..\Deploymentcenter\…` nur IBKRTrader aus. Eine `ProjectReference` nach `..\..\..\..\Deploymentcenter\…`
macht den Build auf beiden Matrix-Zielen rot. Siehe die Entscheidung in §2.2. macht den Build auf beiden Matrix-Zielen rot. Siehe die Entscheidung in §2.2.
> **Seit 2026-08-23 eingetreten, nicht mehr nur vorhergesagt.** Die
> `ProjectReference` ist mit der Integration auf `main` gelandet, die CI ist
> damit rot. Das war die bewusst in Kauf genommene Folge der Interimslösung aus
> §2.2 — lokal baut die Projektmappe, sobald das Schwester-Repo daneben liegt.
> Auflösung ist Schritt 10: SDK als NuGet-Paket in die Gitea-Registry, dann
> `PackageReference` statt Cross-Repo-Pfad.
**P6 · Konfiguration liegt im Installationsverzeichnis.** Unter Windows schreibt **P6 · Konfiguration liegt im Installationsverzeichnis.** Unter Windows schreibt
`AppPaths` neben die Binärdatei. Das ist mit `preservePatterns` beherrschbar `AppPaths` neben die Binärdatei. Das ist mit `preservePatterns` beherrschbar
(§7.3), muss aber beim ersten Release stimmen — ein Update, das `settings.json` (§7.3), muss aber beim ersten Release stimmen — ein Update, das `settings.json`
@@ -627,16 +637,16 @@ nicht durchgängig beziffert). ✅ **Behoben (2.5.1, Doku)** — Changelog nennt
| Schritt | Inhalt | Abhängig von | Stand | | Schritt | Inhalt | Abhängig von | Stand |
|---|---|---|---| |---|---|---|---|
| 0 | **P1** Zugangsdaten wechseln, Vorgaben auf Platzhalter | — | ⬜ dieser Durchlauf | | 0 | **P1** Zugangsdaten wechseln, Vorgaben auf Platzhalter | — | ✅ Vorgaben sind Platzhalter. **Die Rotation des geleakten Passworts steht weiterhin aus** (Nutzer-Aktion) |
| 1 | **P2** `AppPaths`-Rückfall plattformabhängig, **P4** `Directory.Build.props` | — | ⬜ dieser Durchlauf | | 1 | **P2** `AppPaths`-Rückfall plattformabhängig, **P4** `Directory.Build.props` | — | ✅ 2026-08-23 |
| 2 | SDK-Bezug Stufe 1: Cross-Repo-`ProjectReference` (§2.2) | — | ⬜ dieser Durchlauf | | 2 | SDK-Bezug Stufe 1: Cross-Repo-`ProjectReference` (§2.2) | — | ✅ 2026-08-23, inkl. Prüf-Target mit lesbarer Fehlermeldung |
| 3 | `DcConfig`, `DeploymentcenterSettings`, `DcApiClient`, `BuildInfo` | 1, 2 | ⬜ dieser Durchlauf | | 3 | `DcConfig`, `DeploymentcenterSettings`, `DcApiClient`, `BuildInfo` | 1, 2 | ✅ 2026-08-23 |
| 4 | **P3** globale Handler + Fehler-Stream | 3 | ⬜ dieser Durchlauf | | 4 | **P3** globale Handler + Fehler-Stream | 3 | ✅ 2026-08-23 (`DcCrashHandlers`, `DcErrorSink`, `DcErrorReporter`) |
| 5 | Watchdog-Heartbeat inkl. `stopped` | 3 | ⬜ dieser Durchlauf | | 5 | Watchdog-Heartbeat inkl. `stopped` | 3 | ✅ 2026-08-23 (`DcHeartbeatWorker`) |
| 6 | Lizenz mit Sperrbetrieb statt Abbruch (§5.2), `EnsureLicensedAsync` | 3 | ⬜ dieser Durchlauf | | 6 | Lizenz mit Sperrbetrieb statt Abbruch (§5.2), `EnsureLicensedAsync` | 3 | ✅ 2026-08-23 (`LicenseGuard`) |
| 7 | Update-Prüfung **mit** `ReleaseCredentials`, `exitCurrentApp:false` bei offenem Zustand | 6 (braucht den Schlüssel) | ⬜ dieser Durchlauf | | 7 | Update-Prüfung **mit** `ReleaseCredentials`, `exitCurrentApp:false` bei offenem Zustand | 6 (braucht den Schlüssel) | 🔶 Die **Prüfung** läuft beim Start. Das **Anwenden** ist es nicht: `LaunchAgent` ist fertig, aber kein Aufrufer fährt danach geordnet herunter |
| 8 | `setup.json`, `preserve`/`exclude`, Release-Pipeline (Vorlage per `curl` von `/docs/release-template/`) | 17 | ⬜ dieser Durchlauf | | 8 | `setup.json`, `preserve`/`exclude`, Release-Pipeline (Vorlage per `curl` von `/docs/release-template/`) | 17 | ✅ 2026-08-23 (`setup.json`, `scripts/release.*`). **Noch nie ausgeführt** das erste Release steht aus |
| 9 | Bugtracker-Baustein nach `AGENTS.md` / `.agents/rules` | Projekt-Slug angelegt | ⬜ separat (Projekt `ibkrtrader` muss im WebUI erst angelegt werden) | | 9 | Bugtracker-Baustein nach `AGENTS.md` / `.agents/rules` | Projekt-Slug angelegt | ⬜ offen — Projekt `ibkrtrader` muss im WebUI erst angelegt werden |
| 10 | **Folgeschritt, nicht Teil dieses Durchlaufs:** `Deploymentcenter.Client` als NuGet-Paket in die Gitea-Registry pushen, `<Import>` durch `PackageReference` ersetzen, Gitea-CI (**P5**) auf den Paketbezug umstellen | 2 | ⬜ offen — siehe §2.2 | | 10 | **Folgeschritt, nicht Teil dieses Durchlaufs:** `Deploymentcenter.Client` als NuGet-Paket in die Gitea-Registry pushen, `<Import>` durch `PackageReference` ersetzen, Gitea-CI (**P5**) auf den Paketbezug umstellen | 2 | ⬜ offen — siehe §2.2 |
Schritt 7 und 8 hängen zusammen: **der erste ausgelieferte Build muss die Schritt 7 und 8 hängen zusammen: **der erste ausgelieferte Build muss die
+10
View File
@@ -1,5 +1,15 @@
# Konzept: Modul „Accounting" (Buchhaltung/Reporting aller Konten) # Konzept: Modul „Accounting" (Buchhaltung/Reporting aller Konten)
> **UMGESETZT (Modulgerüst).** Das Modul steht: `acc_`-Schema mit Migration `InitialAccounting`,
> `AccountingIngestService` (append-only, idempotent über `IdempotencyKey`), `AccountingClassifier`,
> `AccountingEngine`, `FxConverter`, `AccountingReportService` sowie CSV- und PDF-Export. Die
> Ingest-Quellen liegen hinter Interfaces mit **Offline-Null-Stubs** — das Modul läuft vollständig
> und bucht dabei korrekt nichts.
>
> **Weiterhin offen ist genau die Zielland-Arbeit aus §6** — vor allem der Live-Flex-Abruf, ohne den
> keine echten Buchungen entstehen, und die Steuerschicht, deren Jurisdiktion nicht festgelegt ist.
> Das Modul ist damit lauffähig, aber noch nicht in Betrieb.
> Stand: 2026-07-30 > Stand: 2026-07-30
> Ziel: Vollständige, **von unserer Trading-DB unabhängige**, buchhalterisch korrekte Erfassung ALLER > Ziel: Vollständige, **von unserer Trading-DB unabhängige**, buchhalterisch korrekte Erfassung ALLER
> Kontobewegungen der IBKR-Konten. Periodische (meist monatliche), vor einer Steuerbehörde > Kontobewegungen der IBKR-Konten. Periodische (meist monatliche), vor einer Steuerbehörde
@@ -1,5 +1,13 @@
# Konzept: Modul „Supervisor" (KI-gestützte Handels-Analyse & Forensik) # Konzept: Modul „Supervisor" (KI-gestützte Handels-Analyse & Forensik)
> **UMGESETZT (S-0 bis S-4).** Datenfundament im Core (`core_decision_journal`, `core_order_events`,
> durchgereichte `SignalId`, JSONL-Log-Sink), `DossierService`/`DossierBuilder`, der
> OpenRouter-Agent mit read-only Tool-Registry und Profilen, `sup_reports`, `CounterfactualJob`,
> `DailyReportService` und der MCP-Server (`McpLightServer`, `McpJsonRpc`).
>
> **Weiterhin offen** sind die beiden Punkte am Ende dieses Dokuments: die Counterfactual-Kursauflösung
> (Interface + Stub vorhanden) und der externe Versand des Tagesberichts.
> Stand: 2026-07-30 > Stand: 2026-07-30
> Ziel: ALLES, was IBKRTrader getan (und bewusst NICHT getan) hat, detailliert analysierbar machen — > Ziel: ALLES, was IBKRTrader getan (und bewusst NICHT getan) hat, detailliert analysierbar machen —
> Entscheidungen, Orders, Trades und Logs — und die Analyse durch ein KI-Modell (OpenRouter) durchführen > Entscheidungen, Orders, Trades und Logs — und die Analyse durch ein KI-Modell (OpenRouter) durchführen
+4 -1
View File
@@ -44,7 +44,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<!-- Die Symbole der bisherigen Oberfläche unverändert weiterverwenden (siehe Shell/ViewIcons.cs). --> <!-- Resources/ enthält genau die Symbole, die Shell/ViewIcons.cs auf einen Schlüssel abbildet.
Der Ordner trug bis 2026-08-23 zusätzlich 17 Symbole der WinForms-Oberfläche mit, die das
Wildcard-Muster mit in die Binärdatei nahm, ohne dass sie je aufgelöst wurden. Kommt ein
neuer Schlüssel dazu, gehört das PNG hierher eine Datei ohne Eintrag in ViewIcons nicht. -->
<AvaloniaResource Include="..\..\Resources\*.png" Link="Assets\%(Filename)%(Extension)" /> <AvaloniaResource Include="..\..\Resources\*.png" Link="Assets\%(Filename)%(Extension)" />
</ItemGroup> </ItemGroup>
-24
View File
@@ -1,24 +0,0 @@
using IBKRTrader.Core.Logging;
namespace IBKRTrader.Core.AI;
/// <summary>
/// Platzhalter für KI-Modell-Integration.
/// Wird in einer späteren Phase mit echten ML-Modellen ersetzt.
/// </summary>
public class AIModelService
{
private readonly LoggingService _logger;
public AIModelService(LoggingService logger)
{
_logger = logger;
}
/// <summary>Platzhalter: Gibt immer 0.5 zurück (keine echte Vorhersage).</summary>
public Task<double> PredictAsync(string symbol, object features)
{
_logger.Warn("AI", $"AIModelService ist ein Platzhalter keine echte Vorhersage für {symbol}.");
return Task.FromResult(0.5);
}
}
@@ -19,13 +19,6 @@ public class BudgetService
_logger = logger; _logger = logger;
} }
public async Task<decimal> GetAvailableBudgetAsync(string module)
{
await using var db = await _dbf.CreateDbContextAsync();
var b = await db.Budgets.FindAsync(module);
return b is null ? 0m : b.TotalBudget - b.UsedBudget;
}
public async Task ReserveBudgetAsync(string module, decimal amount) public async Task ReserveBudgetAsync(string module, decimal amount)
{ {
await using var db = await _dbf.CreateDbContextAsync(); await using var db = await _dbf.CreateDbContextAsync();
@@ -119,26 +119,6 @@ public class IBKRGatewayService
} }
} }
/// <summary>
/// Initialisiert die Brokerage-Session über den Gateway.
/// </summary>
public async Task<bool> InitBrokerageSessionAsync(CancellationToken ct = default)
{
try
{
await RateLimitAsync(ct);
var body = new StringContent("{\"publish\":true,\"compete\":true}",
System.Text.Encoding.UTF8, "application/json");
var response = await _http.PostAsync("iserver/auth/ssodh/init", body, ct);
return response.IsSuccessStatusCode;
}
catch (Exception ex)
{
_logger.Warn("IBKR", $"Brokerage-Session-Init fehlgeschlagen: {ex.Message}");
return false;
}
}
// ─── Contract Search ───────────────────────────────────────────────────── // ─── Contract Search ─────────────────────────────────────────────────────
/// <summary> /// <summary>
@@ -198,33 +178,6 @@ public class IBKRGatewayService
} }
} }
/// <summary>
/// Sucht Aktien-Contracts nach Symbolen.
/// GET /trsrv/stocks?symbols=AAPL,MSFT
/// </summary>
public async Task<Dictionary<string, List<IBKRStockContract>>?> SearchStocksBySymbolAsync(
string symbols, CancellationToken ct = default)
{
try
{
await RateLimitAsync(ct);
var response = await _http.GetAsync($"trsrv/stocks?symbols={Uri.EscapeDataString(symbols)}", ct);
if (!response.IsSuccessStatusCode)
{
_logger.Warn("IBKR", $"Stock-Suche fehlgeschlagen: HTTP {(int)response.StatusCode}");
return null;
}
return await response.Content.ReadFromJsonAsync<Dictionary<string, List<IBKRStockContract>>>(JsonOpts, ct);
}
catch (Exception ex)
{
_logger.Error("IBKR", $"Stock-Suche fehlgeschlagen: {ex.Message}", ex);
return null;
}
}
// ─── Historical Market Data ────────────────────────────────────────────── // ─── Historical Market Data ──────────────────────────────────────────────
/// <summary> /// <summary>
@@ -263,12 +216,4 @@ public class IBKRGatewayService
return null; return null;
} }
} }
// ─── Disconnect ──────────────────────────────────────────────────────────
public Task DisconnectAsync()
{
IsConnected = false;
return Task.CompletedTask;
}
} }
@@ -92,10 +92,6 @@ public static class SecretProtection
return Encoding.UTF8.GetString(pt); return Encoding.UTF8.GetString(pt);
} }
/// <summary>True, wenn der Wert bereits im verschlüsselten Format vorliegt.</summary>
public static bool IsEncrypted(string? value) =>
!string.IsNullOrEmpty(value) && value!.StartsWith(Prefix, StringComparison.Ordinal);
private static byte[] DeriveKey(string raw) private static byte[] DeriveKey(string raw)
{ {
// 32-Byte-Key als Base64? // 32-Byte-Key als Base64?
@@ -33,10 +33,6 @@ internal static class IbkrMapping
return null; return null;
} }
/// <summary>Der zum Handelsmodus passende Gateway-Port.</summary>
public static int DefaultPortFor(TradingMode mode) =>
mode == TradingMode.Live ? GatewayLivePort : GatewayPaperPort;
/// <summary>US-Aktie über die SMART-Route der einzige Instrumententyp, den die Module handeln.</summary> /// <summary>US-Aktie über die SMART-Route der einzige Instrumententyp, den die Module handeln.</summary>
public static Contract Stock(string symbol) => new() public static Contract Stock(string symbol) => new()
{ {
@@ -42,13 +42,4 @@ public class TradeHistoryService
_logger.Info(module, $"Trade gespeichert: {action} {quantity}x {symbol} @ {price:F2}"); _logger.Info(module, $"Trade gespeichert: {action} {quantity}x {symbol} @ {price:F2}");
} }
public async Task<IReadOnlyList<CoreTrade>> GetRecentTradesAsync(int limit = 100)
{
await using var db = await _dbf.CreateDbContextAsync();
return await db.TradeHistory
.OrderByDescending(t => t.TradedAt)
.Take(limit)
.ToListAsync();
}
} }
-2
View File
@@ -1,4 +1,3 @@
using IBKRTrader.Core.AI;
using IBKRTrader.Core.Budget; using IBKRTrader.Core.Budget;
using IBKRTrader.Core.Configuration; using IBKRTrader.Core.Configuration;
using IBKRTrader.Core.DependencyInjection; using IBKRTrader.Core.DependencyInjection;
@@ -166,7 +165,6 @@ public static class AppHostBuilder
services.AddSingleton<BudgetService>(); services.AddSingleton<BudgetService>();
services.AddSingleton<TradeHistoryService>(); services.AddSingleton<TradeHistoryService>();
services.AddSingleton<AIModelService>();
// Datenfundament für Analyse/Forensik (Supervisor): Entscheidungsjournal + Order-Events. // Datenfundament für Analyse/Forensik (Supervisor): Entscheidungsjournal + Order-Events.
services.AddSingleton<IDecisionJournal, EfDecisionJournal>(); services.AddSingleton<IDecisionJournal, EfDecisionJournal>();
@@ -1,4 +1,3 @@
using IBKRTrader.Core.Logging;
using IBKRTrader.Core.Settings; using IBKRTrader.Core.Settings;
using IBKRTrader.Modules.CongressTrading.Models; using IBKRTrader.Modules.CongressTrading.Models;
using IBKRTrader.Modules.CongressTrading.Persistence.Ef; using IBKRTrader.Modules.CongressTrading.Persistence.Ef;
@@ -14,16 +13,13 @@ public class CongressRepository
{ {
private readonly IDbContextFactory<CongressTradingDbContext> _dbf; private readonly IDbContextFactory<CongressTradingDbContext> _dbf;
private readonly CoreSettingsService _settings; private readonly CoreSettingsService _settings;
private readonly LoggingService _logger;
public CongressRepository( public CongressRepository(
IDbContextFactory<CongressTradingDbContext> dbf, IDbContextFactory<CongressTradingDbContext> dbf,
CoreSettingsService settings, CoreSettingsService settings)
LoggingService logger)
{ {
_dbf = dbf; _dbf = dbf;
_settings = settings; _settings = settings;
_logger = logger;
} }
// ─── CongressMember ─────────────────────────────────────────────────────── // ─── CongressMember ───────────────────────────────────────────────────────
@@ -71,13 +67,6 @@ public class CongressRepository
return await db.Trades.AnyAsync(t => t.TradeId == tradeId); return await db.Trades.AnyAsync(t => t.TradeId == tradeId);
} }
public async Task<HashSet<string>> GetAllTradeIdsAsync()
{
await using var db = await _dbf.CreateDbContextAsync();
var ids = await db.Trades.Select(t => t.TradeId).ToListAsync();
return ids.ToHashSet();
}
/// <summary>Fügt einen Trade ein, sofern die TradeId noch nicht existiert.</summary> /// <summary>Fügt einen Trade ein, sofern die TradeId noch nicht existiert.</summary>
public async Task InsertTradeAsync(CongressTrade trade, bool detailsFetched = true) public async Task InsertTradeAsync(CongressTrade trade, bool detailsFetched = true)
{ {
@@ -133,19 +122,4 @@ public class CongressRepository
public Task<string?> GetSettingAsync(string key) => _settings.GetAsync(key); public Task<string?> GetSettingAsync(string key) => _settings.GetAsync(key);
public Task SetSettingAsync(string key, string v) => _settings.SetAsync(key, v); public Task SetSettingAsync(string key, string v) => _settings.SetAsync(key, v);
public Task DeleteSettingAsync(string key) => _settings.DeleteAsync(key); public Task DeleteSettingAsync(string key) => _settings.DeleteAsync(key);
// ─── Reset ────────────────────────────────────────────────────────────────
/// <summary>Löscht alle CT-Fortschritts-Flags und alle CT-Daten aus der DB.</summary>
public async Task ResetHistoryImportAsync()
{
await DeleteSettingAsync("ct.history_import_done");
await DeleteSettingAsync("ct.history_import_page");
await DeleteSettingAsync("ct.history_import_total");
await using var db = await _dbf.CreateDbContextAsync();
await db.Trades.ExecuteDeleteAsync();
await db.Members.ExecuteDeleteAsync();
_logger.Warn("CT", "History-Import-Reset durchgeführt alle CT-Daten gelöscht.");
}
} }
@@ -9,20 +9,6 @@ namespace IBKRTrader.Modules.CongressTrading.Scraper;
// ─── JSON-Modelle (exakte Feldnamen aus dem RSC-Stream) ────────────────────── // ─── JSON-Modelle (exakte Feldnamen aus dem RSC-Stream) ──────────────────────
internal class CtApiWrapper
{
[JsonPropertyName("data")] public List<CtTrade>? Data { get; set; }
[JsonPropertyName("meta")] public CtMeta? Meta { get; set; }
}
internal class CtMeta
{
[JsonPropertyName("totalPages")] public int TotalPages { get; set; }
[JsonPropertyName("pageSize")] public int PageSize { get; set; }
[JsonPropertyName("totalCount")] public int TotalCount { get; set; }
[JsonPropertyName("page")] public int Page { get; set; }
}
internal class CtTrade internal class CtTrade
{ {
[JsonPropertyName("_txId")] public long TxId { get; set; } [JsonPropertyName("_txId")] public long TxId { get; set; }
@@ -26,7 +26,7 @@ public class CongressRepositoryTests
.UseInMemoryDatabase(Guid.NewGuid().ToString()).Options; .UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;
var settings = new CoreSettingsService(new Factory<CoreDbContext>(coreOpts)); var settings = new CoreSettingsService(new Factory<CoreDbContext>(coreOpts));
return new CongressRepository(new Factory<CongressTradingDbContext>(ctOpts), settings, new LoggingService()); return new CongressRepository(new Factory<CongressTradingDbContext>(ctOpts), settings);
} }
[Fact] [Fact]