Modul-Fenster nach Avalonia - UI-Portierung inhaltlich abgeschlossen

Alle acht Fenster laufen jetzt unter Avalonia: Launcher, Dashboard, Settings, Terminal,
Server Jobs, Copytrading, ResolutionFarming, Supervisor, Accounting (+ Shutdown- und
Allzweck-Dialog).

- Copytrading: vier Tabs (Master-Trader mit Account-Zuweisung, Offene Trades, Geschlossene
  Trades mit Filterleiste, Account-Einstellungen). Zeilenfaerbung nach PnL laeuft ueber
  DataGrid.LoadingRow - greift damit auch bei virtualisierten Zeilen, anders als das
  fruehere Faerben in DataBindingComplete.
- ResolutionFarming: Kandidaten, Positionen, Historie, Settings - je Konto.
- Supervisor: Analyse-Chat gegen den Agenten (Tool-Fortschritt in der Statuszeile),
  Dossiers mit Markdown-Ansicht, Berichte, Counterfactuals.
- Accounting: KPI-Kacheln, Monats-BWA, Ledger, Abruf/Status, PDF- und CSV-Export ueber
  den plattformneutralen Datei-Dialog.

Der SettingsEditor traegt wie erwartet die drei restlichen PropertyGrid-Stellen
(Master-Trader, Account-Einstellungen, ResolutionFarming) mit je einem Aufruf.

ENTSCHEIDUNG - Modul-Fenster liegen in der App, nicht in den Modulen
(begruendet in Views/Modules/README.md): Die App ist der Kompositionswurzel und
referenziert ohnehin alle Module. So bleiben die Modulprojekte FREI VON AVALONIA, was fuer
den kopflosen Linux-Betrieb den Ausschlag gibt - der Daemon soll keine GUI-Bibliothek
mitschleppen. Verifiziert: kein Modul zieht Avalonia. Registrierung in Shell/ModuleViews.cs,
und zwar nur fuer tatsaechlich geladene Module - ein per DisabledModules abgeschaltetes
Modul bekommt gar kein Fenster.

Nebenbei: eigene View-Model-Typen CopyOpenTradeRow/CopyClosedTradeRow statt des
Modul-Modells ClosedTradeRow - sie tragen den aufgeloesten Master-Trader-Namen und die
Zeilenfarbe, die es dort nicht gibt (und vermeiden die Namensmehrdeutigkeit).

