feat(trades): add live execution cockpit, closing cockpit, calculation cards and precision trade settings
This commit is contained in:
@@ -10,7 +10,6 @@ import 'trade_execution_ai_plan_card.dart';
|
||||
class TradeExecutionDialog {
|
||||
static const double _defaultPositionSize = 1000.0;
|
||||
static const double _defaultLeverage = 1.0;
|
||||
static const List<String> _allowedInstruments = ['Stock', 'KnockOut', 'Option', 'CFD', 'Crypto'];
|
||||
|
||||
static String _normalizeInstrumentType(String raw) {
|
||||
final clean = raw.toLowerCase().trim();
|
||||
@@ -167,25 +166,56 @@ class TradeExecutionDialog {
|
||||
return StatefulBuilder(
|
||||
builder: (stfContext, setModalState) {
|
||||
final isKnockout = selectedInstrumentType.toLowerCase().contains('knock') ||
|
||||
selectedInstrumentType.toLowerCase().contains('zertifikat') ||
|
||||
selectedInstrumentType.toLowerCase().contains('option') ||
|
||||
selectedInstrumentType.toLowerCase().contains('cfd');
|
||||
selectedInstrumentType.toLowerCase().contains('factor') ||
|
||||
selectedInstrumentType.toLowerCase().contains('derivat');
|
||||
|
||||
final safeInstrumentValue = _allowedInstruments.contains(selectedInstrumentType) ? selectedInstrumentType : 'KnockOut';
|
||||
final assetType = trade.assetType.toLowerCase();
|
||||
final categories = trade.derivativeProductCategories;
|
||||
final hasCfd = trade.hasCfd;
|
||||
|
||||
final availableOptions = <MapEntry<String, String>>[];
|
||||
if (assetType == 'crypto') {
|
||||
availableOptions.add(const MapEntry('Crypto', 'Krypto'));
|
||||
if (hasCfd) availableOptions.add(const MapEntry('CFD', 'Krypto CFD'));
|
||||
} else if (assetType == 'etf') {
|
||||
availableOptions.add(const MapEntry('Stock', 'ETF (Direktinvestment)'));
|
||||
if (categories.isEmpty || categories.contains('knockOutProduct')) {
|
||||
availableOptions.add(const MapEntry('KnockOut', 'Knock-Out Zertifikat'));
|
||||
}
|
||||
if (categories.contains('vanillaWarrant')) {
|
||||
availableOptions.add(const MapEntry('Option', 'Optionsschein'));
|
||||
}
|
||||
if (categories.contains('factorCertificate')) {
|
||||
availableOptions.add(const MapEntry('Factor', 'Faktor-Zertifikat'));
|
||||
}
|
||||
if (hasCfd) availableOptions.add(const MapEntry('CFD', 'CFD (Hebel-Derivat)'));
|
||||
} else {
|
||||
availableOptions.add(const MapEntry('Stock', 'Aktie (Direktinvestment)'));
|
||||
if (categories.isEmpty || categories.contains('knockOutProduct')) {
|
||||
availableOptions.add(const MapEntry('KnockOut', 'Knock-Out Zertifikat'));
|
||||
}
|
||||
if (categories.contains('vanillaWarrant')) {
|
||||
availableOptions.add(const MapEntry('Option', 'Optionsschein'));
|
||||
}
|
||||
if (categories.contains('factorCertificate')) {
|
||||
availableOptions.add(const MapEntry('Factor', 'Faktor-Zertifikat'));
|
||||
}
|
||||
if (hasCfd) availableOptions.add(const MapEntry('CFD', 'CFD (Hebel-Derivat)'));
|
||||
}
|
||||
|
||||
final safeInstrumentValue = availableOptions.any((o) => o.key == selectedInstrumentType)
|
||||
? selectedInstrumentType
|
||||
: (availableOptions.isNotEmpty ? availableOptions.first.key : 'Stock');
|
||||
|
||||
return AlertDialog(
|
||||
backgroundColor: AppTheme.cardSurface,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16), side: BorderSide(color: AppTheme.glassBorder)),
|
||||
title: Row(
|
||||
children: [
|
||||
Icon(isActive ? Icons.tune : Icons.edit_note_outlined, color: AppTheme.primaryEmerald, size: 22),
|
||||
Icon(Icons.flash_on, color: AppTheme.primaryEmerald),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
isActive ? 'Einstellungen für Trade #${trade.id}' : 'Trade-Ausführung & Parameter',
|
||||
style: const TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
Text(isActive ? 'Aktiven Trade anpassen' : 'Trade-Vorschlag ausführen', style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16)),
|
||||
],
|
||||
),
|
||||
content: SizedBox(
|
||||
@@ -205,13 +235,9 @@ class TradeExecutionDialog {
|
||||
initialValue: safeInstrumentValue,
|
||||
dropdownColor: AppTheme.cardSurface,
|
||||
decoration: const InputDecoration(labelText: 'Finanzinstrument Typ', contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 8)),
|
||||
items: const [
|
||||
DropdownMenuItem(value: 'Stock', child: Text('Aktie / ETF (Direktinvestment)', style: TextStyle(color: Colors.white, fontSize: 13))),
|
||||
DropdownMenuItem(value: 'KnockOut', child: Text('Knock-Out Zertifikat', style: TextStyle(color: Colors.white, fontSize: 13))),
|
||||
DropdownMenuItem(value: 'Option', child: Text('Optionsschein / Derivat', style: TextStyle(color: Colors.white, fontSize: 13))),
|
||||
DropdownMenuItem(value: 'CFD', child: Text('CFD (Hebel-Derivat)', style: TextStyle(color: Colors.white, fontSize: 13))),
|
||||
DropdownMenuItem(value: 'Crypto', child: Text('Krypto', style: TextStyle(color: Colors.white, fontSize: 13))),
|
||||
],
|
||||
items: availableOptions.map((opt) {
|
||||
return DropdownMenuItem(value: opt.key, child: Text(opt.value, style: const TextStyle(color: Colors.white, fontSize: 13)));
|
||||
}).toList(),
|
||||
onChanged: (val) {
|
||||
if (val != null) setModalState(() => selectedInstrumentType = val);
|
||||
},
|
||||
@@ -318,6 +344,48 @@ class TradeExecutionDialog {
|
||||
),
|
||||
],
|
||||
),
|
||||
if (trade.takeProfitTargets.isNotEmpty) ...[
|
||||
const SizedBox(height: 8),
|
||||
Wrap(
|
||||
spacing: 6,
|
||||
runSpacing: 4,
|
||||
children: trade.takeProfitTargets.asMap().entries.map((entry) {
|
||||
final idx = entry.key;
|
||||
final targetPrice = entry.value;
|
||||
return ActionChip(
|
||||
label: Text('TP${idx + 1}: €${targetPrice.toStringAsFixed(2)}', style: const TextStyle(fontSize: 11, fontWeight: FontWeight.bold)),
|
||||
onPressed: () {
|
||||
tpController.text = targetPrice.toStringAsFixed(2);
|
||||
},
|
||||
backgroundColor: Colors.white10,
|
||||
side: BorderSide(color: AppTheme.primaryEmerald.withValues(alpha: 0.4)),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 0),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 12),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.amber.withValues(alpha: 0.05),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: Colors.amber.withValues(alpha: 0.25)),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(Icons.gavel_outlined, size: 14, color: Colors.amber.withValues(alpha: 0.85)),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Rechtlicher Hinweis: Keine Anlageberatung. Sämtliche Angaben dienen ausschließlich Informationszwecken. Hebelprodukte bergen ein hohes Verlustrisiko bis hin zum Totalverlust.',
|
||||
style: TextStyle(color: AppTheme.textMuted, fontSize: 10, height: 1.3),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user