1dac482cc71ee7e07626c5de83c702863cf33442
12
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1dac482cc7 |
DebugTrading: ein Modul, das absichtlich Last erzeugt
Alles, was den Handel absichert - Limits, Deckung, Kapitalpool, Reservierungen, Abgleich, Sperren - war bisher ausschliesslich durch Unit-Tests mit gemockten Gegenstellen belegt. Im Betrieb gab es fast keine Trades. Ein Fehler in der Buchungskette faellt so erst auf, wenn eine echte Strategie scharf geht. Das Modul eroeffnet kleine Positionen, haelt sie eine gewuerfelte Zeit von Minuten bis Tagen und schliesst sie selbst. Es soll keine Rendite erzeugen, sondern Last; die Auswahl ist zufaellig und ausdruecklich nicht renditegetrieben. Planung und Sicherungen sind reine Rechnung mit einer von aussen gereichten Zufallsquelle - genau deshalb ist ein Modul, das absichtlich wuerfelt, ueberhaupt pruefbar. 14 Tests. Die Sicherung, die nicht verhandelbar ist: Der Worker prueft bei JEDEM Lauf, ob der Handelsmodus eindeutig Paper ist, und wirft sonst. Nicht nur beim Start - Einstellungen werden kopiert, wenn eine Instanz umzieht. Geprueft wird gegen den Rohwert UND den geparsten Modus: TradingSettings.ParsedMode faellt bei einem unbekannten Wert auf Paper zurueck, und darauf darf sich diese Pruefung nicht verlassen. Dazu Tagesbudget (in Betriebszeitzone, nicht UTC), Obergrenze offener Positionen, Grenze je Trade und ein Not-Aus, der das Eroeffnen stoppt und offene Positionen weiter betreut. Schliessen hat Vorrang vor Eroeffnen: Sonst koennte eine erreichte Obergrenze verhindern, dass faellige Positionen je geschlossen werden - die Sperre bliebe fuer immer. Beim Bauen hat der Architekturtest aus #474 seinen ersten echten Fang gemacht: Das Modul griff nach IBrokerClient, um Kurse zu holen. Das verstoesst gegen Regel 4. Statt den Test aufzuweichen ist eine lesende Kursquelle entstanden (IQuoteSource) - wer einen Kurs braucht, soll dafuer nicht den Zugang bekommen, mit dem sich Orders platzieren lassen. Auf dem Testserver nachgewiesen: Das Modul laeuft im Takt, plant, wird bei fehlendem Kurs sauber abgelehnt und meldet das - und mit Trading.Mode=Live verweigert es den Dienst, waehrend unabhaengig davon auch der Broker-Adapter den Paper-Port gegen den Live-Modus sperrt. Zwei Schichten, die nichts voneinander wissen. 438 Tests gruen. Arbeit an #468. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
3bccd90d97 |
Eigentumsregeln 3 und 4: gebundener Ausfuehrungszugang und eine Grenze mit Zaehnen
Regel 3 verlangt, dass die Buchzuordnung serverseitig gesetzt wird und TradeSignal.SourceModule nicht vertrauenswuerdig ist. Bisher war nur der unbekannte Name abgefangen; ein Modul konnte weiterhin das Kuerzel eines ANDEREN registrierten Moduls eintragen und dessen Cap, dessen Konzentration und dessen GuV belasten. Jedes Modul bekommt jetzt einen an sein Buch gebundenen IModuleExecution-Zugang statt des gemeinsamen IExecutionService. Der Zugang ueberschreibt die Herkunft mit seinem eigenen Buch - was im Signal steht, spielt keine Rolle mehr. Der Zugang steht ausdruecklich NICHT im Container: was dort steht, kann jedes Modul aufloesen, auch den Zugang eines anderen. Der Host uebergibt stattdessen eine Fabrik beim Registrieren (neue Ueberladung von IModule.RegisterServices mit Vorgabe, damit ein nicht handelndes Modul nichts davon wissen muss), und das Modul reicht den erzeugten Zugang direkt an seine Strategie. Regel 4 - Module bekommen den Broker nicht per DI - war eingehalten, aber nicht erzwungen. Jetzt zwei Tests ueber alle vier Modul-Assemblies: der eine prueft per Reflection Konstruktorparameter, Felder und Eigenschaften auf IBrokerClient, IBrokerPortfolioReader und IExecutionService; der andere durchsucht die Modulquellen nach dem zweiten Weg, dem Griff in den Container. Beide Gegenproben mit einem absichtlichen Regelbruch gefahren: jeder Test schlaegt bei genau seinem Weg an. Getrennte Container je Modul waeren der harte Weg, aendern aber die Modularchitektur. Der Fall, um den es geht, ist ein NEUES Modul, das den Core versehentlich umgeht - und den faengt der Test beim Uebersetzen. 404 Tests gruen, auf Windows und auf der Test-VM. Behebt #474, damit ist auch #302 vollstaendig. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
084cd7ef77 |
Options-Fundament und Kapitalmodell im Core; Modul OptionsWheel
Das OptionsWheel setzt auf Dingen auf, die es im Core nicht gab. Diese Sitzung baut sie. #298 Optionen als Instrument. InstrumentKind/OptionSpec und ein druckbarer Instrumentenschluessel ("AAPL|20260918|C|150"); TradeSignal und OrderRequest tragen ein optionales OptionSpec, ohne das sich der Aktienpfad unveraendert verhaelt. Position.Notional rechnet ab jetzt mit der Kontraktgroesse - vorher war jede Option um Faktor 100 zu klein bewertet und damit jedes Risikolimit wirkungslos, lautlos und in die gefaehrliche Richtung. Daneben neu BoundCapital: ein Short Put bindet Strike x Kontraktgroesse, nicht die vereinnahmte Praemie. #300 sell-to-open. Jeder Auftrag zerfaellt in einen schliessenden und einen eroeffnenden Teil; der schliessende wird von keinem Limit verhindert - auch nicht vom Kaufstopp, denn ein Rueckkauf baut eine Verpflichtung ab. Deckungspruefung im Core, nicht im Modul: Short Call nur mit freien Aktien, Short Put nur mit reservierbarem Bargeld. #302-#305 Kapital- und Buchmodell. Buecher mit reservierten Namen und Eigentumsregeln, Pool mit Caps und Headroom, Margin-Sperre in vier Schichten, core_reservation mit Lebenszyklus, Frist, Idempotenz ueber (SignalId, ContractKey) und Quarantaene beim Start. #309/#310 Modul OptionsWheel: ow_-Schema mit fuenf Tabellen, Zustandsautomat, StrikeSelector, RollDecider, PremiumMath - vollstaendig ohne Broker testbar. Der Handelsbetrieb bleibt gesperrt, solange #299 und #294 fehlen; das Modul sagt das ueber GetActivationBlocker, statt still nichts zu tun. #293 --verify-order am Daemon: eine Order durch die vollstaendige Kette (Buch, Risiko, Bindung, Order, Fill, Buchung, Abschluss). Ohne --confirm ein Trockenlauf; Abbruch ausserhalb von Paper-Modus UND Paper-Port. Drei Widersprueche in den Konzepten sind dabei entschieden worden: Schicht B heisst ab jetzt "kein UNGEDECKTER Short" (der Grund der Regel war der Kredit, nicht der Short), die Hausreserve wird einmal abgezogen statt zweimal, und der Positionsschluessel ist eine Spalte statt eines Sechser-Verbunds (MySQL verlangt NOT NULL fuer Schluesselspalten). Begruendungen stehen in docs/ROADMAP.md. Enthaelt ausserdem die noch nicht committete Arbeit aus der vorigen Sitzung: die Fehlerbehebungen aus Epic X (WorkerBase-Intervall, BackupWorker, --check gegen die Datenbank, CapitolTrades-429, SIGTERM) samt DatabaseEndpoint, MysqlDumpTool und der Roadmap-Umstellung. Sie lag im Arbeitsbaum und liess sich nicht abtrennen, weil beide Staende dieselben Dateien beruehren. 213 -> 369 Tests, Build ohne Warnung. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
e1546bd1b1 |
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>
|
||
|
|
8b9b993d1d |
L1b/2: Kultur und Dateisystem plattformunabhaengig machen
Kultur - Ausgaben und Parsen haengen nicht mehr am Host:
- PdfExporter formatierte Betraege mit ToString("N2") ohne Formatanbieter,
also CurrentCulture. Auf dem deutschen Desktop "1.234,56", in einem
Container mit LANG=C "1,234.56" - dieselbe Zahl, fuer einen Leser eine
andere. Fuer ein ausdruecklich pruefbares Dokument jetzt fest de-DE.
- CapitolTradesScraper.ParseDate nutzte DateOnly.TryParse ohne
Formatanbieter. Das ist nicht theoretisch: gemessen wurde aus
"2026-08-04" unter th-TH das Jahr 1483 (buddhistischer Kalender), unter
fa-IR das Jahr 2647 (persischer Kalender), unter ar-SA schlug das Parsen
ganz fehl. de-DE und en-US kommen mit ISO klar - genau deshalb faellt so
etwas auf dem Entwicklungsrechner nie auf. Jetzt TryParseExact mit
InvariantCulture; ein Formatwechsel der Quelle faellt damit auf, statt
still ein falsches Datum zu erzeugen. Regressionstest ueber vier Kulturen.
- IBKRGatewayService baute den Query-Parameter mit .ToString().ToLower()
(Tuerkisch-I) - jetzt fest "true"/"false".
PDF-Schriften: PDFsharp 6 loest auf Nicht-Windows-Plattformen nichts von
selbst auf, "Segoe UI" gibt es dort nicht - der Export waere zur Laufzeit
gescheitert. Neuer DocumentFontResolver: unter Windows bleibt die Plattform
zustaendig (unveraenderte Optik), auf Linux wird eine freie Systemschrift
gesucht (DejaVu/Liberation/Noto/FreeSans). Bewusst keine Schrift im Repo -
das erspart eine Lizenzfrage; fehlt sie, nennt die Fehlermeldung das zu
installierende Paket.
BackupWorker:
- Suchte "mysqldump.exe" in C:\Program Files\... und splittete PATH mit ';'.
Auf Linux ist das Trennzeichen ':' - der gesamte PATH waere als ein
Eintrag gelesen worden. Jetzt Path.PathSeparator, plattformabhaengige
Suchpfade und zusaetzlich "mariadb-dump" (MariaDB hat mysqldump ab 10.5
umbenannt).
- Das DB-Passwort stand als Kommandozeilenargument im Prozessbaum. Unter
Linux ist /proc/<pid>/cmdline fuer jeden lokalen Nutzer lesbar - das waere
eine neue Offenlegung gewesen, die es unter Windows so nicht gab. Jetzt
ueber MYSQL_PWD, nur an den Kindprozess vererbt. Argumente einzeln statt
als Zeichenkette (kein Quoting-Problem bei Pfaden mit Leerzeichen).
Verifiziert: 188 Tests gruen (+5), Build 0 Fehler/0 Warnungen, Core + 3
Module + Tests bauen fuer linux-x64, --smoke-ui konstruiert alle 7 Fenster.
Offen aus L1b und nach L2 verschoben: IAppPaths (Logs/Backups/settings.json/
master.key liegen neben der Binaerdatei; unter /opt ist das nicht schreibbar).
Gehoert zum Daemon, wo die Pfade tatsaechlich gebraucht werden.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
d8273c3a1e |
L1b/1: Betriebszeitzone statt Rechnerzeit - EU- und US-Instanzen sauber trennen
Wir betreiben Instanzen in zwei Regionen. Bisher hing jede Ortszeit an der Zeitzone des Rechners (DateTime.Now, DateTimeKind.Local): derselbe Code haette auf einem Windows-Desktop mit Europe/Berlin und in einem Linux-Container mit UTC lautlos unterschiedliche Werte geliefert - ohne Fehler, nur um Stunden verschoben, mitten in Buchungszeitstempeln. AppTimeZone (Core/Time): Betriebszeitzone der Instanz, einmalig aus Trading.ApplicationTimeZoneId gesetzt, IANA- und Windows-Schreibweise tragen beide, unbekannter Wert weicht auf die Systemzone aus und warnt. Wird laut Festlegung vor den ersten Trades gesetzt und danach nie gewechselt - ein Wechsel verschoebe rueckwirkend alle Tagesgrenzen. Persistenz bleibt UTC, damit die Daten beider Instanzen vergleichbar sind. IbkrMapping.ParseExecutionTime verwirft die von TWS gemeldete Zeitzone nicht mehr, sondern rechnet gegen sie nach UTC; ohne Zonenangabe gilt die Betriebszeitzone. Das ist der Kern: eine NYSE-Ausfuehrung darf nicht mit demselben nackten Zeitwert in die Buecher wie eine an der Eurex. Rueckgabe ist jetzt immer Kind=Utc. DailyReportService.NextRun -> NextRunUtc(nowUtc, hour, zone): der Bericht laeuft zu einer festen ORTSZEIT. Sommerzeitumstellung wird behandelt - bei der uebersprungenen Stunde weicht er aus, statt den Tag ausfallen zu lassen. LoggingService fuehrt Anzeigezeit und UTC getrennt: Dateinamen und Anzeige in Ortszeit (Tagesgrenzen gehoeren zur Instanz, der Supervisor liest die JSONL-Dateien ueber diese Namen), das ts-Feld im JSONL in UTC. Beides musste getrennt werden, weil die umgerechnete Ortszeit Kind=Unspecified traegt und ein ToUniversalTime() darauf sie als Zeit des HOSTS gedeutet haette. Verbleibende DateTime.Now in Worker-Zeitplaenen und Statuszeilen ebenfalls auf AppTimeZone.Now umgestellt. Verifiziert: 183 Tests gruen (+20), darunter EU/US-Versatz, Winter-/Sommerzeit, unbekannte Zone und die uebersprungene Stunde bei der Zeitumstellung. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
123f38ab6f |
L1a: Core und Module von WinForms entkoppeln - net10.0 statt net10.0-windows
Core, alle drei Module und das Testprojekt tragen keinen UI-Code mehr und bauen fuer linux-x64. Nur noch IBKRTrader.App ist Windows-gebunden. UI-Contract toolkit-neutral (Vorbild: PolytraderSharp): - ModuleView.CreateForm (Func<Form>) -> CreateView (Func<object>) - ModuleView.Icon (System.Drawing.Image) -> IconKey (string). System.Drawing.Common ist seit .NET 7 Windows-only und wirft auf Linux. - WindowMenu.cs war reine WinForms-Umsetzung -> in die Shell verschoben. LoggingService haelt keine RichTextBox mehr, sondern meldet Eintraege ueber event EntryWritten. Einfaerbung und UI-Thread-Wechsel liegen jetzt im LogPanelController der Shell. Nebenbei: ToUpper() -> ToUpperInvariant() (tr-TR haette aus "info" ein "İNFO" gemacht) und \r\n -> Environment.NewLine. Die drei Modul-Fenster liegen jetzt unter UI/Views/Modules/; RegisterUi der Module ist bewusst leer, die Shell registriert sie zentral ueber UI/ModuleViews.cs (nur fuer tatsaechlich geladene Module). ViewIcons loest IconKey gegen die PNG-Ressourcen auf - dieselben Schluessel bekommt spaeter die Avalonia-Shell. UiConstructionTests entfernt: die Konstruktionspruefung deckt --smoke-ui ab, das Testprojekt braucht dafuer keine UI-Referenz mehr. Der Test RegisterUi_RegistersMainView haelt jetzt das Gegenteil fest - das Modul darf nichts registrieren, sonst waere es wieder toolkit-gebunden. Verifiziert: Build 0 Fehler/0 Warnungen, 163 Tests gruen, --smoke-ui konstruiert alle 7 Fenster, und Core + 3 Module + Tests bauen fuer linux-x64. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
2a312ca035 |
R8: Accounting- + Supervisor-Modul + Core-Datenfundament (S-0)
Portierung der beiden fehlenden Grundbausteine aus PolytraderSharp (voller Ausbau). Core S-0 (Datenfundament fuer Analyse/Forensik): - core_decision_journal + core_order_events (+ ReasonCode/Decision/OrderEvent-Enums), IDecisionJournal/IOrderEventLog mit fehlertoleranten EF-Impls (Handel bricht nie). - SignalId-Durchreichung TradeSignal -> ExecutionService -> core_trade_history; ExecutionService schreibt an jeder Verzweigung Journal/Order-Events. - JSONL-Log-Sink (LogJson + Dual-Sink), pure Analytik: RealizedPnlEngine (FIFO), TradeAnalytics, DossierBuilder. Migration AddAnalysisFoundation. Accounting-Modul (acc_): unabhaengiger IBKR-Kontoauszug (Activity Flex Query) hinter Interfaces mit Offline-Null-Stubs -> append-only Ledger + Periodenabrechnung/BWA + FX (USD/EUR) + CSV/PDF (PDFsharp/MigraDoc). Steuerschicht bewusst offen (Platzhalter-Tab). Kein Handel. Migration InitialAccounting. Supervisor-Modul (sup_): read-only OpenRouter-Agent (Function-Calling-Loop) + read-only Tool-Registry (8 Tools) + Profile + Dossier-Browser + Counterfactual-Job (Stub) + Tagesbericht/MCP-Light (opt-in). Migration InitialSupervisor. Verdrahtung: Program.cs (beide Module + Icons), slnx/App/Tests-Referenzen, provision-db.ps1, AppSettings-Sektionen, docs/konzepte, README. Tests: 79 -> 117 gruen (FIFO/KPIs/Dossier/JSONL, Classifier/Engine/FX/Idempotenz, OpenRouter/Registry/Agent/MCP, STA-Konstruktion beider neuen Fenster). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
331623d4f3 |
@
R5: CongressTrading als Strategie (Signal -> ExecutionService) + Positionen im Modul-Fenster
- CongressTradingStrategy: neuer Scrape-Trade -> TradeSignal (buy/sell-Mapping, sonst ignoriert)
-> Core-IExecutionService; CongressScrapeWorker ruft sie je neuem Trade (try/catch-isoliert)
- Modul-Fenster: offene Positionen des Moduls via IPortfolioService.GetPositionsAsync("CT")
- Tests: CongressTradingStrategy (Mapping/Ausfuehrung, gemockter ExecutionService) -> 51/51 gruen
- Handel bleibt sicher aus (TradingEnabled=false + NullBrokerClient), bis Broker+Freigabe
- Build + smoke-ui + App-Start ok
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
|
||
|
|
6c8e36dc3c |
@
R3 Slice 3: CongressTrading-Modul + Worker-Log + core_settings auf EF Core - Modul: CongressTradingDbContext (ct_congressMember/ct_trade) + Design-Time-Factory; CongressRepository von Dapper auf EF; CongressTrade.DetailsFetched ergaenzt; Dapper entfernt - Core: CoreSettingsService (core_settings via EF); WorkerBase-Log auf EF (core_worker_log); 7 Worker-Ctors DatabaseService -> IDbContextFactory<CoreDbContext> - CoreMigrations + CongressMigrations (Dapper) entfernt; core_-Schema nun rein EF - EF-Migration InitialCongressTrading; AddCorePersistence-Fallback fuer leeren Connection-String (App startet ohne DB); Connection aus appsettings.Local.json (gitignored) - Tests: +4 CongressRepository (EF-InMemory) -> 39/39 gruen; Build + smoke-ui + App-Start ok Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> @ |
||
|
|
8f44c0fd82 |
@
R2: Generic Host + Modul-Vertrag + Shell-UI (PolytraderSharp-Konzept) - Core/Modularity: neuer IModule (Name, DbPrefix, RegisterServices(services,config), RegisterUi(host,sp), StartAsync/StopAsync, GetActivationBlocker) + ModuleView + IModuleUiHost + WindowMenu. Alte IModule/ModuleRegistry/WindowManager/ModuleFormBase entfernt. - Program.cs: Host.CreateDefaultBuilder + IConfiguration (appsettings.json/.Local.json); Core-Services registriert, Module via RegisterServices, Views via RegisterUi. - UI: ShellUiHost (Einzelinstanz-Fenster + Fenster-Menue), LauncherForm als Shell (Buttons je View), Core-Views Logs/Settings/Workers als eigene Fenster. - CongressTrading auf neuen Vertrag; Worker als IWorker registriert. - --smoke-ui Headless-Test (konstruiert jede View + Launcher). - appsettings.Local.json gitignored. - Tests angepasst -> 30/30 gruen; Build + Smoke-UI + App-Start verifiziert. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> @ |
||
|
|
c20538c8d8 |
@
R1: Umbau auf Multi-Projekt-Struktur (Vorbild PolytraderSharp) Kurskorrektur: Vorbild ist PolytraderSharp (C#), nicht die veraltete Python-Version. Reiner Strukturumbau, Verhalten unveraendert. - src/IBKRTrader.Core (classlib): Core-Code + UI-Contract (ModuleFormBase, WindowManager) - src/IBKRTrader.Modules.CongressTrading (classlib, referenziert nur Core) - Root: IBKRTrader.App (WinExe) referenziert Core + Modul - tests/IBKRTrader.Tests: Referenzen auf Core + Modul - Neue .slnx; ungenutztes HtmlAgilityPack entfernt - docs/ARCHITECTURE.md: korrigierter Ziel-Stand + R-Phasenplan - Build + 38/38 Tests gruen; App startet Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> @ |