feat(App): update Finlytic Flutter app UI and blocs

This commit is contained in:
2026-08-09 21:01:46 +02:00
parent e7427b7464
commit a708d2977c
591 changed files with 1095105 additions and 0 deletions
@@ -0,0 +1,142 @@
import 'package:flutter/material.dart';
import '../widgets/metric_explanation_modal.dart';
class MetricExplanations {
static const Map<String, Map<String, String>> data = {
'EMA (20)': {
'title': 'Exponential Moving Average (20 Perioden)',
'formula': 'EMA_t = (Preis_t * (2 / (20 + 1))) + EMA_{t-1} * (1 - (2 / (20 + 1)))',
'description': 'Exponentiell gewichteter gleitender Durchschnitt der letzten 20 Kerzen. Gewichtete aktuelle Kurse stärker als ältere.',
'tradingSignificance': 'Dient als dynamische Unterstützung/Widerstand für kurzfristige Trends. Ein Schnittpunkt über die Kerzen zeigt Kaufsignale.',
},
'SMA (50)': {
'title': 'Simple Moving Average (50 Perioden)',
'formula': 'SMA = (Summe der Schlusskurse der letzten 50 Kerzen) / 50',
'description': 'Einfacher gleitender Durchschnitt der letzten 50 Perioden.',
'tradingSignificance': 'Standard-Indikator für mittelfristige Trends. Preis über SMA50 deutet auf einen intakten Aufwärtstrend hin.',
},
'SMA (200)': {
'title': 'Simple Moving Average (200 Perioden)',
'formula': 'SMA = (Summe der Schlusskurse der letzten 200 Kerzen) / 200',
'description': 'Einfacher gleitender Durchschnitt der letzten 200 Perioden.',
'tradingSignificance': 'Wichtigster Indikator für den langfristigen Trend. "Golden Cross" (SMA50 schneidet SMA200 nach oben) ist ein starkes Bullen-Signal.',
},
'Supertrend': {
'title': 'Supertrend Indikator',
'formula': 'Upper/Lower Band = (High + Low)/2 ± (Multiplier * ATR(10))',
'description': 'Kombiniert ATR (Average True Range) und Durchschnittskurs zur Trendfolge.',
'tradingSignificance': 'Grün zeigt einen etablierten Aufwärtstrend mit dynamischem Stop-Loss Level; Rot signalisiert Abwärtstrend.',
},
'RSI (14)': {
'title': 'Relative Strength Index (14 Perioden)',
'formula': 'RSI = 100 - (100 / (1 + (Durchschnittl. Gewinn / Durchschnittl. Verlust)))',
'description': 'Oszillator zur Messung der Geschwindigkeit und Veränderung von Kursbewegungen.',
'tradingSignificance': 'Werte > 70 gelten als überkauft (Verkaufsrisiko), Werte < 30 gelten als überverkauft (Kaufchance).',
},
'KGV (Trailing P/E)': {
'title': 'Kurs-Gewinn-Verhältnis (Trailing P/E)',
'formula': 'KGV = Aktienkurs / Gewinn pro Aktie (EPS der letzten 12 Monate)',
'description': 'Gibt an, das Wievielfache des Jahresgewinns für eine Aktie gezahlt wird.',
'tradingSignificance': 'Ein niedriges KGV kann auf eine Unterbewertung hindeuten; ein hohes KGV verlangt hohes zukünftiges Gewinnwachstum.',
},
'KGV (Forward P/E)': {
'title': 'Zukünftiges KGV (Forward P/E)',
'formula': 'Forward KGV = Aktueller Kurs / Erwarteter Gewinn pro Aktie (nächste 12 Monate)',
'description': 'Basiert auf den Konsens-Gewinnerwartungen von Analysten für das kommende Jahr.',
'tradingSignificance': 'Ermöglicht den Vergleich mit dem historischen KGV, um festzustellen, ob das Gewinnwachstum die Bewertung verbilligt.',
},
'PEG Ratio': {
'title': 'Price/Earnings-to-Growth Ratio',
'formula': 'PEG = KGV / Zukünftiges Gewinnwachstum in %',
'description': 'Setzt das KGV ins Verhältnis zum erwarteten Gewinnwachstum des Unternehmens.',
'tradingSignificance': 'PEG < 1.0 gilt als fair oder unterbewertet im Verhältnis zum Wachstum. PEG > 2.0 gilt als teuer.',
},
'KBV (P/B Ratio)': {
'title': 'Kurs-Buchwert-Verhältnis (P/B Ratio)',
'formula': 'KBV = Aktienkurs / Buchwert pro Aktie',
'description': 'Vergleicht den Börsenwert des Unternehmens mit seinem bilanziellen Eigenkapital.',
'tradingSignificance': 'Besonders wichtig für Finanzwerte und Substanzwerte. KBV < 1 bedeutet, dass die Aktie unter ihrem Buchwert handelt.',
},
'KUV (P/S Ratio)': {
'title': 'Kurs-Umsatz-Verhältnis (P/S Ratio)',
'formula': 'KUV = Marktkapitalisierung / Gesamter Jahresumsatz',
'description': 'Vergleicht den Marktwert des Unternehmens mit seinem Jahresumsatz.',
'tradingSignificance': 'Nützlich bei noch unprofitablen Wachstumsunternehmen, bei denen noch kein positives KGV berechnet werden kann.',
},
'EV / EBITDA': {
'title': 'Enterprise Value zu EBITDA',
'formula': 'EV/EBITDA = Enterprise Value / (Gewinn vor Zinsen, Steuern & Abschreibungen)',
'description': 'Misst den Unternehmenswert inklusive Schulden im Verhältnis zur operativen Cash-Generierung.',
'tradingSignificance': 'Kapitalstruktur-neutraler Bewertungs-Multiple. Erlaubt fairen Vergleich zwischen Unternehmen mit unterschiedlicher Verschuldung.',
},
'EV / Sales': {
'title': 'Enterprise Value zu Umsatz',
'formula': 'EV/Sales = Enterprise Value / Jahresumsatz',
'description': 'Vergleicht den gesamten Unternehmenswert (Eigen- + Fremdkapital) mit den Erlösen.',
'tradingSignificance': 'Robustere Kennzahl als KUV, da sie auch die Schuldenlast des Unternehmens berücksichtigt.',
},
'Enterprise Value': {
'title': 'Enterprise Value (Unternehmenswert)',
'formula': 'EV = Marktkapitalisierung + Gesamtschulden - Liquide Mittel (Cash)',
'description': 'Der theoretische Übernahmepreis für das gesamte Unternehmen inklusive Tilgung aller Verbindlichkeiten.',
'tradingSignificance': 'Der tatsächliche wirtschaftliche Wert des Geschäftsbetriebs.',
},
'Marktkapitalisierung': {
'title': 'Marktkapitalisierung (Market Cap)',
'formula': 'Market Cap = Gesamtzahl ausstehender Aktien * Aktueller Aktienkurs',
'description': 'Der Gesamtwert aller frei gehandelten Aktien des Unternehmens an der Börse.',
'tradingSignificance': 'Teilt Unternehmen in Large Cap (>10 Mrd. €), Mid Cap (2-10 Mrd. €) und Small Cap (<2 Mrd. €) ein.',
},
'Short Ratio': {
'title': 'Days to Cover (Short Ratio)',
'formula': 'Short Ratio = Anzahl leerverkaufter Aktien / Durchschnittliches Tagesvolumen',
'description': 'Gibt an, wie viele Handelstage Leerverkäufer bräuchten, um alle Positionen einzudecken.',
'tradingSignificance': 'Hohe Werte (> 5-7 Tage) erhöhen die Wahrscheinlichkeit eines heftigen "Short Squeezes" bei positiven News.',
},
'Bruttomarge (Gross)': {
'title': 'Bruttogewinnmarge (Gross Margin)',
'formula': 'Gross Margin = ((Umsatz - Herstellkosten) / Umsatz) * 100',
'description': 'Prozentualer Anteil des Umsatzes, der nach Abzug der direkten Produktionskosten verbleibt.',
'tradingSignificance': 'Hohe Bruttomargen (> 50-70%) zeigen eine starke Preissetzungsmacht und Wettbewerbsvorteile (Moat).',
},
'Operative Marge': {
'title': 'Operative Gewinnmarge (EBIT Margin)',
'formula': 'Operating Margin = (Operatives Ergebnis (EBIT) / Umsatz) * 100',
'description': 'Prozentualer Anteil des Umsatzes, der nach allen operativen Kosten (F&E, Vertrieb, Admin) übrig bleibt.',
'tradingSignificance': 'Kerngröße für die operative Effizienz des Managements.',
},
'Nettogewinnmarge': {
'title': 'Nettogewinnmarge (Net Profit Margin)',
'formula': 'Net Profit Margin = (Nettogewinn nach Steuern / Umsatz) * 100',
'description': 'Prozentualer Reingewinn, der von jedem Euro Umsatz im Unternehmen verbleibt.',
'tradingSignificance': 'Zeigt die finale Rentabilität nach allen Zinsen und Steuern.',
},
'Eigenkapitalrendite (ROE)': {
'title': 'Eigenkapitalrendite (Return on Equity)',
'formula': 'ROE = (Nettogewinn / Eigenkapital) * 100',
'description': 'Misst, wie effizient das Management das eingesetzte Eigenkapital verzinst.',
'tradingSignificance': 'Werte > 15-20% stehen für hochprofitable Qualitätsunternehmen.',
},
'Verschuldungsgrad (D/E)': {
'title': 'Debt-to-Equity Ratio (D/E)',
'formula': 'D/E = Gesamtschulden / Eigenkapital',
'description': 'Setzt das Fremdkapital ins Verhältnis zum Eigenkapital.',
'tradingSignificance': 'Werte > 1.5 - 2.0 deuten auf ein erhöhtes mehraufwand- und Insolvenzrisiko bei steigenden Zinsen hin.',
},
};
static void show(BuildContext context, String key) {
final info = data[key];
if (info == null) return;
showDialog(
context: context,
builder: (context) => MetricExplanationModal(
title: info['title']!,
formula: info['formula']!,
description: info['description']!,
tradingSignificance: info['tradingSignificance']!,
),
);
}
}
@@ -0,0 +1,170 @@
import 'package:flutter/material.dart';
import '../../../../core/theme/app_theme.dart';
class PatternExplanations {
static const Map<String, Map<String, String>> dictionary = {
'ASCENDING_TRIANGLE': {
'title': 'Steigendes Dreieck (Ascending Triangle)',
'bias': 'BULLISH',
'description': 'Ein bullisches Fortsetzungsmuster, das durch eine horizontale Widerstandslinie oben und eine steigende Unterstützungslinie unten gekennzeichnet ist.',
'significance': 'Käufer werden bei jedem Rücksetzer aggressiver (höhere Tiefs). Ein Ausbruch über die obere Widerstandslinie signalisiert eine starke Fortsetzung des Aufwärtstrends.',
'action': 'Kauf-Order / Breakout-Trade beim Ausbruch über den horizontalen Widerstand mit Stop-Loss knapp unter der steigenden Trendlinie.',
},
'DESCENDING_TRIANGLE': {
'title': 'Fallendes Dreieck (Descending Triangle)',
'bias': 'BEARISH',
'description': 'Ein bärisches Fortsetzungsmuster mit einer horizontalen Unterstützungslinie unten und fallenden Hochs oben.',
'significance': 'Verkäufer drücken den Kurs bei jeder Erholung schneller nach unten. Ein Bruch der unteren Unterstützung führt meist zu dynamischen Abverkäufen.',
'action': 'Short-Trade oder Verkauf bei Durchbruch der unteren Unterstützungslinie.',
},
'HEAD_AND_SHOULDERS': {
'title': 'Kopf-Schulter-Formation (Head & Shoulders)',
'bias': 'BEARISH',
'description': 'Klassisches Umkehrmuster bestehend aus drei Höchstständen: der mittleren höchsten Spitze (Kopf) und zwei kleineren Höchstständen links und rechts (Schultern).',
'significance': 'Ein nachhaltiger Bruch der Nackenlinie (Neckline) markiert das Ende eines Aufwärtstrends und den Beginn einer Bärenphase.',
'action': 'Verkauf/Short-Position beim Bruch der Nackenlinie mit Kursziel entsprechend der Distanz zwischen Kopf und Nackenlinie.',
},
'INVERSE_HEAD_AND_SHOULDERS': {
'title': 'Umgekehrte Kopf-Schulter-Formation',
'bias': 'BULLISH',
'description': 'Bullisches Bodenbildungsmuster nach einem Abwärtstrend mit drei Tiefspunkten.',
'significance': 'Signalisiert das Ende des Abwärtstrends und den Beginn eines neuen Bullenmarktes.',
'action': 'Kauf bei Ausbruch über die obere Nackenlinie.',
},
'BULL_FLAG': {
'title': 'Bullische Flagge (Bull Flag)',
'bias': 'BULLISH',
'description': 'Kurze Konsolidierung gegen den übergeordneten starken Aufwärtstrend (Fahnenstange).',
'significance': 'Zeigt eine temporäre Gewinnmitnahme vor der nächsten Welle nach oben.',
'action': 'Kauf beim Ausbruch aus der oberen Begrenzung des Flaggenkanals.',
},
'BEAR_FLAG': {
'title': 'Bärische Flagge (Bear Flag)',
'bias': 'BEARISH',
'description': 'Kurze Aufwärtskonsolidierung in einem steilen Abwärtstrend.',
'significance': 'Signalisiert eine Fortsetzung des steilen Abverkaufs.',
'action': 'Short-Position bei Durchbrechen der unteren Flaggenkante.',
},
'DOUBLE_BOTTOM': {
'title': 'Doppelboden (W-Formation)',
'bias': 'BULLISH',
'description': 'Zwei aufeinanderfolgende Tiefpunkte auf etwa gleichem Kursniveau.',
'significance': 'Starke Unterstützung auf dem Tiefststand wurde zweimal erfolgreich verteidigt. Ausbruch über das Zwischenhoch bestätigt W-Boden.',
'action': 'Kauf bei Überschreiten des W-Zwischenhochs.',
},
'DOUBLE_TOP': {
'title': 'Doppeltopp (M-Formation)',
'bias': 'BEARISH',
'description': 'Zwei markante Höchststände auf ähnlicher Höhe, die nicht durchbrochen werden konnten.',
'significance': 'Widerstandszone ist zu stark für die Bullen. Bruch des Zwischen-Tiefs leitet Trendwende ein.',
'action': 'Verkauf/Short bei Bruch des Zwischentiefs.',
},
'CHANNEL': {
'title': 'Trendkanal (Trading Channel)',
'bias': 'NEUTRAL',
'description': 'Parallele obere und untere Trendlinien, zwischen denen der Kurs Oszilliert.',
'significance': 'Erlaubt Swing-Trading zwischen den Kanallinien oder Breakout-Trading beim Ausbruch.',
'action': 'Kauf an der Unterkante, Verkauf an der Oberkante oder Breakout-Trading.',
},
'SUPPORT_RESISTANCE': {
'title': 'Unterstützungs- & Widerstandslinien',
'bias': 'NEUTRAL',
'description': 'Preisniveaus, an denen historisch gehäuft Kauf- oder Verkaufsinteresse auftrat.',
'significance': 'Wichtige Marken für Stop-Loss Platzierungen und Kursziele.',
'action': 'Trading an Key-Levels mit engem Risikomanagement.',
},
};
static void showPatternDetails(BuildContext context, String rawPatternType) {
final key = dictionary.keys.firstWhere(
(k) => rawPatternType.toUpperCase().contains(k) || k.contains(rawPatternType.toUpperCase()),
orElse: () => '',
);
final info = key.isNotEmpty ? dictionary[key]! : {
'title': rawPatternType,
'bias': 'NEUTRAL',
'description': 'Ein vom FinlyticAnalyzer erkanntes technisches Chart-Muster ($rawPatternType).',
'significance': 'Trendlinien und Schlüssel-Zonen zur Bestimmung von Ein- und Ausstiegssignalen.',
'action': 'Nutzen Sie Stopp-Orders und beachten Sie den übergeordneten Markt-Trend.',
};
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('Formationsbeschreibung:', 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('Markt-Bedeutung & Psychologie:', 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('Empfohlene Trading-Handlung:', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white, fontSize: 13)),
const SizedBox(height: 4),
Container(
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)),
),
],
),
);
}
}