Statt je Ansicht ein eigenes Fenster (3 Launcher-Buttons) gibt es jetzt EIN Modul-Fenster mit Tabs – wie im alten PolyTrader. Skaliert sauber, wenn weitere Module dazukommen (ein Button je Modul). - MasterTradersView/ClosedTradesView/AccountSettingsView: von Form -> UserControl (Tab-Inhalte); Designer-Root auf Size statt ClientSize/Text/MinimumSize. - Neu: CopyTradingMainForm (Designer) mit TabControl + 3 TabPages, hostet die drei UserControls; Initialize(IServiceProvider) versorgt jeden Tab per DI. - CopyTradingModule.RegisterUi registriert nur noch EINE View "Copytrading". Verifiziert: Build grün, --smoke-ui grün (eine View copytrading.main + Launcher konstruieren fehlerfrei, 3 Accounts / 32 Trader hydriert). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
102 lines
3.9 KiB
C#
102 lines
3.9 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Windows.Forms;
|
|
using PolyTrader.Modules.CopyTrading.Persistence;
|
|
using PolyTraderSharp;
|
|
using PolyTraderSharp.Models;
|
|
|
|
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 partial class ClosedTradesView : UserControl
|
|
{
|
|
private ICopyTradeLogRepository? _tradeLog;
|
|
private TradingState? _state;
|
|
private CopyTradingState? _copyState;
|
|
|
|
// Parameterloser Konstruktor für den WinForms-Designer.
|
|
public ClosedTradesView()
|
|
{
|
|
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";
|
|
|
|
btnRefresh.Click += (_, _) => LoadData();
|
|
}
|
|
|
|
/// <summary>Injiziert die Abhängigkeiten (nach der DI-Auflösung) und lädt die Daten.</summary>
|
|
public void Initialize(ICopyTradeLogRepository tradeLog, TradingState state, CopyTradingState copyState)
|
|
{
|
|
_tradeLog = tradeLog;
|
|
_state = state;
|
|
_copyState = copyState;
|
|
LoadData();
|
|
}
|
|
|
|
private void LoadData()
|
|
{
|
|
if (_tradeLog == null) return;
|
|
|
|
var rows = _tradeLog.Find(_ => true)
|
|
.OrderByDescending(t => t.ClosedAt)
|
|
.Select(t => new ClosedTradeRow
|
|
{
|
|
TradeId = t.TradeId,
|
|
AccountId = t.AccountId,
|
|
SourceTraderId = t.SourceTraderId,
|
|
IsDemo = t.IsDemo,
|
|
TokenId = t.TokenId,
|
|
MarketSlug = t.MarketSlug,
|
|
MarketQuestion = t.MarketQuestion,
|
|
Outcome = t.Outcome,
|
|
Side = t.Side,
|
|
EntryPrice = t.EntryPrice,
|
|
ExitPrice = t.ExitPrice,
|
|
Size = t.Size,
|
|
RealizedPnl = t.RealizedPnl,
|
|
PnlPercent = t.PnlPercent,
|
|
TotalFees = t.TotalFees,
|
|
OpenedAt = t.OpenedAt,
|
|
ClosedAt = t.ClosedAt,
|
|
ExitReason = t.ExitReason,
|
|
AccountName = ResolveAccount(t.AccountId, t.IsDemo),
|
|
SourceTraderName = ResolveTrader(t.SourceTraderId)
|
|
})
|
|
.ToList();
|
|
|
|
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;
|
|
lblSummary.Text = $"{rows.Count} Trades | PnL gesamt: {totalPnl:F2} USDC | Winrate: {winrate:F1}%";
|
|
}
|
|
|
|
private string ResolveAccount(int accountId, bool isDemo)
|
|
{
|
|
string suffix = isDemo ? " (Demo)" : "";
|
|
if (_state != null && _state.Accounts.TryGetValue(accountId, out var acc) && !string.IsNullOrEmpty(acc.Name))
|
|
return acc.Name + suffix;
|
|
return $"#{accountId}{suffix}";
|
|
}
|
|
|
|
private string ResolveTrader(int traderId)
|
|
{
|
|
if (_copyState != null && _copyState.Traders.TryGetValue(traderId, out var t) && !string.IsNullOrEmpty(t.DisplayName))
|
|
return t.DisplayName;
|
|
return traderId > 0 ? $"#{traderId}" : "Unbekannt";
|
|
}
|
|
}
|
|
}
|