docs: add comprehensive platform STATE.md and diagnostic PROBLEMS.md
This commit is contained in:
+221
@@ -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 |
|
||||
Reference in New Issue
Block a user