From 6a0f9af3f80d9c29bd632dcac19b975d80f37525 Mon Sep 17 00:00:00 2001 From: Kleidukos Date: Tue, 1 Sep 2026 17:37:49 +0200 Subject: [PATCH] docs: add comprehensive platform STATE.md and diagnostic PROBLEMS.md --- PROBLEMS.md | 221 +++++++++++++++++++ STATE.md | 612 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 833 insertions(+) create mode 100644 PROBLEMS.md create mode 100644 STATE.md diff --git a/PROBLEMS.md b/PROBLEMS.md new file mode 100644 index 0000000..d67576f --- /dev/null +++ b/PROBLEMS.md @@ -0,0 +1,221 @@ +# Finlytic Problemanalyse & Schwachstellenbericht (PROBLEMS.md) + +Dieses Dokument analysiert detailliert alle identifizierten Fehler, logischen Inkonsistenzen, mathematischen/finanziellen Ungenauigkeitsquellen, fehlenden Funktionen und Skalierungsrisiken im gesamten Finlytic-Codebase. + +--- + +## Inhaltsverzeichnis +1. [Kritische Bugs & Logikfehler](#1-kritische-bugs--logikfehler) +2. [Ursachen für Ungenauigkeiten (Inaccuracies & Drift)](#2-ursachen-für-ungenauigkeiten-inaccuracies--drift) +3. [Fehlende Funktionen & Architekturlücken](#3-fehlende-funktionen--architekturlücken) +4. [Skalierungs-, Performance- & Resilienz-Risiken](#4-skalierungs--performance---resilienz-risiken) +5. [Konkreter Maßnahmen- & Optimierungs-Fahrplan](#5-konkreter-maßnahmen---optimierungs-fahrplan) + +--- + +## 1. Kritische Bugs & Logikfehler + +### 1.1 Alpaca Bracket-Order Stop-Loss Update Fehler +- **Ort**: `FinlyticBot/Services/Alpaca/AlpacaPaperTradingService.cs` (Zeilen 123–147) +- **Problem**: + Beim Platzieren einer Bracket-Order (`PostOrderAsync`) gibt Alpaca die Order-ID der **übergeordneten Market-Order** zurück. Sobald diese ausgeführt wird, ist diese Order abgeschlossen (`filled`). + In `UpdateStopLossAsync` wird versucht, `client.PatchOrderAsync(new ChangeOrderRequest(orderGuid) { StopPrice = ... })` direkt mit der übergeordneten Market-Order-ID aufzurufen. +- **Auswirkung**: + Alpaca lehnt das Update mit `422 Unprocessable Entity` oder `404 Not Found` ab, da nicht die Parent-Order, sondern die untergeordnete Stop-Loss-Leg-Order gepatcht werden muss. +- **Lösung**: + Nach der Ausführung muss die Order über `client.GetOrderAsync()` abgefragt werden, um die `legs` (Child-Orders) zu inspizieren und die ID der Stop-Loss-Order in `BotPositionEntity` zu speichern. + +--- + +### 1.2 Bot-Positionsüberwachung fragt nicht existierende 1m-Kerzen ab +- **Ort**: `FinlyticBot/Services/Monitoring/BotTradeLifecycleBackgroundService.cs` (Zeile 82–86) +- **Problem**: + Der Lifecycle-Service pollt `ta_GetCandles` mit `Timeframe = "1m"`. + `FinlyticTechnicals` befüllt seine Ringpuffer jedoch primär via Yahoo Finance mit den Timeframes `15m`, `1h` und `1d`. Die `1m`-Kerzen werden ausschließlich live generiert, wenn `TradeRepublicIngestionService` für genau dieses Asset Ticks streamt. +- **Auswirkung**: + Für Assets, die nicht aktiv über Trade Republic gestreamt werden, gibt `ta_GetCandles` eine leere Liste zurück (`candles.Count == 0`). Der Bot führt `continue` aus und aktualisiert weder den aktuellen Kurs (`CurrentPrice`), noch prüft er Stop-Loss- oder Take-Profit-Bedingungen. +- **Lösung**: + Fallback auf den kleinsten verfügbaren Timeframe (`15m`) oder direkte Abfrage des letzten Live-Kurses (`tr_GetLivePrice`). + +--- + +### 1.3 Inkonsistente Datenbankbenennung für FinlyticSentiment +- **Ort**: `compose.yaml` (Zeile 138) vs. Dokumentation & Konventionen +- **Problem**: + In `compose.yaml` heißt die Datenbank `finlytic_sentimental`, während die Namenskonvention aller anderen Services `finlytic_{service}` lautet (also `finlytic_sentiment`). +- **Auswirkung**: + Bei automatisierten Backups, Init-Skripten oder manuellen SQL-Inspektionen führt dieser Tippfehler zu Verwirrung oder fehlgeschlagenen Migrations-Skripten. +- **Lösung**: + Vereinheitlichung auf `finlytic_sentiment`. + +--- + +### 1.4 Unbenutzte Gebührenvariable im Synthetischen Ledger +- **Ort**: `FinlyticBot/Services/Ledger/SyntheticPaperBroker.cs` (Zeile 134, 149) +- **Problem**: + In `GetSummaryAsync` wird `decimal totalFees = positions.Sum(p => p.TotalFeesEur);` berechnet, aber in der Equity-Formel nicht verwendet: + `decimal currentEquity = baseCapital + totalRealized + unrealizedPnl;` + *(Hinweis: `totalRealized` hat die Gebühren bereits bei Schließung abgezogen; die Variable `totalFees` ist toter Code).* +- **Lösung**: + Bereinigung oder explizite Dokumentation der Netto-PnL-Logik. + +--- + +## 2. Ursachen für Ungenauigkeiten (Inaccuracies & Drift) + +### 2.1 Fehlende Währungskonvertierung (USD vs. EUR bei Alpaca) +- **Ort**: `FinlyticBot/Services/Execution/BotOrderExecutor.cs` & `FinlyticBot/Services/Alpaca/AlpacaPaperTradingService.cs` +- **Problem**: + - Finlytics Kontoführung, synthetischer Ledger und Risikoberechnungen (`SyntheticBaseCapitalEur`, Sizing-Formel) rechnen strikt in **EUR (€)**. + - Alpaca US-Equities (z.B. AAPL, NVDA) werden in **USD ($)** abgerechnet und bepreist. + - `BotOrderExecutor` übergibt den EUR-Preis 1:1 an Alpaca bzw. nimmt für das Sizing an, dass $1 = 1 €$. +- **Ungenauigkeit**: + Je nach EUR/USD-Wechselkurs (z.B. 1,08) weicht das tatsächliche Risiko um **8–15%** von der 1%-Risikoregel ab. +- **Lösung**: + Integration eines FX-Umrechnungskurses (z.B. über EZB-Feed oder Yahoo EURUSD=X) in die Sizing- und Positionsbewertungslogik. + +--- + +### 2.2 Warmup-Verzerrung bei EMA 200 & langfristigen Indikatoren `[BEHOBEN]` +- **Ort**: `FinlyticTechnicals/Indicators/TechnicalIndicatorsEngine.cs`, `CoreStrategies.cs` & `TechnicalScoringEngineV2.cs` +- **Problem**: + Wenn für ein neu hinzugefügtes Asset weniger als 200 historische Kerzen vorlagen, wurde der EMA 200 aus den verfügbaren Kerzen berechnet (Fallback auf SMA über z.B. 50 Kerzen). +- **Lösung / Status**: + **Behoben**: `CalculateEma` gibt bei `candles.Count < period` strikt `0m` zurück. `TrendPullbackFvgStrategy` und `MovingAverageCrossoverStrategy` prüfen strikt $\ge 205$ Kerzen, und `TechnicalScoringEngineV2` vergibt Confluence-Punkte nur bei `EMA > 0m`. + +--- + +### 2.3 Intrabar-Pfad-Ungewissheit im Backtesting `[BEHOBEN]` +- **Ort**: `FinlyticSimulation/Engine/VirtualBacktestBroker.cs` +- **Problem**: + Eine Kerze liefert nur $O, H, L, C$. Wenn innerhalb derselben Kerze sowohl das Take-Profit-Level ($H$) als auch das Stop-Loss-Level ($L$) berührt wurden, konnte der Backtester nicht feststellen, welches Extremum zuerst eintrat. +- **Lösung / Status**: + **Behoben**: Konservatives Worst-Case-Prinzip implementiert. Stop-Loss und Knock-Out-Checks werden strikt vor Take-Profit ausgeführt. Wird TP1 in einer Kerze ausgelöst und der Stop auf Break-Even gezogen, wird sofort geprüft, ob das Bar-Tief auch das Break-Even-Level schneidet, um die Restposition ggf. direkt als Break-Even auszustoppen. + +--- + +### 2.4 Feste Slippage `[BEHOBEN / ENTFERNT]` +- **Ort**: `FinlyticSimulation/Engine/VirtualBacktestBroker.cs` & `SimulationSettingKeys.cs` +- **Problem**: + Bisher wurde neben der festen Ordergebühr zusätzlich eine prozentuale Slippage (0.05%) auf Kursdaten angewendet. +- **Lösung / Status**: + **Behoben**: Künstlicher Slippage-Aufschlag/-Abschlag vollständig aus der Kursausführung entfernt; Transaktionskosten werden transparent und sauber über die Ordergebühren (`_orderFeeEur = 1.00 €`) abgebildet. `DefaultSlippagePercent` wurde auf `0.0m` gesetzt. + +--- + +### 2.5 Trade Republic WebSocket-Inaktivitäts-Timeout +- **Ort**: `FinlyticCore/Services/TradeRepublic/TradeRepublicService.cs` (`_inactivityTimer = 461 Sekunden`) +- **Problem**: + Wenn 7,6 Minuten lang keine Anfrage an Trade Republic gestellt wird, schließt der Timer die WebSocket-Verbindung. Bei der nächsten Anfrage muss die Verbindung neu aufgebaut werden. +- **Ungenauigkeit**: + Der Neuaufbau dauert 1–3 Sekunden. In dieser Zeit schlagen Live-Kurs-Abfragen fehl oder liefern veraltete Cache-Preise. +- **Lösung**: + Automatischer Ping/Keepalive statt Schließung oder resilienter Reconnect mit Retry. + +--- + +### 2.6 Typkonvertierungen (`double` vs. `decimal`) +- **Ort**: Mehrere Services (FinBERT DTOs nutzen `double`, Engine/Technicals nutzen `decimal`) +- **Problem**: + In `CompositeOpportunityScorerV2` wird `(decimal)sentiment.CurrentSummary.CompoundScore` gecastet. Fließkommazahlen (`double`) können binäre Rundungsfehler aufweisen (z.B. `0.15000000000000002`). +- **Lösung**: + Rundung auf 4 Nachkommastellen vor dem Casten (`Math.Round((decimal)score, 4)`). + +--- + +## 3. Fehlende Funktionen & Architekturlücken + +### 3.1 Fehlende Short-Derivate-Alternativen bei Trade Republic +- **Ort**: `FinlyticEngine/Services/Derivatives/KnockOutDerivativeResolver.cs` +- **Lücke**: + Wenn `FinlyticTechnicals` ein starkes Short-Signal (Verkauf) generiert, sucht der Resolver ausschließlich nach `knockOutProduct` mit `OptionType.Short` (Put Knock-Outs). Gibt es für das Asset keine KO-Puts bei Trade Republic, scheitert die Derivate-Zuweisung komplett. +- **Erweiterung**: + Automatischer Fallback auf klassische Put-Optionsscheine (`vanillaWarrant`) oder Faktor-Short-Zertifikate. + +--- + +### 3.2 Keine Portfolio-Korrelations- & Branchenrisiko-Prüfung +- **Ort**: `FinlyticBot/Services/Execution/BotOrderExecutor.cs` +- **Lücke**: + Der Bot prüft lediglich, ob `activeCount < MaxConcurrentPositions` (5) ist. Er prüft nicht, ob alle 5 Positionen aus demselben Sektor stammen (z.B. 5x Halbleiter/Tech). +- **Erweiterung**: + Sektoren-Exposure-Limit: Maximal 2 Positionen pro Sektor oder maximal 40% Gesamtallokation in einer Branche. + +--- + +### 3.3 Fehlende Multi-User-Isolation im Bot +- **Ort**: `FinlyticBot/Database/Entities/BotPositionEntity.cs` +- **Lücke**: + `EngineTradeEntity` in `FinlyticEngine` besitzt bereits ein `UserId`-Feld für Multi-Tenancy. `BotPositionEntity` im `FinlyticBot` besitzt jedoch **kein `UserId`-Feld** – alle Bot-Trades laufen in einem globalen Pool. +- **Erweiterung**: + Erweiterung von `BotPositionEntity` um `UserId` und Filterung im `BotController` nach dem authentifizierten Benutzer. + +--- + +### 3.4 Fehlender nativer Trailing-Stop bei Alpaca +- **Ort**: `FinlyticBot/Services/Alpaca/AlpacaPaperTradingService.cs` +- **Lücke**: + Alpaca unterstützt native Trailing-Stop-Orders (`trailing_stop`). Der Service nutzt bisher nur feste Bracket-Orders und versucht, den Stop-Loss diskret im 15s-Polling-Intervall nachzuziehen. +- **Erweiterung**: + Nutzung der nativen Alpaca `TrailingStopOrder`-API für exaktes Tick-basiertes Nachziehen ohne Latenzrisiko. + +--- + +### 3.5 Fehlende Historienbereinigung (Data Retention Cleanup Cron) +- **Ort**: `FinlyticNews`, `FinlyticSentiment`, `FinlyticEngine` +- **Lücke**: + Obwohl `SettingKeys.ArticleRetentionDays` (90 Tage) existiert, läuft kein automatischer Hintergrund-Cleanup-Job, der abgelaufene Artikel, Snapshots oder Logs physisch aus der PostgreSQL-Datenbank löscht. +- **Erweiterung**: + Einrichten eines täglichen Wartungs-Background-Services (`DataRetentionCleanupWorker`). + +--- + +## 4. Skalierungs-, Performance- & Resilienz-Risiken + +### 4.1 Unbegrenztes Speicherwachstum bei In-Memory-Ringpuffern +- **Ort**: `FinlyticTechnicals/Services/MultiTimeframeCandleAggregator.cs` +- **Risiko**: + `_buffers` hält für jedes jemals abgefragte Asset ein `ConcurrentDictionary` mit je 500 Kerzen über 5 Timeframes. Werden über den Scanner 10.000 Assets abgefragt, belegt dies mehrere Gigabyte RAM im Container. +- **Lösung**: + Einführung einer LRU-Cache-Bereinigung (z.B. `MemoryCache` mit Ablaufzeit für Assets außerhalb der Watchlist). + +--- + +### 4.2 Playwright-Browser-Instanzen & Zombie-Prozesse +- **Ort**: `FinlyticNews/Services/PlaywrightScraperService.cs` & `FinlyticFundamentals` +- **Risiko**: + Playwright startet Chromium-Headless-Instanzen. Bei Netzwerk-Timeouts oder abrupten Thread-Abbrüchen können verwaiste `chrome`-Prozesse im Docker-Container verbleiben und Speicher/CPU leersaugen. +- **Lösung**: + Striktes `using`-Ressourcenmanagement mit `BrowserContext.CloseAsync()` und Docker-Container-Speicherlimits (`mem_limit` in `compose.yaml`). + +--- + +### 4.3 Rate-Limiting & IP-Blocking bei Yahoo Finance +- **Ort**: `FinlyticCore/Clients/YahooFinanceClient.cs` & `YahooFinanceScraper.cs` +- **Risiko**: + Yahoo Finance besitzt unangekündigte Rate-Limits. Werden 100 Assets parallel gescannt, antwortet Yahoo mit `HTTP 429 Too Many Requests`. +- **Lösung**: + Zentraler Request-Throttler mit Polly-Retry und Exponential-Backoff im `YahooFinanceClient`. + +--- + +### 4.4 Single Point of Failure (MQTT-Broker & OmniDB) +- **Risiko**: + Alle Microservices sind über einen einzelnen MQTT-Broker verbunden. Fällt dieser aus, bricht die gesamte Inter-Service-Kommunikation ab. +- **Lösung**: + Polly-basierte Reconnect-Pipelines sind in `ManagedMqttClient` vorhanden, sollten jedoch mit Offline-Queuing ergänzt werden. + +--- + +## 5. Konkreter Maßnahmen- & Optimierungs-Fahrplan + +| Priorität | Bereich | Maßnahme | Aufwand | +| :---: | :--- | :--- | :---: | +| 🔴 **P1** | `FinlyticBot` | **Alpaca Bracket-Order Leg-ID Fix**: Stop-Loss-Leg nach Orderplatzierung ermitteln und speichern, um `UpdateStopLossAsync` funktionsfähig zu machen. | Gering | +| 🔴 **P1** | `FinlyticBot` | **1m-Kerzen-Polling beheben**: Fallback auf `15m` oder `tr_GetLivePrice` im `BotTradeLifecycleBackgroundService`. | Gering | +| 🟡 **P2** | `FinlyticBot` | **USD/EUR Währungskonvertierung**: Integration eines dynamischen Wechselkurses für US-Positionen. | Mittel | +| 🟡 **P2** | `FinlyticEngine` | **Derivate-Fallback erweitern**: Optionsscheine/Faktor-Zertifikate als Fallback bei fehlenden KO-Puts. | Mittel | +| 🟡 **P2** | `FinlyticTechnicals`| **EMA 200 Warmup-Guard**: Keine Signalfreigabe bei unvollständiger Kerzenhistorie ($<200$). | Gering | +| 🟢 **P3** | `FinlyticBot` | **Multi-User Isolation**: `UserId` zu `BotPositionEntity` hinzufügen. | Mittel | +| 🟢 **P3** | `FinlyticCore` | **Data Retention Background-Worker**: Automatisches Löschen alter News/Logs nach 90 Tagen. | Mittel | +| 🟢 **P3** | `FinlyticTechnicals`| **LRU-Cache für Ringpuffer**: Speicherdeckelung bei großen Asset-Zahlen. | Mittel | diff --git a/STATE.md b/STATE.md new file mode 100644 index 0000000..e4db21f --- /dev/null +++ b/STATE.md @@ -0,0 +1,612 @@ +# Finlytic Systemdokumentation (STATE.md) + +Dieses Dokument bietet eine lückenlose, detaillierte und strukturierte Gesamtdokumentation der gesamten Finlytic-Plattform. Es umfasst die Architektur, alle Konfigurationen & Einstellungen, mathematische/finanzielle Formeln, sämtliche Schnittstellen (MQTT RPC, MQTT Pub/Sub, REST API, SignalR Hubs), Datenbankstrukturen sowie die genaue Funktionsweise der 9 Microservices und des Flutter-Frontends. + +--- + +## Inhaltsverzeichnis +1. [Systemarchitektur & Topologie](#1-systemarchitektur--topologie) +2. [Microservices-Übersicht & Datenbanken](#2-microservices-übersicht--datenbanken) +3. [Einstellungen & Konfiguration (Settings)](#3-einstellungen--konfiguration-settings) +4. [Mathematische, Technische & Finanzielle Formeln](#4-mathematische-technische--finanzielle-formeln) +5. [Schnittstellen & Endpunkte](#5-schnittstellen--endpunkte) + - [5.1 MQTT RPC-Kanäle](#51-mqtt-rpc-kanäle) + - [5.2 MQTT Pub/Sub Event-Topics](#52-mqtt-pubsub-event-topics) + - [5.3 REST API Endpunkte (FinlyticBackend)](#53-rest-api-endpunkte-finlyticbackend) + - [5.4 SignalR Hubs & Methoden](#54-signalr-hubs--methoden) +6. [Detaillierte Funktionsweise & Datenfluss](#6-detaillierte-funktionsweise--datenfluss) +7. [Frontend-Architektur (FinlyticApp)](#7-frontend-architektur-finlyticapp) + +--- + +## 1. Systemarchitektur & Topologie + +Finlytic ist eine modulare, ereignisgesteuerte Finanzanalyse- und automatisierte Trading-Plattform für Aktien und Derivate (Knock-Out-Zertifikate, Optionsscheine). + +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ FinlyticApp (Flutter Web & Mobile) │ +└───────────────────────────────────┬────────────────────────────────────┘ + │ HTTP / WebSocket (SignalR) + ▼ +┌────────────────────────────────────────────────────────────────────────┐ +│ FinlyticBackend (API & Gateway) │ +└───────────────────────────────────┬────────────────────────────────────┘ + │ MQTT RPC & Pub/Sub + ┌──────────────┬───────────────┼──────────────┬──────────────┐ + ▼ ▼ ▼ ▼ ▼ +┌──────────┐ ┌──────────────┐ ┌───────────┐ ┌─────────────┐ ┌────────────┐ +│Finlytic │ │FinlyticNews │ │Finlytic │ │Finlytic │ │Finlytic │ +│Assets │ │ │ │Sentiment │ │Fundamentals │ │Technicals │ +└────┬─────┘ └──────┬───────┘ └─────┬─────┘ └──────┬──────┘ └─────┬──────┘ + │ │ │ │ │ + └──────────────┴───────┬───────┴──────────────┴──────────────┘ + │ MQTT (Signale, Scores, Setups) + ┌──────────────────────┼──────────────────────┐ + ▼ ▼ ▼ +┌──────────┐ ┌──────────────┐ ┌────────────┐ +│Finlytic │ ──────► │FinlyticBot │ │Finlytic │ +│Engine │ (Trades)│(Auto-Trading)│ │Simulation │ +└────┬─────┘ └──────────────┘ └────────────┘ + │ + ▼ +┌──────────┐ +│Finlytic │ ──────► ntfy Push-Server (Mobil & Webhooks) +│Notify │ +└──────────┘ +``` + +### Kernprinzipien & Regeln (Rules.md): +1. **MQTT-Exklusivität im Backend**: Alle internen Microservices kommunizieren ausschließlich über MQTT. Es gibt keine direkten HTTP-Verbindungen zwischen Backend-Diensten. +2. **Einziges Web-Gateway**: `FinlyticBackend` ist der einzige Dienst mit Kestrel-HTTP/WebSocket-Port (`5000:8080`). +3. **Strikte Datenisolation**: Jeder Service besitzt seine eigene PostgreSQL-Datenbank (keine geteilten Tabellen). +4. **Dynamische Konfiguration**: Dynamic Settings (`ISettingsService`) werden in DB persistiert und per MQTT aktualisiert, ohne Neustart. +5. **Kanalbasiertes Logging**: Jeder Service sendet strukturierte Logs per MQTT (`finlytic/logs/{service}`), die im Admin-Panel live gestreamt werden. +6. **Keine Scheindaten**: Reine Echtdaten oder explizite Empty-States/Exceptions. + +--- + +## 2. Microservices-Übersicht & Datenbanken + +| Service | Typ / Basis | PostgreSQL-Datenbank | Hauptaufgabe | +| :--- | :--- | :--- | :--- | +| **FinlyticCore** | Shared Class Library | *(Keine eigene DB)* | Gemeinsame DTOs, Enums, MQTT-Clients, TradeRepublic-Client, Settings-Interface. | +| **FinlyticAssets** | Background Worker | `finlytic_assets` | Stammdaten-Synchronisation (Stocks, ETFs), Lokale Logo-Speicherung, Trade Republic Ticker-Proxy, KO-Derivate-Abfrage. | +| **FinlyticNews** | Playwright Worker | `finlytic_news` | Scraping von 10 Finanzportalen, Duplikaterkennung (SimHash/Jaccard), Regex/NLP-Asset-Matching, Sector-Clustering. | +| **FinlyticSentiment** | Background Worker | `finlytic_sentimental` | FinBERT KI-Sentiment-Analyse (Deutsch & Englisch Webhooks), Exponentielle Zeit-Decay-Gewichtung ($\lambda = \ln(2)/\tau$). | +| **FinlyticFundamentals** | Playwright Worker | `finlytic_fundamentals`| Fundamentaldaten & Kennzahlen (KGV, ROE, Cashflow, Analysten-Ratings, Dividenden, Earnings-Kalender). | +| **FinlyticTechnicals** | Background Worker | `finlytic_ta` | Multi-Timeframe-Kerzen (15m, 1h, 1d), 10 Kernstrategien, 15 Pattern-Detektoren (SMC & Chart), Symmetrisches Scoring V2. | +| **FinlyticEngine** | Background Worker | `finlytic_engine` | Composite Opportunity Scorer (COS V2), Earnings/Dividenden-Sperren, n8n AI Reasoning Gate, Trade Lifecycle & Monitoring. | +| **FinlyticSimulation** | Background Worker | `finlytic_simulation` | Quantitative Backtesting-Engine, Replay-Runner (Anti-Lookahead), Zuverlässigkeitsmatrix, Slippage- & Gebührenmodellierung. | +| **FinlyticBot** | Background Worker | `finlytic_bot` | Automatisierte Orderausführung (1-2% Risikoregel), Alpaca Paper Trading (US-Equities) & Interner Synthetischer Ledger. | +| **FinlyticNotify** | Background Worker | `finlytic_notify` | Push-Benachrichtigungen via ntfy (Proposals, Trade-Events, Bot-Status, News). | +| **FinlyticBackend** | ASP.NET Core Kestrel | `finlytic_backend` | JWT-Authentifizierung, User- & Favoritenverwaltung, SignalR-Streaming, MQTT-Bridge. | + +--- + +## 3. Einstellungen & Konfiguration (Settings) + +### 3.1 Umgebungsvariablen (`compose.yaml` / `.env`) + +| Variable | Standardwert | Beschreibung | +| :--- | :--- | :--- | +| `DB_HOST` | `OmniDB` | Hostname der PostgreSQL-Instanz | +| `DB_PORT` | `5432` | Port der PostgreSQL-Instanz | +| `DB_PASSWORD` | *(Pflichtfeld)* | Passwort für den PostgreSQL-Benutzer `admin` | +| `MQTT_HOST` | `host.docker.internal` | Hostname des MQTT-Brokers (z.B. Mosquitto) | +| `MQTT_PORT` | `4545` | Port des MQTT-Brokers | +| `JWT_SECRET_KEY` | *(Pflichtfeld, $\ge 32$ Zeichen)* | Signaturschlüssel für JWT-Token | +| `ADMIN_DEFAULT_PASSWORD` | *(Pflichtfeld)* | Initiales Passwort für den Standard-Admin | +| `FINLYTIC_DATA_ROOT` | `C:/Users/larsh/Documents/docker/finlytic` | Pfad für persistente Assets (Logos, Index) | +| `NTFY_BASE_URL` | `http://host.docker.internal:8080` | Basis-URL des ntfy-Push-Servers | +| `Webhooks__German` | `https://n8n.kleidukos.me/webhook/sentiment/de` | FinBERT Webhook für deutsche Artikel | +| `Webhooks__English` | `https://n8n.kleidukos.me/webhook/sentiment/en` | FinBERT Webhook für englische Artikel | +| `Ai__N8nValidationWebhookUrl`| `https://n8n.kleidukos.me/webhook/trade-validation` | n8n Webhook für AI-Trade-Validierung | + +--- + +### 3.2 Dynamische Service-Einstellungen (`ISettingsService`) + +Jeder Microservice verwaltet typisierte, zur Laufzeit änderbare Konfigurationswerte: + +#### **FinlyticAssets (`SettingKeys.cs`)** +- `Logging.Channel.Assets` (bool, default: `true`): Logging für Asset-Scans +- `Logging.Channel.MQTT` (bool, default: `true`): Logging für MQTT-Verkehr +- `Logging.Channel.Health` (bool, default: `true`): Logging für Ping-Healthchecks +- `Logging.Channel.TradeRepublic` (bool, default: `true`): Logging für TR-WebSocket +- `TradeRepublic.WsReconnectIntervalSeconds` (int, default: `5`): Reconnect-Wartezeit +- `TradeRepublic.WsTimeoutSeconds` (int, default: `15`): Timeout für TR-Anfragen +- `Scanner.EnableAutoScan` (bool, default: `true`): Automatischer Asset-Sync aktiviert +- `Scanner.CurrentScanningType` (string, default: `"Stock"`): Aktueller Typ im Loop +- `Scanner.CurrentScanningPage` (int, default: `0`): Aktuelle Paginierungsseite (Recovery-Modus) +- `Scanner.FinishedInitialScan` (bool, default: `false`): Status des Initial-Scans +- `Scanner.BatchAssetUpdateDelay` (int, default: `0`): Pause zwischen Batches (Sekunden) +- `Scanner.AssetUpdateTypeDelay` (int, default: `0`): Pause zwischen Typen (Sekunden) +- `Scanner.TradeRepublicMaxRequestPageSize` (int, default: `50`): Batchgröße pro TR-Call +- `Scanner.CycleDelayMinutes` (int, default: `1440`): Wartezeit bis zum nächsten Vollscan (24h) + +#### **FinlyticNews (`SettingKeys.cs`)** +- `Logging.Channel.News` (bool, default: `true`): News-Verarbeitungs-Logs +- `Logging.Channel.Scraper` (bool, default: `true`): Scraper-Adapter-Logs +- `Logging.Channel.Matcher` (bool, default: `true`): In-Memory Asset-Matcher-Logs +- `Logging.Channel.Deduplication` (bool, default: `true`): Duplikaterkennungs-Logs +- `Scraping.IntervalMinutes` (int, default: `15`): Scraping-Intervall +- `Scraping.MaxArticlesPerFeed` (int, default: `20`): Maximale Artikel pro Feed +- `Feature.EnableAutoScraping` (bool, default: `true`): Automatisches Scraping aktiv +- `Scraping.HttpTimeoutSeconds` (int, default: `30`): Timeout für HTTP/Playwright +- `Deduplication.TitleSimilarityThreshold` (double, default: `0.85`): Jaccard-Schwellenwert +- `Deduplication.SimHashMaxHammingDistance` (int, default: `3`): Max. SimHash-Bitdistanz +- `Deduplication.WindowDays` (int, default: `7`): Historienfenster für Duplikate +- `Matching.MinNameLength` (int, default: `3`): Minimale Zeichenlänge für Namensmatching +- `Matching.EnableSectorClustering` (bool, default: `true`): Sektorenprüfung bei Einzeltreffern +- `Matching.RequireFinancialContextForShortNames` (bool, default: `true`): Finanzkontext für kurze Namen +- `Data.ArticleRetentionDays` (int, default: `90`): Aufbewahrungsdauer für News + +#### **FinlyticSentiment (`SettingKeys.cs`)** +- `Logging.Channel.Sentiment` (bool, default: `true`): Sentiment-Logs +- `Sentiment.GermanWebhookUrl` (string, default: `https://n8n.kleidukos.me/webhook/sentiment/de`) +- `Sentiment.EnglishWebhookUrl` (string, default: `https://n8n.kleidukos.me/webhook/sentiment/en`) +- `Sentiment.MinimumConfidenceThreshold` (double, default: `0.60`): Mindestkonfidenz +- `Sentiment.TimeDecayHalfLifeDays` (double, default: `7.0`): Halbwertszeit $\tau$ für Zeit-Decay +- `Sentiment.SentimentWindowDays` (int, default: `30`): Zeitfenster für Aggregation +- `Sentiment.AnalysisBatchSize` (int, default: `10`): Artikel pro Analysezyklus +- `Sentiment.PollIntervalSeconds` (int, default: `30`): Polling für neue Artikel +- `Sentiment.EnableAutoSentiment` (bool, default: `true`): Automatische Analyse aktiv + +#### **FinlyticFundamentals (`SettingKeys.cs`)** +- `Logging.Channel.Fundamentals` (bool, default: `true`): Fundamentaldaten-Logs +- `Logging.Channel.HtmlScrapper` (bool, default: `true`): Playwright-Scraper-Logs +- `Logging.Channel.YahooClient` (bool, default: `true`): Yahoo Finance API-Logs +- `Feature.EnableHtmlFallback` (bool, default: `true`): HTML-Scraping falls API fehlt +- `Scraper.ForceHtmlFallback` (bool, default: `false`): HTML-Scraping erzwingen +- `Feature.AllowForceRefresh` (bool, default: `true`): Cache-Umgehung erlauben +- `Cache.FundamentalDataValidityDays` (int, default: `30`): Cache-Gültigkeit + +#### **FinlyticTechnicals (`SettingKeys.cs`)** +- `Logging.Channel.TechnicalAnalysis` (bool, default: `true`): TA-Berechnungs-Logs +- `Indicators.RsiPeriod` (int, default: `14`): RSI-Periode +- `Indicators.MacdFastPeriod` (int, default: `12`): MACD Fast EMA +- `Indicators.MacdSlowPeriod` (int, default: `26`): MACD Slow EMA +- `Indicators.MacdSignalPeriod` (int, default: `9`): MACD Signal Line +- `Indicators.EmaShortPeriod` (int, default: `50`): EMA Short +- `Indicators.EmaLongPeriod` (int, default: `200`): EMA Long +- `Indicators.BollingerBandsPeriod` (int, default: `20`): Bollinger-Periode +- `Indicators.BollingerBandsStdDev` (double, default: `2.0`): Bollinger Standardabweichung +- `Indicators.AtrPeriod` (int, default: `14`): ATR-Periode +- `Cache.DurationMinutes` (int, default: `60`): Cache-Dauer + +#### **FinlyticEngine (`EngineSettingKeys.cs`)** +- `Engine.MinCompositeScore` (decimal, default: `75.0`): Mindest-Gesamtscore für Proposals +- `Engine.WeightTechnical` (decimal, default: `0.45`): Gewichtung Technik (45%) +- `Engine.WeightSentiment` (decimal, default: `0.35`): Gewichtung Sentiment (35%) +- `Engine.WeightFundamental` (decimal, default: `0.20`): Gewichtung Fundamentaldaten (20%) +- `Engine.EarningsLockoutDays` (int, default: `2`): Vorlaufzeit vor Earnings (Score-Suppression) +- `Engine.DividendGateDays` (int, default: `1`): Vorlaufzeit vor Ex-Dividende +- `Engine.MinDerivativeLeverage` (decimal, default: `5.0`): Mindesthebel für KO-Derivate +- `Engine.TargetDefaultLeverage` (decimal, default: `7.0`): Zielhebel für KO-Derivate +- `Engine.KnockOutSafetyBufferPercent` (decimal, default: `2.0`): Sicherheitsabstand Barrier zu SL +- `Engine.AiValidationTimeoutSeconds` (int, default: `15`): Timeout für n8n AI-Validierung +- `Engine.EnableAiValidation` (bool, default: `true`): KI-Gate aktiv (sonst Fast-Pass) +- `Engine.EnablePaperTradingBot` (bool, default: `false`): Automatische Bot-Ausführung +- `Engine.PollingIntervalSeconds` (int, default: `120`): Poller-Intervall (Opportunity-Scan) +- `Engine.MonitoringIntervalSeconds` (int, default: `60`): Aktives Trade-Monitoring-Intervall +- `Engine.PollerMinScore` (decimal, default: `70.0`): Mindestscore für FTA-Abfrage +- `Engine.PollerTopPicksOnly` (bool, default: `true`): Nur Top-Picks abfragen ($\ge 75$) +- `Engine.PollerLimit` (int, default: `25`): Max. Setups pro Scan +- `Engine.ProposalValidityHours` (int, default: `24`): Gültigkeitsdauer eines Vorschlags (24h) + +#### **FinlyticSimulation (`SimulationSettingKeys.cs`)** +- `Simulation.DefaultSlippagePercent` (decimal, default: `0.00`): Slippage deaktiviert (wird in Ordergebühren `DefaultOrderFeeEur` abgebildet) +- `Simulation.DefaultOrderFeeEur` (decimal, default: `1.00`): Ordergebühr pro Transaktion (1 €) +- `Simulation.DefaultStartingCapital` (decimal, default: `10000.00`): Startkapital für Backtests +- `Simulation.MinSampleTradesForApproval` (int, default: `5`): Mindest-Trades für Matrix-Zulassung +- `Simulation.HighProfitFactorThreshold` (decimal, default: `1.60`): PF für Score-Bonus (+15 Pkt) +- `Simulation.LowProfitFactorThreshold` (decimal, default: `1.00`): PF für Veto-Sperre +- `Simulation.KnockOutBarrierBufferPercent` (decimal, default: `2.0`): KO-Barrier-Simulation +- `Simulation.DefaultTrailingStopPercent` (decimal, default: `3.0`): Fallback-Trailing-Stop +- `Simulation.EnableScheduledMatrixRecompute` (bool, default: `true`): Periodische Matrix-Neuberechnung +- `Simulation.MatrixRecomputeIntervalHours` (int, default: `24`): Matrix-Stale-Schwelle (24h) +- `Simulation.MatrixRecomputeCheckIntervalMinutes` (int, default: `60`): Recompute-Check-Intervall + +#### **FinlyticBot (`BotSettingKeys.cs`)** +- `Alpaca.KeyId` (string): Alpaca API Key +- `Alpaca.SecretKey` (string): Alpaca Secret Key +- `Alpaca.IsPaper` (bool, default: `true`): Alpaca Paper vs. Live +- `Bot.EnableAutoExecution` (bool, default: `true`): Automatische Ausführung aktiv +- `Bot.RiskPerTradePercent` (decimal, default: `1.0`): 1% Risiko pro Trade bezogen auf Gesamtkapital +- `Bot.MaxPositionAllocationPercent` (decimal, default: `20.0`): Max. 20% Kapital pro Einzelposition +- `Bot.MaxConcurrentPositions` (int, default: `5`): Max. 5 offene Positionen gleichzeitig +- `Bot.DailyLossLimitPercent` (decimal, default: `3.0`): Täglicher Verluststopp (3%) +- `Bot.MonitoringIntervalSeconds` (int, default: `15`): Bot-Positionsüberwachung (15s) +- `Bot.SyntheticBaseCapitalEur` (decimal, default: `50000.0`): Startkapital Synthetischer Ledger + +#### **FinlyticNotify (`NotifySettingKeys.cs`)** +- `Ntfy.BaseUrl` (string, default: `http://localhost:8080`) +- `Ntfy.TopicPrefix` (string, default: `finlytic`) +- `Ntfy.BroadcastChannel` (string, default: `broadcast`) +- `Ntfy.NewsChannel` (string, default: `news`) +- `Ntfy.DefaultUsername` (string, default: `admin`) +- `Ntfy.MinProposalScore` (decimal, default: `70.0`) +- `Ntfy.NotifyOnProposals` (bool, default: `true`) +- `Ntfy.NotifyOnTradeUpdates` (bool, default: `true`) +- `Ntfy.NotifyOnBotTrades` (bool, default: `true`) +- `Ntfy.NotifyOnNews` (bool, default: `true`) +- `Ntfy.ClickBaseUrl` (string, default: `http://localhost:3000`) + +--- + +## 4. Mathematische, Technische & Finanzielle Formeln + +### 4.1 Technische Indikatoren (`TechnicalIndicatorsEngine.cs`) + +#### 1. Simple Moving Average (SMA) +$$\text{SMA}_n = \frac{1}{n} \sum_{i=0}^{n-1} P_{t-i}$$ + +#### 2. Exponential Moving Average (EMA) +Glättungsfaktor $k$: +$$k = \frac{2}{n + 1}$$ +$$\text{EMA}_t = (P_t \cdot k) + (\text{EMA}_{t-1} \cdot (1 - k))$$ +*(Initialisierung über SMA der ersten $n$ Kerzen)* + +#### 3. Relative Strength Index (RSI - Wilder's Smoothing) +Gewinne $U_t = \max(0, P_t - P_{t-1})$, Verluste $D_t = \max(0, P_{t-1} - P_t)$ +$$\overline{U}_t = \frac{\overline{U}_{t-1} \cdot (n-1) + U_t}{n}, \quad \overline{D}_t = \frac{\overline{D}_{t-1} \cdot (n-1) + D_t}{n}$$ +$$\text{RS} = \frac{\overline{U}_t}{\overline{D}_t}, \quad \text{RSI} = 100 - \frac{100}{1 + \text{RS}}$$ + +#### 4. Average True Range (ATR) +$$\text{TR}_t = \max \left( H_t - L_t, \, |H_t - C_{t-1}|, \, |L_t - C_{t-1}| \right)$$ +$$\text{ATR}_n = \frac{1}{n} \sum_{i=0}^{n-1} \text{TR}_{t-i}$$ + +#### 5. Moving Average Convergence Divergence (MACD) +$$\text{MACD Line} = \text{EMA}_{12}(P) - \text{EMA}_{26}(P)$$ +$$\text{Signal Line} = \text{EMA}_9(\text{MACD Line})$$ +$$\text{Histogram} = \text{MACD Line} - \text{Signal Line}$$ + +#### 6. Bollinger Bands & %B +$$\text{Middle Band} = \text{SMA}_{20}(P)$$ +$$\sigma = \sqrt{\frac{1}{20} \sum_{i=0}^{19} (P_{t-i} - \text{Middle Band})^2}$$ +$$\text{Upper Band} = \text{Middle Band} + 2\sigma, \quad \text{Lower Band} = \text{Middle Band} - 2\sigma$$ +$$\text{Bandwidth} = \frac{\text{Upper} - \text{Lower}}{\text{Middle}} \cdot 100, \quad \%B = \frac{P_t - \text{Lower}}{\text{Upper} - \text{Lower}}$$ + +#### 7. Keltner Channels & Volatility Squeeze +$$\text{KC Middle} = \text{EMA}_{20}(P), \quad \text{KC Upper} = \text{EMA}_{20} + 1.5 \cdot \text{ATR}_{20}, \quad \text{KC Lower} = \text{EMA}_{20} - 1.5 \cdot \text{ATR}_{20}$$ +$$\text{Squeeze On} \iff \text{BB Lower} > \text{KC Lower} \quad \text{UND} \quad \text{BB Upper} < \text{KC Upper}$$ + +#### 8. SuperTrend +$$\text{HL2} = \frac{H_t + L_t}{2}$$ +$$\text{Upper Band} = \text{HL2} + 3.0 \cdot \text{ATR}_{10}, \quad \text{Lower Band} = \text{HL2} - 3.0 \cdot \text{ATR}_{10}$$ + +#### 9. Average Directional Index (ADX / DMI) +$$+\text{DM} = \begin{cases} H_t - H_{t-1} & \text{falls } H_t - H_{t-1} > L_{t-1} - L_t \text{ und } > 0 \\ 0 & \text{sonst} \end{cases}$$ +$$-\text{DM} = \begin{cases} L_{t-1} - L_t & \text{falls } L_{t-1} - L_t > H_t - H_{t-1} \text{ und } > 0 \\ 0 & \text{sonst} \end{cases}$$ +$$+\text{DI}_{14} = \frac{\sum +\text{DM}}{\sum \text{TR}} \cdot 100, \quad -\text{DI}_{14} = \frac{\sum -\text{DM}}{\sum \text{TR}} \cdot 100$$ +$$\text{DX} = \frac{|+\text{DI} - -\text{DI}|}{+\text{DI} + -\text{DI}} \cdot 100, \quad \text{ADX} = \text{SMA}_{14}(\text{DX})$$ + +#### 10. Volume Weighted Average Price (VWAP) +$$\text{VWAP} = \frac{\sum_{i=1}^N \left( \frac{H_i + L_i + C_i}{3} \cdot V_i \right)}{\sum_{i=1}^N V_i}$$ + +--- + +### 4.2 Symmetrisches Technisches Scoring V2 (`TechnicalScoringEngineV2.cs`) + +$$\text{FinalScore} = \text{Clamp}\Big( (0.35 \cdot S_{\text{Ind}}) + (0.35 \cdot S_{\text{Pattern}}) + (0.30 \cdot S_{\text{BaseStrategy}}), \; 0, \; 100 \Big)$$ + +#### Indikator-Confluence ($S_{\text{Ind}}$ Basis: 50 Pkt): +- **Buy (Long)**: + - $\text{EMA}_{20} > \text{EMA}_{50} \implies +15$ Pkt + - $\text{RSI}_{14} \in [45, 65] \implies +15$ Pkt + - $\text{ADX}_{14} \ge 25 \implies +10$ Pkt + - $P > \text{VWAP} \text{ oder } \text{EMA}_{20} > \text{VWAP} \implies +10$ Pkt +- **Sell (Short)**: + - $\text{EMA}_{20} < \text{EMA}_{50} \implies +15$ Pkt + - $\text{RSI}_{14} \in [35, 55] \implies +15$ Pkt + - $\text{ADX}_{14} \ge 25 \implies +10$ Pkt + - $P < \text{VWAP} \text{ oder } \text{EMA}_{20} < \text{VWAP} \implies +10$ Pkt + +--- + +### 4.3 Exponentielles Zeit-Decay-Sentiment (`SentimentDbService.cs`) + +Jeder Artikel $i$ hat Alter $\Delta t_i = \text{Now} - t_{\text{published}}$ in Tagen und FinBERT-Konfidenz $C_i$. +Abklingkonstante $\lambda$: +$$\lambda = \frac{\ln(2)}{\tau} \quad (\tau = \text{HalfLifeDays}, \text{ Standard: } 7.0)$$ +Gewicht des Artikels $w_i$: +$$w_i = \max(0.01, C_i) \cdot e^{-\lambda \cdot \Delta t_i}$$ +Aggregierter gewichteter Sentiment-Score $S_{\text{weighted}} \in [-1.0, +1.0]$: +$$S_{\text{weighted}} = \frac{\sum_{i=1}^N (w_i \cdot \text{CompoundScore}_i)}{\sum_{i=1}^N w_i}$$ + +--- + +### 4.4 Composite Opportunity Score (COS V2) (`CompositeOpportunityScorerV2.cs`) + +Gewichtete Faktoren: +- Technischer Score $S_{\text{Tech}} \in [0, 100]$ (Gewicht: $w_{\text{Tech}} = 0.45$) +- Sentiment Score $S_{\text{Sent}} \in [0, 100]$ (Gewicht: $w_{\text{Sent}} = 0.35$): + - Für Buy: $S_{\text{Sent}} = \frac{S_{\text{weighted}} + 1}{2} \cdot 100$ + - Für Sell: $S_{\text{Sent}} = \frac{1 - S_{\text{weighted}}}{2} \cdot 100$ +- Fundamentaler Score $S_{\text{Fund}} \in [0, 100]$ (Gewicht: $w_{\text{Fund}} = 0.20$): + - Richtungsabhängige Bewertung von KGV, ROE, Debt/Equity, Consensus-Rating und Short-Interest. +- Simulations-Matrix-Bonus: $B_{\text{Sim}} = +15$ falls $\text{PF} \ge 1.60$, Veto-Multiplikator $M_{\text{Veto}} = 0.20$ falls $\text{PF} < 1.00$. +- Sperr-Multiplikatoren: + - Earnings-Sperre: $M_{\text{Earnings}} = 0.15$ falls $\text{Tage zu Earnings} \le 2$. + - Dividenden-Sperre: $M_{\text{Dividend}} = 0.50$ falls $\text{Tage zu Ex-Dividende} \le 1$. + +$$\text{RawScore} = (w_{\text{Tech}} \cdot S_{\text{Tech}}) + (w_{\text{Sent}} \cdot S_{\text{Sent}}) + (w_{\text{Fund}} \cdot S_{\text{Fund}}) + B_{\text{Sim}}$$ +$$\text{COS} = \text{Clamp}\Big( \text{RawScore} \cdot M_{\text{Earnings}} \cdot M_{\text{Dividend}} \cdot M_{\text{Veto}}, \; 0, \; 100 \Big)$$ + +--- + +### 4.5 Positionsgrößenbestimmung & Risikomodell (1-2% Regel) (`BotOrderExecutor.cs`) + +Gesamtes Kontokapital $E$, Risiko pro Trade $R_{\%} = 1.0\%$, Maximalallokation $A_{\%} = 20.0\%$. +$$\text{MaxRiskCapital} = E \cdot \frac{R_{\%}}{100}$$ +$$\text{UnitRisk} = |\text{EntryPrice} - \text{StopLossPrice}|$$ +Berechnete Stückzahl $Q_{\text{calc}}$: +$$Q_{\text{calc}} = \frac{\text{MaxRiskCapital}}{\text{UnitRisk}}$$ +Allokations-Deckelung: +$$Q_{\text{max}} = \frac{E \cdot \frac{A_{\%}}{100}}{\text{EntryPrice}}$$ +$$Q_{\text{final}} = \max\Big(1, \, \text{Round}\big(\min(Q_{\text{calc}}, Q_{\text{max}})\big)\Big)$$ + +--- + +### 4.6 Quantitative Simulations- & Performancemetriken (`VirtualBacktestBroker.cs`) + +- **Win Rate (WR)**: + $$\text{WR} = \frac{N_{\text{Wins}}}{N_{\text{Trades}}} \cdot 100$$ +- **Profit Factor (PF)**: + $$\text{PF} = \frac{\sum \text{Gewinne}}{\sum |\text{Verluste}|}$$ +- **Erwartungswert (Expectancy in €)**: + $$\text{Expectancy} = \left(\frac{\text{WR}}{100} \cdot \overline{\text{Win}}\right) - \left(\left(1 - \frac{\text{WR}}{100}\right) \cdot \overline{\text{Loss}}\right)$$ +- **Annualisierte Sharpe Ratio**: + $$\overline{R} = \frac{1}{N}\sum R_i, \quad \sigma_R = \sqrt{\frac{1}{N-1}\sum (R_i - \overline{R})^2}$$ + $$\text{Sharpe Ratio} = \frac{\overline{R}}{\sigma_R} \cdot \sqrt{252}$$ +- **R-Multiple**: + $$R_{\text{mult}} = \frac{\text{Realisierter PnL}}{\text{UnitRisk} \cdot \text{Menge}}$$ +- **Max Adverse / Favorable Excursion (MAE / MFE)**: + $$\text{MAE}_{\text{Long}} = \frac{P_{\text{Entry}} - P_{\text{Min}}}{P_{\text{Entry}}} \cdot 100, \quad \text{MFE}_{\text{Long}} = \frac{P_{\text{Max}} - P_{\text{Entry}}}{P_{\text{Entry}}} \cdot 100$$ + +--- + +## 5. Schnittstellen & Endpunkte + +### 5.1 MQTT RPC-Kanäle + +Schema: Request auf `services/request/{channel}/{correlationId}`, Response auf `services/response/{channel}/{correlationId}`. + +| Kanalname (`MqttTopics.Channels`) | Betreuender Service | Request-DTO | Response-DTO | Beschreibung | +| :--- | :--- | :--- | :--- | :--- | +| `health_Ping` | *(Alle Services)* | `object` | `ServiceHealthResponse` | Liveness-Check pro Service | +| `assets_Get` | FinlyticAssets | `GetValidAssetRequest` | `List` | Stammdaten für ISIN auflösen | +| `assets_GetDiscovery` | FinlyticAssets | `GetDiscoveryAssetsRequest` | `List` | Kuratierte Discovery-Assets | +| `assets_GetDerivatives` | FinlyticAssets | `GetDerivativesRequest` | `List` | KO-Derivate nach Hebel/Typ suchen | +| `tr_GetLivePrice` | FinlyticAssets | `IsinRequest` | `LivePriceDto?` | Realtime-Kurs via Trade Republic | +| `assets_settings_GetAll` | FinlyticAssets | `object` | `List` | Einstellungen abfragen | +| `assets_settings_Update` | FinlyticAssets | `Dictionary` | `List` | Einstellungen aktualisieren | +| `news_Get` | FinlyticNews | `DailyNewsRequest` | `List` | Paginierte/gefilterte News | +| `news_GetById` | FinlyticNews | `ArticleRequest` | `NewsArticleDto?` | Einzelartikel nach ID | +| `news_GetPending` | FinlyticNews | `object` | `List` | Artikel zur Sentiment-Analyse | +| `news_UpdateStatus` | FinlyticNews | `UpdateNewsStatusRequest` | `UpdateNewsStatusResponse` | Artikel-Status aktualisieren | +| `news_settings_GetAll` | FinlyticNews | `object` | `List` | Einstellungen abfragen | +| `news_settings_Update` | FinlyticNews | `Dictionary` | `List` | Einstellungen aktualisieren | +| `sentiment_GetIsin` | FinlyticSentiment | `GetSentimentByIsinRequest` | `IsinSentimentSummaryDto?` | Aggregiertes Sentiment für ISIN | +| `sentiment_GetSector` | FinlyticSentiment | `GetSectorSentimentRequest` | `SectorSentimentSummaryDto?`| Sektoren-Sentiment | +| `sentiment_GetArticle` | FinlyticSentiment | `ArticleRequest` | `IsinAnalysisEntry?` | FinBERT-Ergebnis für Artikel | +| `sentiment_GetAll` | FinlyticSentiment | `PaginatedRequest` | `List` | Alle Unternehmens-Sentiments | +| `sentiment_Analyze` | FinlyticSentiment | `JsonElement` / `NewsArticleDto` | `IsinAnalysisEntry?` | Ad-hoc FinBERT-Analyse | +| `sentiment_settings_GetAll` | FinlyticSentiment | `object` | `List` | Einstellungen abfragen | +| `sentiment_settings_Update` | FinlyticSentiment | `Dictionary` | `List` | Einstellungen aktualisieren | +| `fundamentals_Get` | FinlyticFundamentals | `IsinRequest` / `GetFundamentalsRequest` | `AssetFundamentalsDto?` | Fundamentaldaten & Kennzahlen | +| `events_GetAll` | FinlyticFundamentals | `object` | `List` | Alle Termine/Events | +| `events_GetByMonth` | FinlyticFundamentals | `GetEventsByMonthRequest` | `List` | Monatliche Termine/Earnings | +| `fundamentals_settings_GetAll`| FinlyticFundamentals | `object` | `List` | Einstellungen abfragen | +| `fundamentals_settings_Update`| FinlyticFundamentals | `Dictionary` | `List` | Einstellungen aktualisieren | +| `ta_GetAnalysis` | FinlyticTechnicals | `IsinRequest` | `TechnicalAnalysisDto?` | Komplette TA inkl. Indikatoren | +| `ta_GetSetupsForIsin` | FinlyticTechnicals | `IsinRequest` | `List` | Aktive Setups für eine ISIN | +| `ta_GetSetups` | FinlyticTechnicals | `GetSetupsRequest` | `List` | Universe-weite Setups/Top-Picks | +| `ta_GetCandles` | FinlyticTechnicals | `GetCandlesRequest` | `IReadOnlyList` | Kerzen nach Timeframe | +| `ta_GetWatchlist` | FinlyticTechnicals | `object` | `List` | Monitorte Universe-Assets | +| `ta_GetRecentSetupHistory` | FinlyticTechnicals | `GetRecentSetupHistoryRequest` | `List` | Historische Setup-Scores | +| `ta_settings_GetAll` | FinlyticTechnicals | `object` | `List` | Einstellungen abfragen | +| `ta_settings_Update` | FinlyticTechnicals | `Dictionary` | `List` | Einstellungen aktualisieren | +| `engine_GetProposals` | FinlyticEngine | `GetProposalsRequest` | `List` | Aktive Trade-Vorschläge | +| `engine_GetTrades` | FinlyticEngine | `GetTradesRequest` | `List` | Aktive Benutzertrades | +| `engine_EvaluateIsin` | FinlyticEngine | `EvaluateIsinRequest` | `AssetEvaluationResultDto?`| Manuelle ISIN-Evaluierung | +| `engine_AddFill` | FinlyticEngine | `AddFillRequest` | `ActiveTradeDto?` | Teil-/Vollausführung buchen | +| `engine_UpdateStopLoss` | FinlyticEngine | `UpdateStopLossRequest` | `ActiveTradeDto?` | Stop-Loss anpassen | +| `engine_CloseTrade` | FinlyticEngine | `CloseTradeRequest` | `ActiveTradeDto?` | Trade schließen | +| `engine_AcceptProposal` | FinlyticEngine | `AcceptTradeProposalRequest` | `ActiveTradeDto?` | Vorschlag als Trade annehmen | +| `engine_CreateManualTrade` | FinlyticEngine | `CreateManualTradeRequest` | `ActiveTradeDto?` | Manuellen Trade eröffnen | +| `engine_GetEvaluationHistory` | FinlyticEngine | `GetEvaluationHistoryRequest` | `GetEvaluationHistoryResponse` | Admin-Evaluierungs-Historie | +| `engine_settings_GetAll` | FinlyticEngine | `object` | `List` | Einstellungen abfragen | +| `engine_settings_Update` | FinlyticEngine | `Dictionary` | `List` | Einstellungen aktualisieren | +| `sim_RunBacktest` | FinlyticSimulation | `BacktestRequestDto` | `BacktestReportDto` | Quantitativen Backtest starten | +| `sim_GetReliability` | FinlyticSimulation | `GetReliabilityRequest` | `StrategyAssetReliabilityDto?`| Zuverlässigkeit für Setup | +| `sim_GetMatrixForAsset` | FinlyticSimulation | `IsinRequest` | `List`| Komplette Asset-Matrix | +| `sim_GetBacktestHistory` | FinlyticSimulation | `GetBacktestHistoryRequest` | `GetBacktestHistoryResponse` | Historische Backtest-Läufe | +| `sim_GetBacktestRunDetail` | FinlyticSimulation | `RunIdRequest` | `BacktestReportDto?` | Detailbericht eines Backtests | +| `sim_GetStrategyParameters` | FinlyticSimulation | `GetStrategyParametersRequest` | `StrategyParameterProfileDto?`| Gespeicherte TA-Parameter | +| `sim_SaveStrategyParameters` | FinlyticSimulation | `SaveStrategyParametersRequest`| `StrategyParameterProfileDto` | TA-Parameter speichern | +| `sim_settings_GetAll` | FinlyticSimulation | `object` | `List` | Einstellungen abfragen | +| `sim_settings_Update` | FinlyticSimulation | `Dictionary` | `List` | Einstellungen aktualisieren | +| `bot_GetStatus` | FinlyticBot | `object` | `BotStatusDto` | Bot-Status & Venue | +| `bot_GetPositions` | FinlyticBot | `object` | `List` | Offene Bot-Positionen | +| `bot_GetSummary` | FinlyticBot | `object` | `AccountSummaryDto` | Kontostand & PnL | +| `bot_ExecuteProposal` | FinlyticBot | `ExecuteProposalRequest` | `BotTradeOrderDto?` | Order für Proposal aufgeben | +| `bot_PanicClose` | FinlyticBot | `object` | `PanicCloseResultDto` | Notfall-Schließung aller Positionen | +| `bot_settings_GetAll` | FinlyticBot | `object` | `List` | Einstellungen abfragen | +| `bot_settings_Update` | FinlyticBot | `Dictionary` | `List` | Einstellungen aktualisieren | +| `notify_settings_GetAll` | FinlyticNotify | `object` | `List` | Einstellungen abfragen | +| `notify_settings_Update` | FinlyticNotify | `Dictionary` | `List` | Einstellungen aktualisieren | +| `backend_GetAggregatedFavorites`| FinlyticBackend | `object` | `List` | Alle Benutzer-Favoriten-ISINs | +| `backend_GetUsername` | FinlyticBackend | `UserIdRequest` | `string?` | Benutzernamen nach GUID | + +--- + +### 5.2 MQTT Pub/Sub Event-Topics + +| Topic | Publisher | Konsumenten | Payload-Typ | Beschreibung | +| :--- | :--- | :--- | :--- | :--- | +| `services/news/completed` | FinlyticNews | FinlyticSentiment, Backend | `NewsArticleDto` | Neuer fertig verarbeiteter Artikel | +| `finlytic/news/stream/{isin}` | FinlyticNews | BackendMqttBridge | `NewsArticleDto` | ISIN-spezifischer News-Stream | +| `finlytic/sentiment/stream/{isin}`| FinlyticSentiment | FinlyticTechnicals, Backend | `IsinSentimentSummaryDto` | Aktualisiertes Sentiment | +| `finlytic/engine/proposals/created`| FinlyticEngine | FinlyticBot, FinlyticNotify, Backend | `TradeProposalDto` | Neuer Trade-Vorschlag erstellt | +| `finlytic/engine/trades/status_changed`| FinlyticEngine| FinlyticNotify, Backend | `ActiveTradeDto` | Trade-Statusänderung (TP/SL/Close) | +| `finlytic/bot/trades/stream` | FinlyticBot | FinlyticNotify, Backend | `BotTradeOrderDto` | Bot-Order-Lifecycle-Event | +| `finlytic/logs/{service}` | *(Alle Services)* | BackendMqttBridge | `LogMessageDto` | Strukturierter Service-Logstream | + +--- + +### 5.3 REST API Endpunkte (`FinlyticBackend`) + +Alle Endpunkte erfordern `Authorization: Bearer ` (außer Login und Health). + +#### 1. Authentifizierung & Benutzer (`/api/v1/auth`, `/api/v1/user`, `/api/v1/admin`) +- `POST /api/v1/auth/login` `[AllowAnonymous]`: Login mit Username/Passwort $\to$ JWT Token & User-Objekt. +- `POST /api/v1/auth/change-initial-password`: Ändern des Initialpassworts bei `RequiresPasswordChange`. +- `POST /api/v1/user/fcm-token`: Hinterlegen des Firebase Cloud Messaging Push-Tokens. +- `GET /api/v1/user/me`: Profil des aktuell angemeldeten Benutzers abrufen. +- `GET /api/v1/admin/users` `[Roles: Admin]`: Benutzerliste. +- `POST /api/v1/admin/users` `[Roles: Admin]`: Neuen Benutzer anlegen. +- `PUT /api/v1/admin/users/{id}` `[Roles: Admin]`: Benutzer bearbeiten (Rolle, Status). +- `DELETE /api/v1/admin/users/{id}` `[Roles: Admin]`: Benutzer deaktivieren/löschen. +- `POST /api/v1/admin/users/{id}/reset-password` `[Roles: Admin]`: Passwort zurücksetzen. + +#### 2. Assets & Discovery (`/api/v1/assets`) +- `GET /api/v1/assets/search?q={query}`: Volltextsuche nach Name/ISIN im lokalen Index. +- `GET /api/v1/assets/discovery?limit={limit}`: Kuratierte Trend-/Discovery-Assets. +- `GET /api/v1/assets/{isin}/fundamentals`: Fundamentaldaten, KGV, Events. +- `GET /api/v1/assets/{isin}/technicals`: TA-Indikatoren, Kerzen, Setups. +- `GET /api/v1/assets/{isin}/live`: Trade Republic Realtime-Tick (Bid/Ask/Last). +- `GET /api/v1/assets/{isin}/derivatives?optionType={long|short}&targetLeverage={x}`: Passende KO-Zertifikate. +- `GET /api/v1/logo/{isin}` `[AllowAnonymous]`: Lokales SVG-Logo ausliefern. + +#### 3. Analyse & Engine (`/api/v1/analyze`, `/api/v1/engine`) +- `POST /api/v1/analyze/manual`: Ad-hoc Auswertung einer ISIN (TA, Sentiment, KI-Gate). +- `GET /api/v1/analyze/proposals`: Vorschläge abrufen. +- `GET /api/v1/engine/proposals?onlyActive={bool}&limit={limit}`: Aktive Vorschläge. +- `GET /api/v1/engine/trades?mode={Manual|Bot}`: Trades des eingeloggten Users. +- `POST /api/v1/engine/evaluate`: Evaluierungs-Trigger für ISIN. +- `POST /api/v1/engine/trades/{id}/fills`: Fill buchen. +- `PUT /api/v1/engine/trades/{id}/stoploss`: SL-Anpassung. +- `POST /api/v1/engine/trades/{id}/close`: Trade schließen. + +#### 4. Benutzer-Trades (`/api/v1/user/trades`) +- `GET /api/v1/user/trades`: Eigene aktive & historische Trades. +- `POST /api/v1/user/trades/accept`: Vorschlag verbindlich annehmen. +- `POST /api/v1/user/trades/manual`: Eigenen Trade ohne Vorschlag eröffnen. +- `POST /api/v1/user/trades/{id}/close`: Eigenen Trade manuell schließen. + +#### 5. Favoriten & Präferenzen (`/api/v1/user/favorites`, `/api/v1/user/preferences`) +- `GET /api/v1/user/favorites`: Favoritenliste mit Live-Preisen & Tagesänderung. +- `POST /api/v1/user/favorites/{symbol}`: Asset zu Favoriten hinzufügen. +- `POST /api/v1/user/favorites/{symbol}/ticker`: Ticker-Symbol zuweisen. +- `DELETE /api/v1/user/favorites/{symbol}`: Asset aus Favoriten entfernen. +- `GET /api/v1/user/preferences`: UI-Präferenzen (Theme, Layout). +- `PUT /api/v1/user/preferences/theme`: Theme anpassen. + +#### 6. Backtesting & Simulation (`/api/v1/simulation`) +- `POST /api/v1/simulation/run`: Quantitativen Backtest starten. +- `GET /api/v1/simulation/matrix/{isin}`: Zuverlässigkeitsmatrix für ISIN. +- `GET /api/v1/simulation/history/{isin}`: Historische Backtests für ISIN. +- `GET /api/v1/simulation/history/run/{runId}`: Vollständiger Backtest-Report. +- `GET /api/v1/simulation/parameters/{isin}/{strategyKey}`: Gespeicherte Strategie-Parameter. +- `POST /api/v1/simulation/parameters`: Parameterprofil speichern. + +#### 7. Bot & Paper-Trading (`/api/v1/bot`) +- `GET /api/v1/bot/status`: Bot-Status & Venue. +- `GET /api/v1/bot/positions/active`: Offene Bot-Positionen. +- `GET /api/v1/bot/portfolio/summary`: Kontostand & PnL. +- `POST /api/v1/bot/orders/execute`: Manuelle Order über Bot abschicken. +- `POST /api/v1/bot/orders/panic-close`: Notfall-Schließung. +- `POST /api/v1/bot/settings/update`: Bot-Einstellungen aktualisieren. + +#### 8. News & Kalender (`/api/v1/news`, `/api/v1/calendar`) +- `GET /api/v1/news?limit={limit}&offset={offset}&isin={isin}&status={status}`: Gefilterte News. +- `GET /api/v1/calendar/events/{year}/{month}`: Corporate Events & Earnings. + +#### 9. Admin-System (`/api/v1/admin/settings`, `/api/v1/admin/evaluations`) +- `GET /api/v1/admin/settings`: Einstellungen aller Services. +- `GET /api/v1/admin/settings/{serviceName}`: Einstellungen eines Services. +- `PUT /api/v1/admin/settings/{serviceName}`: Einstellungen dynamisch ändern. +- `GET /api/v1/admin/settings/health`: Health-Status aller Services. +- `GET /api/v1/admin/settings/logs/{serviceName}`: Letzte 250 Ringpuffer-Logs. +- `GET /api/v1/admin/evaluations`: Evaluierungs-Historie ("Warum kein Proposal?"). +- `GET /api/v1/admin/evaluations/watchlist`: Gescannte Watchlist-Assets. +- `GET /api/v1/admin/evaluations/watchlist/{isin}/history`: Setup-Verlauf eines Assets. + +--- + +### 5.4 SignalR Hubs & Methoden + +Verbindung über `/hubs/{hubname}?access_token=`. + +| Hub-Route | Server-Methoden | Client-Events (Callbacks) | Zweck | +| :--- | :--- | :--- | :--- | +| `/hubs/trade-stream` | `SubscribeToAsset(isin)`
`UnsubscribeFromAsset(isin)` | `ReceiveTradeProposal(proposal)`
`ReceiveTradeUpdate(trade)` | Realtime-Updates zu Proposals & Trades | +| `/hubs/news` | `SubscribeToIsin(isin)` | `ReceiveNewsArticle(article)` | Neue gescrapte/analysierte News | +| `/hubs/health` | *(Keine)* | `ReceiveServiceHealth(health)` | Live-Healthcheck der Services | +| `/hubs/favorites-prices`| *(Keine)* | `ReceivePriceUpdate(isin, price, change)`| Realtime-Kursupdates der Favoriten (15s Takt) | +| `/hubs/logs` | *(Keine)* | `ReceiveLogMessage(logDto)` | Admin Live-Logstream | + +--- + +## 6. Detaillierte Funktionsweise & Datenfluss + +### 6.1 End-to-End Opportunity- & Trade-Lifecycle + +``` +1. DATA INGESTION + ├── FinlyticNews: RSS/Scraping -> SimHash Deduplication -> In-Memory Matcher -> MQTT "services/news/completed" + ├── FinlyticSentiment: FinBERT Webhook -> Time-Decay DB Update -> MQTT "finlytic/sentiment/stream/{isin}" + └── FinlyticTechnicals: Trade Republic & Yahoo Ticks -> Resampler -> Indicator Math (RSI, EMA, Squeeze, etc.) + +2. TECHNICAL SCANNING (FinlyticTechnicals) + ├── MultiTimeframeCandleAggregator aktualisiert Ringpuffer (15m, 1h, 1d) + ├── 15 Pattern-Detektoren identifizieren FVG, OrderBlocks, DoubleBottom, Liquidity Sweeps + ├── 10 CoreStrategies evaluieren Signale & erzeugen Exit-Pläne (TP1, TP2, Trailing-Stop, Break-Even) + └── TechnicalScoringEngineV2 berechnet Confluence-Score (Indikatoren + Patterns + Strategie) + +3. ENGINE EVALUATION (FinlyticEngine) + ├── OpportunityPollerBackgroundService pollt Top-Picks (Score >= 70) + ├── CompositeOpportunityScorerV2 berechnet COS (Tech 45%, Sent 35%, Fund 20%) + ├── Filter-Gates: EarningsLockout (2 Tage), DividendGate (1 Tag), Simulation Matrix Veto + ├── AiReasoningGateService sendet strukturierten Context an n8n AI-Webhook + └── KnockOutDerivativeResolver matcht Hebel & Safety-Buffer -> Proposal persistiert & publiziert + +4. EXECUTION & BOT (FinlyticBot / FinlyticApp) + ├── FinlyticApp: User sieht Proposal im UI, klickt "Accept" -> Trade eröffnet + ├── FinlyticBot: Falls AutoExecution aktiv -> 1-2% Risikosizing -> Orderausführung (Alpaca/Ledger) + └── FinlyticNotify: ntfy Push-Notification an Smartphone/Desktop + +5. ACTIVE MONITORING & EXITS + ├── ActiveTradeMonitoringBackgroundService (Engine) & BotTradeLifecycleBackgroundService (Bot) + ├── Regelmäßige Kursabfrage (15s - 60s) + ├── Bei TP1: Teilverkauf (50%) & Verschieben des Stop-Loss auf Break-Even (gebührenbereinigt) + ├── Bei TP2: Teilverkauf (30%) & Aktivierung des ATR-Trailing-Stops für verbleibende 20% + └── Bei Stop-Loss / Knock-Out / MaxBars: Positionsschließung & PnL-Verbuchung +``` + +--- + +## 7. Frontend-Architektur (FinlyticApp) + +- **Technologie**: Flutter (Dart) mit Web- und Mobile-Unterstützung. +- **State Management**: `flutter_bloc` (`BlocProvider`, `BlocBuilder`, `BlocConsumer`, `Cubit`). +- **Netzwerk & Security**: + - Zentraler `Dio`-Client mit `AuthInterceptor`. + - Injiziert automatisch `Authorization: Bearer ` in jeden Request. + - **Automatischer Logout**: Fängt `401 Unauthorized` und `403 Forbidden` zentral ab, löscht Secure Storage und leitet sofort auf den Login-Bildschirm um. +- **Realtime-Kommunikation**: `SignalRService` mit automatischem Reconnect und Event-Subskriptionen (`trade-stream`, `news`, `health`, `favorites-prices`, `logs`). +- **Feature-Struktur**: + - `features/auth`: Login, Passwortänderung. + - `features/dashboard`: Schnellübersicht, aktive Trades, Markttrends. + - `features/discovery`: Top-Assets, Scanner-Ergebnisse. + - `features/asset_detail`: Interaktiver Chart, Multi-Timeframe-Indikatoren, Fundamentaldaten, Sentiment-Historie, Derivate-Selektor. + - `features/proposals`: Trade-Vorschläge mit detaillierter KI-Begründung, Setup-Chart und Direkt-Annahme. + - `features/trades`: Eigene Positionen, TP/SL-Visualisierung, manuelles Schließen. + - `features/bot`: Bot-Positionen, Performance-Graphen, Kontostand, Panic-Close-Button. + - `features/simulation`: Backtest-Runner, Equity-Kurven, Strategie-Zuverlässigkeitsmatrix, Parameter-Tuning. + - `features/news`: Live-Newsfeed mit Sentiment-Badges und Filter nach Asset. + - `features/calendar`: Earnings- und Corporate-Events-Kalender. + - `features/favorites`: Realtime-Watchlist mit Kurs-Ticker. + - `features/admin`: Dynamische Service-Settings, Live-Log-Konsole, System-Health, Benutzerverwaltung, Evaluierungs-Historie ("Warum kein Proposal?").