Verifiziert: Solution baut, 450 Tests gruen, --smoke-ui gruen (alle 8 Fenster + Launcher +
Dialog + Editor-Pruefung), App laeuft real mit allen Trading-Diensten, Linux-Publish laeuft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-08-06 22:19:42 +02:00
co-authored by Claude Opus 5
parent 929fa20ee0
commit 669676ac60
15 changed files with 1658 additions and 2 deletions
@@ -0,0 +1,161 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:PolyTrader.App.Avalonia.Controls"
xmlns:vm="using:PolyTrader.App.Avalonia.ViewModels"
xmlns:ct="using:PolyTraderSharp.Models"
x:Class="PolyTrader.App.Avalonia.Views.Modules.CopyTradingWindow"
Title="Copytrading"
Width="1714" Height="1167">
<!--
Ein Fenster fürs ganze Modul, vier Tabs – Aufbau nach docs/UI-SPEZIFIKATION-WinForms.md.
Spaltenreihenfolge und -überschriften entsprechen der bisherigen Oberfläche; feste
Pixelbreiten sind in Sternbreiten übersetzt, damit das Fenster mitwächst.
-->
<DockPanel>
<controls:WindowMenuBar Name="menuBar" DockPanel.Dock="Top" />
<TabControl>
<TabItem Header="Master-Trader">
<DockPanel>
<Border Classes="toolbar" DockPanel.Dock="Top">
<StackPanel Orientation="Horizontal">
<Button Name="btnTraderRefresh" Content="Aktualisieren" />
<Button Name="btnTraderSave" Content="Speichern" />
<TextBlock Name="lblTraderHint" VerticalAlignment="Center"
Margin="12,0,0,0" Foreground="#777777" />
</StackPanel>
</Border>
<Grid ColumnDefinitions="*,4,460">
<DataGrid Name="gridTraders" Grid.Column="0" x:DataType="ct:TrackedTrader">
<DataGrid.Columns>
<DataGridTextColumn Header="#" Width="50" Binding="{Binding Id}" />
<DataGridTextColumn Header="Wallet" Width="170" Binding="{Binding WalletAddress}" />
<DataGridTextColumn Header="Name" Width="*" Binding="{Binding DisplayName}" />
<DataGridTextColumn Header="Kategorie" Width="110" Binding="{Binding Category}" />
<DataGridCheckBoxColumn Header="Aktiv" Width="50" Binding="{Binding IsActive}" />
<DataGridTextColumn Header="Trades (7T)" Width="90" Binding="{Binding TotalTrades}" />
<DataGridTextColumn Header="Winrate %" Width="90" Binding="{Binding Winrate30t, StringFormat=\{0:F1\}}" />
<DataGridTextColumn Header="PnL (7T)" Width="100" Binding="{Binding TotalPnl, StringFormat=\{0:F2\}}" />
<DataGridTextColumn Header="Copy-PnL (30T)" Width="110" Binding="{Binding CopyPnl30d, StringFormat=\{0:F2\}}" />
<DataGridTextColumn Header="Profit-Faktor" Width="100" Binding="{Binding CopyProfitFactor, StringFormat=\{0:F2\}}" />
<DataGridTextColumn Header="Ø PnL/Trade" Width="100" Binding="{Binding CopyAvgPnlPerTrade, StringFormat=\{0:F2\}}" />
<DataGridTextColumn Header="Copy-Trades" Width="90" Binding="{Binding CopyTradeCount30d}" />
</DataGrid.Columns>
</DataGrid>
<GridSplitter Grid.Column="1" Background="#DDDDDD" />
<DockPanel Grid.Column="2">
<HeaderedContentControl DockPanel.Dock="Bottom" Header="Zugewiesene Accounts"
Margin="8" Height="220">
<ListBox Name="listAccounts">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="vm:AccountAssignment">
<CheckBox IsChecked="{Binding IsAssigned, Mode=TwoWay}"
Content="{Binding Label}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</HeaderedContentControl>
<controls:SettingsEditor Name="editorTrader" />
</DockPanel>
</Grid>
</DockPanel>
</TabItem>
<TabItem Header="Offene Trades">
<DockPanel>
<Border Classes="toolbar" DockPanel.Dock="Top">
<StackPanel Orientation="Horizontal">
<Button Name="btnOpenRefresh" Content="Aktualisieren" />
</StackPanel>
</Border>
<Border Classes="statusbar" DockPanel.Dock="Bottom">
<TextBlock Name="lblOpenSummary" Text="—" />
</Border>
<DataGrid Name="gridOpen" x:DataType="vm:CopyOpenTradeRow">
<DataGrid.Columns>
<DataGridTextColumn Header="Account" Width="120" Binding="{Binding Account}" />
<DataGridTextColumn Header="Master-Trader" Width="120" Binding="{Binding Trader}" />
<DataGridTextColumn Header="Markt" Width="*" Binding="{Binding Market}" />
<DataGridTextColumn Header="Outcome" Width="80" Binding="{Binding Outcome}" />
<DataGridTextColumn Header="Side" Width="55" Binding="{Binding Side}" />
<DataGridTextColumn Header="Entry" Width="65" Binding="{Binding Entry, StringFormat=\{0:F3\}}" />
<DataGridTextColumn Header="Aktuell" Width="65" Binding="{Binding Current, StringFormat=\{0:F3\}}" />
<DataGridTextColumn Header="Size" Width="70" Binding="{Binding Size, StringFormat=\{0:F2\}}" />
<DataGridTextColumn Header="Einsatz" Width="80" Binding="{Binding Amount, StringFormat=\{0:F2\}}" />
<DataGridTextColumn Header="Wert" Width="80" Binding="{Binding Value, StringFormat=\{0:F2\}}" />
<DataGridTextColumn Header="Buchgewinn" Width="90" Binding="{Binding Unrealized, StringFormat=\{0:F2\}}" />
<DataGridTextColumn Header="Buchgew. %" Width="80" Binding="{Binding UnrealizedPct, StringFormat=\{0:F1\}}" />
<DataGridTextColumn Header="Status" Width="90" Binding="{Binding Status}" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</TabItem>
<TabItem Header="Geschlossene Trades">
<DockPanel>
<Border Classes="toolbar" DockPanel.Dock="Top">
<StackPanel Orientation="Horizontal" Spacing="8">
<Button Name="btnClosedRefresh" Content="Aktualisieren" />
<TextBlock Text="Markt:" VerticalAlignment="Center" />
<TextBox Name="tbClosedMarket" MinWidth="200" Watermark="Suche …" />
<TextBlock Text="Master:" VerticalAlignment="Center" />
<ComboBox Name="cbClosedMaster" MinWidth="160" />
<TextBlock Text="Ergebnis:" VerticalAlignment="Center" />
<ComboBox Name="cbClosedResult" MinWidth="120" />
<TextBlock Text="Von:" VerticalAlignment="Center" />
<CalendarDatePicker Name="dtClosedFrom" MinWidth="140" />
<TextBlock Text="Bis:" VerticalAlignment="Center" />
<CalendarDatePicker Name="dtClosedTo" MinWidth="140" />
<Button Name="btnClosedReset" Content="Zurücksetzen" />
</StackPanel>
</Border>
<Border Classes="statusbar" DockPanel.Dock="Bottom">
<TextBlock Name="lblClosedSummary" Text="—" />
</Border>
<DataGrid Name="gridClosed" x:DataType="vm:CopyClosedTradeRow">
<DataGrid.Columns>
<DataGridTextColumn Header="#" Width="60" Binding="{Binding TradeId}" />
<DataGridTextColumn Header="Account" Width="130" Binding="{Binding Account}" />
<DataGridTextColumn Header="Master-Trader" Width="130" Binding="{Binding Trader}" />
<DataGridTextColumn Header="Markt" Width="*" Binding="{Binding Market}" />
<DataGridTextColumn Header="Outcome" Width="80" Binding="{Binding Outcome}" />
<DataGridTextColumn Header="Side" Width="60" Binding="{Binding Side}" />
<DataGridTextColumn Header="Entry" Width="70" Binding="{Binding Entry, StringFormat=\{0:F3\}}" />
<DataGridTextColumn Header="Exit" Width="70" Binding="{Binding Exit, StringFormat=\{0:F3\}}" />
<DataGridTextColumn Header="Size" Width="70" Binding="{Binding Size, StringFormat=\{0:F2\}}" />
<DataGridTextColumn Header="PnL" Width="80" Binding="{Binding Pnl, StringFormat=\{0:F2\}}" />
<DataGridTextColumn Header="PnL %" Width="70" Binding="{Binding PnlPercent, StringFormat=\{0:F1\}}" />
<DataGridTextColumn Header="Eröffnet" Width="130" Binding="{Binding OpenedAt, StringFormat=\{0:dd.MM.yyyy HH:mm\}}" />
<DataGridTextColumn Header="Geschlossen" Width="130" Binding="{Binding ClosedAt, StringFormat=\{0:dd.MM.yyyy HH:mm\}}" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</TabItem>
<TabItem Header="Account-Einstellungen">
<DockPanel>
<Border Classes="toolbar" DockPanel.Dock="Top">
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="Konto:" VerticalAlignment="Center" />
<ComboBox Name="cbSettingsAccount" MinWidth="240" />
<Button Name="btnSettingsSave" Content="Speichern" />
<TextBlock Name="lblSettingsHint" VerticalAlignment="Center" Foreground="#777777" />
</StackPanel>
</Border>
<controls:SettingsEditor Name="editorAccount" />
</DockPanel>
</TabItem>
</TabControl>
</DockPanel>
</Window>