feat(app): add evaluation history, bot control panel, simulation visualizer, and vendored signalr_core
This commit is contained in:
@@ -47,9 +47,7 @@ class _TradeClosingCockpitState extends State<TradeClosingCockpit> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final defaultPrice = widget.trade.currentPrice > 0
|
||||
? widget.trade.currentPrice
|
||||
: (widget.trade.actualEntryPrice > 0 ? widget.trade.actualEntryPrice : widget.trade.entryPrice);
|
||||
final defaultPrice = widget.trade.currentPrice > 0 ? widget.trade.currentPrice : widget.trade.averageBuyIn;
|
||||
|
||||
_exitPriceCtrl = TextEditingController(text: defaultPrice.toStringAsFixed(2));
|
||||
_exitFeeCtrl = TextEditingController(text: '1.00');
|
||||
@@ -72,27 +70,29 @@ class _TradeClosingCockpitState extends State<TradeClosingCockpit> {
|
||||
return double.tryParse(clean) ?? fallback;
|
||||
}
|
||||
|
||||
double get _exitPrice => _parse(_exitPriceCtrl, widget.trade.entryPrice);
|
||||
double get _exitPrice => _parse(_exitPriceCtrl, widget.trade.averageBuyIn);
|
||||
double get _exitFee => _parse(_exitFeeCtrl, 1.0);
|
||||
|
||||
double get _entryPrice => widget.trade.actualEntryPrice > 0 ? widget.trade.actualEntryPrice : (widget.trade.entryPrice > 0 ? widget.trade.entryPrice : 1.0);
|
||||
double get _posSize => widget.trade.positionSize > 0 ? widget.trade.positionSize : 1000.0;
|
||||
double get _quantity => widget.trade.quantity > 0 ? widget.trade.quantity : (_posSize / _entryPrice);
|
||||
double get _entryPrice => widget.trade.averageBuyIn;
|
||||
double get _quantity => widget.trade.totalQuantity;
|
||||
double get _posSize => _entryPrice * _quantity;
|
||||
|
||||
double get _calculatedProceeds {
|
||||
if (_exitPrice <= 0 || _quantity <= 0) return 0.0;
|
||||
return _quantity * _exitPrice;
|
||||
}
|
||||
|
||||
/// Forward preview of the realized P&L this closing input would produce —
|
||||
/// computed from real trade fields only (averageBuyIn, totalQuantity,
|
||||
/// direction) plus the fee the user is entering right now. This is NOT a
|
||||
/// re-derivation of the server's `realizedPnlEur`: the trade isn't closed
|
||||
/// yet, so the server has no such value to show (Rules.md §4 — a genuine
|
||||
/// "what happens if I close now" preview, not an invented duplicate).
|
||||
double get _calculatedPnlAbs {
|
||||
if (_entryPrice <= 0 || _exitPrice <= 0) return 0.0;
|
||||
final isShort = widget.trade.signalType.toUpperCase() == 'SELL' || widget.trade.signalType.toUpperCase() == 'SHORT';
|
||||
final movePct = isShort ? ((_entryPrice - _exitPrice) / _entryPrice) : ((_exitPrice - _entryPrice) / _entryPrice);
|
||||
final lev = (widget.trade.instrumentType.toLowerCase().contains('knock') || widget.trade.instrumentType.toLowerCase().contains('option'))
|
||||
? 1.0
|
||||
: (widget.trade.leverageUsed > 0 ? widget.trade.leverageUsed : 1.0);
|
||||
final totalFees = (widget.trade.entryFee > 0 ? widget.trade.entryFee : 1.0) + _exitFee;
|
||||
return (movePct * _posSize * lev) - totalFees;
|
||||
final isShort = !widget.trade.direction.isLong;
|
||||
final rawMove = isShort ? (_entryPrice - _exitPrice) : (_exitPrice - _entryPrice);
|
||||
return (rawMove * _quantity) - _exitFee;
|
||||
}
|
||||
|
||||
double get _calculatedPnlPct {
|
||||
@@ -188,7 +188,7 @@ class _TradeClosingCockpitState extends State<TradeClosingCockpit> {
|
||||
style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text(
|
||||
'Trade #${widget.trade.id} • ${widget.trade.companyName.isNotEmpty ? widget.trade.companyName : widget.defaultSymbol}',
|
||||
'Trade #${widget.trade.id} • ${widget.trade.symbol.isNotEmpty ? widget.trade.symbol : widget.defaultSymbol}',
|
||||
style: TextStyle(color: AppTheme.textMuted, fontSize: 12),
|
||||
),
|
||||
],
|
||||
@@ -224,7 +224,7 @@ class _TradeClosingCockpitState extends State<TradeClosingCockpit> {
|
||||
_summaryCol('Einstiegskurs', '€${_entryPrice.toStringAsFixed(2)}'),
|
||||
_summaryCol('Investition', '€${_posSize.toStringAsFixed(0)}'),
|
||||
_summaryCol('Stückzahl', '${_quantity.toStringAsFixed(2)} Stk.'),
|
||||
_summaryCol('Instrument', widget.trade.instrumentType),
|
||||
_summaryCol('Instrument', widget.trade.instrumentType.label),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user