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:
co-authored by
Claude Opus 4.8
parent
f1451b547c
commit
4caba5bfd1
@@ -0,0 +1,128 @@
|
||||
namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
{
|
||||
partial class AccountSettingsView
|
||||
{
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Vom Komponenten-Designer generierter Code
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.pnlTop = new System.Windows.Forms.Panel();
|
||||
this.cmbAccounts = new System.Windows.Forms.ComboBox();
|
||||
this.lblAccount = new System.Windows.Forms.Label();
|
||||
this.pgSettings = new System.Windows.Forms.PropertyGrid();
|
||||
this.pnlBottom = new System.Windows.Forms.Panel();
|
||||
this.lblHint = new System.Windows.Forms.Label();
|
||||
this.btnSave = new System.Windows.Forms.Button();
|
||||
this.pnlTop.SuspendLayout();
|
||||
this.pnlBottom.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// pnlTop
|
||||
//
|
||||
this.pnlTop.Controls.Add(this.cmbAccounts);
|
||||
this.pnlTop.Controls.Add(this.lblAccount);
|
||||
this.pnlTop.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.pnlTop.Location = new System.Drawing.Point(0, 0);
|
||||
this.pnlTop.Name = "pnlTop";
|
||||
this.pnlTop.Padding = new System.Windows.Forms.Padding(8, 8, 8, 6);
|
||||
this.pnlTop.Size = new System.Drawing.Size(560, 44);
|
||||
this.pnlTop.TabIndex = 0;
|
||||
//
|
||||
// cmbAccounts
|
||||
//
|
||||
this.cmbAccounts.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.cmbAccounts.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cmbAccounts.Location = new System.Drawing.Point(68, 8);
|
||||
this.cmbAccounts.Name = "cmbAccounts";
|
||||
this.cmbAccounts.Size = new System.Drawing.Size(484, 23);
|
||||
this.cmbAccounts.TabIndex = 1;
|
||||
//
|
||||
// lblAccount
|
||||
//
|
||||
this.lblAccount.Dock = System.Windows.Forms.DockStyle.Left;
|
||||
this.lblAccount.Location = new System.Drawing.Point(8, 8);
|
||||
this.lblAccount.Name = "lblAccount";
|
||||
this.lblAccount.Size = new System.Drawing.Size(60, 30);
|
||||
this.lblAccount.TabIndex = 0;
|
||||
this.lblAccount.Text = "Account:";
|
||||
this.lblAccount.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// pgSettings
|
||||
//
|
||||
this.pgSettings.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.pgSettings.Location = new System.Drawing.Point(0, 44);
|
||||
this.pgSettings.Name = "pgSettings";
|
||||
this.pgSettings.PropertySort = System.Windows.Forms.PropertySort.Categorized;
|
||||
this.pgSettings.Size = new System.Drawing.Size(560, 508);
|
||||
this.pgSettings.TabIndex = 1;
|
||||
this.pgSettings.ToolbarVisible = false;
|
||||
//
|
||||
// pnlBottom
|
||||
//
|
||||
this.pnlBottom.Controls.Add(this.lblHint);
|
||||
this.pnlBottom.Controls.Add(this.btnSave);
|
||||
this.pnlBottom.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.pnlBottom.Location = new System.Drawing.Point(0, 552);
|
||||
this.pnlBottom.Name = "pnlBottom";
|
||||
this.pnlBottom.Padding = new System.Windows.Forms.Padding(8);
|
||||
this.pnlBottom.Size = new System.Drawing.Size(560, 48);
|
||||
this.pnlBottom.TabIndex = 2;
|
||||
//
|
||||
// lblHint
|
||||
//
|
||||
this.lblHint.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.lblHint.ForeColor = System.Drawing.Color.DimGray;
|
||||
this.lblHint.Location = new System.Drawing.Point(8, 8);
|
||||
this.lblHint.Name = "lblHint";
|
||||
this.lblHint.Size = new System.Drawing.Size(424, 32);
|
||||
this.lblHint.TabIndex = 1;
|
||||
this.lblHint.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// btnSave
|
||||
//
|
||||
this.btnSave.Dock = System.Windows.Forms.DockStyle.Right;
|
||||
this.btnSave.Location = new System.Drawing.Point(432, 8);
|
||||
this.btnSave.Name = "btnSave";
|
||||
this.btnSave.Size = new System.Drawing.Size(120, 32);
|
||||
this.btnSave.TabIndex = 0;
|
||||
this.btnSave.Text = "Speichern";
|
||||
this.btnSave.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// AccountSettingsView
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(560, 600);
|
||||
this.Controls.Add(this.pgSettings);
|
||||
this.Controls.Add(this.pnlBottom);
|
||||
this.Controls.Add(this.pnlTop);
|
||||
this.MinimumSize = new System.Drawing.Size(420, 400);
|
||||
this.Name = "AccountSettingsView";
|
||||
this.Text = "Copytrading-Account-Einstellungen";
|
||||
this.pnlTop.ResumeLayout(false);
|
||||
this.pnlBottom.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Panel pnlTop;
|
||||
private System.Windows.Forms.ComboBox cmbAccounts;
|
||||
private System.Windows.Forms.Label lblAccount;
|
||||
private System.Windows.Forms.PropertyGrid pgSettings;
|
||||
private System.Windows.Forms.Panel pnlBottom;
|
||||
private System.Windows.Forms.Label lblHint;
|
||||
private System.Windows.Forms.Button btnSave;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using PolyTrader.Modules.CopyTrading.Persistence;
|
||||
@@ -12,17 +11,14 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
/// Bearbeitet die copytrading-spezifischen Detail-Einstellungen je Account
|
||||
/// (Investment-/Zeit-Limits, <see cref="CopyTradingAccountSettings"/>). Persistiert über
|
||||
/// das Repo und aktualisiert den Hot-Path-State (<see cref="CopyTradingState.AccountSettings"/>).
|
||||
/// Layout im Designer (AccountSettingsView.Designer.cs), Daten/Logik hier.
|
||||
/// </summary>
|
||||
public class AccountSettingsView : Form
|
||||
public partial class AccountSettingsView : Form
|
||||
{
|
||||
private readonly ICopyTradingAccountSettingsRepository _repo;
|
||||
private readonly TradingState _state;
|
||||
private readonly CopyTradingState _copyState;
|
||||
|
||||
private readonly ComboBox _accounts = new();
|
||||
private readonly PropertyGrid _grid = new();
|
||||
private readonly Label _hint = new();
|
||||
|
||||
private CopyTradingAccountSettings? _current;
|
||||
|
||||
public AccountSettingsView(ICopyTradingAccountSettingsRepository repo, TradingState state, CopyTradingState copyState)
|
||||
@@ -31,35 +27,10 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
_state = state;
|
||||
_copyState = copyState;
|
||||
|
||||
Text = "Copytrading-Account-Einstellungen";
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Size = new Size(560, 620);
|
||||
MinimumSize = new Size(420, 400);
|
||||
InitializeComponent();
|
||||
|
||||
var top = new Panel { Dock = DockStyle.Top, Height = 44, Padding = new Padding(8, 8, 8, 6) };
|
||||
var lbl = new Label { Text = "Account:", Dock = DockStyle.Left, Width = 60, TextAlign = ContentAlignment.MiddleLeft };
|
||||
_accounts.Dock = DockStyle.Fill;
|
||||
_accounts.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
_accounts.SelectedIndexChanged += (_, _) => LoadSelected();
|
||||
top.Controls.Add(_accounts);
|
||||
top.Controls.Add(lbl);
|
||||
|
||||
_grid.Dock = DockStyle.Fill;
|
||||
_grid.ToolbarVisible = false;
|
||||
_grid.PropertySort = PropertySort.Categorized;
|
||||
|
||||
var bottom = new Panel { Dock = DockStyle.Bottom, Height = 48, Padding = new Padding(8) };
|
||||
var btnSave = new Button { Text = "Speichern", Dock = DockStyle.Right, Width = 120 };
|
||||
cmbAccounts.SelectedIndexChanged += (_, _) => LoadSelected();
|
||||
btnSave.Click += (_, _) => Save();
|
||||
_hint.Dock = DockStyle.Fill;
|
||||
_hint.TextAlign = ContentAlignment.MiddleLeft;
|
||||
_hint.ForeColor = Color.DimGray;
|
||||
bottom.Controls.Add(_hint);
|
||||
bottom.Controls.Add(btnSave);
|
||||
|
||||
Controls.Add(_grid);
|
||||
Controls.Add(bottom);
|
||||
Controls.Add(top);
|
||||
|
||||
PopulateAccounts();
|
||||
}
|
||||
@@ -71,20 +42,20 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
.Select(a => new AccountItem(a.AccountId, string.IsNullOrEmpty(a.Name) ? $"#{a.AccountId}" : $"{a.Name} (#{a.AccountId}){(a.IsDemo ? " · Demo" : "")}"))
|
||||
.ToList();
|
||||
|
||||
_accounts.DisplayMember = nameof(AccountItem.Label);
|
||||
_accounts.ValueMember = nameof(AccountItem.Id);
|
||||
_accounts.DataSource = items;
|
||||
cmbAccounts.DisplayMember = nameof(AccountItem.Label);
|
||||
cmbAccounts.ValueMember = nameof(AccountItem.Id);
|
||||
cmbAccounts.DataSource = items;
|
||||
|
||||
if (items.Count > 0) LoadSelected();
|
||||
else _hint.Text = "Keine Accounts vorhanden.";
|
||||
else lblHint.Text = "Keine Accounts vorhanden.";
|
||||
}
|
||||
|
||||
private void LoadSelected()
|
||||
{
|
||||
if (_accounts.SelectedItem is not AccountItem item) return;
|
||||
if (cmbAccounts.SelectedItem is not AccountItem item) return;
|
||||
_current = _repo.Get(item.Id) ?? new CopyTradingAccountSettings { AccountId = item.Id };
|
||||
_grid.SelectedObject = _current;
|
||||
_hint.Text = $"Einstellungen für Account #{item.Id}.";
|
||||
pgSettings.SelectedObject = _current;
|
||||
lblHint.Text = $"Einstellungen für Account #{item.Id}.";
|
||||
}
|
||||
|
||||
private void Save()
|
||||
@@ -92,7 +63,7 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
if (_current == null) return;
|
||||
_repo.Upsert(_current);
|
||||
_copyState.AccountSettings[_current.AccountId] = _current;
|
||||
_hint.Text = $"Gespeichert für Account #{_current.AccountId} um {DateTime.Now:HH:mm:ss}.";
|
||||
lblHint.Text = $"Gespeichert für Account #{_current.AccountId} um {DateTime.Now:HH:mm:ss}.";
|
||||
}
|
||||
|
||||
private sealed record AccountItem(int Id, string Label);
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
{
|
||||
partial class ClosedTradesView
|
||||
{
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Vom Komponenten-Designer generierter Code
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.pnlTop = new System.Windows.Forms.Panel();
|
||||
this.lblSummary = new System.Windows.Forms.Label();
|
||||
this.btnRefresh = new System.Windows.Forms.Button();
|
||||
this.dgvTrades = new System.Windows.Forms.DataGridView();
|
||||
this.colTradeId = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colAccount = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colTrader = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colMarket = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colOutcome = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colSide = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colEntry = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colExit = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colSize = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colPnl = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colPnlPct = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colOpenedAt = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colClosedAt = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.pnlTop.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgvTrades)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// pnlTop
|
||||
//
|
||||
this.pnlTop.Controls.Add(this.lblSummary);
|
||||
this.pnlTop.Controls.Add(this.btnRefresh);
|
||||
this.pnlTop.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.pnlTop.Location = new System.Drawing.Point(0, 0);
|
||||
this.pnlTop.Name = "pnlTop";
|
||||
this.pnlTop.Size = new System.Drawing.Size(1100, 40);
|
||||
this.pnlTop.TabIndex = 0;
|
||||
//
|
||||
// lblSummary
|
||||
//
|
||||
this.lblSummary.AutoSize = true;
|
||||
this.lblSummary.Location = new System.Drawing.Point(148, 12);
|
||||
this.lblSummary.Name = "lblSummary";
|
||||
this.lblSummary.Size = new System.Drawing.Size(16, 15);
|
||||
this.lblSummary.TabIndex = 1;
|
||||
this.lblSummary.Text = "—";
|
||||
//
|
||||
// btnRefresh
|
||||
//
|
||||
this.btnRefresh.Location = new System.Drawing.Point(8, 6);
|
||||
this.btnRefresh.Name = "btnRefresh";
|
||||
this.btnRefresh.Size = new System.Drawing.Size(130, 28);
|
||||
this.btnRefresh.TabIndex = 0;
|
||||
this.btnRefresh.Text = "Aktualisieren";
|
||||
this.btnRefresh.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// dgvTrades
|
||||
//
|
||||
this.dgvTrades.AllowUserToAddRows = false;
|
||||
this.dgvTrades.AllowUserToDeleteRows = false;
|
||||
this.dgvTrades.AutoGenerateColumns = false;
|
||||
this.dgvTrades.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.dgvTrades.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
||||
this.colTradeId,
|
||||
this.colAccount,
|
||||
this.colTrader,
|
||||
this.colMarket,
|
||||
this.colOutcome,
|
||||
this.colSide,
|
||||
this.colEntry,
|
||||
this.colExit,
|
||||
this.colSize,
|
||||
this.colPnl,
|
||||
this.colPnlPct,
|
||||
this.colOpenedAt,
|
||||
this.colClosedAt});
|
||||
this.dgvTrades.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.dgvTrades.Location = new System.Drawing.Point(0, 40);
|
||||
this.dgvTrades.Name = "dgvTrades";
|
||||
this.dgvTrades.ReadOnly = true;
|
||||
this.dgvTrades.RowHeadersVisible = false;
|
||||
this.dgvTrades.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
||||
this.dgvTrades.Size = new System.Drawing.Size(1100, 560);
|
||||
this.dgvTrades.TabIndex = 1;
|
||||
//
|
||||
// colTradeId
|
||||
//
|
||||
this.colTradeId.DataPropertyName = "TradeId";
|
||||
this.colTradeId.HeaderText = "#";
|
||||
this.colTradeId.Name = "colTradeId";
|
||||
this.colTradeId.ReadOnly = true;
|
||||
this.colTradeId.Width = 60;
|
||||
//
|
||||
// colAccount
|
||||
//
|
||||
this.colAccount.DataPropertyName = "AccountName";
|
||||
this.colAccount.HeaderText = "Account";
|
||||
this.colAccount.Name = "colAccount";
|
||||
this.colAccount.ReadOnly = true;
|
||||
this.colAccount.Width = 130;
|
||||
//
|
||||
// colTrader
|
||||
//
|
||||
this.colTrader.DataPropertyName = "SourceTraderName";
|
||||
this.colTrader.HeaderText = "Master-Trader";
|
||||
this.colTrader.Name = "colTrader";
|
||||
this.colTrader.ReadOnly = true;
|
||||
this.colTrader.Width = 130;
|
||||
//
|
||||
// colMarket
|
||||
//
|
||||
this.colMarket.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
|
||||
this.colMarket.DataPropertyName = "MarketQuestion";
|
||||
this.colMarket.HeaderText = "Markt";
|
||||
this.colMarket.Name = "colMarket";
|
||||
this.colMarket.ReadOnly = true;
|
||||
//
|
||||
// colOutcome
|
||||
//
|
||||
this.colOutcome.DataPropertyName = "Outcome";
|
||||
this.colOutcome.HeaderText = "Outcome";
|
||||
this.colOutcome.Name = "colOutcome";
|
||||
this.colOutcome.ReadOnly = true;
|
||||
this.colOutcome.Width = 80;
|
||||
//
|
||||
// colSide
|
||||
//
|
||||
this.colSide.DataPropertyName = "Side";
|
||||
this.colSide.HeaderText = "Side";
|
||||
this.colSide.Name = "colSide";
|
||||
this.colSide.ReadOnly = true;
|
||||
this.colSide.Width = 60;
|
||||
//
|
||||
// colEntry
|
||||
//
|
||||
this.colEntry.DataPropertyName = "EntryPrice";
|
||||
this.colEntry.HeaderText = "Entry";
|
||||
this.colEntry.Name = "colEntry";
|
||||
this.colEntry.ReadOnly = true;
|
||||
this.colEntry.Width = 70;
|
||||
//
|
||||
// colExit
|
||||
//
|
||||
this.colExit.DataPropertyName = "ExitPrice";
|
||||
this.colExit.HeaderText = "Exit";
|
||||
this.colExit.Name = "colExit";
|
||||
this.colExit.ReadOnly = true;
|
||||
this.colExit.Width = 70;
|
||||
//
|
||||
// colSize
|
||||
//
|
||||
this.colSize.DataPropertyName = "Size";
|
||||
this.colSize.HeaderText = "Size";
|
||||
this.colSize.Name = "colSize";
|
||||
this.colSize.ReadOnly = true;
|
||||
this.colSize.Width = 70;
|
||||
//
|
||||
// colPnl
|
||||
//
|
||||
this.colPnl.DataPropertyName = "RealizedPnl";
|
||||
this.colPnl.HeaderText = "PnL";
|
||||
this.colPnl.Name = "colPnl";
|
||||
this.colPnl.ReadOnly = true;
|
||||
this.colPnl.Width = 80;
|
||||
//
|
||||
// colPnlPct
|
||||
//
|
||||
this.colPnlPct.DataPropertyName = "PnlPercent";
|
||||
this.colPnlPct.HeaderText = "PnL %";
|
||||
this.colPnlPct.Name = "colPnlPct";
|
||||
this.colPnlPct.ReadOnly = true;
|
||||
this.colPnlPct.Width = 70;
|
||||
//
|
||||
// colOpenedAt
|
||||
//
|
||||
this.colOpenedAt.DataPropertyName = "OpenedAt";
|
||||
this.colOpenedAt.HeaderText = "Eröffnet";
|
||||
this.colOpenedAt.Name = "colOpenedAt";
|
||||
this.colOpenedAt.ReadOnly = true;
|
||||
this.colOpenedAt.Width = 130;
|
||||
//
|
||||
// colClosedAt
|
||||
//
|
||||
this.colClosedAt.DataPropertyName = "ClosedAt";
|
||||
this.colClosedAt.HeaderText = "Geschlossen";
|
||||
this.colClosedAt.Name = "colClosedAt";
|
||||
this.colClosedAt.ReadOnly = true;
|
||||
this.colClosedAt.Width = 130;
|
||||
//
|
||||
// ClosedTradesView
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(1100, 600);
|
||||
this.Controls.Add(this.dgvTrades);
|
||||
this.Controls.Add(this.pnlTop);
|
||||
this.MinimumSize = new System.Drawing.Size(700, 400);
|
||||
this.Name = "ClosedTradesView";
|
||||
this.Text = "Geschlossene Copytrades";
|
||||
this.pnlTop.ResumeLayout(false);
|
||||
this.pnlTop.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgvTrades)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Panel pnlTop;
|
||||
private System.Windows.Forms.Button btnRefresh;
|
||||
private System.Windows.Forms.Label lblSummary;
|
||||
private System.Windows.Forms.DataGridView dgvTrades;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colTradeId;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colAccount;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colTrader;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colMarket;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colOutcome;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colSide;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colEntry;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colExit;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colSize;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colPnl;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colPnlPct;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colOpenedAt;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colClosedAt;
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
{
|
||||
partial class MasterTradersView
|
||||
{
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Vom Komponenten-Designer generierter Code
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.toolbar = new System.Windows.Forms.ToolStrip();
|
||||
this.tsNew = new System.Windows.Forms.ToolStripButton();
|
||||
this.tsSave = new System.Windows.Forms.ToolStripButton();
|
||||
this.tsDelete = new System.Windows.Forms.ToolStripButton();
|
||||
this.tsSep = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.tsRefresh = new System.Windows.Forms.ToolStripButton();
|
||||
this.grid = new System.Windows.Forms.DataGridView();
|
||||
this.colId = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colWallet = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colName = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colCategory = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colActive = new System.Windows.Forms.DataGridViewCheckBoxColumn();
|
||||
this.colTrades = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colWinrate = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colPnl = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.splitter = new System.Windows.Forms.Splitter();
|
||||
this.rightPanel = new System.Windows.Forms.Panel();
|
||||
this.pgDetail = new System.Windows.Forms.PropertyGrid();
|
||||
this.grpAccounts = new System.Windows.Forms.GroupBox();
|
||||
this.clbAccounts = new System.Windows.Forms.CheckedListBox();
|
||||
this.statusPanel = new System.Windows.Forms.Panel();
|
||||
this.lblHint = new System.Windows.Forms.Label();
|
||||
this.toolbar.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.grid)).BeginInit();
|
||||
this.rightPanel.SuspendLayout();
|
||||
this.grpAccounts.SuspendLayout();
|
||||
this.statusPanel.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// toolbar
|
||||
//
|
||||
this.toolbar.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
|
||||
this.toolbar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.tsNew,
|
||||
this.tsSave,
|
||||
this.tsDelete,
|
||||
this.tsSep,
|
||||
this.tsRefresh});
|
||||
this.toolbar.Location = new System.Drawing.Point(0, 0);
|
||||
this.toolbar.Name = "toolbar";
|
||||
this.toolbar.Size = new System.Drawing.Size(1180, 25);
|
||||
this.toolbar.TabIndex = 0;
|
||||
//
|
||||
// tsNew
|
||||
//
|
||||
this.tsNew.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
|
||||
this.tsNew.Name = "tsNew";
|
||||
this.tsNew.Size = new System.Drawing.Size(35, 22);
|
||||
this.tsNew.Text = "Neu";
|
||||
//
|
||||
// tsSave
|
||||
//
|
||||
this.tsSave.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
|
||||
this.tsSave.Name = "tsSave";
|
||||
this.tsSave.Size = new System.Drawing.Size(69, 22);
|
||||
this.tsSave.Text = "Speichern";
|
||||
//
|
||||
// tsDelete
|
||||
//
|
||||
this.tsDelete.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
|
||||
this.tsDelete.Name = "tsDelete";
|
||||
this.tsDelete.Size = new System.Drawing.Size(57, 22);
|
||||
this.tsDelete.Text = "Löschen";
|
||||
//
|
||||
// tsSep
|
||||
//
|
||||
this.tsSep.Name = "tsSep";
|
||||
this.tsSep.Size = new System.Drawing.Size(6, 25);
|
||||
//
|
||||
// tsRefresh
|
||||
//
|
||||
this.tsRefresh.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
|
||||
this.tsRefresh.Name = "tsRefresh";
|
||||
this.tsRefresh.Size = new System.Drawing.Size(90, 22);
|
||||
this.tsRefresh.Text = "Aktualisieren";
|
||||
//
|
||||
// grid
|
||||
//
|
||||
this.grid.AllowUserToAddRows = false;
|
||||
this.grid.AllowUserToDeleteRows = false;
|
||||
this.grid.AutoGenerateColumns = false;
|
||||
this.grid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.grid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
||||
this.colId,
|
||||
this.colWallet,
|
||||
this.colName,
|
||||
this.colCategory,
|
||||
this.colActive,
|
||||
this.colTrades,
|
||||
this.colWinrate,
|
||||
this.colPnl});
|
||||
this.grid.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.grid.Location = new System.Drawing.Point(0, 25);
|
||||
this.grid.MultiSelect = false;
|
||||
this.grid.Name = "grid";
|
||||
this.grid.ReadOnly = true;
|
||||
this.grid.RowHeadersVisible = false;
|
||||
this.grid.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
||||
this.grid.Size = new System.Drawing.Size(715, 589);
|
||||
this.grid.TabIndex = 4;
|
||||
//
|
||||
// colId
|
||||
//
|
||||
this.colId.DataPropertyName = "Id";
|
||||
this.colId.HeaderText = "#";
|
||||
this.colId.Name = "colId";
|
||||
this.colId.ReadOnly = true;
|
||||
this.colId.Width = 50;
|
||||
//
|
||||
// colWallet
|
||||
//
|
||||
this.colWallet.DataPropertyName = "WalletAddress";
|
||||
this.colWallet.HeaderText = "Wallet";
|
||||
this.colWallet.Name = "colWallet";
|
||||
this.colWallet.ReadOnly = true;
|
||||
this.colWallet.Width = 170;
|
||||
//
|
||||
// colName
|
||||
//
|
||||
this.colName.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
|
||||
this.colName.DataPropertyName = "DisplayName";
|
||||
this.colName.HeaderText = "Name";
|
||||
this.colName.Name = "colName";
|
||||
this.colName.ReadOnly = true;
|
||||
//
|
||||
// colCategory
|
||||
//
|
||||
this.colCategory.DataPropertyName = "Category";
|
||||
this.colCategory.HeaderText = "Kategorie";
|
||||
this.colCategory.Name = "colCategory";
|
||||
this.colCategory.ReadOnly = true;
|
||||
this.colCategory.Width = 110;
|
||||
//
|
||||
// colActive
|
||||
//
|
||||
this.colActive.DataPropertyName = "IsActive";
|
||||
this.colActive.HeaderText = "Aktiv";
|
||||
this.colActive.Name = "colActive";
|
||||
this.colActive.ReadOnly = true;
|
||||
this.colActive.Width = 50;
|
||||
//
|
||||
// colTrades
|
||||
//
|
||||
this.colTrades.DataPropertyName = "TotalTrades";
|
||||
this.colTrades.HeaderText = "Trades (7T)";
|
||||
this.colTrades.Name = "colTrades";
|
||||
this.colTrades.ReadOnly = true;
|
||||
this.colTrades.Width = 90;
|
||||
//
|
||||
// colWinrate
|
||||
//
|
||||
this.colWinrate.DataPropertyName = "Winrate30t";
|
||||
this.colWinrate.HeaderText = "Winrate %";
|
||||
this.colWinrate.Name = "colWinrate";
|
||||
this.colWinrate.ReadOnly = true;
|
||||
this.colWinrate.Width = 90;
|
||||
//
|
||||
// colPnl
|
||||
//
|
||||
this.colPnl.DataPropertyName = "TotalPnl";
|
||||
this.colPnl.HeaderText = "PnL (7T)";
|
||||
this.colPnl.Name = "colPnl";
|
||||
this.colPnl.ReadOnly = true;
|
||||
this.colPnl.Width = 100;
|
||||
//
|
||||
// splitter
|
||||
//
|
||||
this.splitter.Dock = System.Windows.Forms.DockStyle.Right;
|
||||
this.splitter.Location = new System.Drawing.Point(715, 25);
|
||||
this.splitter.Name = "splitter";
|
||||
this.splitter.Size = new System.Drawing.Size(5, 589);
|
||||
this.splitter.TabIndex = 3;
|
||||
this.splitter.TabStop = false;
|
||||
//
|
||||
// rightPanel
|
||||
//
|
||||
this.rightPanel.Controls.Add(this.pgDetail);
|
||||
this.rightPanel.Controls.Add(this.grpAccounts);
|
||||
this.rightPanel.Dock = System.Windows.Forms.DockStyle.Right;
|
||||
this.rightPanel.Location = new System.Drawing.Point(720, 25);
|
||||
this.rightPanel.Name = "rightPanel";
|
||||
this.rightPanel.Padding = new System.Windows.Forms.Padding(6, 0, 0, 0);
|
||||
this.rightPanel.Size = new System.Drawing.Size(460, 589);
|
||||
this.rightPanel.TabIndex = 2;
|
||||
//
|
||||
// pgDetail
|
||||
//
|
||||
this.pgDetail.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.pgDetail.Location = new System.Drawing.Point(6, 0);
|
||||
this.pgDetail.Name = "pgDetail";
|
||||
this.pgDetail.PropertySort = System.Windows.Forms.PropertySort.Categorized;
|
||||
this.pgDetail.Size = new System.Drawing.Size(454, 399);
|
||||
this.pgDetail.TabIndex = 0;
|
||||
this.pgDetail.ToolbarVisible = false;
|
||||
//
|
||||
// grpAccounts
|
||||
//
|
||||
this.grpAccounts.Controls.Add(this.clbAccounts);
|
||||
this.grpAccounts.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.grpAccounts.Location = new System.Drawing.Point(6, 399);
|
||||
this.grpAccounts.Name = "grpAccounts";
|
||||
this.grpAccounts.Padding = new System.Windows.Forms.Padding(8);
|
||||
this.grpAccounts.Size = new System.Drawing.Size(454, 190);
|
||||
this.grpAccounts.TabIndex = 1;
|
||||
this.grpAccounts.TabStop = false;
|
||||
this.grpAccounts.Text = "Zugewiesene Accounts (kopieren diesen Trader)";
|
||||
//
|
||||
// clbAccounts
|
||||
//
|
||||
this.clbAccounts.CheckOnClick = true;
|
||||
this.clbAccounts.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.clbAccounts.IntegralHeight = false;
|
||||
this.clbAccounts.Location = new System.Drawing.Point(8, 24);
|
||||
this.clbAccounts.Name = "clbAccounts";
|
||||
this.clbAccounts.Size = new System.Drawing.Size(438, 158);
|
||||
this.clbAccounts.TabIndex = 0;
|
||||
//
|
||||
// statusPanel
|
||||
//
|
||||
this.statusPanel.Controls.Add(this.lblHint);
|
||||
this.statusPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.statusPanel.Location = new System.Drawing.Point(0, 614);
|
||||
this.statusPanel.Name = "statusPanel";
|
||||
this.statusPanel.Size = new System.Drawing.Size(1180, 26);
|
||||
this.statusPanel.TabIndex = 1;
|
||||
//
|
||||
// lblHint
|
||||
//
|
||||
this.lblHint.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.lblHint.ForeColor = System.Drawing.Color.DimGray;
|
||||
this.lblHint.Location = new System.Drawing.Point(0, 0);
|
||||
this.lblHint.Name = "lblHint";
|
||||
this.lblHint.Padding = new System.Windows.Forms.Padding(8, 0, 0, 0);
|
||||
this.lblHint.Size = new System.Drawing.Size(1180, 26);
|
||||
this.lblHint.TabIndex = 0;
|
||||
this.lblHint.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// MasterTradersView
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(1180, 640);
|
||||
this.Controls.Add(this.grid);
|
||||
this.Controls.Add(this.splitter);
|
||||
this.Controls.Add(this.rightPanel);
|
||||
this.Controls.Add(this.statusPanel);
|
||||
this.Controls.Add(this.toolbar);
|
||||
this.MinimumSize = new System.Drawing.Size(820, 460);
|
||||
this.Name = "MasterTradersView";
|
||||
this.Text = "Master-Trader";
|
||||
this.toolbar.ResumeLayout(false);
|
||||
this.toolbar.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.grid)).EndInit();
|
||||
this.rightPanel.ResumeLayout(false);
|
||||
this.grpAccounts.ResumeLayout(false);
|
||||
this.statusPanel.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ToolStrip toolbar;
|
||||
private System.Windows.Forms.ToolStripButton tsNew;
|
||||
private System.Windows.Forms.ToolStripButton tsSave;
|
||||
private System.Windows.Forms.ToolStripButton tsDelete;
|
||||
private System.Windows.Forms.ToolStripSeparator tsSep;
|
||||
private System.Windows.Forms.ToolStripButton tsRefresh;
|
||||
private System.Windows.Forms.DataGridView grid;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colId;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colWallet;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colName;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colCategory;
|
||||
private System.Windows.Forms.DataGridViewCheckBoxColumn colActive;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colTrades;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colWinrate;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colPnl;
|
||||
private System.Windows.Forms.Splitter splitter;
|
||||
private System.Windows.Forms.Panel rightPanel;
|
||||
private System.Windows.Forms.PropertyGrid pgDetail;
|
||||
private System.Windows.Forms.GroupBox grpAccounts;
|
||||
private System.Windows.Forms.CheckedListBox clbAccounts;
|
||||
private System.Windows.Forms.Panel statusPanel;
|
||||
private System.Windows.Forms.Label lblHint;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using PolyTrader.Modules.CopyTrading.Persistence;
|
||||
@@ -14,18 +13,14 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
/// (PropertyGrid) und Account-Zuweisung (welche Accounts diesen Trader kopieren).
|
||||
/// Persistiert über das Repo und hält den Hot-Path-State
|
||||
/// (<see cref="CopyTradingState.Traders"/>) synchron.
|
||||
/// Layout im Designer (MasterTradersView.Designer.cs), Daten/Logik hier.
|
||||
/// </summary>
|
||||
public class MasterTradersView : Form
|
||||
public partial class MasterTradersView : Form
|
||||
{
|
||||
private readonly ITrackedTraderRepository _repo;
|
||||
private readonly TradingState _state;
|
||||
private readonly CopyTradingState _copyState;
|
||||
|
||||
private readonly DataGridView _grid = new();
|
||||
private readonly PropertyGrid _detail = new();
|
||||
private readonly CheckedListBox _accounts = new();
|
||||
private readonly Label _hint = new();
|
||||
|
||||
private BindingList<TrackedTrader> _binding = new();
|
||||
private TrackedTrader? _current;
|
||||
|
||||
@@ -35,66 +30,16 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
_state = state;
|
||||
_copyState = copyState;
|
||||
|
||||
Text = "Master-Trader";
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Size = new Size(1180, 640);
|
||||
MinimumSize = new Size(820, 460);
|
||||
InitializeComponent();
|
||||
|
||||
colWinrate.DefaultCellStyle.Format = "F1";
|
||||
colPnl.DefaultCellStyle.Format = "F2";
|
||||
|
||||
// Toolbar
|
||||
var toolbar = new ToolStrip { GripStyle = ToolStripGripStyle.Hidden };
|
||||
var tsNew = new ToolStripButton("Neu");
|
||||
var tsSave = new ToolStripButton("Speichern");
|
||||
var tsDelete = new ToolStripButton("Löschen");
|
||||
var tsRefresh = new ToolStripButton("Aktualisieren");
|
||||
tsNew.Click += (_, _) => AddNew();
|
||||
tsSave.Click += (_, _) => SaveCurrent();
|
||||
tsDelete.Click += (_, _) => DeleteCurrent();
|
||||
tsRefresh.Click += (_, _) => LoadData();
|
||||
toolbar.Items.AddRange(new ToolStripItem[]
|
||||
{
|
||||
tsNew, tsSave, tsDelete, new ToolStripSeparator(), tsRefresh
|
||||
});
|
||||
|
||||
// Liste links
|
||||
_grid.Dock = DockStyle.Fill;
|
||||
_grid.ReadOnly = true;
|
||||
_grid.AllowUserToAddRows = false;
|
||||
_grid.AllowUserToDeleteRows = false;
|
||||
_grid.RowHeadersVisible = false;
|
||||
_grid.MultiSelect = false;
|
||||
_grid.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
_grid.AutoGenerateColumns = true;
|
||||
_grid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
|
||||
_grid.SelectionChanged += (_, _) => OnSelectionChanged();
|
||||
|
||||
// Detail rechts: PropertyGrid + Account-Zuweisung
|
||||
_detail.Dock = DockStyle.Fill;
|
||||
_detail.ToolbarVisible = false;
|
||||
_detail.PropertySort = PropertySort.Categorized;
|
||||
|
||||
var accBox = new GroupBox { Text = "Zugewiesene Accounts (kopieren diesen Trader)", Dock = DockStyle.Bottom, Height = 190, Padding = new Padding(8) };
|
||||
_accounts.Dock = DockStyle.Fill;
|
||||
_accounts.CheckOnClick = true;
|
||||
accBox.Controls.Add(_accounts);
|
||||
|
||||
var right = new Panel { Dock = DockStyle.Right, Width = 460, Padding = new Padding(6, 0, 0, 0) };
|
||||
right.Controls.Add(_detail);
|
||||
right.Controls.Add(accBox);
|
||||
|
||||
var split = new Splitter { Dock = DockStyle.Right, Width = 5 };
|
||||
|
||||
var status = new Panel { Dock = DockStyle.Bottom, Height = 26 };
|
||||
_hint.Dock = DockStyle.Fill;
|
||||
_hint.TextAlign = ContentAlignment.MiddleLeft;
|
||||
_hint.ForeColor = Color.DimGray;
|
||||
_hint.Padding = new Padding(8, 0, 0, 0);
|
||||
status.Controls.Add(_hint);
|
||||
|
||||
Controls.Add(_grid);
|
||||
Controls.Add(split);
|
||||
Controls.Add(right);
|
||||
Controls.Add(status);
|
||||
Controls.Add(toolbar);
|
||||
grid.SelectionChanged += (_, _) => OnSelectionChanged();
|
||||
|
||||
LoadData();
|
||||
}
|
||||
@@ -103,63 +48,39 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
{
|
||||
var traders = _repo.GetAll().OrderBy(t => t.Id).ToList();
|
||||
_binding = new BindingList<TrackedTrader>(traders);
|
||||
_grid.DataSource = _binding;
|
||||
FormatColumns();
|
||||
grid.DataSource = _binding;
|
||||
if (traders.Count > 0)
|
||||
_grid.CurrentCell = _grid.Rows[0].Cells[0];
|
||||
grid.CurrentCell = grid.Rows[0].Cells[0];
|
||||
else
|
||||
ClearDetail();
|
||||
_hint.Text = $"{traders.Count} Master-Trader geladen.";
|
||||
}
|
||||
|
||||
private void FormatColumns()
|
||||
{
|
||||
void Hide(string n) { if (_grid.Columns[n] is { } c) c.Visible = false; }
|
||||
void Head(string n, string h) { if (_grid.Columns[n] is { } c) c.HeaderText = h; }
|
||||
void Fmt(string n, string f) { if (_grid.Columns[n] is { } c) c.DefaultCellStyle.Format = f; }
|
||||
|
||||
Hide(nameof(TrackedTrader.Description));
|
||||
Hide(nameof(TrackedTrader.Reasoning));
|
||||
Hide(nameof(TrackedTrader.IsHidden));
|
||||
Hide(nameof(TrackedTrader.WinningTrades));
|
||||
|
||||
Head(nameof(TrackedTrader.Id), "#");
|
||||
Head(nameof(TrackedTrader.WalletAddress), "Wallet");
|
||||
Head(nameof(TrackedTrader.DisplayName), "Name");
|
||||
Head(nameof(TrackedTrader.Category), "Kategorie");
|
||||
Head(nameof(TrackedTrader.IsActive), "Aktiv");
|
||||
Head(nameof(TrackedTrader.TotalTrades), "Trades (7T)");
|
||||
Head(nameof(TrackedTrader.Winrate30t), "Winrate %");
|
||||
Head(nameof(TrackedTrader.TotalPnl), "PnL (7T)");
|
||||
Fmt(nameof(TrackedTrader.Winrate30t), "F1");
|
||||
Fmt(nameof(TrackedTrader.TotalPnl), "F2");
|
||||
lblHint.Text = $"{traders.Count} Master-Trader geladen.";
|
||||
}
|
||||
|
||||
private void OnSelectionChanged()
|
||||
{
|
||||
if (_grid.CurrentRow?.DataBoundItem is TrackedTrader t)
|
||||
if (grid.CurrentRow?.DataBoundItem is TrackedTrader t)
|
||||
BindDetail(t);
|
||||
}
|
||||
|
||||
private void BindDetail(TrackedTrader trader)
|
||||
{
|
||||
_current = trader;
|
||||
_detail.SelectedObject = trader;
|
||||
pgDetail.SelectedObject = trader;
|
||||
|
||||
_accounts.Items.Clear();
|
||||
clbAccounts.Items.Clear();
|
||||
foreach (var acc in _state.Accounts.Values.OrderBy(a => a.AccountId))
|
||||
{
|
||||
string label = string.IsNullOrEmpty(acc.Name) ? $"#{acc.AccountId}" : $"{acc.Name} (#{acc.AccountId}){(acc.IsDemo ? " · Demo" : "")}";
|
||||
int idx = _accounts.Items.Add(new AccountItem(acc.AccountId, label));
|
||||
_accounts.SetItemChecked(idx, trader.AssignedAccountIds.Contains(acc.AccountId));
|
||||
int idx = clbAccounts.Items.Add(new AccountItem(acc.AccountId, label));
|
||||
clbAccounts.SetItemChecked(idx, trader.AssignedAccountIds.Contains(acc.AccountId));
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearDetail()
|
||||
{
|
||||
_current = null;
|
||||
_detail.SelectedObject = null;
|
||||
_accounts.Items.Clear();
|
||||
pgDetail.SelectedObject = null;
|
||||
clbAccounts.Items.Clear();
|
||||
}
|
||||
|
||||
private void AddNew()
|
||||
@@ -167,25 +88,25 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
int nextId = _binding.Count > 0 ? _binding.Max(t => t.Id) + 1 : 1;
|
||||
var trader = new TrackedTrader { Id = nextId, DisplayName = $"Neuer Trader {nextId}" };
|
||||
_binding.Add(trader);
|
||||
_grid.CurrentCell = _grid.Rows[_binding.Count - 1].Cells[0];
|
||||
_hint.Text = $"Neuer Master-Trader #{nextId} – Felder ausfüllen und Speichern.";
|
||||
grid.CurrentCell = grid.Rows[_binding.Count - 1].Cells[0];
|
||||
lblHint.Text = $"Neuer Master-Trader #{nextId} – Felder ausfüllen und Speichern.";
|
||||
}
|
||||
|
||||
private void SaveCurrent()
|
||||
{
|
||||
if (_current == null) { _hint.Text = "Kein Trader ausgewählt."; return; }
|
||||
if (_current == null) { lblHint.Text = "Kein Trader ausgewählt."; return; }
|
||||
|
||||
_current.AssignedAccountIds = _accounts.CheckedItems.Cast<AccountItem>().Select(a => a.Id).ToHashSet();
|
||||
_current.AssignedAccountIds = clbAccounts.CheckedItems.Cast<AccountItem>().Select(a => a.Id).ToHashSet();
|
||||
|
||||
_repo.Upsert(_current);
|
||||
_copyState.Traders[_current.Id] = _current;
|
||||
_grid.Refresh();
|
||||
_hint.Text = $"Gespeichert: #{_current.Id} {_current.DisplayName} ({_current.AssignedAccountIds.Count} Account(s)) um {DateTime.Now:HH:mm:ss}.";
|
||||
grid.Refresh();
|
||||
lblHint.Text = $"Gespeichert: #{_current.Id} {_current.DisplayName} ({_current.AssignedAccountIds.Count} Account(s)) um {DateTime.Now:HH:mm:ss}.";
|
||||
}
|
||||
|
||||
private void DeleteCurrent()
|
||||
{
|
||||
if (_current == null) { _hint.Text = "Kein Trader ausgewählt."; return; }
|
||||
if (_current == null) { lblHint.Text = "Kein Trader ausgewählt."; return; }
|
||||
var id = _current.Id;
|
||||
if (MessageBox.Show($"Master-Trader #{id} ({_current.DisplayName}) wirklich löschen?",
|
||||
"Löschen bestätigen", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes)
|
||||
@@ -195,7 +116,7 @@ namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
_copyState.Traders.TryRemove(id, out _);
|
||||
_binding.Remove(_current);
|
||||
ClearDetail();
|
||||
_hint.Text = $"Master-Trader #{id} gelöscht.";
|
||||
lblHint.Text = $"Master-Trader #{id} gelöscht.";
|
||||
}
|
||||
|
||||
private sealed record AccountItem(int Id, string Label)
|
||||
|
||||
Reference in New Issue
Block a user