Commit Graph
12 Commits
Author SHA1 Message Date
RichardandClaude Opus 5 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>
2026-09-05 14:27:58 +02:00
RichardandClaude Opus 5 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>
2026-09-05 12:59:44 +02:00
RichardandClaude Opus 5 084cd7ef77 Options-Fundament und Kapitalmodell im Core; Modul OptionsWheel
Build & Test / build (ubuntu-latest) (push) Canceled after 0s
Build & Test / build (windows-latest) (push) Canceled after 0s
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>
2026-09-04 09:35:38 +02:00
RichardandClaude Opus 5 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>
2026-08-23 12:25:03 +02:00
RichardandClaude Opus 5 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>
2026-08-06 22:58:10 +02:00
RichardandClaude Opus 5 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>
2026-08-06 22:52:23 +02:00
RichardandClaude Opus 5 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>
2026-08-06 22:38:01 +02:00
RichardandClaude Opus 4.8 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>
2026-07-31 09:25:18 +02:00
Richard 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>
@
2026-07-28 19:14:21 +02:00
Richard 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>
@
2026-07-28 11:34:42 +02:00
Richard 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>
@
2026-07-28 00:24:00 +02:00
Richard 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>
@
2026-07-27 20:26:25 +02:00