import 'package:flutter/material.dart'; import '../../../core/theme/app_theme.dart'; /// Plain-language explanations of all 10 backtestable strategies (`FinlyticTechnicals/Strategies/CoreStrategies.cs`, /// shared 1:1 by FinlyticSimulation - "100% code reuse", see that file's own doc comments). Mirrors /// `FinlyticApp/lib/features/asset_detail/utils/pattern_explanations.dart`'s dictionary shape/detail-sheet /// pattern rather than inventing a new one. Every description below is a plain-language restatement of that /// strategy's actual `Evaluate()` logic as written, not a generic template (Rules.md §4). Every strategy fires /// both a long AND a short setup (mirror-image conditions in the same `Evaluate()` method) - hence /// `'bias': 'BIDIREKTIONAL'` throughout, rather than a single-direction label. class StrategyExplanations { static const Map> dictionary = { 'TrendPullbackFvg': { 'title': 'Trend Pullback FVG Retracement', 'bias': 'BIDIREKTIONAL', 'description': 'Ein Trend ist bereits im Gange (EMA20/EMA50/EMA200 in Trendreihenfolge) und der Kurs zieht sich kurz ' 'in eine Fair-Value-Gap (eine übersprungene Preiszone) zurück. Sobald der Kurs aus dieser Zone ' 'wieder in Trendrichtung zu laufen beginnt, gilt das als Bestätigung, dass der Trend weiterläuft. ' 'Long bei Aufwärtstrend + bullischer FVG, Short bei Abwärtstrend + bärischer FVG (Spiegelbild).', 'significance': 'Genau das "kurzer Rücksetzer, dann Bestätigung durchs erneute Laufen"-Muster: EMA50 bestätigt den ' 'übergeordneten Trend, die Fair-Value-Gap markiert die Rücksetzer-Zone, in der eingestiegen wird.', 'action': 'Einstieg beim erneuten Lauf aus der Fair-Value-Gap-Zone in Trendrichtung, Stop-Loss hinter der Gap bzw. 1,2×ATR vom Entry.', 'reliability': 'Hoch (Quality-Score 88, Top-Pick, Rating A+)', 'target': 'Gestaffelter Ausstieg: TP1 bei 1,5× Risiko (50% Teilverkauf, Stop wandert auf Break-Even), TP2 bei 3,0× Risiko (30%).', 'stop_loss': 'Hinter der Fair-Value-Gap-Grenze bzw. 1,2× ATR vom Einstieg - je nachdem, was enger ist.', }, 'VolatilitySqueeze': { 'title': 'Bollinger/Keltner Squeeze Breakout', 'bias': 'BIDIREKTIONAL', 'description': 'Bollinger-Bänder ziehen sich innerhalb der Keltner-Kanäle zusammen (niedrige Volatilität) und "feuern" ' 'dann mit Momentum in eine Richtung - der klassische Ausbruch aus einer ruhigen Konsolidierungsphase. ' 'Long bei positivem, Short bei negativem Momentum-Histogramm.', 'significance': 'Eine Phase geringer Schwankung geht typischerweise einer impulsiven Bewegung voraus; das Momentum-Histogramm bestätigt die Richtung.', 'action': 'Einstieg direkt beim Squeeze-Ausbruch in Richtung des Momentums.', 'reliability': 'Hoch (Quality-Score 84, Top-Pick, Rating A)', 'target': 'Festes Ziel bei ±2,0× ATR ab Einstieg (100% Ausstieg).', 'stop_loss': '1,0× ATR gegen die Einstiegsrichtung.', }, 'SmcLiquiditySweep': { 'title': 'Smart Money Liquidity Sweep & CHoCH', 'bias': 'BIDIREKTIONAL', 'description': 'Der Kurs "fegt" kurz über ein bekanntes Hoch oder unter ein bekanntes Tief (Stop-Loss-Jagd durch ' 'große Marktteilnehmer) und dreht danach abrupt in die Gegenrichtung - erkennbar an einem ' 'Liquidity-Sweep-Muster und/oder einem Wechsel der Marktstruktur (Change of Character). Long nach ' 'einem Sweep unter einem Tief, Short nach einem Sweep über einem Hoch.', 'significance': 'Interpretiert als Zeichen, dass institutionelle Marktteilnehmer die durch den Sweep freigesetzte Liquidität aufgenommen haben.', 'action': 'Einstieg nach Bestätigung der Ablehnung des Sweeps.', 'reliability': 'Sehr hoch (Quality-Score 91, Top-Pick, Rating A+)', 'target': 'Gestaffelter Ausstieg: TP1 bei 2,0× Risiko (60%, danach Break-Even), TP2 bei 4,0× Risiko (40%).', 'stop_loss': 'Knapp hinter dem Extrempunkt des Sweeps (0,2% Puffer).', }, 'MeanReversion': { 'title': 'Bollinger 2,5-Sigma Mean Reversion', 'bias': 'BIDIREKTIONAL', 'description': 'Nur in ruhigen/schwankenden Seitwärtsmärkten (nicht im Trend) aktiv: Der Kurs berührt das untere ' '(Long) oder obere (Short) 2,5-Sigma-Bollingerband bei niedrigem ADX (<22, kein starker Trend) und ' 'überverkauftem (≤32) bzw. überkauftem (≥68) RSI - eine statistisch übertriebene Bewegung, die ' 'zum Durchschnitt zurückkehren sollte.', 'significance': 'Setzt auf die Rückkehr zum VWAP/Mittelwert nach einer überzogenen kurzfristigen Bewegung, nicht auf eine Trendfortsetzung.', 'action': 'Einstieg bei Berührung des äußeren Bandes mit passendem RSI-Extrem.', 'reliability': 'Mittel (Quality-Score 79, kein Top-Pick, Rating B) - bewusst konservativer eingestuft als die trendfolgenden Strategien.', 'target': 'Ziel ist der VWAP bzw. das mittlere Bollingerband (SMA20), 100% Ausstieg.', 'stop_loss': '0,8× ATR hinter dem Extrem der Signalkerze.', }, 'SuperTrendMultiTf': { 'title': 'SuperTrend Multi-Timeframe Alignment', 'bias': 'BIDIREKTIONAL', 'description': 'Zwei Zeitebenen müssen übereinstimmen: Der SuperTrend-Indikator auf 1h UND auf 15m stehen beide auf ' 'dieselbe Richtung (bullisch für Long, bärisch für Short). Erst wenn beide Zeitrahmen im Einklang ' 'sind, gilt das Setup als bestätigt.', 'significance': 'Reduziert Fehlsignale einzelner Zeitebenen - der übergeordnete (1h) und der feinere (15m) Trend müssen sich decken.', 'action': 'Einstieg bei Bestätigung der Multi-Timeframe-Übereinstimmung.', 'reliability': 'Hoch (Quality-Score 86, Top-Pick, Rating A)', 'target': 'Kein festes Kursziel - reine Trailing-Stop-Strategie entlang der 15m-SuperTrend-Linie, Ausstieg erst bei Trendwechsel.', 'stop_loss': 'Dynamisch an der 15m-SuperTrend-Linie, sofortiger Exit bei Flip der Gegenrichtung.', }, 'MacdCrossover': { 'title': 'MACD Signal Line Crossover', 'bias': 'BIDIREKTIONAL', 'description': 'Klassischer Momentum-Wechsel: Die MACD-Linie kreuzt die Signal-Linie (verglichen mit derselben ' 'Berechnung eine Kerze zuvor) und das Histogramm bestätigt die Richtung. Long bei Kreuzung nach ' 'oben mit positivem Histogramm, Short bei Kreuzung nach unten mit negativem Histogramm.', 'significance': 'Der MACD-Crossover ist eines der bekanntesten Momentum-Signale der technischen Analyse und markiert einen Wechsel im kurzfristigen Trend.', 'action': 'Einstieg direkt bei bestätigter Kreuzung.', 'reliability': 'Mittel (Quality-Score 80, Rating B)', 'target': 'Festes Ziel bei ±2,0× Risiko (100% Ausstieg).', 'stop_loss': '1,5× ATR gegen die Einstiegsrichtung.', }, 'MovingAverageCrossover': { 'title': 'EMA50/EMA200 Golden & Death Cross', 'bias': 'BIDIREKTIONAL', 'description': 'Der langfristige Trendwechsel-Klassiker: Kreuzt EMA50 von unten nach oben durch EMA200, ist das ein ' '"Golden Cross" (Long). Kreuzt sie von oben nach unten, ist das ein "Death Cross" (Short).', 'significance': 'Einer der ältesten und am weitesten verbreiteten langfristigen Trendindikatoren - signalisiert einen strukturellen Wechsel der Marktrichtung.', 'action': 'Einstieg direkt bei bestätigter Kreuzung.', 'reliability': 'Hoch (Quality-Score 82, Top-Pick, Rating A) - aber selten, da EMA50/EMA200 sich nicht oft kreuzen.', 'target': 'Kein festes Kursziel - Trailing-Stop mit 2,5× ATR-Abstand, für langfristige Trends gedacht.', 'stop_loss': '2,0× ATR gegen die Einstiegsrichtung.', }, 'RsiReversal': { 'title': 'RSI Overbought/Oversold Threshold Cross', 'bias': 'BIDIREKTIONAL', 'description': 'Einfaches, richtungsoffenes Momentum-Reversal: Long, wenn der RSI von unterhalb 30 wieder darüber ' 'steigt (Ende der Überverkauftheit). Short, wenn der RSI von oberhalb 70 wieder darunter fällt ' '(Ende der Überkauftheit). Anders als "Bollinger 2,5-Sigma Mean Reversion" wird hier NICHT ' 'zusätzlich ein niedriger ADX oder eine Bollinger-Band-Berührung verlangt - rein der RSI-Schwellenwert zählt.', 'significance': 'Der RSI-Schwellenwert-Durchbruch ist eines der einfachsten und am längsten genutzten Reversal-Signale.', 'action': 'Einstieg direkt beim erneuten Über- bzw. Unterschreiten der 30/70-Schwelle.', 'reliability': 'Mittel (Quality-Score 75, Rating B) - bewusst einfacher/häufiger auslösend als die kombinierten Strategien.', 'target': 'Festes Ziel bei ±1,5× Risiko (100% Ausstieg).', 'stop_loss': '1,2× ATR gegen die Einstiegsrichtung.', }, 'DonchianBreakout': { 'title': '20-Perioden Donchian-Kanal-Ausbruch', 'bias': 'BIDIREKTIONAL', 'description': 'Der klassische "Turtle Trading"-Ausbruch: Long, wenn der Schlusskurs über das Hoch der letzten 20 ' 'Kerzen (vor der aktuellen) ausbricht. Short, wenn er unter das Tief der letzten 20 Kerzen fällt.', 'significance': 'Einer der ältesten systematischen Breakout-Ansätze - setzt darauf, dass ein Ausbruch aus einer etablierten Handelsspanne eine neue Bewegung einleitet.', 'action': 'Einstieg direkt beim Ausbruch über/unter den 20-Perioden-Kanal.', 'reliability': 'Hoch (Quality-Score 83, Top-Pick, Rating A)', 'target': 'Kein festes Kursziel - Trailing-Stop mit 2,0× ATR-Abstand.', 'stop_loss': 'Am gegenüberliegenden Kanalrand (Tief bei Long, Hoch bei Short).', }, 'VwapBounce': { 'title': 'VWAP Pullback & Bounce Confirmation', 'bias': 'BIDIREKTIONAL', 'description': 'Im Aufwärtstrend (EMA20>EMA50): Der Kurs sinkt kurz zum/unter den VWAP und schließt wieder darüber ' '(Bounce) - Long-Einstieg. Im Abwärtstrend (EMA20 _infoFor(String strategyKey) { return dictionary[strategyKey] ?? { 'title': strategyKey, 'bias': 'NEUTRAL', 'description': 'Eine von FinlyticTechnicals bereitgestellte technische Strategie ($strategyKey).', 'significance': 'Details zu dieser Strategie sind noch nicht dokumentiert.', 'action': 'Backtest-Ergebnisse und Score-Aufschlüsselung beachten.', 'reliability': 'Unbekannt', 'target': 'Abhängig vom jeweiligen Setup.', 'stop_loss': 'Siehe individuelles Setup.', }; } static void showStrategyDetails(BuildContext context, String strategyKey) { final info = _infoFor(strategyKey); final isBullish = info['bias'] == 'BULLISH'; final isBearish = info['bias'] == 'BEARISH'; final biasColor = isBullish ? AppTheme.primaryEmerald : (isBearish ? AppTheme.accentRed : AppTheme.accentCyan); showDialog( context: context, builder: (modalContext) => AlertDialog( backgroundColor: AppTheme.cardSurface, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), side: BorderSide(color: AppTheme.glassBorder), ), title: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( info['title']!, style: const TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold), ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: biasColor.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(6), border: Border.all(color: biasColor), ), child: Text( info['bias']!, style: TextStyle(color: biasColor, fontWeight: FontWeight.bold, fontSize: 11), ), ), ], ), ], ), content: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ const Text('Funktionsweise:', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white, fontSize: 13)), const SizedBox(height: 4), Text(info['description']!, style: TextStyle(color: AppTheme.textSecondary, fontSize: 13, height: 1.4)), const SizedBox(height: 14), const Text('Warum das ein Signal ist:', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white, fontSize: 13)), const SizedBox(height: 4), Text(info['significance']!, style: const TextStyle(color: Colors.white70, fontSize: 13, height: 1.4)), const SizedBox(height: 14), const Text('Einstufung:', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white, fontSize: 13)), const SizedBox(height: 2), Text(info['reliability']!, style: TextStyle(color: AppTheme.textSecondary, fontSize: 13)), const SizedBox(height: 14), const Text('Kursziel:', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white, fontSize: 13)), const SizedBox(height: 4), Text(info['target']!, style: TextStyle(color: AppTheme.primaryEmerald, fontSize: 13, height: 1.4)), const SizedBox(height: 14), const Text('Stop-Loss:', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white, fontSize: 13)), const SizedBox(height: 4), Text(info['stop_loss']!, style: TextStyle(color: AppTheme.accentRed, fontSize: 13, height: 1.4)), const SizedBox(height: 18), const Text('Einstiegsauslöser:', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white, fontSize: 13)), const SizedBox(height: 4), Container( width: double.infinity, padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: AppTheme.glassSurface, borderRadius: BorderRadius.circular(8), border: Border.all(color: AppTheme.glassBorder), ), child: Text(info['action']!, style: TextStyle(color: AppTheme.accentCyan, fontSize: 12, fontWeight: FontWeight.w600, height: 1.4)), ), ], ), ), actions: [ TextButton( onPressed: () => Navigator.pop(modalContext), child: const Text('Schließen', style: TextStyle(color: Colors.white)), ), ], ), ); } }