- TraderMonitorService las API-Preise kulturabhaengig: unter de-DE wurde aus
"0.53" der Wert 53 (Faktor-100-Fehler im Einstandspreis). Nutzt jetzt den
bereits vorhandenen invarianten Helper ParseDecimal.
- Gleiche Fehlerklasse in PolymarketClobClient (6x) und MasterTraderAnalyticsJob
vorsorglich auf InvariantCulture gestellt.
- Neuer Regressionstest ApiNumberParsingTests (10 Faelle unter erzwungener de-DE-Kultur).
- Threema komplett entfernt (Entscheidung Richard): ThreemaService, vendorte
Bibliothek libs/Threema-MsgApi-Net-Core, ServerSettings-Block, DI-Verdrahtung.
- Ersetzt durch neutrale INotificationSink (No-Throw-Vertrag) + LogNotificationSink
als Uebergang; RocketChat/Telegram folgen spaeter.
- Entfernt nebenbei libsodium 1.0.16, die einzige Registry-Nutzung im Build,
den HttpListener-Webhook und System.Web.HttpUtility (alles Linux-Hindernisse).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Slices W-A/W-B/W-C und L-A aus UMSETZUNGSPLAN-Watchdog-LicenseLabrador-Integration.
Watchdog (Dead-Man's-Switch, externer Server):
- WatchdogHeartbeatService als BackgroundService + DI-Singleton; jeder Sendeversuch
gekapselt, ein Ausfall des Watchdogs beeintraechtigt PolyTrader nie.
- Eigene Implementierung statt Test-Client des Fremdprojekts: TLS-Pruefung bleibt
aktiv, http:// nur fuer localhost (Agent-Token nicht im Klartext ins Netz).
- Status aus dem App-Log abgeleitet (Error mit 5-Minuten-Sticky-Fenster, entprellt),
Lifecycle-Events started/stopping.
- Konfiguration in ServerSettings; Agent-Token [Browsable(false)] mit maskierter
Eingabe + Statusanzeige, bei gesetztem Master-Key verschluesselt (enc:v1:).
Lizenz (LicenseLabrador, Ed25519):
- LicenseGate.RunStartupGate prueft beim Start; bei ungueltiger Lizenz wird die
Modulliste leer gebaut, sodass nur die Core-Shell (Terminal/Einstellungen)
startet. Bewusst kein Environment.Exit - ein Trading-Bot darf nicht mitten im
Lauf hart sterben. TamperSuspected gilt als nicht nutzbar.
- LicenseDialog (partial + .Designer.cs) fuer Start- und Verwalten-Modus, mit
Hardware-ID zum Kopieren; Smoke-UI konstruiert beide Modi headless.
- Master-Key wird jetzt VOR dem Host-Build geladen, da auch der Lizenzschluessel
entschluesselt werden muss; derselbe TerminalLogger wird als Singleton
weitergereicht, damit die Startmeldungen im Terminal-Fenster erscheinen.
Der Lizenz-SDK-Client wird per Cross-Repo-Projektreferenz auf
..\..\LicenseLabrador eingebunden, damit SDK-Fixes ohne Kopie einfliessen.
484 Zeilen Tests fuer den Heartbeat; Suite gruen (438 Tests).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Fenster-Menue: WindowMenu fuellt die oberste MenuStrip mit Top-Level-Eintraegen
nebeneinander (mit Icon) statt Untermenue "Fenster"; ModuleView.Icon zentral in der
App zugewiesen (AssignMenuIcons). Kein miFenster mehr im Launcher-Designer.
- Sicheres Beenden: ShutdownConfirmDialog (10s-Timer sperrt "Jetzt beenden", Abbrechen
jederzeit) via IModuleUiHost.RequestShutdown(). Nur der Launcher (Hauptprozess) bietet
"Beenden"; andere Fenster nur "Fenster schliessen" (kein App-Shutdown, Module laufen
weiter). Launcher-Schliessen-X routet ueber dieselbe Abfrage.
- Modul-Aktivierung (restart-basiert): ServerSettings.DisabledModules, in Program.Main
vor der DI-Registrierung gefiltert -> deaktivierte Module werden nicht geladen.
Dashboard-Tab "Module" zeigt Status + schaltet um (Hinweis: greift nach Neustart).
Optionaler IPolyTraderModule.GetActivationBlocker fuer "nicht aktivierbar"-Info.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- IModuleUiHost (Core) um Navigation erweitert: Views/IsOpen/OpenView/ActivateMain/OpenStateChanged
+ optionales Icon je ModuleView. So kann JEDES Fenster (auch Modul-Fenster, die nur Core kennen)
das gemeinsame Fenster-Menue bauen.
- WindowMenu (Core): baut das 'Fenster'-Dropdown (Launcher + alle Views + Beenden), haakt offene
Fenster an, markiert das aktuelle fett; Neuaufbau beim Aufklappen.
- ShellUiHost: SetMainWindow/ActivateMain; oeffnet ALLE Fenster jetzt MAXIMIERT (Vorgabe).
- Launcher: alle Modul-/Core-Buttons STATISCH im Designer (btn_copytrading/-resolutionfarming/
-supervisor ergaenzt), an View-IDs gebunden; fehlt eine View -> Button deaktiviert. Dynamischer
Laufzeit-Anhang ENTFERNT -> kein doppelter Accounting-Button mehr; leerer btn_accounting_Click raus.
Datei/Beenden -> Fenster-Menue (WindowMenu). Launcher startet maximiert (Sizable, MinSize 1280x720).
Build 0 Fehler, --smoke-ui alle 6 Views + Launcher gruen. Fenster-Menue auf den uebrigen Fenstern folgt (1b).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Behebt den kritischsten Befund (Klartext-Private-Keys in remote-gehosteter MySQL):
- SecretProtection (Core/Security): AES-256-GCM, authenticated. Master-Key AUSSERHALB der DB
(env POLYTRADER_MASTER_KEY, sonst gitignorierte master.key). Format enc:v1:base64(nonce|tag|ct).
Alt-Klartext (ohne Praefix) wird gelesen und beim Speichern verschluesselt (selbstheilend).
Ohne Master-Key: Passthrough + deutliche Startwarnung (kein stiller Sicherheitsverlust).
- EncryptedStringConverter (EF ValueConverter) auf core_accounts.PrivateKey/ApiSecret/ApiPassphrase;
Spalten 256->512 verbreitert (Migration EncryptAccountSecretsWidenColumns, offline generiert).
- Program.cs: Master-Key vor der Hydration laden; nach Start einmalige/idempotente Re-Encryption
vorhandener Klartext-Credentials. Auch in --smoke-ui verdrahtet.
- CoreDbContextFactory nutzt jetzt fixe Server-Version (offline-Migrationsgenerierung, kein DB-Zugriff).
13 neue Krypto-Tests (Round-Trip, Nonce-Frische, Manipulations-/Falscher-Key-Erkennung, Passthrough,
Key-Formate). Build 0 Fehler, 324 Tests gruen, --smoke-ui ok (Warnung ohne Key wie erwartet).
AKTIVIERUNG (im Zielland): POLYTRADER_MASTER_KEY setzen (zufaelliger 32-Byte-Base64-Key, SEPARAT sichern!)
+ Migration anwenden (dotnet ef database update --context CoreDbContext). Danach Alchemy-/Mullvad-Secrets
aus F3 rotieren. WICHTIG: Master-Key-Verlust = Kein Zugriff auf die Keys mehr.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
F4: Newtonsoft.Json in der Threema-Lib von 11.0.2 (Advisory NU1903, high) auf 13.0.4
gehoben (= App-Version). Build ohne NU1903, 311 Tests gruen.
F3: hardcodierte Secrets aus ServerSettings-Defaults entfernt (Alchemy-API-Key in
PolygonRpcUrl, Mullvad-Account-ID) -> leere Defaults; echte Werte kommen aus
server_settings.xml (gitignored). WICHTIG (nicht im Code moeglich): beide Secrets
ROTIEREN, da sie in der Git-History liegen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Vorbereitung fuer das ResolutionFarming-Modul: FeeModel von
PolyTrader.Modules.CopyTrading.Logic nach PolyTrader.Core.Trading verschoben, damit
mehrere Strategiemodule dieselbe Fee-Logik nutzen koennen (Module duerfen nicht
voneinander abhaengen -> geteiltes gehoert in den Core). CopyTrading-Referenzen +
FeeModelTests auf den Core-Namespace umgestellt. Rein mechanisch, verhaltensneutral.
Build 0 Fehler, 244 Tests gruen, --smoke-ui ok.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ruhende GTC-Leiter-/MakerEntry-Orders ueberleben Neustarts auf dem CLOB, der
Verwaltungszustand (ExitLadders/ExitPending/PendingOrderTimestamps) ist transient.
Ohne Bereinigung liefe die Engine gegen Waisen-Orders (Doppel-Leiter, Kaskaden).
- StartupOrderReconciliationService (IHostedService): storniert beim Start je
Live-Account alle offenen CLOB-Orders; danach entscheidet die Engine sauber neu.
Registriert als ERSTER Modul-HostedService (nach Hydration, vor Monitor/Engine),
pro Account fehlertolerant.
- GetOpenOrdersAsync: assetId jetzt optional (default "") -> ohne Filter ALLE
offenen Orders des Accounts. Signaturneutral (HMAC geht ueber Pfad ohne Query),
rueckwaertskompatibel fuer die bestehenden per-Asset-Aufrufer. IClobClient +
FakeClobClient nachgezogen.
Hinweis: "/data/orders ohne asset_id = alle Orders" ist API-gated und im Zielland
live zu verifizieren (wie M6).
Tests: 3 neue (cancelt alle Orders je Live-Account, ueberspringt Demo/credential-los,
no-op ohne offene Orders). Build 0 Fehler, 218 Tests gruen, --smoke-ui ok.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Behebt die April-Verlustquelle: SELLs wurden als Market-Order mit 0.01-Limit ins
oft leergeraeumte Orderbuch geworfen -> wir wurden zur Exit-Liquidity. Jetzt:
GTC-Limit nahe am Master-Exit, stufenweises Nachpreisen bis zum Floor.
- Position.ExitPending (runtime-only, EF-ignoriert): Position wird bei SELL NICHT
mehr optimistisch entfernt, sondern als ExitPending zurueckgestellt (kein
Doppel-SELL, Limits rechnen korrekt; Sync schliesst nach bestaetigtem Fill).
- CopyTradingState.ExitLadders + ExitLadderState (transienter Leiter-Zustand).
- SellLogic (pure, getestet): FirstLimit (HF-fest/prozentual), Floor (SellFloorPct),
NextPrice (relative Stufe, auf Floor geclamped), IsAtFloor, LadderStepPct (3%),
LadderIntervalSeconds (HF 20s / sonst 120s).
- SellLadderService (BackgroundService): senkt offene Exit-Limits stufenweise
(cancel via CancelConflictingOrdersAsync -> tiefer neu platzieren), am Floor ohne
Fill Position halten + Threema-Benachrichtigung. Fills erkennt der bestehende Sync.
- CopyTradingEngine SELL-Live-Pfad ruft die Leiter; Demo-Pfad unveraendert.
Doppel-SELL-Guard ueber ExitPending. Umfangreiches Logging (kein Live-Test moeglich).
163 Tests gruen. Build/Smoke gruen. Backup-Rollback: Commit 1dffc9e.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ursachen (App startete aus bin/ bzw. per Doppelklick ohne UI):
1. appsettings.Local.json (MySQL-Connection) wurde NICHT ins Output kopiert und
nur relativ zum Arbeitsverzeichnis geladen -> leere Connection -> Pomelo fiel
auf localhost:3306 zurueck -> "Connect Timeout expired".
2. ServerVersion.AutoDetect(conn) oeffnet beim Options-Bau eine blockierende
DB-Verbindung -> haengt/crasht den Start, wenn die DB nicht erreichbar ist.
3. CopyTradingEngine.StartAsync lud den MarketCache ungeschuetzt -> DB-Fehler
riss AppHost.Start() ab, bevor die UI erschien.
Fixes:
- csproj: appsettings.Local.json mit ins Output kopieren (CopyToOutputDirectory).
- Program: UseContentRoot(AppContext.BaseDirectory) -> Config wird immer neben
der EXE gesucht (Main + Smoke-Test).
- ServerVersion fest gepinnt: DatabaseServerVersion.Value = MariaDB 11.8.6 (wie
am Server erkannt); AddCorePersistence + CopyTradingModule nutzen sie statt
AutoDetect. Kein blockierender Connect mehr beim Start.
- CopyTradingEngine-Preload in try/catch: DB-Fehler bricht den Start nicht mehr ab.
- Neuer Diagnose-CLI --db-version (gibt @@version aus).
Verifiziert: --smoke-ui aus fremdem Arbeitsverzeichnis laeuft gruen
(3 Accounts / 32 Trader hydriert, alle Views + Launcher OK).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- ModuleView liefert jetzt ein Form (CreateForm statt CreateControl); die 4 Views
(Terminal, Settings, Jobs, Dashboard) von UserControl auf Form umgestellt
(im Designer als Fenster bearbeitbar). ViewHostForm entfernt.
- ShellUiHost verwaltet offene Forms: Einzelinstanz, bereits offenes Fenster wird
in den Vordergrund geholt, OpenStateChanged-Event.
- LauncherForm: Fenster-Buttons an View-IDs gebunden; offene Fenster werden am
Button markiert (Checked), erneuter Klick holt das Fenster nach vorn.
- Build 0 Fehler.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Core: TradeRecord (Modell) + ITradeLogRepository (+ Mongo-Impl, Collection
"trade_log"), in AddCorePersistence registriert. Realisiert den generischen,
modulneutralen Trade-Log aus Entscheidung #2.
- Dual-Write: PersistenceService schreibt geschlossene Copy-Trades zusaetzlich als
generischen TradeRecord (ModuleName="CopyTrading").
- Neue DashboardView (UserControl + Designer): zeigt die letzten Trades ALLER
Module (GetRecent) mit Konto-Aufloesung + Kurzauswertung (Gesamt-PnL, Anzahl,
Aufschluesselung je Modul). btn_dashboard im Launcher, View "core.dashboard".
- Build 0 Fehler.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- IPolyTraderModule um RegisterUi(IModuleUiHost) erweitert.
- Neu: IModuleUiHost + ModuleView (Core, Modularity) — Views sind designbare
Controls (UserControls), die die Shell in eigenständigen Host-Fenstern öffnet.
- Core: UseWindowsForms aktiviert (fuer den Control-Typ im Contract).
- Build 0 Fehler. Noch keine View implementiert (folgt view-fuer-view).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Nach dem TradingState-Split nutzt MarketSyncService nur noch Core-State
(MarketCache) + IMarketRepository + Core-API-Service -> sauber in den Core.
- Ungenutzten Shim-Import entfernt. Build 0 Fehler.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Beide Services nach Core (nutzen nur TerminalLogger/ServerSettings/JobManager,
keine DB/TradingState/Modul-Typen).
- Threema-ProjectReference von App -> Core umgehängt (App nutzte die Lib nur
über ThreemaService).
- Microsoft.Extensions.Hosting.Abstractions als Core-Paket (BackgroundService).
- Toten Stub services/mullvad.cs gelöscht; Mullvad-DB-Usings entfernt.
- Build 0 Fehler.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- ServerSettings-Model nach src/PolyTrader.Core/Models/ (Namespace beibehalten).
- Keine DB-Abhängigkeit; reines Verschieben. Build 0 Fehler.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Interfaces: IAccountRepository, IMarketRepository, IPositionRepository
(IPositionRepository kapselt das Collection-per-Account-Muster).
- Mongo-Implementierungen bilden die bisherige Shim-Semantik 1:1 mit direkten
MongoDB.Driver-Aufrufen nach (kein App-Shim-Bezug im Core).
- AddCorePersistence()-Erweiterung + Registrierung in Program.cs.
- Noch keine Call-Sites umgestellt; Build 0 Fehler.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Neue Core-Klasse DatabaseOptions (Sektion "Database"), gebunden via IOptions.
- appsettings.json im App-Projekt (Mongo-Connection + DB-Name), wird in den
Output kopiert.
- Program.cs: hart codierte "mongodb://localhost:27017" und "PolyTraderDB"
durch konfigurierte Werte ersetzt.
- Startup-Cleanup-Hack aus dem Kopf von Main() entfernt und gekapselt nach
dem Host-Build über die konfigurierte DB neu verankert.
- Solution-Build 0 Fehler; appsettings.json im Output verifiziert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>