Die Regel galt seit dem Umbau auf Avalonia, stand aber nirgends: Der Ausgabeweg ist waehlbar - Desktop, Web oder beides gleichzeitig -, und daraus folgt genau eine harte Vorgabe: Fachlichkeit lebt in einem Core-Dienst, nie in einer Ansicht. Ein Fenster und ein Endpunkt sind zwei Zugaenge auf denselben Dienst. In den Grundregeln steht jetzt die Prueffrage dazu (koennte ein zweiter Ausgabeweg dasselbe tun, ohne diese Zeile zu kopieren?), die Vorgabe, dass Dienst und Endpunkt im selben Zug wie das Fenster entstehen, und der Daemon als Gegenprobe: Was sich kopflos nicht bedienen laesst, haengt zu sehr am Fenster. docs/ANLEITUNG-WebUI.md richtet sich an den Agenten, der #490 uebernimmt. Enthaelt den gemessenen Bestand, die Reihenfolge der drei Bloecke, die Tabelle der 24 Endpunkte mit ihren Diensten, die beiden nicht-mechanischen Stellen (Logs als Push, Settings mit Zugangsdaten) und die Grenzen - vor allem: keine Fachlogik anfassen, keine schreibenden Endpunkte ohne Anmeldung. Ein Punkt darin ist Architektur und keine Geschmacksfrage: Der Core darf die Module nicht kennen, also koennen Modul-Routen nicht im Core registriert werden. Sie gehoeren ins Hosting-Projekt, das die Module ohnehin kennt - so wie die Modulfenster zentral in App/Shell/ModuleViews.cs stehen und nicht im Modul. 473 Tests gruen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.4 KiB
trigger
| trigger |
|---|
| always_on |
Projektname: IBKRTrader 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):
Harter Core + beliebig viele unabhängige Module Module dürfen Core oder andere Module niemals beeinflussen DB-Tabellen-Namensschema: {ModulKürzel}_Tabellenname → Core = core_xxx → CongressTrading = ct_xxx Vollständig modulare Worker-Engine: Jeder Worker ist komplett unabhängig, hat eigenen Zeitplan, ist einzeln aktivierbar/deaktivierbar/manuell startbar Keine gegenseitigen Blockierungen – alles thread-sicher und performant
Technik (fest):
C# .NET 10, Avalonia für die Oberfläche – plattformneutral (Windows und Linux).
KEIN WinForms und kein System.Drawing: beides bindet an Windows. Alle Projekte sind net10.0
ohne Plattform-Suffix; ein net10.0-windows irgendwo ist ein Fehler.
Avalonia bleibt auf der 11er-Linie (11.3.19 / DataGrid 11.3.13), bis LiveCharts2 Avalonia 12
unterstützt – sonst brechen die Diagramme der kommenden Module.
MySQL – Zugangsdaten NUR in settings.json (gitignored), NIE im Repo/Code/Doku hinterlegen
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)
Settings: settings.json (Vorlage: settings.example.json)
Logging: LoggingService meldet Einträge über das Ereignis EntryWritten (die Oberfläche hängt sich
ein und färbt selbst) + Dateien unter Logs/[Modul]/[Level]-dd-MM-yy.txt sowie Logs/[Datum].jsonl
Zeit: Zeitstempel IMMER in UTC persistieren. Für Anzeige, Tagesgrenzen und Zeitpläne
AppTimeZone verwenden, NIE DateTime.Now oder DateTimeKind.Local – wir betreiben Instanzen
in EU und US, die Ortszeit darf nicht am Rechner hängen.
Kultur: Jede Zahl-/Datumsformatierung und jedes Parsen braucht einen ausdrücklichen
IFormatProvider (i. d. R. InvariantCulture). Ohne ihn hängt das Ergebnis an der Kultur des Hosts.
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.
API-First (gilt seit dem Umbau auf Avalonia, seit 2026-09-06 ausgeschrieben):
Der Ausgabeweg ist wählbar – Desktop-UI, Web-UI oder beide gleichzeitig. Daraus folgt genau
eine harte Regel: Fachlichkeit lebt in einem Core-Dienst, nie in einer Ansicht. Ein Fenster
und ein REST-Endpunkt sind zwei Zugänge auf denselben Dienst, und beide dürfen nur formatieren.
Prüffrage vor jedem UI-Code: Könnte ein zweiter Ausgabeweg dasselbe tun, ohne diese Zeile zu
kopieren? Lautet die Antwort nein, gehört die Zeile in den Core.
Jede neue Funktion bekommt ihren Core-Dienst UND ihren Endpunkt, im selben Zug wie ihr Fenster.
Nicht nachträglich: Endpunkte, die später in einem Block nachgezogen werden, kosten mehr und
weichen ab. Vorbild ist Core/Positions/PositionManager.cs – ein Dienst, drei Zugänge
(Shell-Fenster, Daemon-Schalter, GET /api/positions).
Der Daemon ist die Gegenprobe: Lässt sich eine Funktion kopflos nicht bedienen, hängt zu viel
am Fenster. Der Testbetrieb läuft als systemd-Dienst – dort gibt es keines.
Schreibende Endpunkte erst mit Anmeldung. Ohne sie wäre ein Eingriff in die Bücher möglich, den
niemand belegen kann; solange keine steht, bleibt die REST-Schnittstelle lesend.
UI-Grundmodell (Launcher-Prinzip nach Polytrader):
LauncherWindow = Basis-Fenster mit einer Schaltfläche je registrierter Ansicht und dem gemeinsamen Fenster-Menü. Die Inhalte (Dashboard, Workers, Logs, Settings, Modul-Fenster) sind eigenständige Fenster, keine Tabs; je Ansicht höchstens eines, erneutes Öffnen fokussiert. Layout deklarativ in .axaml, nicht zur Laufzeit im Code. Kompilierte Bindings sind aktiv, jeder Datenkontext braucht ein x:DataType – dadurch fallen Bindungsfehler beim Kompilieren auf. Module tragen KEINEN UI-Code: sonst müssten sie Avalonia referenzieren und wären nicht mehr kopflos lauffähig. Ihr RegisterUi bleibt leer, die Fenster registriert die Shell zentral in src/IBKRTrader.App/Shell/ModuleViews.cs. Workers-Ansicht, Spalten: Aktiv | Typ | Modul | Worker | Letzter Lauf | Nächster Lauf | Intervall | Info Type = "Worker" oder "Service" (Service = permanent laufend)
Betriebsformen (beide aus derselben Host-Zusammenstellung, src/IBKRTrader.Hosting):
src/IBKRTrader.App – mit Oberfläche; --smoke-ui prüft die Fenster-Konstruktion ohne Anzeigegerät
src/IBKRTrader.Daemon – kopflos für Linux/systemd; --check fährt die Startprüfungen ohne Dienste
Core-Worker (müssen zuerst):
Backup (alle 30 min) Webserver (Service) WebAPI (Service)
Erstes Modul: CongressTrading → Scrapt https://www.capitoltrades.com/trades?pageSize=96 → Tabellen: ct_congressMember + ct_trade → Zuerst alle Trades der letzten 3 Jahre, danach Worker alle 30 min neue Trades Entwicklungs-Regeln:
Immer extrem saubere, modulare, wartbare Architektur Build-Ordner muss absolut clean sein (nur notwendige Dateien) Arbeite streng schrittweise: zuerst Core fertig, dann Module Jede neue Funktion zuerst als Worker/Service im Core oder im jeweiligen Modul anlegen
Diese Rule hat immer höchste Priorität. Bei jedem Prompt und jedem Neustart gelten diese Vorgaben.