Copytrading-Views auf Designer-Muster umgestellt

Die drei Modul-Views wurden von komplett code-first (alle Controls im Konstruktor)
auf das Standard-WinForms-Designer-Muster umgestellt (je X.cs + X.Designer.cs mit
InitializeComponent), damit sie im Designer geöffnet und bearbeitet werden können:

- ClosedTradesView, AccountSettingsView, MasterTradersView: alle wichtigen
  Steuerelemente (Panels, DataGridView mit expliziten Spalten via
  AutoGenerateColumns=false, PropertyGrid, ToolStrip, GroupBox, CheckedListBox,
  ComboBox, Buttons, Labels, Splitter) sind jetzt Designer-Felder.
- Konsistent mit den Core-Views (DashboardView-Muster): Layout im Designer,
  Zellformate/Event-Wiring/Datenbindung im Code.

Verifiziert: --smoke-ui grün (3 Accounts / 32 Trader; alle Views + Launcher OK).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-07-06 10:11:30 +02:00
co-authored by Claude Opus 4.8
parent f1451b547c
commit 4caba5bfd1
6 changed files with 721 additions and 207 deletions
@@ -1,6 +1,5 @@
using System;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using PolyTrader.Modules.CopyTrading.Persistence;
@@ -12,47 +11,31 @@ namespace PolyTrader.Modules.CopyTrading.Ui
/// <summary>
/// Zeigt die geschlossenen Copytrades des Moduls (mod_copytrading_closed_trades) mit
/// aufgelösten Account-/Master-Trader-Namen und einer Kurzauswertung.
/// Layout im Designer (ClosedTradesView.Designer.cs), Daten/Logik hier.
/// </summary>
public class ClosedTradesView : Form
public partial class ClosedTradesView : Form
{
private readonly ICopyTradeLogRepository _tradeLog;
private readonly TradingState _state;
private readonly CopyTradingState _copyState;
private readonly DataGridView _grid = new();
private readonly Label _summary = new();
public ClosedTradesView(ICopyTradeLogRepository tradeLog, TradingState state, CopyTradingState copyState)
{
_tradeLog = tradeLog;
_state = state;
_copyState = copyState;
Text = "Geschlossene Copytrades";
StartPosition = FormStartPosition.CenterScreen;
Size = new Size(1100, 620);
MinimumSize = new Size(700, 400);
InitializeComponent();
colEntry.DefaultCellStyle.Format = "F3";
colExit.DefaultCellStyle.Format = "F3";
colSize.DefaultCellStyle.Format = "F2";
colPnl.DefaultCellStyle.Format = "F2";
colPnlPct.DefaultCellStyle.Format = "F1";
colOpenedAt.DefaultCellStyle.Format = "dd.MM.yyyy HH:mm";
colClosedAt.DefaultCellStyle.Format = "dd.MM.yyyy HH:mm";
var top = new Panel { Dock = DockStyle.Top, Height = 40, Padding = new Padding(8, 6, 8, 6) };
var btnRefresh = new Button { Text = "Aktualisieren", Dock = DockStyle.Left, Width = 120 };
btnRefresh.Click += (_, _) => LoadData();
_summary.Dock = DockStyle.Fill;
_summary.TextAlign = ContentAlignment.MiddleLeft;
_summary.Padding = new Padding(12, 0, 0, 0);
top.Controls.Add(_summary);
top.Controls.Add(btnRefresh);
_grid.Dock = DockStyle.Fill;
_grid.ReadOnly = true;
_grid.AllowUserToAddRows = false;
_grid.AllowUserToDeleteRows = false;
_grid.RowHeadersVisible = false;
_grid.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
_grid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
_grid.AutoGenerateColumns = true;
Controls.Add(_grid);
Controls.Add(top);
LoadData();
}
@@ -86,44 +69,12 @@ namespace PolyTrader.Modules.CopyTrading.Ui
})
.ToList();
_grid.DataSource = new BindingList<ClosedTradeRow>(rows);
FormatColumns();
dgvTrades.DataSource = new BindingList<ClosedTradeRow>(rows);
decimal totalPnl = rows.Sum(x => x.RealizedPnl);
int wins = rows.Count(x => x.RealizedPnl > 0);
double winrate = rows.Count > 0 ? (double)wins / rows.Count * 100 : 0;
_summary.Text = $"{rows.Count} Trades | PnL gesamt: {totalPnl:F2} USDC | Winrate: {winrate:F1}%";
}
private void FormatColumns()
{
void Hide(string name) { if (_grid.Columns[name] is { } c) c.Visible = false; }
void Fmt(string name, string f) { if (_grid.Columns[name] is { } c) c.DefaultCellStyle.Format = f; }
void Head(string name, string h) { if (_grid.Columns[name] is { } c) c.HeaderText = h; }
Hide(nameof(ClosedTradeRow.TokenId));
Hide(nameof(ClosedTradeRow.MarketSlug));
Hide(nameof(ClosedTradeRow.AccountId));
Hide(nameof(ClosedTradeRow.SourceTraderId));
Hide(nameof(ClosedTradeRow.IsDemo));
Fmt(nameof(ClosedTradeRow.EntryPrice), "F3");
Fmt(nameof(ClosedTradeRow.ExitPrice), "F3");
Fmt(nameof(ClosedTradeRow.Size), "F2");
Fmt(nameof(ClosedTradeRow.RealizedPnl), "F2");
Fmt(nameof(ClosedTradeRow.PnlPercent), "F1");
Fmt(nameof(ClosedTradeRow.TotalFees), "F2");
Fmt(nameof(ClosedTradeRow.OpenedAt), "dd.MM.yyyy HH:mm");
Fmt(nameof(ClosedTradeRow.ClosedAt), "dd.MM.yyyy HH:mm");
Head(nameof(ClosedTradeRow.TradeId), "#");
Head(nameof(ClosedTradeRow.AccountName), "Account");
Head(nameof(ClosedTradeRow.SourceTraderName), "Master-Trader");
Head(nameof(ClosedTradeRow.MarketQuestion), "Markt");
Head(nameof(ClosedTradeRow.RealizedPnl), "PnL");
Head(nameof(ClosedTradeRow.PnlPercent), "PnL %");
Head(nameof(ClosedTradeRow.ClosedAt), "Geschlossen");
Head(nameof(ClosedTradeRow.OpenedAt), "Eröffnet");
lblSummary.Text = $"{rows.Count} Trades | PnL gesamt: {totalPnl:F2} USDC | Winrate: {winrate:F1}%";
}
private string ResolveAccount(int accountId, bool isDemo)