/// Describes one tunable indicator parameter for a strategy - mirrors the `context.GetParameter(StrategyKey, "...", default)` /// calls in `FinlyticTechnicals/Strategies/CoreStrategies.cs`. Keys sent to the backend are always /// `"{strategyKey}.{name}"`, matching `TechnicalContext.ParameterOverrides` exactly. class StrategyParameterDef { final String name; final String label; final double defaultValue; /// Short plain-language explanation of what changing this value actually does, shown via an info tooltip /// next to the field (Rules.md-style transparency: a bare abbreviation like "EMA schnell" means nothing to /// someone who didn't just read the strategy's source code). final String hint; /// Whether the field should be entered/rounded as a whole number (indicator periods) vs. a decimal /// (multipliers, thresholds). final bool isInteger; const StrategyParameterDef({ required this.name, required this.label, required this.defaultValue, required this.hint, this.isInteger = false, }); } /// Per-strategy list of tunable parameters, for the "Erweiterte Parameter" section of the backtest screen. /// Every default value here must match the corresponding hardcoded default in `CoreStrategies.cs` exactly - /// these are the same values the strategy already uses when nothing is overridden (Rules.md §4: never imply a /// different default than what the backend actually falls back to). class StrategyParameterDefinitions { static const Map> byStrategy = { 'TrendPullbackFvg': [ StrategyParameterDef( name: 'EmaFast', label: 'EMA schnell', defaultValue: 20, isInteger: true, hint: 'Perioden der kurzen EMA. Kleiner = reagiert schneller auf Kursänderungen, aber mehr Fehlsignale.', ), StrategyParameterDef( name: 'EmaMid', label: 'EMA mittel', defaultValue: 50, isInteger: true, hint: 'Perioden der mittleren EMA, bestätigt zusammen mit der langsamen EMA den übergeordneten Trend.', ), StrategyParameterDef( name: 'EmaSlow', label: 'EMA langsam', defaultValue: 200, isInteger: true, hint: 'Perioden der langsamen EMA. Größer = stabilerer, aber träger erkannter Trend.', ), StrategyParameterDef( name: 'StopAtrMultiplier', label: 'Stop-Loss (× ATR)', defaultValue: 1.2, hint: 'Abstand des Stop-Loss vom Einstieg, als Vielfaches der aktuellen Volatilität (ATR). Größer = weiterer Stop, weniger vorzeitige Ausstiege.', ), ], 'VolatilitySqueeze': [ StrategyParameterDef( name: 'StopAtrMultiplier', label: 'Stop-Loss (× ATR)', defaultValue: 1.0, hint: 'Abstand des Stop-Loss vom Einstieg, als Vielfaches der aktuellen Volatilität (ATR).', ), StrategyParameterDef( name: 'TargetAtrMultiplier', label: 'Kursziel (× ATR)', defaultValue: 2.0, hint: 'Abstand des Kursziels vom Einstieg, als Vielfaches der aktuellen Volatilität (ATR).', ), ], 'SmcLiquiditySweep': [ StrategyParameterDef( name: 'StopBufferPercent', label: 'Stop-Puffer (%)', defaultValue: 0.2, hint: 'Zusätzlicher Sicherheitsabstand des Stop-Loss hinter dem Sweep-Extrempunkt, in Prozent.', ), ], 'MeanReversion': [ StrategyParameterDef( name: 'BollingerMultiplier', label: 'Bollinger-Multiplikator (σ)', defaultValue: 2.5, hint: 'Breite der Bollinger-Bänder in Standardabweichungen. Größer = seltenere, aber extremere Signale.', ), StrategyParameterDef( name: 'AdxThreshold', label: 'ADX-Schwelle (max.)', defaultValue: 22, hint: 'Nur unterhalb dieser ADX-Trendstärke gilt der Markt als "seitwärts" - Voraussetzung für ein Signal.', ), StrategyParameterDef( name: 'RsiOversold', label: 'RSI überverkauft (≤)', defaultValue: 32, hint: 'RSI-Wert, ab dem der Kurs als überverkauft gilt (Long-Signal-Voraussetzung).', ), StrategyParameterDef( name: 'RsiOverbought', label: 'RSI überkauft (≥)', defaultValue: 68, hint: 'RSI-Wert, ab dem der Kurs als überkauft gilt (Short-Signal-Voraussetzung).', ), ], 'SuperTrendMultiTf': [ StrategyParameterDef( name: 'Period', label: 'SuperTrend-Periode', defaultValue: 10, isInteger: true, hint: 'ATR-Periode, die der SuperTrend-Indikator auf beiden Zeitebenen (1h und 15m) zugrunde legt.', ), StrategyParameterDef( name: 'Multiplier', label: 'SuperTrend-Multiplikator', defaultValue: 3.0, hint: 'Wie weit die SuperTrend-Linie von der ATR-Bandbreite entfernt liegt. Größer = trägere, glattere Linie.', ), ], 'MacdCrossover': [ StrategyParameterDef( name: 'FastPeriod', label: 'MACD schnell', defaultValue: 12, isInteger: true, hint: 'Perioden der schnellen EMA im MACD.', ), StrategyParameterDef( name: 'SlowPeriod', label: 'MACD langsam', defaultValue: 26, isInteger: true, hint: 'Perioden der langsamen EMA im MACD.', ), StrategyParameterDef( name: 'SignalPeriod', label: 'MACD Signal', defaultValue: 9, isInteger: true, hint: 'Perioden der Signal-Linie (EMA der MACD-Linie), gegen die auf Kreuzung geprüft wird.', ), StrategyParameterDef( name: 'StopAtrMultiplier', label: 'Stop-Loss (× ATR)', defaultValue: 1.5, hint: 'Abstand des Stop-Loss vom Einstieg, als Vielfaches der aktuellen Volatilität (ATR).', ), ], 'MovingAverageCrossover': [ StrategyParameterDef( name: 'FastPeriod', label: 'EMA schnell', defaultValue: 50, isInteger: true, hint: 'Perioden der schnellen EMA (kreuzt für ein Golden/Death Cross durch die langsame EMA).', ), StrategyParameterDef( name: 'SlowPeriod', label: 'EMA langsam', defaultValue: 200, isInteger: true, hint: 'Perioden der langsamen EMA - je größer, desto seltener und langfristiger die Signale.', ), StrategyParameterDef( name: 'StopAtrMultiplier', label: 'Stop-Loss (× ATR)', defaultValue: 2.0, hint: 'Abstand des Stop-Loss vom Einstieg, als Vielfaches der aktuellen Volatilität (ATR).', ), ], 'RsiReversal': [ StrategyParameterDef( name: 'Period', label: 'RSI-Periode', defaultValue: 14, isInteger: true, hint: 'Anzahl Kerzen, über die der RSI berechnet wird.', ), StrategyParameterDef( name: 'OversoldThreshold', label: 'Überverkauft-Schwelle', defaultValue: 30, hint: 'RSI-Schwelle, deren erneutes Überschreiten von unten ein Long-Signal auslöst.', ), StrategyParameterDef( name: 'OverboughtThreshold', label: 'Überkauft-Schwelle', defaultValue: 70, hint: 'RSI-Schwelle, deren erneutes Unterschreiten von oben ein Short-Signal auslöst.', ), StrategyParameterDef( name: 'StopAtrMultiplier', label: 'Stop-Loss (× ATR)', defaultValue: 1.2, hint: 'Abstand des Stop-Loss vom Einstieg, als Vielfaches der aktuellen Volatilität (ATR).', ), ], 'DonchianBreakout': [ StrategyParameterDef( name: 'Period', label: 'Kanal-Periode', defaultValue: 20, isInteger: true, hint: 'Anzahl vorheriger Kerzen, deren Hoch/Tief den Ausbruchskanal bilden. Größer = seltenere, dafür signifikantere Ausbrüche.', ), ], 'VwapBounce': [ StrategyParameterDef( name: 'EmaFast', label: 'EMA schnell', defaultValue: 20, isInteger: true, hint: 'Perioden der schnellen EMA, bestimmt zusammen mit der langsamen EMA die Trendrichtung.', ), StrategyParameterDef( name: 'EmaSlow', label: 'EMA langsam', defaultValue: 50, isInteger: true, hint: 'Perioden der langsamen EMA, bestimmt zusammen mit der schnellen EMA die Trendrichtung.', ), StrategyParameterDef( name: 'StopAtrMultiplier', label: 'Stop-Loss (× ATR)', defaultValue: 1.0, hint: 'Abstand des Stop-Loss vom Einstieg, als Vielfaches der aktuellen Volatilität (ATR).', ), ], }; static List forStrategy(String strategyKey) => byStrategy[strategyKey] ?? const []; }