P1c+P4: Module und Tests auf net8.0 - WinForms nur noch in PolyTrader.App
Variante B (Entscheidung Richard): Modul-UI entfernt statt in Zwischenprojekte ausgelagert. Avalonia ist plattformuebergreifend, die neuen Ansichten kommen spaeter direkt in die Modul-Projekte zurueck - kein Zwischenschritt, keine Wegwerfarbeit. - 23 WinForms-Dateien aus den 4 Modulen entfernt (Spezifikation steht in docs/UI-SPEZIFIKATION-WinForms.md, Originalcode im Tag winforms-final). - RegisterUi ist jetzt je Modul ein dokumentierter No-Op: View-ID, Titel, Gruppe, Order und der Tab-Aufbau stehen als XML-Doku drin, damit der Avalonia-Nachbau die stabilen IDs und die Struktur uebernimmt. - Alle 4 Modulprojekte + Testprojekt: net8.0 statt net8.0-windows, UseWindowsForms raus. - P4 vorgezogen (war durch den Testprojekt-Wechsel faellig): PDFsharp-MigraDoc-GDI -> PDFsharp-MigraDoc (Core-Build). Der Core-Build findet keine Systemschriften, daher neu Logic/PdfFontResolver.cs: durchsucht die Schriftverzeichnisse des OS nach Segoe UI/DejaVu/Liberation/Noto/Arial/FreeSans. Keine Schriftdateien im Repo noetig; fehlt auf Linux alles, kommt eine klare Meldung mit apt-Hinweis statt eines kryptischen Renderer-Fehlers. Verifiziert: Core, alle 4 Module und das Testprojekt publishen fuer linux-x64, und zwar ohne ein einziges Windows-spezifisches Paket in den deps.json. 442 Tests gruen (inkl. PDF-Rendering) auf net8.0. Windows-App laeuft weiter mit den Core-Fenstern. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -49,21 +49,22 @@ namespace PolyTrader.Modules.Accounting
|
||||
services.AddHostedService(sp => sp.GetRequiredService<AccountingIngestService>());
|
||||
}
|
||||
|
||||
public void RegisterUi(IModuleUiHost host, System.IServiceProvider services)
|
||||
/// <summary>
|
||||
/// Aktuell ohne Ansicht: Die WinForms-UI wurde mit der Linux-Portierung entfernt, die
|
||||
/// Avalonia-Ansicht folgt (Stufe L3/L4). Die Fachlogik dieses Moduls laeuft davon
|
||||
/// unabhaengig weiter – die Shell zeigt schlicht kein Fenster fuer das Modul an.
|
||||
///
|
||||
/// <para><b>Beim Nachbau zu erhalten</b> (Spezifikation: docs/UI-SPEZIFIKATION-WinForms.md,
|
||||
/// Originalcode: Git-Tag <c>winforms-final</c>):</para>
|
||||
/// <list type="bullet">
|
||||
/// <item>View-ID <c>accounting.main</c> (stabil – Launcher-Button und Symbol haengen daran)</item>
|
||||
/// <item>Titel <c>Accounting</c>, Gruppe <c>Accounting</c>, Order <c>400</c></item>
|
||||
/// <item>Ein Fenster fuers ganze Modul: AccountingMainForm mit Tabs: Uebersicht+BWA / Ledger / Abruf+Status</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public void RegisterUi(IModuleUiHost host, IServiceProvider services)
|
||||
{
|
||||
host.RegisterView(new ModuleView
|
||||
{
|
||||
Id = "accounting.main",
|
||||
Title = "Accounting",
|
||||
Group = "Accounting",
|
||||
Order = 400,
|
||||
CreateView = () =>
|
||||
{
|
||||
var form = new Ui.AccountingMainForm();
|
||||
form.Initialize(services);
|
||||
return form;
|
||||
}
|
||||
});
|
||||
// Bewusst leer, bis die Avalonia-Ansicht steht (siehe Doku oben).
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -28,9 +28,15 @@ namespace PolyTrader.Modules.Accounting.Logic
|
||||
decimal V(decimal usdc) => Math.Round(usdc * currencyFactor, 2, MidpointRounding.AwayFromZero);
|
||||
string M(decimal usdc) => V(usdc).ToString("N2") + " " + currencyCode;
|
||||
|
||||
// Schriftauflösung sicherstellen: der PDFsharp-Core-Build findet ohne Resolver keine
|
||||
// Systemschriften (siehe PdfFontResolver). Idempotent, kostet nach dem ersten Mal nichts.
|
||||
PdfFontResolver.EnsureRegistered();
|
||||
|
||||
var doc = new Document();
|
||||
doc.Info.Title = "Buchhalterische Abrechnung";
|
||||
var style = doc.Styles["Normal"];
|
||||
// Wunschschrift; der Resolver weicht auf eine verfügbare aus, wenn es sie nicht gibt
|
||||
// (auf Linux z.B. DejaVu Sans).
|
||||
style.Font.Name = "Segoe UI";
|
||||
style.Font.Size = 9;
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using PdfSharp.Fonts;
|
||||
|
||||
namespace PolyTrader.Modules.Accounting.Logic
|
||||
{
|
||||
/// <summary>
|
||||
/// Schriftauflösung für den PDF-Export. Nötig, seit der plattformneutrale PDFsharp-Core-Build
|
||||
/// verwendet wird: der frühere <c>-GDI</c>-Build zog Systemschriften über
|
||||
/// <c>System.Drawing.Common</c>, das seit .NET 7 Windows-only ist. Der Core-Build bringt keine
|
||||
/// eigene Schriftsuche mit und braucht deshalb diesen Resolver.
|
||||
///
|
||||
/// <para>Der Resolver durchsucht die üblichen Schriftverzeichnisse des Betriebssystems nach einer
|
||||
/// Kandidatenliste (Windows: Segoe UI/Arial, Linux: DejaVu/Liberation/Noto). Damit sind keine
|
||||
/// Schriftdateien im Repository nötig und die Lizenzfrage der Schriften bleibt beim System.</para>
|
||||
///
|
||||
/// <para><b>Voraussetzung auf Linux:</b> mindestens eine der Kandidatenschriften muss installiert
|
||||
/// sein. Auf Desktop-Distributionen ist das der Normalfall; auf schlanken Servern/Containern
|
||||
/// genügt <c>apt install fonts-dejavu-core</c> (bzw. <c>fonts-liberation</c>). Fehlt jede Schrift,
|
||||
/// wirft <see cref="EnsureRegistered"/> beim ersten Export eine Meldung mit genau diesem Hinweis –
|
||||
/// besser als eine kryptische Meldung aus dem Renderer-Inneren.</para>
|
||||
/// </summary>
|
||||
public sealed class PdfFontResolver : IFontResolver
|
||||
{
|
||||
/// <summary>Bevorzugte Schriftfamilien in Reihenfolge – erste gefundene gewinnt.</summary>
|
||||
private static readonly string[] PreferredFamilies =
|
||||
{
|
||||
"Segoe UI", "DejaVu Sans", "Liberation Sans", "Noto Sans", "Arial", "FreeSans"
|
||||
};
|
||||
|
||||
/// <summary>Dateinamens-Kandidaten je Familie und Schnitt (klein geschrieben, ohne Endung).</summary>
|
||||
private static readonly Dictionary<string, (string Regular, string Bold)> FileNames = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["Segoe UI"] = ("segoeui", "segoeuib"),
|
||||
["DejaVu Sans"] = ("DejaVuSans", "DejaVuSans-Bold"),
|
||||
["Liberation Sans"] = ("LiberationSans-Regular", "LiberationSans-Bold"),
|
||||
["Noto Sans"] = ("NotoSans-Regular", "NotoSans-Bold"),
|
||||
["Arial"] = ("arial", "arialbd"),
|
||||
["FreeSans"] = ("FreeSans", "FreeSansBold"),
|
||||
};
|
||||
|
||||
private static readonly ConcurrentDictionary<string, byte[]> Cache = new();
|
||||
private static readonly object RegisterLock = new();
|
||||
private static bool _registered;
|
||||
|
||||
/// <summary>
|
||||
/// Registriert den Resolver einmalig global. Muss vor dem ersten Rendern laufen; mehrfache
|
||||
/// Aufrufe sind unschädlich (PDFsharp erlaubt nur eine Zuweisung pro Prozess).
|
||||
/// </summary>
|
||||
public static void EnsureRegistered()
|
||||
{
|
||||
if (_registered) return;
|
||||
lock (RegisterLock)
|
||||
{
|
||||
if (_registered) return;
|
||||
if (FindAnyAvailableFamily() == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Keine geeignete Schriftart gefunden. Der PDF-Export braucht mindestens eine von: " +
|
||||
string.Join(", ", PreferredFamilies) + ". " +
|
||||
"Auf schlanken Linux-Systemen nachinstallieren, z.B. 'apt install fonts-dejavu-core'.");
|
||||
}
|
||||
GlobalFontSettings.FontResolver = new PdfFontResolver();
|
||||
_registered = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Erste verfügbare Familie aus <see cref="PreferredFamilies"/>, sonst <c>null</c>.</summary>
|
||||
internal static string? FindAnyAvailableFamily() =>
|
||||
PreferredFamilies.FirstOrDefault(f => LocateFile(f, bold: false) != null);
|
||||
|
||||
public FontResolverInfo? ResolveTypeface(string familyName, bool isBold, bool isItalic)
|
||||
{
|
||||
// Angeforderte Familie bevorzugen, sonst die erste verfügbare (z.B. "Segoe UI" auf Linux).
|
||||
string? family = LocateFile(familyName, isBold) != null ? familyName : FindAnyAvailableFamily();
|
||||
if (family == null) return null;
|
||||
|
||||
// Kursiv wird bewusst nicht aufgelöst: der Bericht nutzt es nicht, und ein fehlender
|
||||
// Kursiv-Schnitt wäre sonst ein harter Fehler statt einer kleinen Abweichung.
|
||||
return new FontResolverInfo($"{family}|{(isBold ? "b" : "r")}");
|
||||
}
|
||||
|
||||
public byte[]? GetFont(string faceName)
|
||||
{
|
||||
return Cache.GetOrAdd(faceName, key =>
|
||||
{
|
||||
var parts = key.Split('|');
|
||||
string family = parts[0];
|
||||
bool bold = parts.Length > 1 && parts[1] == "b";
|
||||
|
||||
string? path = LocateFile(family, bold) ?? LocateFile(family, bold: false);
|
||||
return path != null ? File.ReadAllBytes(path) : Array.Empty<byte>();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>Sucht die Datei zu Familie + Schnitt in allen Schriftverzeichnissen des Systems.</summary>
|
||||
private static string? LocateFile(string family, bool bold)
|
||||
{
|
||||
if (!FileNames.TryGetValue(family, out var names)) return null;
|
||||
string stem = bold ? names.Bold : names.Regular;
|
||||
|
||||
foreach (string dir in FontDirectories())
|
||||
{
|
||||
if (!Directory.Exists(dir)) continue;
|
||||
foreach (string ext in new[] { ".ttf", ".otf" })
|
||||
{
|
||||
try
|
||||
{
|
||||
// Rekursiv, weil Linux die Schriften in Unterordnern ablegt (truetype/dejavu/…).
|
||||
var hit = Directory.EnumerateFiles(dir, stem + ext, SearchOption.AllDirectories)
|
||||
.FirstOrDefault();
|
||||
if (hit != null) return hit;
|
||||
}
|
||||
catch (UnauthorizedAccessException) { /* einzelne Ordner ohne Zugriff überspringen */ }
|
||||
catch (IOException) { /* z.B. defekter Symlink */ }
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Schriftverzeichnisse je Plattform.</summary>
|
||||
private static IEnumerable<string> FontDirectories()
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
yield return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "Fonts");
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
yield return "/System/Library/Fonts";
|
||||
yield return "/Library/Fonts";
|
||||
yield break;
|
||||
}
|
||||
|
||||
// Linux/Unix
|
||||
yield return "/usr/share/fonts";
|
||||
yield return "/usr/local/share/fonts";
|
||||
string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||
if (!string.IsNullOrEmpty(home))
|
||||
{
|
||||
yield return Path.Combine(home, ".fonts");
|
||||
yield return Path.Combine(home, ".local", "share", "fonts");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PolyTrader.Core\PolyTrader.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="PDFsharp-MigraDoc-GDI" Version="6.2.4" />
|
||||
<!-- Core-Build statt -GDI: der GDI-Build braucht System.Drawing.Common und ist damit
|
||||
Windows-only. Der Core-Build findet dafuer keine Systemschriften von selbst -
|
||||
siehe Logic/PdfFontResolver.cs. -->
|
||||
<PackageReference Include="PDFsharp-MigraDoc" Version="6.2.4" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.11">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
@@ -21,11 +24,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<!-- Linux-Portierung: plattformneutral. Die WinForms-UI dieses Moduls (Ingest, BWA, Export)
|
||||
wurde entfernt; die Avalonia-Ansicht kommt spaeter direkt hierher zurueck – Avalonia ist
|
||||
im Gegensatz zu WinForms plattformuebergreifend und braucht kein eigenes UI-Projekt. -->
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<!-- Modul trägt eigene WinForms-UI bei (Ledger/Status; BWA/Steuer/Export folgen A-2..A-4). -->
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,609 +0,0 @@
|
||||
namespace PolyTrader.Modules.Accounting.Ui
|
||||
{
|
||||
partial class AccountingMainForm
|
||||
{
|
||||
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()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AccountingMainForm));
|
||||
tabControlAcc = new TabControl();
|
||||
tabUebersicht = new TabPage();
|
||||
dgvMonthly = new DataGridView();
|
||||
flpKpis = new FlowLayoutPanel();
|
||||
lblKpiNet = new Label();
|
||||
lblKpiClosing = new Label();
|
||||
lblKpiDeposits = new Label();
|
||||
lblKpiWithdrawals = new Label();
|
||||
lblKpiFees = new Label();
|
||||
lblKpiRewards = new Label();
|
||||
lblKpiVolume = new Label();
|
||||
lblKpiTrades = new Label();
|
||||
pnlOverviewTop = new Panel();
|
||||
btnExportPdf = new Button();
|
||||
btnExportCsv = new Button();
|
||||
btnCalc = new Button();
|
||||
cbCurrency = new ComboBox();
|
||||
lblWaehrung = new Label();
|
||||
dtTo = new DateTimePicker();
|
||||
lblBis = new Label();
|
||||
dtFrom = new DateTimePicker();
|
||||
lblVon = new Label();
|
||||
cbOvAccount = new ComboBox();
|
||||
lblOvKonto = new Label();
|
||||
tabLedger = new TabPage();
|
||||
dgvLedger = new DataGridView();
|
||||
toolStripLedger = new ToolStrip();
|
||||
lblLedgerKonto = new ToolStripLabel();
|
||||
cbLedgerAccount = new ToolStripComboBox();
|
||||
sepLedger = new ToolStripSeparator();
|
||||
btnLedgerRefresh = new ToolStripButton();
|
||||
tabStatus = new TabPage();
|
||||
dgvRuns = new DataGridView();
|
||||
toolStripStatus = new ToolStrip();
|
||||
lblStatusKonto = new ToolStripLabel();
|
||||
cbStatusAccount = new ToolStripComboBox();
|
||||
sepStatus = new ToolStripSeparator();
|
||||
btnIncremental = new ToolStripButton();
|
||||
btnBackfill = new ToolStripButton();
|
||||
sepStatus2 = new ToolStripSeparator();
|
||||
btnStatusRefresh = new ToolStripButton();
|
||||
lblAccStatus = new Label();
|
||||
tabControlAcc.SuspendLayout();
|
||||
tabUebersicht.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)dgvMonthly).BeginInit();
|
||||
flpKpis.SuspendLayout();
|
||||
pnlOverviewTop.SuspendLayout();
|
||||
tabLedger.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)dgvLedger).BeginInit();
|
||||
toolStripLedger.SuspendLayout();
|
||||
tabStatus.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)dgvRuns).BeginInit();
|
||||
toolStripStatus.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// tabControlAcc
|
||||
//
|
||||
tabControlAcc.Controls.Add(tabUebersicht);
|
||||
tabControlAcc.Controls.Add(tabLedger);
|
||||
tabControlAcc.Controls.Add(tabStatus);
|
||||
tabControlAcc.Dock = DockStyle.Fill;
|
||||
tabControlAcc.Location = new Point(0, 0);
|
||||
tabControlAcc.Margin = new Padding(4, 5, 4, 5);
|
||||
tabControlAcc.Name = "tabControlAcc";
|
||||
tabControlAcc.SelectedIndex = 0;
|
||||
tabControlAcc.Size = new Size(1571, 1030);
|
||||
tabControlAcc.TabIndex = 0;
|
||||
//
|
||||
// tabUebersicht
|
||||
//
|
||||
tabUebersicht.Controls.Add(dgvMonthly);
|
||||
tabUebersicht.Controls.Add(flpKpis);
|
||||
tabUebersicht.Controls.Add(pnlOverviewTop);
|
||||
tabUebersicht.Location = new Point(4, 34);
|
||||
tabUebersicht.Margin = new Padding(4, 5, 4, 5);
|
||||
tabUebersicht.Name = "tabUebersicht";
|
||||
tabUebersicht.Padding = new Padding(4, 5, 4, 5);
|
||||
tabUebersicht.Size = new Size(1563, 992);
|
||||
tabUebersicht.TabIndex = 0;
|
||||
tabUebersicht.Text = "Übersicht / BWA";
|
||||
tabUebersicht.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// dgvMonthly
|
||||
//
|
||||
dgvMonthly.AllowUserToAddRows = false;
|
||||
dgvMonthly.AllowUserToDeleteRows = false;
|
||||
dgvMonthly.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
dgvMonthly.Dock = DockStyle.Fill;
|
||||
dgvMonthly.Location = new Point(4, 222);
|
||||
dgvMonthly.Margin = new Padding(4, 5, 4, 5);
|
||||
dgvMonthly.Name = "dgvMonthly";
|
||||
dgvMonthly.ReadOnly = true;
|
||||
dgvMonthly.RowHeadersVisible = false;
|
||||
dgvMonthly.RowHeadersWidth = 62;
|
||||
dgvMonthly.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
dgvMonthly.Size = new Size(1555, 765);
|
||||
dgvMonthly.TabIndex = 2;
|
||||
//
|
||||
// flpKpis
|
||||
//
|
||||
flpKpis.Controls.Add(lblKpiNet);
|
||||
flpKpis.Controls.Add(lblKpiClosing);
|
||||
flpKpis.Controls.Add(lblKpiDeposits);
|
||||
flpKpis.Controls.Add(lblKpiWithdrawals);
|
||||
flpKpis.Controls.Add(lblKpiFees);
|
||||
flpKpis.Controls.Add(lblKpiRewards);
|
||||
flpKpis.Controls.Add(lblKpiVolume);
|
||||
flpKpis.Controls.Add(lblKpiTrades);
|
||||
flpKpis.Dock = DockStyle.Top;
|
||||
flpKpis.Location = new Point(4, 65);
|
||||
flpKpis.Margin = new Padding(4, 5, 4, 5);
|
||||
flpKpis.Name = "flpKpis";
|
||||
flpKpis.Padding = new Padding(6, 7, 6, 7);
|
||||
flpKpis.Size = new Size(1555, 157);
|
||||
flpKpis.TabIndex = 1;
|
||||
//
|
||||
// lblKpiNet
|
||||
//
|
||||
lblKpiNet.BorderStyle = BorderStyle.FixedSingle;
|
||||
lblKpiNet.Font = new Font("Segoe UI", 10F, FontStyle.Bold);
|
||||
lblKpiNet.Location = new Point(12, 14);
|
||||
lblKpiNet.Margin = new Padding(6, 7, 6, 7);
|
||||
lblKpiNet.MinimumSize = new Size(285, 122);
|
||||
lblKpiNet.Name = "lblKpiNet";
|
||||
lblKpiNet.Padding = new Padding(11, 13, 11, 13);
|
||||
lblKpiNet.Size = new Size(285, 122);
|
||||
lblKpiNet.TabIndex = 0;
|
||||
lblKpiNet.Text = "Netto-Handelsergebnis\n—";
|
||||
lblKpiNet.TextAlign = ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// lblKpiClosing
|
||||
//
|
||||
lblKpiClosing.BorderStyle = BorderStyle.FixedSingle;
|
||||
lblKpiClosing.Font = new Font("Segoe UI", 10F, FontStyle.Bold);
|
||||
lblKpiClosing.Location = new Point(309, 14);
|
||||
lblKpiClosing.Margin = new Padding(6, 7, 6, 7);
|
||||
lblKpiClosing.MinimumSize = new Size(256, 122);
|
||||
lblKpiClosing.Name = "lblKpiClosing";
|
||||
lblKpiClosing.Padding = new Padding(11, 13, 11, 13);
|
||||
lblKpiClosing.Size = new Size(256, 122);
|
||||
lblKpiClosing.TabIndex = 1;
|
||||
lblKpiClosing.Text = "Endsaldo\n—";
|
||||
lblKpiClosing.TextAlign = ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// lblKpiDeposits
|
||||
//
|
||||
lblKpiDeposits.BorderStyle = BorderStyle.FixedSingle;
|
||||
lblKpiDeposits.Font = new Font("Segoe UI", 10F, FontStyle.Bold);
|
||||
lblKpiDeposits.Location = new Point(577, 14);
|
||||
lblKpiDeposits.Margin = new Padding(6, 7, 6, 7);
|
||||
lblKpiDeposits.MinimumSize = new Size(213, 122);
|
||||
lblKpiDeposits.Name = "lblKpiDeposits";
|
||||
lblKpiDeposits.Padding = new Padding(11, 13, 11, 13);
|
||||
lblKpiDeposits.Size = new Size(213, 122);
|
||||
lblKpiDeposits.TabIndex = 2;
|
||||
lblKpiDeposits.Text = "Einzahlungen\n—";
|
||||
lblKpiDeposits.TextAlign = ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// lblKpiWithdrawals
|
||||
//
|
||||
lblKpiWithdrawals.BorderStyle = BorderStyle.FixedSingle;
|
||||
lblKpiWithdrawals.Font = new Font("Segoe UI", 10F, FontStyle.Bold);
|
||||
lblKpiWithdrawals.Location = new Point(802, 14);
|
||||
lblKpiWithdrawals.Margin = new Padding(6, 7, 6, 7);
|
||||
lblKpiWithdrawals.MinimumSize = new Size(213, 122);
|
||||
lblKpiWithdrawals.Name = "lblKpiWithdrawals";
|
||||
lblKpiWithdrawals.Padding = new Padding(11, 13, 11, 13);
|
||||
lblKpiWithdrawals.Size = new Size(213, 122);
|
||||
lblKpiWithdrawals.TabIndex = 3;
|
||||
lblKpiWithdrawals.Text = "Auszahlungen\n—";
|
||||
lblKpiWithdrawals.TextAlign = ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// lblKpiFees
|
||||
//
|
||||
lblKpiFees.BorderStyle = BorderStyle.FixedSingle;
|
||||
lblKpiFees.Font = new Font("Segoe UI", 10F, FontStyle.Bold);
|
||||
lblKpiFees.Location = new Point(1027, 14);
|
||||
lblKpiFees.Margin = new Padding(6, 7, 6, 7);
|
||||
lblKpiFees.MinimumSize = new Size(199, 122);
|
||||
lblKpiFees.Name = "lblKpiFees";
|
||||
lblKpiFees.Padding = new Padding(11, 13, 11, 13);
|
||||
lblKpiFees.Size = new Size(199, 122);
|
||||
lblKpiFees.TabIndex = 4;
|
||||
lblKpiFees.Text = "Fees\n—";
|
||||
lblKpiFees.TextAlign = ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// lblKpiRewards
|
||||
//
|
||||
lblKpiRewards.BorderStyle = BorderStyle.FixedSingle;
|
||||
lblKpiRewards.Font = new Font("Segoe UI", 10F, FontStyle.Bold);
|
||||
lblKpiRewards.Location = new Point(1238, 14);
|
||||
lblKpiRewards.Margin = new Padding(6, 7, 6, 7);
|
||||
lblKpiRewards.MinimumSize = new Size(199, 122);
|
||||
lblKpiRewards.Name = "lblKpiRewards";
|
||||
lblKpiRewards.Padding = new Padding(11, 13, 11, 13);
|
||||
lblKpiRewards.Size = new Size(199, 122);
|
||||
lblKpiRewards.TabIndex = 5;
|
||||
lblKpiRewards.Text = "Rewards\n—";
|
||||
lblKpiRewards.TextAlign = ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// lblKpiVolume
|
||||
//
|
||||
lblKpiVolume.BorderStyle = BorderStyle.FixedSingle;
|
||||
lblKpiVolume.Font = new Font("Segoe UI", 10F, FontStyle.Bold);
|
||||
lblKpiVolume.Location = new Point(12, 150);
|
||||
lblKpiVolume.Margin = new Padding(6, 7, 6, 7);
|
||||
lblKpiVolume.MinimumSize = new Size(228, 122);
|
||||
lblKpiVolume.Name = "lblKpiVolume";
|
||||
lblKpiVolume.Padding = new Padding(11, 13, 11, 13);
|
||||
lblKpiVolume.Size = new Size(228, 122);
|
||||
lblKpiVolume.TabIndex = 6;
|
||||
lblKpiVolume.Text = "Handelsvolumen\n—";
|
||||
lblKpiVolume.TextAlign = ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// lblKpiTrades
|
||||
//
|
||||
lblKpiTrades.BorderStyle = BorderStyle.FixedSingle;
|
||||
lblKpiTrades.Font = new Font("Segoe UI", 10F, FontStyle.Bold);
|
||||
lblKpiTrades.Location = new Point(252, 150);
|
||||
lblKpiTrades.Margin = new Padding(6, 7, 6, 7);
|
||||
lblKpiTrades.MinimumSize = new Size(171, 122);
|
||||
lblKpiTrades.Name = "lblKpiTrades";
|
||||
lblKpiTrades.Padding = new Padding(11, 13, 11, 13);
|
||||
lblKpiTrades.Size = new Size(171, 122);
|
||||
lblKpiTrades.TabIndex = 7;
|
||||
lblKpiTrades.Text = "Trades\n—";
|
||||
lblKpiTrades.TextAlign = ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// pnlOverviewTop
|
||||
//
|
||||
pnlOverviewTop.Controls.Add(btnExportPdf);
|
||||
pnlOverviewTop.Controls.Add(btnExportCsv);
|
||||
pnlOverviewTop.Controls.Add(btnCalc);
|
||||
pnlOverviewTop.Controls.Add(cbCurrency);
|
||||
pnlOverviewTop.Controls.Add(lblWaehrung);
|
||||
pnlOverviewTop.Controls.Add(dtTo);
|
||||
pnlOverviewTop.Controls.Add(lblBis);
|
||||
pnlOverviewTop.Controls.Add(dtFrom);
|
||||
pnlOverviewTop.Controls.Add(lblVon);
|
||||
pnlOverviewTop.Controls.Add(cbOvAccount);
|
||||
pnlOverviewTop.Controls.Add(lblOvKonto);
|
||||
pnlOverviewTop.Dock = DockStyle.Top;
|
||||
pnlOverviewTop.Location = new Point(4, 5);
|
||||
pnlOverviewTop.Margin = new Padding(4, 5, 4, 5);
|
||||
pnlOverviewTop.Name = "pnlOverviewTop";
|
||||
pnlOverviewTop.Size = new Size(1555, 60);
|
||||
pnlOverviewTop.TabIndex = 0;
|
||||
//
|
||||
// btnExportPdf
|
||||
//
|
||||
btnExportPdf.Location = new Point(1334, 8);
|
||||
btnExportPdf.Margin = new Padding(4, 5, 4, 5);
|
||||
btnExportPdf.Name = "btnExportPdf";
|
||||
btnExportPdf.Size = new Size(129, 43);
|
||||
btnExportPdf.TabIndex = 10;
|
||||
btnExportPdf.Text = "PDF-Export";
|
||||
btnExportPdf.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnExportCsv
|
||||
//
|
||||
btnExportCsv.Location = new Point(1197, 8);
|
||||
btnExportCsv.Margin = new Padding(4, 5, 4, 5);
|
||||
btnExportCsv.Name = "btnExportCsv";
|
||||
btnExportCsv.Size = new Size(129, 43);
|
||||
btnExportCsv.TabIndex = 9;
|
||||
btnExportCsv.Text = "CSV-Export";
|
||||
btnExportCsv.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnCalc
|
||||
//
|
||||
btnCalc.Location = new Point(1046, 8);
|
||||
btnCalc.Margin = new Padding(4, 5, 4, 5);
|
||||
btnCalc.Name = "btnCalc";
|
||||
btnCalc.Size = new Size(143, 43);
|
||||
btnCalc.TabIndex = 8;
|
||||
btnCalc.Text = "Berechnen";
|
||||
btnCalc.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// cbCurrency
|
||||
//
|
||||
cbCurrency.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
cbCurrency.Items.AddRange(new object[] { "USDC", "USD", "EUR" });
|
||||
cbCurrency.Location = new Point(921, 10);
|
||||
cbCurrency.Margin = new Padding(4, 5, 4, 5);
|
||||
cbCurrency.Name = "cbCurrency";
|
||||
cbCurrency.Size = new Size(113, 33);
|
||||
cbCurrency.TabIndex = 7;
|
||||
//
|
||||
// lblWaehrung
|
||||
//
|
||||
lblWaehrung.AutoSize = true;
|
||||
lblWaehrung.Location = new Point(821, 15);
|
||||
lblWaehrung.Margin = new Padding(4, 0, 4, 0);
|
||||
lblWaehrung.Name = "lblWaehrung";
|
||||
lblWaehrung.Size = new Size(88, 25);
|
||||
lblWaehrung.TabIndex = 6;
|
||||
lblWaehrung.Text = "Währung:";
|
||||
//
|
||||
// dtTo
|
||||
//
|
||||
dtTo.Format = DateTimePickerFormat.Short;
|
||||
dtTo.Location = new Point(636, 10);
|
||||
dtTo.Margin = new Padding(4, 5, 4, 5);
|
||||
dtTo.Name = "dtTo";
|
||||
dtTo.Size = new Size(155, 31);
|
||||
dtTo.TabIndex = 5;
|
||||
//
|
||||
// lblBis
|
||||
//
|
||||
lblBis.AutoSize = true;
|
||||
lblBis.Location = new Point(593, 15);
|
||||
lblBis.Margin = new Padding(4, 0, 4, 0);
|
||||
lblBis.Name = "lblBis";
|
||||
lblBis.Size = new Size(38, 25);
|
||||
lblBis.TabIndex = 4;
|
||||
lblBis.Text = "Bis:";
|
||||
//
|
||||
// dtFrom
|
||||
//
|
||||
dtFrom.Format = DateTimePickerFormat.Short;
|
||||
dtFrom.Location = new Point(429, 10);
|
||||
dtFrom.Margin = new Padding(4, 5, 4, 5);
|
||||
dtFrom.Name = "dtFrom";
|
||||
dtFrom.Size = new Size(155, 31);
|
||||
dtFrom.TabIndex = 3;
|
||||
//
|
||||
// lblVon
|
||||
//
|
||||
lblVon.AutoSize = true;
|
||||
lblVon.Location = new Point(381, 15);
|
||||
lblVon.Margin = new Padding(4, 0, 4, 0);
|
||||
lblVon.Name = "lblVon";
|
||||
lblVon.Size = new Size(47, 25);
|
||||
lblVon.TabIndex = 2;
|
||||
lblVon.Text = "Von:";
|
||||
//
|
||||
// cbOvAccount
|
||||
//
|
||||
cbOvAccount.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
cbOvAccount.Location = new Point(79, 10);
|
||||
cbOvAccount.Margin = new Padding(4, 5, 4, 5);
|
||||
cbOvAccount.Name = "cbOvAccount";
|
||||
cbOvAccount.Size = new Size(284, 33);
|
||||
cbOvAccount.TabIndex = 1;
|
||||
//
|
||||
// lblOvKonto
|
||||
//
|
||||
lblOvKonto.AutoSize = true;
|
||||
lblOvKonto.Location = new Point(9, 15);
|
||||
lblOvKonto.Margin = new Padding(4, 0, 4, 0);
|
||||
lblOvKonto.Name = "lblOvKonto";
|
||||
lblOvKonto.Size = new Size(64, 25);
|
||||
lblOvKonto.TabIndex = 0;
|
||||
lblOvKonto.Text = "Konto:";
|
||||
//
|
||||
// tabLedger
|
||||
//
|
||||
tabLedger.Controls.Add(dgvLedger);
|
||||
tabLedger.Controls.Add(toolStripLedger);
|
||||
tabLedger.Location = new Point(4, 34);
|
||||
tabLedger.Margin = new Padding(4, 5, 4, 5);
|
||||
tabLedger.Name = "tabLedger";
|
||||
tabLedger.Padding = new Padding(4, 5, 4, 5);
|
||||
tabLedger.Size = new Size(1563, 992);
|
||||
tabLedger.TabIndex = 1;
|
||||
tabLedger.Text = "Ledger";
|
||||
tabLedger.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// dgvLedger
|
||||
//
|
||||
dgvLedger.AllowUserToAddRows = false;
|
||||
dgvLedger.AllowUserToDeleteRows = false;
|
||||
dgvLedger.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
dgvLedger.Dock = DockStyle.Fill;
|
||||
dgvLedger.Location = new Point(4, 39);
|
||||
dgvLedger.Margin = new Padding(4, 5, 4, 5);
|
||||
dgvLedger.Name = "dgvLedger";
|
||||
dgvLedger.ReadOnly = true;
|
||||
dgvLedger.RowHeadersVisible = false;
|
||||
dgvLedger.RowHeadersWidth = 62;
|
||||
dgvLedger.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
dgvLedger.Size = new Size(1555, 948);
|
||||
dgvLedger.TabIndex = 1;
|
||||
//
|
||||
// toolStripLedger
|
||||
//
|
||||
toolStripLedger.ImageScalingSize = new Size(24, 24);
|
||||
toolStripLedger.Items.AddRange(new ToolStripItem[] { lblLedgerKonto, cbLedgerAccount, sepLedger, btnLedgerRefresh });
|
||||
toolStripLedger.Location = new Point(4, 5);
|
||||
toolStripLedger.Name = "toolStripLedger";
|
||||
toolStripLedger.Padding = new Padding(0, 0, 3, 0);
|
||||
toolStripLedger.Size = new Size(1555, 34);
|
||||
toolStripLedger.TabIndex = 0;
|
||||
//
|
||||
// lblLedgerKonto
|
||||
//
|
||||
lblLedgerKonto.Name = "lblLedgerKonto";
|
||||
lblLedgerKonto.Size = new Size(64, 29);
|
||||
lblLedgerKonto.Text = "Konto:";
|
||||
//
|
||||
// cbLedgerAccount
|
||||
//
|
||||
cbLedgerAccount.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
cbLedgerAccount.Name = "cbLedgerAccount";
|
||||
cbLedgerAccount.Size = new Size(341, 34);
|
||||
//
|
||||
// sepLedger
|
||||
//
|
||||
sepLedger.Name = "sepLedger";
|
||||
sepLedger.Size = new Size(6, 34);
|
||||
//
|
||||
// btnLedgerRefresh
|
||||
//
|
||||
btnLedgerRefresh.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
||||
btnLedgerRefresh.Name = "btnLedgerRefresh";
|
||||
btnLedgerRefresh.Size = new Size(116, 29);
|
||||
btnLedgerRefresh.Text = "Aktualisieren";
|
||||
//
|
||||
// tabStatus
|
||||
//
|
||||
tabStatus.Controls.Add(dgvRuns);
|
||||
tabStatus.Controls.Add(toolStripStatus);
|
||||
tabStatus.Location = new Point(4, 34);
|
||||
tabStatus.Margin = new Padding(4, 5, 4, 5);
|
||||
tabStatus.Name = "tabStatus";
|
||||
tabStatus.Padding = new Padding(4, 5, 4, 5);
|
||||
tabStatus.Size = new Size(1563, 992);
|
||||
tabStatus.TabIndex = 2;
|
||||
tabStatus.Text = "Abruf / Status";
|
||||
tabStatus.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// dgvRuns
|
||||
//
|
||||
dgvRuns.AllowUserToAddRows = false;
|
||||
dgvRuns.AllowUserToDeleteRows = false;
|
||||
dgvRuns.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
dgvRuns.Dock = DockStyle.Fill;
|
||||
dgvRuns.Location = new Point(4, 39);
|
||||
dgvRuns.Margin = new Padding(4, 5, 4, 5);
|
||||
dgvRuns.Name = "dgvRuns";
|
||||
dgvRuns.ReadOnly = true;
|
||||
dgvRuns.RowHeadersVisible = false;
|
||||
dgvRuns.RowHeadersWidth = 62;
|
||||
dgvRuns.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
dgvRuns.Size = new Size(1555, 948);
|
||||
dgvRuns.TabIndex = 1;
|
||||
//
|
||||
// toolStripStatus
|
||||
//
|
||||
toolStripStatus.ImageScalingSize = new Size(24, 24);
|
||||
toolStripStatus.Items.AddRange(new ToolStripItem[] { lblStatusKonto, cbStatusAccount, sepStatus, btnIncremental, btnBackfill, sepStatus2, btnStatusRefresh });
|
||||
toolStripStatus.Location = new Point(4, 5);
|
||||
toolStripStatus.Name = "toolStripStatus";
|
||||
toolStripStatus.Padding = new Padding(0, 0, 3, 0);
|
||||
toolStripStatus.Size = new Size(1555, 34);
|
||||
toolStripStatus.TabIndex = 0;
|
||||
//
|
||||
// lblStatusKonto
|
||||
//
|
||||
lblStatusKonto.Name = "lblStatusKonto";
|
||||
lblStatusKonto.Size = new Size(64, 29);
|
||||
lblStatusKonto.Text = "Konto:";
|
||||
//
|
||||
// cbStatusAccount
|
||||
//
|
||||
cbStatusAccount.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
cbStatusAccount.Name = "cbStatusAccount";
|
||||
cbStatusAccount.Size = new Size(341, 34);
|
||||
//
|
||||
// sepStatus
|
||||
//
|
||||
sepStatus.Name = "sepStatus";
|
||||
sepStatus.Size = new Size(6, 34);
|
||||
//
|
||||
// btnIncremental
|
||||
//
|
||||
btnIncremental.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
||||
btnIncremental.Name = "btnIncremental";
|
||||
btnIncremental.Size = new Size(134, 29);
|
||||
btnIncremental.Text = "Inkrement jetzt";
|
||||
btnIncremental.ToolTipText = "Nur neue Ereignisse seit dem letzten Stand abrufen (mit Lookback-Überlappung).";
|
||||
//
|
||||
// btnBackfill
|
||||
//
|
||||
btnBackfill.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
||||
btnBackfill.Name = "btnBackfill";
|
||||
btnBackfill.Size = new Size(188, 29);
|
||||
btnBackfill.Text = "Backfill (volle Historie)";
|
||||
btnBackfill.ToolTipText = "Komplette Historie neu abrufen (idempotent – bucht nichts doppelt).";
|
||||
//
|
||||
// sepStatus2
|
||||
//
|
||||
sepStatus2.Name = "sepStatus2";
|
||||
sepStatus2.Size = new Size(6, 34);
|
||||
//
|
||||
// btnStatusRefresh
|
||||
//
|
||||
btnStatusRefresh.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
||||
btnStatusRefresh.Name = "btnStatusRefresh";
|
||||
btnStatusRefresh.Size = new Size(116, 29);
|
||||
btnStatusRefresh.Text = "Aktualisieren";
|
||||
//
|
||||
// lblAccStatus
|
||||
//
|
||||
lblAccStatus.Dock = DockStyle.Bottom;
|
||||
lblAccStatus.Location = new Point(0, 1030);
|
||||
lblAccStatus.Margin = new Padding(4, 0, 4, 0);
|
||||
lblAccStatus.Name = "lblAccStatus";
|
||||
lblAccStatus.Padding = new Padding(9, 3, 9, 3);
|
||||
lblAccStatus.Size = new Size(1571, 37);
|
||||
lblAccStatus.TabIndex = 1;
|
||||
//
|
||||
// AccountingMainForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(10F, 25F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(1571, 1067);
|
||||
Controls.Add(tabControlAcc);
|
||||
Controls.Add(lblAccStatus);
|
||||
Icon = (Icon)resources.GetObject("$this.Icon");
|
||||
Margin = new Padding(4, 5, 4, 5);
|
||||
Name = "AccountingMainForm";
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Text = "Accounting";
|
||||
tabControlAcc.ResumeLayout(false);
|
||||
tabUebersicht.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)dgvMonthly).EndInit();
|
||||
flpKpis.ResumeLayout(false);
|
||||
pnlOverviewTop.ResumeLayout(false);
|
||||
pnlOverviewTop.PerformLayout();
|
||||
tabLedger.ResumeLayout(false);
|
||||
tabLedger.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)dgvLedger).EndInit();
|
||||
toolStripLedger.ResumeLayout(false);
|
||||
toolStripLedger.PerformLayout();
|
||||
tabStatus.ResumeLayout(false);
|
||||
tabStatus.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)dgvRuns).EndInit();
|
||||
toolStripStatus.ResumeLayout(false);
|
||||
toolStripStatus.PerformLayout();
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TabControl tabControlAcc;
|
||||
private System.Windows.Forms.TabPage tabUebersicht;
|
||||
private System.Windows.Forms.Panel pnlOverviewTop;
|
||||
private System.Windows.Forms.Label lblOvKonto;
|
||||
private System.Windows.Forms.ComboBox cbOvAccount;
|
||||
private System.Windows.Forms.Label lblVon;
|
||||
private System.Windows.Forms.DateTimePicker dtFrom;
|
||||
private System.Windows.Forms.Label lblBis;
|
||||
private System.Windows.Forms.DateTimePicker dtTo;
|
||||
private System.Windows.Forms.Label lblWaehrung;
|
||||
private System.Windows.Forms.ComboBox cbCurrency;
|
||||
private System.Windows.Forms.Button btnCalc;
|
||||
private System.Windows.Forms.Button btnExportCsv;
|
||||
private System.Windows.Forms.Button btnExportPdf;
|
||||
private System.Windows.Forms.FlowLayoutPanel flpKpis;
|
||||
private System.Windows.Forms.Label lblKpiNet;
|
||||
private System.Windows.Forms.Label lblKpiClosing;
|
||||
private System.Windows.Forms.Label lblKpiDeposits;
|
||||
private System.Windows.Forms.Label lblKpiWithdrawals;
|
||||
private System.Windows.Forms.Label lblKpiFees;
|
||||
private System.Windows.Forms.Label lblKpiRewards;
|
||||
private System.Windows.Forms.Label lblKpiVolume;
|
||||
private System.Windows.Forms.Label lblKpiTrades;
|
||||
private System.Windows.Forms.DataGridView dgvMonthly;
|
||||
private System.Windows.Forms.TabPage tabLedger;
|
||||
private System.Windows.Forms.ToolStrip toolStripLedger;
|
||||
private System.Windows.Forms.ToolStripLabel lblLedgerKonto;
|
||||
private System.Windows.Forms.ToolStripComboBox cbLedgerAccount;
|
||||
private System.Windows.Forms.ToolStripSeparator sepLedger;
|
||||
private System.Windows.Forms.ToolStripButton btnLedgerRefresh;
|
||||
private System.Windows.Forms.DataGridView dgvLedger;
|
||||
private System.Windows.Forms.TabPage tabStatus;
|
||||
private System.Windows.Forms.ToolStrip toolStripStatus;
|
||||
private System.Windows.Forms.ToolStripLabel lblStatusKonto;
|
||||
private System.Windows.Forms.ToolStripComboBox cbStatusAccount;
|
||||
private System.Windows.Forms.ToolStripSeparator sepStatus;
|
||||
private System.Windows.Forms.ToolStripButton btnIncremental;
|
||||
private System.Windows.Forms.ToolStripButton btnBackfill;
|
||||
private System.Windows.Forms.ToolStripSeparator sepStatus2;
|
||||
private System.Windows.Forms.ToolStripButton btnStatusRefresh;
|
||||
private System.Windows.Forms.DataGridView dgvRuns;
|
||||
private System.Windows.Forms.Label lblAccStatus;
|
||||
}
|
||||
}
|
||||
@@ -1,322 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using PolyTrader.Modules.Accounting.Logic;
|
||||
using PolyTrader.Modules.Accounting.Persistence;
|
||||
using PolyTrader.Modules.Accounting.Services;
|
||||
using PolyTraderSharp;
|
||||
|
||||
namespace PolyTrader.Modules.Accounting.Ui
|
||||
{
|
||||
/// <summary>
|
||||
/// Hauptfenster des Accounting-Moduls: Tab „Übersicht / BWA" (neutrale Periodenabrechnung + KPIs +
|
||||
/// Monatsvergleich, Währung USDC/USD/EUR, CSV-Export), „Ledger" (Buchungssätze) und „Abruf / Status"
|
||||
/// (Ingest-Läufe, manueller Backfill/Inkrement). Layout im Designer; Aggregation pur im
|
||||
/// <see cref="AccountingEngine"/>. Die US-Steuerschicht (A-3) ist bewusst NICHT hier – sie hängt an
|
||||
/// den CPA-Antworten.
|
||||
/// </summary>
|
||||
public partial class AccountingMainForm : Form
|
||||
{
|
||||
private ILedgerRepository? _ledger;
|
||||
private IIngestRunRepository? _runs;
|
||||
private AccountingIngestService? _ingest;
|
||||
private AccountingReportService? _report;
|
||||
private TradingState? _state;
|
||||
|
||||
public AccountingMainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Übersicht / BWA
|
||||
btnCalc.Click += (_, _) => Recalculate();
|
||||
btnExportCsv.Click += (_, _) => ExportCsv();
|
||||
btnExportPdf.Click += (_, _) => ExportPdf();
|
||||
cbOvAccount.SelectedIndexChanged += (_, _) => Recalculate();
|
||||
cbCurrency.SelectedIndexChanged += (_, _) => Recalculate();
|
||||
|
||||
// Ledger + Status
|
||||
btnLedgerRefresh.Click += (_, _) => LoadLedger();
|
||||
cbLedgerAccount.SelectedIndexChanged += (_, _) => LoadLedger();
|
||||
btnStatusRefresh.Click += (_, _) => LoadRuns();
|
||||
btnIncremental.Click += async (_, _) => await RunIngestAsync(backfill: false);
|
||||
btnBackfill.Click += async (_, _) => await RunIngestAsync(backfill: true);
|
||||
}
|
||||
|
||||
public void Initialize(IServiceProvider services)
|
||||
{
|
||||
_ledger = services.GetRequiredService<ILedgerRepository>();
|
||||
_runs = services.GetRequiredService<IIngestRunRepository>();
|
||||
_ingest = services.GetRequiredService<AccountingIngestService>();
|
||||
_report = services.GetRequiredService<AccountingReportService>();
|
||||
_state = services.GetRequiredService<TradingState>();
|
||||
|
||||
// Standard-Zeitraum: laufender Monat.
|
||||
var now = DateTime.Now;
|
||||
dtFrom.Value = new DateTime(now.Year, now.Month, 1);
|
||||
dtTo.Value = now;
|
||||
if (cbCurrency.Items.Count > 0) cbCurrency.SelectedIndex = 0; // USDC
|
||||
|
||||
PopulateAccounts();
|
||||
Recalculate();
|
||||
LoadLedger();
|
||||
LoadRuns();
|
||||
}
|
||||
|
||||
// ---------------- Konten-Filter ----------------
|
||||
|
||||
private void PopulateAccounts()
|
||||
{
|
||||
var items = new List<AccountItem> { new(null, "Alle Live-Konten") };
|
||||
if (_state != null)
|
||||
items.AddRange(_state.Accounts.Values
|
||||
.Where(a => !a.IsDemo && !string.IsNullOrWhiteSpace(a.WalletAddress))
|
||||
.OrderBy(a => a.AccountId)
|
||||
.Select(a => new AccountItem(a.AccountId, string.IsNullOrEmpty(a.Name) ? $"#{a.AccountId}" : $"{a.Name} (#{a.AccountId})")));
|
||||
|
||||
cbOvAccount.DisplayMember = nameof(AccountItem.Label);
|
||||
cbOvAccount.DataSource = new List<AccountItem>(items);
|
||||
foreach (var combo in new[] { cbLedgerAccount, cbStatusAccount })
|
||||
{
|
||||
combo.ComboBox.DisplayMember = nameof(AccountItem.Label);
|
||||
combo.ComboBox.DataSource = new List<AccountItem>(items);
|
||||
}
|
||||
}
|
||||
|
||||
private static int? IdOf(object? item) => item is AccountItem it ? it.Id : null;
|
||||
|
||||
// ---------------- Übersicht / BWA ----------------
|
||||
|
||||
private void Recalculate()
|
||||
{
|
||||
if (_report == null) return;
|
||||
try
|
||||
{
|
||||
DateTime from = dtFrom.Value.Date;
|
||||
DateTime to = dtTo.Value.Date.AddDays(1).AddTicks(-1); // inklusive gewählter Bis-Tag
|
||||
int? accId = IdOf(cbOvAccount.SelectedItem);
|
||||
|
||||
var statement = _report.BuildStatement(accId, from, to);
|
||||
var monthly = _report.BuildMonthly(accId, from, to);
|
||||
var cur = _report.ResolveCurrency(cbCurrency.SelectedItem?.ToString() ?? "USDC", to);
|
||||
|
||||
UpdateKpis(statement, cur);
|
||||
dgvMonthly.DataSource = monthly.Select(m => new MonthlyRow(m, cur)).ToList();
|
||||
|
||||
lblAccStatus.Text = cur.Available
|
||||
? $"Währung {cur.Code}: {cur.Note}"
|
||||
: $"⚠️ {cur.Note} (Anzeige in USDC).";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lblAccStatus.Text = $"Abrechnung nicht möglich (acc_-Migration angewendet?): {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateKpis(PeriodStatement s, CurrencyContext cur)
|
||||
{
|
||||
CurrencyContext view = cur.Available ? cur : new CurrencyContext("USDC", 1m, true, "");
|
||||
string unit = view.Code;
|
||||
decimal V(decimal usdc) => AccountingReportService.Convert(usdc, view);
|
||||
|
||||
lblKpiNet.Text = $"Netto-Handelsergebnis\n{V(s.NetTradingResultUsdc):N2} {unit}";
|
||||
lblKpiNet.ForeColor = s.NetTradingResultUsdc >= 0 ? System.Drawing.Color.ForestGreen : System.Drawing.Color.Firebrick;
|
||||
lblKpiClosing.Text = $"Endsaldo\n{V(s.ClosingBalanceUsdc):N2} {unit}";
|
||||
lblKpiDeposits.Text = $"Einzahlungen\n{V(s.Deposits):N2} {unit}";
|
||||
lblKpiWithdrawals.Text = $"Auszahlungen\n{V(s.Withdrawals):N2} {unit}";
|
||||
lblKpiFees.Text = $"Fees\n{V(s.Fees):N2} {unit}";
|
||||
lblKpiRewards.Text = $"Rewards\n{V(s.Rewards):N2} {unit}";
|
||||
lblKpiVolume.Text = $"Handelsvolumen\n{V(s.TradeVolume):N2} {unit}";
|
||||
lblKpiTrades.Text = $"Trades\n{s.TradeCount}";
|
||||
}
|
||||
|
||||
private void ExportCsv()
|
||||
{
|
||||
if (_ledger == null || _report == null) return;
|
||||
DateTime from = dtFrom.Value.Date;
|
||||
DateTime to = dtTo.Value.Date.AddDays(1).AddTicks(-1);
|
||||
int? accId = IdOf(cbOvAccount.SelectedItem);
|
||||
|
||||
using var dlg = new SaveFileDialog
|
||||
{
|
||||
Filter = "CSV-Datei (*.csv)|*.csv",
|
||||
FileName = $"accounting_{(accId?.ToString() ?? "alle")}_{from:yyyyMMdd}-{dtTo.Value:yyyyMMdd}.csv"
|
||||
};
|
||||
if (dlg.ShowDialog(this) != DialogResult.OK) return;
|
||||
|
||||
try
|
||||
{
|
||||
var statement = _report.BuildStatement(accId, from, to);
|
||||
var entries = _ledger.Query(accId, from, to, 100000);
|
||||
string csv = CsvExporter.Statement(statement) + Environment.NewLine + CsvExporter.Ledger(entries);
|
||||
System.IO.File.WriteAllText(dlg.FileName, csv, new System.Text.UTF8Encoding(true));
|
||||
lblAccStatus.Text = $"CSV exportiert: {dlg.FileName} ({entries.Count} Buchungen).";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lblAccStatus.Text = $"CSV-Export fehlgeschlagen: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
private void ExportPdf()
|
||||
{
|
||||
if (_ledger == null || _report == null) return;
|
||||
DateTime from = dtFrom.Value.Date;
|
||||
DateTime to = dtTo.Value.Date.AddDays(1).AddTicks(-1);
|
||||
int? accId = IdOf(cbOvAccount.SelectedItem);
|
||||
|
||||
using var dlg = new SaveFileDialog
|
||||
{
|
||||
Filter = "PDF-Datei (*.pdf)|*.pdf",
|
||||
FileName = $"abrechnung_{(accId?.ToString() ?? "alle")}_{from:yyyyMMdd}-{dtTo.Value:yyyyMMdd}.pdf"
|
||||
};
|
||||
if (dlg.ShowDialog(this) != DialogResult.OK) return;
|
||||
|
||||
try
|
||||
{
|
||||
var statement = _report.BuildStatement(accId, from, to);
|
||||
var monthly = _report.BuildMonthly(accId, from, to);
|
||||
var entries = _ledger.Query(accId, from, to, 100000);
|
||||
var cur = _report.ResolveCurrency(cbCurrency.SelectedItem?.ToString() ?? "USDC", to);
|
||||
CurrencyContext view = cur.Available ? cur : new CurrencyContext("USDC", 1m, true, "Native Buchungswährung.");
|
||||
|
||||
byte[] pdf = PdfExporter.Render(statement, monthly, entries, view.Code, view.Factor, view.Note);
|
||||
System.IO.File.WriteAllBytes(dlg.FileName, pdf);
|
||||
lblAccStatus.Text = $"PDF exportiert: {dlg.FileName} ({entries.Count} Buchungen, {view.Code}).";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lblAccStatus.Text = $"PDF-Export fehlgeschlagen: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- Ledger ----------------
|
||||
|
||||
private void LoadLedger()
|
||||
{
|
||||
if (_ledger == null) return;
|
||||
try
|
||||
{
|
||||
var rows = _ledger.Query(IdOf(cbLedgerAccount.SelectedItem), null, null, 1000);
|
||||
dgvLedger.DataSource = rows.Select(e => new LedgerRow(e)).ToList();
|
||||
lblAccStatus.Text = rows.Count == 0
|
||||
? "Noch keine Buchungen. (Ingest-Quellen sind offline bis zur Live-Anbindung im Zielland.)"
|
||||
: $"{rows.Count} Buchungssätze angezeigt.";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lblAccStatus.Text = $"Ledger nicht lesbar (acc_-Migration angewendet?): {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- Abruf / Status ----------------
|
||||
|
||||
private void LoadRuns()
|
||||
{
|
||||
if (_runs == null) return;
|
||||
try
|
||||
{
|
||||
dgvRuns.DataSource = _runs.GetRecent(IdOf(cbStatusAccount.SelectedItem), 100);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lblAccStatus.Text = $"Ingest-Läufe nicht lesbar: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task RunIngestAsync(bool backfill)
|
||||
{
|
||||
if (_ingest == null) return;
|
||||
btnBackfill.Enabled = false;
|
||||
btnIncremental.Enabled = false;
|
||||
lblAccStatus.Text = backfill ? "Backfill läuft …" : "Inkrementeller Abruf läuft …";
|
||||
try
|
||||
{
|
||||
await System.Threading.Tasks.Task.Run(() => _ingest.IngestAllAsync(backfill, CancellationToken.None));
|
||||
lblAccStatus.Text = "Abruf abgeschlossen.";
|
||||
LoadRuns();
|
||||
LoadLedger();
|
||||
Recalculate();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lblAccStatus.Text = $"Abruf-Fehler: {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
btnBackfill.Enabled = true;
|
||||
btnIncremental.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed record AccountItem(int? Id, string Label);
|
||||
|
||||
/// <summary>Anzeige-Zeile des Monatsvergleichs (Beträge in der gewählten Währung).</summary>
|
||||
private sealed class MonthlyRow
|
||||
{
|
||||
public MonthlyRow(PeriodStatement m, CurrencyContext cur)
|
||||
{
|
||||
CurrencyContext view = cur.Available ? cur : new CurrencyContext("USDC", 1m, true, "");
|
||||
decimal V(decimal usdc) => AccountingReportService.Convert(usdc, view);
|
||||
Monat = m.From.ToString("yyyy-MM");
|
||||
Anfangssaldo = V(m.OpeningBalanceUsdc);
|
||||
Einzahlungen = V(m.Deposits);
|
||||
Auszahlungen = V(m.Withdrawals);
|
||||
Handelsvolumen = V(m.TradeVolume);
|
||||
Rewards = V(m.Rewards);
|
||||
Fees = V(m.Fees);
|
||||
Handelsergebnis = V(m.NetTradingResultUsdc);
|
||||
Endsaldo = V(m.ClosingBalanceUsdc);
|
||||
Trades = m.TradeCount;
|
||||
}
|
||||
|
||||
public string Monat { get; }
|
||||
public decimal Anfangssaldo { get; }
|
||||
public decimal Einzahlungen { get; }
|
||||
public decimal Auszahlungen { get; }
|
||||
public decimal Handelsvolumen { get; }
|
||||
public decimal Rewards { get; }
|
||||
public decimal Fees { get; }
|
||||
public decimal Handelsergebnis { get; }
|
||||
public decimal Endsaldo { get; }
|
||||
public int Trades { get; }
|
||||
}
|
||||
|
||||
/// <summary>Anzeige-Zeile fürs Ledger-Grid.</summary>
|
||||
private sealed class LedgerRow
|
||||
{
|
||||
public LedgerRow(Models.LedgerEntry e)
|
||||
{
|
||||
Zeit = e.Timestamp;
|
||||
Konto = e.AccountId;
|
||||
Typ = e.EventType.ToString();
|
||||
Markt = e.MarketSlug;
|
||||
Outcome = e.Outcome;
|
||||
Side = e.Side;
|
||||
Size = e.Size;
|
||||
Preis = e.PriceUsdc;
|
||||
Brutto = e.GrossUsdc;
|
||||
Fee = e.FeeUsdc;
|
||||
Netto = e.NetUsdc;
|
||||
TxHash = e.TxHash;
|
||||
Quelle = e.Source;
|
||||
}
|
||||
|
||||
public DateTime Zeit { get; }
|
||||
public int Konto { get; }
|
||||
public string Typ { get; }
|
||||
public string Markt { get; }
|
||||
public string Outcome { get; }
|
||||
public string Side { get; }
|
||||
public decimal Size { get; }
|
||||
public decimal Preis { get; }
|
||||
public decimal Brutto { get; }
|
||||
public decimal Fee { get; }
|
||||
public decimal Netto { get; }
|
||||
public string TxHash { get; }
|
||||
public string Quelle { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="toolStripLedger.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="toolStripStatus.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>206, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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
|
||||
AABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -10,7 +10,6 @@ using PolyTrader.Core.Modularity;
|
||||
using PolyTrader.Core.Streaming;
|
||||
using PolyTrader.Modules.CopyTrading.Persistence;
|
||||
using PolyTrader.Modules.CopyTrading.Persistence.Ef;
|
||||
using PolyTrader.Modules.CopyTrading.Ui;
|
||||
using PolyTraderSharp;
|
||||
using PolyTraderSharp.Models;
|
||||
using PolyTraderSharp.Services;
|
||||
@@ -81,24 +80,22 @@ namespace PolyTrader.Modules.CopyTrading
|
||||
services.AddHostedService(sp => sp.GetRequiredService<SellLadderService>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aktuell ohne Ansicht: Die WinForms-UI wurde mit der Linux-Portierung entfernt, die
|
||||
/// Avalonia-Ansicht folgt (Stufe L3/L4). Die Fachlogik dieses Moduls laeuft davon
|
||||
/// unabhaengig weiter – die Shell zeigt schlicht kein Fenster fuer das Modul an.
|
||||
///
|
||||
/// <para><b>Beim Nachbau zu erhalten</b> (Spezifikation: docs/UI-SPEZIFIKATION-WinForms.md,
|
||||
/// Originalcode: Git-Tag <c>winforms-final</c>):</para>
|
||||
/// <list type="bullet">
|
||||
/// <item>View-ID <c>copytrading.main</c> (stabil – Launcher-Button und Symbol haengen daran)</item>
|
||||
/// <item>Titel <c>Copytrading</c>, Gruppe <c>CopyTrading</c>, Order <c>100</c></item>
|
||||
/// <item>Ein Fenster fuers ganze Modul: CopyTradingMainForm mit Tabs: Master-Trader / Offene Trades / Geschlossene Trades / Account-Einstellungen</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public void RegisterUi(IModuleUiHost host, IServiceProvider services)
|
||||
{
|
||||
// EIN Fenster fürs ganze Modul: die einzelnen Ansichten sind Tabs im
|
||||
// CopyTradingMainForm (Master-Trader / geschlossene Trades / Account-Einstellungen).
|
||||
// So bleibt der Launcher schlank – ein Button je Modul statt je View.
|
||||
host.RegisterView(new ModuleView
|
||||
{
|
||||
Id = "copytrading.main",
|
||||
Title = "Copytrading",
|
||||
Group = "CopyTrading",
|
||||
Order = 100,
|
||||
CreateView = () =>
|
||||
{
|
||||
var form = new CopyTradingMainForm();
|
||||
form.Initialize(services);
|
||||
return form;
|
||||
}
|
||||
});
|
||||
// Bewusst leer, bis die Avalonia-Ansicht steht (siehe Doku oben).
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PolyTrader.Core\PolyTrader.Core.csproj" />
|
||||
@@ -20,11 +20,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<!-- Linux-Portierung: plattformneutral. Die WinForms-UI dieses Moduls (Trading-Engine, SELL-Leiter, Master-Trader-Analytics)
|
||||
wurde entfernt; die Avalonia-Ansicht kommt spaeter direkt hierher zurueck – Avalonia ist
|
||||
im Gegensatz zu WinForms plattformuebergreifend und braucht kein eigenes UI-Projekt. -->
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<!-- Modul trägt später eigene WinForms-UI-Tabs bei. -->
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
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.toolbar = new System.Windows.Forms.ToolStrip();
|
||||
this.tsAccountLabel = new System.Windows.Forms.ToolStripLabel();
|
||||
this.tsAccounts = new System.Windows.Forms.ToolStripComboBox();
|
||||
this.tsSep = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.tsSave = new System.Windows.Forms.ToolStripButton();
|
||||
this.pgSettings = new System.Windows.Forms.PropertyGrid();
|
||||
this.statusPanel = new System.Windows.Forms.Panel();
|
||||
this.lblHint = new System.Windows.Forms.Label();
|
||||
this.toolbar.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.tsAccountLabel,
|
||||
this.tsAccounts,
|
||||
this.tsSep,
|
||||
this.tsSave});
|
||||
this.toolbar.Location = new System.Drawing.Point(0, 0);
|
||||
this.toolbar.Name = "toolbar";
|
||||
this.toolbar.Size = new System.Drawing.Size(560, 25);
|
||||
this.toolbar.TabIndex = 0;
|
||||
//
|
||||
// tsAccountLabel
|
||||
//
|
||||
this.tsAccountLabel.Name = "tsAccountLabel";
|
||||
this.tsAccountLabel.Size = new System.Drawing.Size(56, 22);
|
||||
this.tsAccountLabel.Text = "Account:";
|
||||
//
|
||||
// tsAccounts
|
||||
//
|
||||
this.tsAccounts.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.tsAccounts.Name = "tsAccounts";
|
||||
this.tsAccounts.Size = new System.Drawing.Size(320, 25);
|
||||
//
|
||||
// tsSep
|
||||
//
|
||||
this.tsSep.Name = "tsSep";
|
||||
this.tsSep.Size = new System.Drawing.Size(6, 25);
|
||||
//
|
||||
// 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";
|
||||
//
|
||||
// pgSettings
|
||||
//
|
||||
this.pgSettings.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.pgSettings.Location = new System.Drawing.Point(0, 25);
|
||||
this.pgSettings.Name = "pgSettings";
|
||||
this.pgSettings.PropertySort = System.Windows.Forms.PropertySort.Categorized;
|
||||
this.pgSettings.Size = new System.Drawing.Size(560, 549);
|
||||
this.pgSettings.TabIndex = 1;
|
||||
this.pgSettings.ToolbarVisible = false;
|
||||
//
|
||||
// statusPanel
|
||||
//
|
||||
this.statusPanel.Controls.Add(this.lblHint);
|
||||
this.statusPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.statusPanel.Location = new System.Drawing.Point(0, 574);
|
||||
this.statusPanel.Name = "statusPanel";
|
||||
this.statusPanel.Size = new System.Drawing.Size(560, 26);
|
||||
this.statusPanel.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(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(560, 26);
|
||||
this.lblHint.TabIndex = 0;
|
||||
this.lblHint.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// AccountSettingsView
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.pgSettings);
|
||||
this.Controls.Add(this.statusPanel);
|
||||
this.Controls.Add(this.toolbar);
|
||||
this.Name = "AccountSettingsView";
|
||||
this.Size = new System.Drawing.Size(560, 600);
|
||||
this.toolbar.ResumeLayout(false);
|
||||
this.toolbar.PerformLayout();
|
||||
this.statusPanel.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ToolStrip toolbar;
|
||||
private System.Windows.Forms.ToolStripLabel tsAccountLabel;
|
||||
private System.Windows.Forms.ToolStripComboBox tsAccounts;
|
||||
private System.Windows.Forms.ToolStripSeparator tsSep;
|
||||
private System.Windows.Forms.ToolStripButton tsSave;
|
||||
private System.Windows.Forms.PropertyGrid pgSettings;
|
||||
private System.Windows.Forms.Panel statusPanel;
|
||||
private System.Windows.Forms.Label lblHint;
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using PolyTrader.Modules.CopyTrading.Persistence;
|
||||
using PolyTraderSharp;
|
||||
using PolyTraderSharp.Models;
|
||||
|
||||
namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
{
|
||||
/// <summary>
|
||||
/// 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 partial class AccountSettingsView : UserControl
|
||||
{
|
||||
private ICopyTradingAccountSettingsRepository? _repo;
|
||||
private TradingState? _state;
|
||||
private CopyTradingState? _copyState;
|
||||
|
||||
private CopyTradingAccountSettings? _current;
|
||||
|
||||
// Parameterloser Konstruktor für den WinForms-Designer.
|
||||
public AccountSettingsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
tsAccounts.SelectedIndexChanged += (_, _) => LoadSelected();
|
||||
tsSave.Click += (_, _) => Save();
|
||||
}
|
||||
|
||||
/// <summary>Injiziert die Abhängigkeiten (nach der DI-Auflösung) und füllt die Auswahl.</summary>
|
||||
public void Initialize(ICopyTradingAccountSettingsRepository repo, TradingState state, CopyTradingState copyState)
|
||||
{
|
||||
_repo = repo;
|
||||
_state = state;
|
||||
_copyState = copyState;
|
||||
PopulateAccounts();
|
||||
}
|
||||
|
||||
private void PopulateAccounts()
|
||||
{
|
||||
if (_state == null) return;
|
||||
|
||||
var items = _state.Accounts.Values
|
||||
.OrderBy(a => a.AccountId)
|
||||
.Select(a => new AccountItem(a.AccountId, string.IsNullOrEmpty(a.Name) ? $"#{a.AccountId}" : $"{a.Name} (#{a.AccountId}){(a.IsDemo ? " · Demo" : "")}"))
|
||||
.ToList();
|
||||
|
||||
tsAccounts.ComboBox.DisplayMember = nameof(AccountItem.Label);
|
||||
tsAccounts.ComboBox.ValueMember = nameof(AccountItem.Id);
|
||||
tsAccounts.ComboBox.DataSource = items;
|
||||
|
||||
if (items.Count > 0) LoadSelected();
|
||||
else lblHint.Text = "Keine Accounts vorhanden.";
|
||||
}
|
||||
|
||||
private void LoadSelected()
|
||||
{
|
||||
if (_repo == null || tsAccounts.SelectedItem is not AccountItem item) return;
|
||||
_current = _repo.Get(item.Id) ?? new CopyTradingAccountSettings { AccountId = item.Id };
|
||||
pgSettings.SelectedObject = _current;
|
||||
lblHint.Text = $"Einstellungen für Account #{item.Id}.";
|
||||
}
|
||||
|
||||
private void Save()
|
||||
{
|
||||
if (_current == null || _repo == null || _copyState == null) return;
|
||||
_repo.Upsert(_current);
|
||||
_copyState.AccountSettings[_current.AccountId] = _current;
|
||||
lblHint.Text = $"Gespeichert für Account #{_current.AccountId} um {DateTime.Now:HH:mm:ss}.";
|
||||
}
|
||||
|
||||
private sealed record AccountItem(int Id, string Label);
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -1,392 +0,0 @@
|
||||
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.toolbar = new System.Windows.Forms.ToolStrip();
|
||||
this.tsRefresh = new System.Windows.Forms.ToolStripButton();
|
||||
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.statusPanel = new System.Windows.Forms.Panel();
|
||||
this.lblSummary = new System.Windows.Forms.Label();
|
||||
this.pnlFilters = new System.Windows.Forms.Panel();
|
||||
this.lblMarkt = new System.Windows.Forms.Label();
|
||||
this.tbMarket = new System.Windows.Forms.TextBox();
|
||||
this.lblMaster = new System.Windows.Forms.Label();
|
||||
this.cbMaster = new System.Windows.Forms.ComboBox();
|
||||
this.lblErgebnis = new System.Windows.Forms.Label();
|
||||
this.cbResult = new System.Windows.Forms.ComboBox();
|
||||
this.lblVon = new System.Windows.Forms.Label();
|
||||
this.dtFrom = new System.Windows.Forms.DateTimePicker();
|
||||
this.lblBis = new System.Windows.Forms.Label();
|
||||
this.dtTo = new System.Windows.Forms.DateTimePicker();
|
||||
this.btnReset = new System.Windows.Forms.Button();
|
||||
this.toolbar.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgvTrades)).BeginInit();
|
||||
this.statusPanel.SuspendLayout();
|
||||
this.pnlFilters.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// toolbar
|
||||
//
|
||||
this.toolbar.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
|
||||
this.toolbar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.tsRefresh});
|
||||
this.toolbar.Location = new System.Drawing.Point(0, 0);
|
||||
this.toolbar.Name = "toolbar";
|
||||
this.toolbar.Size = new System.Drawing.Size(1100, 25);
|
||||
this.toolbar.TabIndex = 0;
|
||||
//
|
||||
// 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";
|
||||
//
|
||||
// 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, 25);
|
||||
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, 549);
|
||||
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;
|
||||
//
|
||||
// statusPanel
|
||||
//
|
||||
this.statusPanel.Controls.Add(this.lblSummary);
|
||||
this.statusPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.statusPanel.Location = new System.Drawing.Point(0, 574);
|
||||
this.statusPanel.Name = "statusPanel";
|
||||
this.statusPanel.Size = new System.Drawing.Size(1100, 26);
|
||||
this.statusPanel.TabIndex = 2;
|
||||
//
|
||||
// lblSummary
|
||||
//
|
||||
this.lblSummary.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.lblSummary.Location = new System.Drawing.Point(0, 0);
|
||||
this.lblSummary.Name = "lblSummary";
|
||||
this.lblSummary.Padding = new System.Windows.Forms.Padding(8, 0, 0, 0);
|
||||
this.lblSummary.Size = new System.Drawing.Size(1100, 26);
|
||||
this.lblSummary.TabIndex = 0;
|
||||
this.lblSummary.Text = "—";
|
||||
this.lblSummary.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// pnlFilters
|
||||
//
|
||||
this.pnlFilters.Controls.Add(this.lblMarkt);
|
||||
this.pnlFilters.Controls.Add(this.tbMarket);
|
||||
this.pnlFilters.Controls.Add(this.lblMaster);
|
||||
this.pnlFilters.Controls.Add(this.cbMaster);
|
||||
this.pnlFilters.Controls.Add(this.lblErgebnis);
|
||||
this.pnlFilters.Controls.Add(this.cbResult);
|
||||
this.pnlFilters.Controls.Add(this.lblVon);
|
||||
this.pnlFilters.Controls.Add(this.dtFrom);
|
||||
this.pnlFilters.Controls.Add(this.lblBis);
|
||||
this.pnlFilters.Controls.Add(this.dtTo);
|
||||
this.pnlFilters.Controls.Add(this.btnReset);
|
||||
this.pnlFilters.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.pnlFilters.Location = new System.Drawing.Point(0, 25);
|
||||
this.pnlFilters.Name = "pnlFilters";
|
||||
this.pnlFilters.Size = new System.Drawing.Size(1100, 34);
|
||||
this.pnlFilters.TabIndex = 3;
|
||||
//
|
||||
// lblMarkt
|
||||
//
|
||||
this.lblMarkt.AutoSize = true;
|
||||
this.lblMarkt.Location = new System.Drawing.Point(6, 9);
|
||||
this.lblMarkt.Name = "lblMarkt";
|
||||
this.lblMarkt.Size = new System.Drawing.Size(41, 15);
|
||||
this.lblMarkt.Text = "Markt:";
|
||||
//
|
||||
// tbMarket
|
||||
//
|
||||
this.tbMarket.Location = new System.Drawing.Point(51, 6);
|
||||
this.tbMarket.Name = "tbMarket";
|
||||
this.tbMarket.PlaceholderText = "Suchtext …";
|
||||
this.tbMarket.Size = new System.Drawing.Size(200, 23);
|
||||
this.tbMarket.TabIndex = 0;
|
||||
//
|
||||
// lblMaster
|
||||
//
|
||||
this.lblMaster.AutoSize = true;
|
||||
this.lblMaster.Location = new System.Drawing.Point(263, 9);
|
||||
this.lblMaster.Name = "lblMaster";
|
||||
this.lblMaster.Size = new System.Drawing.Size(48, 15);
|
||||
this.lblMaster.Text = "Master:";
|
||||
//
|
||||
// cbMaster
|
||||
//
|
||||
this.cbMaster.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cbMaster.Location = new System.Drawing.Point(315, 6);
|
||||
this.cbMaster.Name = "cbMaster";
|
||||
this.cbMaster.Size = new System.Drawing.Size(170, 23);
|
||||
this.cbMaster.TabIndex = 1;
|
||||
//
|
||||
// lblErgebnis
|
||||
//
|
||||
this.lblErgebnis.AutoSize = true;
|
||||
this.lblErgebnis.Location = new System.Drawing.Point(497, 9);
|
||||
this.lblErgebnis.Name = "lblErgebnis";
|
||||
this.lblErgebnis.Size = new System.Drawing.Size(58, 15);
|
||||
this.lblErgebnis.Text = "Ergebnis:";
|
||||
//
|
||||
// cbResult
|
||||
//
|
||||
this.cbResult.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cbResult.Items.AddRange(new object[] { "Alle", "Gewinner", "Verlierer" });
|
||||
this.cbResult.Location = new System.Drawing.Point(559, 6);
|
||||
this.cbResult.Name = "cbResult";
|
||||
this.cbResult.Size = new System.Drawing.Size(110, 23);
|
||||
this.cbResult.TabIndex = 2;
|
||||
//
|
||||
// lblVon
|
||||
//
|
||||
this.lblVon.AutoSize = true;
|
||||
this.lblVon.Location = new System.Drawing.Point(681, 9);
|
||||
this.lblVon.Name = "lblVon";
|
||||
this.lblVon.Size = new System.Drawing.Size(31, 15);
|
||||
this.lblVon.Text = "Von:";
|
||||
//
|
||||
// dtFrom
|
||||
//
|
||||
this.dtFrom.Checked = false;
|
||||
this.dtFrom.Format = System.Windows.Forms.DateTimePickerFormat.Short;
|
||||
this.dtFrom.Location = new System.Drawing.Point(714, 6);
|
||||
this.dtFrom.Name = "dtFrom";
|
||||
this.dtFrom.ShowCheckBox = true;
|
||||
this.dtFrom.Size = new System.Drawing.Size(120, 23);
|
||||
this.dtFrom.TabIndex = 3;
|
||||
//
|
||||
// lblBis
|
||||
//
|
||||
this.lblBis.AutoSize = true;
|
||||
this.lblBis.Location = new System.Drawing.Point(840, 9);
|
||||
this.lblBis.Name = "lblBis";
|
||||
this.lblBis.Size = new System.Drawing.Size(26, 15);
|
||||
this.lblBis.Text = "Bis:";
|
||||
//
|
||||
// dtTo
|
||||
//
|
||||
this.dtTo.Checked = false;
|
||||
this.dtTo.Format = System.Windows.Forms.DateTimePickerFormat.Short;
|
||||
this.dtTo.Location = new System.Drawing.Point(868, 6);
|
||||
this.dtTo.Name = "dtTo";
|
||||
this.dtTo.ShowCheckBox = true;
|
||||
this.dtTo.Size = new System.Drawing.Size(120, 23);
|
||||
this.dtTo.TabIndex = 4;
|
||||
//
|
||||
// btnReset
|
||||
//
|
||||
this.btnReset.Location = new System.Drawing.Point(994, 5);
|
||||
this.btnReset.Name = "btnReset";
|
||||
this.btnReset.Size = new System.Drawing.Size(90, 25);
|
||||
this.btnReset.TabIndex = 5;
|
||||
this.btnReset.Text = "Zurücksetzen";
|
||||
this.btnReset.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ClosedTradesView
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.dgvTrades);
|
||||
this.Controls.Add(this.statusPanel);
|
||||
this.Controls.Add(this.pnlFilters);
|
||||
this.Controls.Add(this.toolbar);
|
||||
this.Name = "ClosedTradesView";
|
||||
this.Size = new System.Drawing.Size(1100, 600);
|
||||
this.toolbar.ResumeLayout(false);
|
||||
this.toolbar.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgvTrades)).EndInit();
|
||||
this.statusPanel.ResumeLayout(false);
|
||||
this.pnlFilters.ResumeLayout(false);
|
||||
this.pnlFilters.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ToolStrip toolbar;
|
||||
private System.Windows.Forms.ToolStripButton tsRefresh;
|
||||
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;
|
||||
private System.Windows.Forms.Panel statusPanel;
|
||||
private System.Windows.Forms.Label lblSummary;
|
||||
private System.Windows.Forms.Panel pnlFilters;
|
||||
private System.Windows.Forms.Label lblMarkt;
|
||||
private System.Windows.Forms.TextBox tbMarket;
|
||||
private System.Windows.Forms.Label lblMaster;
|
||||
private System.Windows.Forms.ComboBox cbMaster;
|
||||
private System.Windows.Forms.Label lblErgebnis;
|
||||
private System.Windows.Forms.ComboBox cbResult;
|
||||
private System.Windows.Forms.Label lblVon;
|
||||
private System.Windows.Forms.DateTimePicker dtFrom;
|
||||
private System.Windows.Forms.Label lblBis;
|
||||
private System.Windows.Forms.DateTimePicker dtTo;
|
||||
private System.Windows.Forms.Button btnReset;
|
||||
}
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using PolyTrader.Modules.CopyTrading.Logic;
|
||||
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;
|
||||
|
||||
private List<ClosedTradeRow> _allRows = new();
|
||||
private bool _loading;
|
||||
|
||||
// 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";
|
||||
|
||||
tsRefresh.Click += (_, _) => LoadData();
|
||||
|
||||
// Zeilenfärbung nach PnL-% (grün/hellgrün/rot) nach jedem (Neu-)Binden.
|
||||
dgvTrades.DataBindingComplete += (_, _) => ColorRows();
|
||||
|
||||
// Filter: Markt (Text), Master (Combo), Ergebnis (Win/Loss), Datum (Von/Bis, optional).
|
||||
tbMarket.TextChanged += (_, _) => ApplyFilter();
|
||||
cbMaster.SelectedIndexChanged += (_, _) => ApplyFilter();
|
||||
cbResult.SelectedIndexChanged += (_, _) => ApplyFilter();
|
||||
dtFrom.ValueChanged += (_, _) => ApplyFilter();
|
||||
dtTo.ValueChanged += (_, _) => ApplyFilter();
|
||||
btnReset.Click += (_, _) => ResetFilters();
|
||||
if (cbResult.Items.Count > 0) cbResult.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
_allRows = _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();
|
||||
|
||||
PopulateMasters();
|
||||
ApplyFilter();
|
||||
}
|
||||
|
||||
private void PopulateMasters()
|
||||
{
|
||||
_loading = true;
|
||||
string prev = cbMaster.SelectedItem as string ?? "Alle";
|
||||
cbMaster.Items.Clear();
|
||||
cbMaster.Items.Add("Alle");
|
||||
foreach (var m in _allRows.Select(r => r.SourceTraderName)
|
||||
.Where(s => !string.IsNullOrEmpty(s)).Distinct().OrderBy(s => s))
|
||||
cbMaster.Items.Add(m);
|
||||
int idx = cbMaster.Items.IndexOf(prev);
|
||||
cbMaster.SelectedIndex = idx >= 0 ? idx : 0;
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
private void ApplyFilter()
|
||||
{
|
||||
if (_loading) return;
|
||||
|
||||
IEnumerable<ClosedTradeRow> q = _allRows;
|
||||
|
||||
string market = tbMarket.Text.Trim();
|
||||
if (market.Length > 0)
|
||||
q = q.Where(r => (r.MarketQuestion?.Contains(market, StringComparison.OrdinalIgnoreCase) ?? false)
|
||||
|| (r.MarketSlug?.Contains(market, StringComparison.OrdinalIgnoreCase) ?? false));
|
||||
|
||||
if (cbMaster.SelectedItem is string master && master != "Alle")
|
||||
q = q.Where(r => r.SourceTraderName == master);
|
||||
|
||||
string result = cbResult.SelectedItem as string ?? "Alle";
|
||||
if (result == "Gewinner") q = q.Where(r => r.RealizedPnl > 0m);
|
||||
else if (result == "Verlierer") q = q.Where(r => r.RealizedPnl < 0m);
|
||||
|
||||
if (dtFrom.Checked) { DateTime f = dtFrom.Value.Date; q = q.Where(r => r.ClosedAt >= f); }
|
||||
if (dtTo.Checked) { DateTime t = dtTo.Value.Date.AddDays(1).AddTicks(-1); q = q.Where(r => r.ClosedAt <= t); }
|
||||
|
||||
var rows = q.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} / {_allRows.Count} Trades | PnL: {totalPnl:F2} USDC | Winrate: {winrate:F1}%";
|
||||
}
|
||||
|
||||
private void ResetFilters()
|
||||
{
|
||||
_loading = true;
|
||||
tbMarket.Text = string.Empty;
|
||||
if (cbMaster.Items.Count > 0) cbMaster.SelectedIndex = 0;
|
||||
if (cbResult.Items.Count > 0) cbResult.SelectedIndex = 0;
|
||||
dtFrom.Checked = false;
|
||||
dtTo.Checked = false;
|
||||
_loading = false;
|
||||
ApplyFilter();
|
||||
}
|
||||
|
||||
private void ColorRows()
|
||||
{
|
||||
foreach (DataGridViewRow row in dgvTrades.Rows)
|
||||
if (row.DataBoundItem is ClosedTradeRow r)
|
||||
row.DefaultCellStyle.BackColor = TradeRowPalette.ForPnlPercent(r.PnlPercent);
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
{
|
||||
partial class CopyTradingMainForm
|
||||
{
|
||||
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()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CopyTradingMainForm));
|
||||
tabControl = new TabControl();
|
||||
tabMasters = new TabPage();
|
||||
masterTradersView = new MasterTradersView();
|
||||
tabOpen = new TabPage();
|
||||
openTradesView = new OpenTradesView();
|
||||
tabClosed = new TabPage();
|
||||
closedTradesView = new ClosedTradesView();
|
||||
tabSettings = new TabPage();
|
||||
accountSettingsView = new AccountSettingsView();
|
||||
tabControl.SuspendLayout();
|
||||
tabMasters.SuspendLayout();
|
||||
tabOpen.SuspendLayout();
|
||||
tabClosed.SuspendLayout();
|
||||
tabSettings.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// tabControl
|
||||
//
|
||||
tabControl.Controls.Add(tabMasters);
|
||||
tabControl.Controls.Add(tabOpen);
|
||||
tabControl.Controls.Add(tabClosed);
|
||||
tabControl.Controls.Add(tabSettings);
|
||||
tabControl.Dock = DockStyle.Fill;
|
||||
tabControl.Location = new Point(0, 0);
|
||||
tabControl.Margin = new Padding(4, 5, 4, 5);
|
||||
tabControl.Name = "tabControl";
|
||||
tabControl.SelectedIndex = 0;
|
||||
tabControl.Size = new Size(1714, 1167);
|
||||
tabControl.TabIndex = 0;
|
||||
//
|
||||
// tabMasters
|
||||
//
|
||||
tabMasters.Controls.Add(masterTradersView);
|
||||
tabMasters.Location = new Point(4, 34);
|
||||
tabMasters.Margin = new Padding(4, 5, 4, 5);
|
||||
tabMasters.Name = "tabMasters";
|
||||
tabMasters.Padding = new Padding(4, 5, 4, 5);
|
||||
tabMasters.Size = new Size(1706, 1129);
|
||||
tabMasters.TabIndex = 0;
|
||||
tabMasters.Text = "Master-Trader";
|
||||
tabMasters.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// masterTradersView
|
||||
//
|
||||
masterTradersView.Dock = DockStyle.Fill;
|
||||
masterTradersView.Location = new Point(4, 5);
|
||||
masterTradersView.Margin = new Padding(6, 8, 6, 8);
|
||||
masterTradersView.Name = "masterTradersView";
|
||||
masterTradersView.Size = new Size(1698, 1119);
|
||||
masterTradersView.TabIndex = 0;
|
||||
//
|
||||
// tabOpen
|
||||
//
|
||||
tabOpen.Controls.Add(openTradesView);
|
||||
tabOpen.Location = new Point(4, 34);
|
||||
tabOpen.Margin = new Padding(4, 5, 4, 5);
|
||||
tabOpen.Name = "tabOpen";
|
||||
tabOpen.Padding = new Padding(4, 5, 4, 5);
|
||||
tabOpen.Size = new Size(1706, 1129);
|
||||
tabOpen.TabIndex = 3;
|
||||
tabOpen.Text = "Offene Trades";
|
||||
tabOpen.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// openTradesView
|
||||
//
|
||||
openTradesView.Dock = DockStyle.Fill;
|
||||
openTradesView.Location = new Point(4, 5);
|
||||
openTradesView.Margin = new Padding(6, 8, 6, 8);
|
||||
openTradesView.Name = "openTradesView";
|
||||
openTradesView.Size = new Size(1698, 1119);
|
||||
openTradesView.TabIndex = 0;
|
||||
//
|
||||
// tabClosed
|
||||
//
|
||||
tabClosed.Controls.Add(closedTradesView);
|
||||
tabClosed.Location = new Point(4, 34);
|
||||
tabClosed.Margin = new Padding(4, 5, 4, 5);
|
||||
tabClosed.Name = "tabClosed";
|
||||
tabClosed.Padding = new Padding(4, 5, 4, 5);
|
||||
tabClosed.Size = new Size(1706, 1129);
|
||||
tabClosed.TabIndex = 1;
|
||||
tabClosed.Text = "Geschlossene Trades";
|
||||
tabClosed.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// closedTradesView
|
||||
//
|
||||
closedTradesView.Dock = DockStyle.Fill;
|
||||
closedTradesView.Location = new Point(4, 5);
|
||||
closedTradesView.Margin = new Padding(6, 8, 6, 8);
|
||||
closedTradesView.Name = "closedTradesView";
|
||||
closedTradesView.Size = new Size(1698, 1119);
|
||||
closedTradesView.TabIndex = 0;
|
||||
//
|
||||
// tabSettings
|
||||
//
|
||||
tabSettings.Controls.Add(accountSettingsView);
|
||||
tabSettings.Location = new Point(4, 34);
|
||||
tabSettings.Margin = new Padding(4, 5, 4, 5);
|
||||
tabSettings.Name = "tabSettings";
|
||||
tabSettings.Padding = new Padding(4, 5, 4, 5);
|
||||
tabSettings.Size = new Size(1706, 1129);
|
||||
tabSettings.TabIndex = 2;
|
||||
tabSettings.Text = "Account-Einstellungen";
|
||||
tabSettings.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// accountSettingsView
|
||||
//
|
||||
accountSettingsView.Dock = DockStyle.Fill;
|
||||
accountSettingsView.Location = new Point(4, 5);
|
||||
accountSettingsView.Margin = new Padding(6, 8, 6, 8);
|
||||
accountSettingsView.Name = "accountSettingsView";
|
||||
accountSettingsView.Size = new Size(1698, 1119);
|
||||
accountSettingsView.TabIndex = 0;
|
||||
//
|
||||
// CopyTradingMainForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(10F, 25F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(1714, 1167);
|
||||
Controls.Add(tabControl);
|
||||
Icon = (Icon)resources.GetObject("$this.Icon");
|
||||
Margin = new Padding(4, 5, 4, 5);
|
||||
MinimumSize = new Size(1162, 763);
|
||||
Name = "CopyTradingMainForm";
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Text = "Copytrading";
|
||||
tabControl.ResumeLayout(false);
|
||||
tabMasters.ResumeLayout(false);
|
||||
tabOpen.ResumeLayout(false);
|
||||
tabClosed.ResumeLayout(false);
|
||||
tabSettings.ResumeLayout(false);
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TabControl tabControl;
|
||||
private System.Windows.Forms.TabPage tabMasters;
|
||||
private System.Windows.Forms.TabPage tabOpen;
|
||||
private System.Windows.Forms.TabPage tabClosed;
|
||||
private System.Windows.Forms.TabPage tabSettings;
|
||||
private MasterTradersView masterTradersView;
|
||||
private OpenTradesView openTradesView;
|
||||
private ClosedTradesView closedTradesView;
|
||||
private AccountSettingsView accountSettingsView;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using PolyTrader.Modules.CopyTrading.Persistence;
|
||||
using PolyTraderSharp;
|
||||
|
||||
namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
{
|
||||
/// <summary>
|
||||
/// Das Hauptfenster des Copytrading-Moduls. Bündelt alle Modul-Ansichten in einem
|
||||
/// TabControl (Master-Trader, geschlossene Trades, Account-Einstellungen), sodass der
|
||||
/// Launcher nur EINEN "Copytrading"-Button braucht und nicht je View ein eigenes Fenster
|
||||
/// öffnet. Layout im Designer (CopyTradingMainForm.Designer.cs).
|
||||
/// </summary>
|
||||
public partial class CopyTradingMainForm : Form
|
||||
{
|
||||
// Parameterloser Konstruktor für den WinForms-Designer.
|
||||
public CopyTradingMainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
/// <summary>Versorgt die einzelnen Tab-Ansichten mit ihren Abhängigkeiten (aus dem DI-Container).</summary>
|
||||
public void Initialize(IServiceProvider services)
|
||||
{
|
||||
var state = services.GetRequiredService<TradingState>();
|
||||
var copyState = services.GetRequiredService<CopyTradingState>();
|
||||
|
||||
masterTradersView.Initialize(
|
||||
services.GetRequiredService<ITrackedTraderRepository>(), state, copyState);
|
||||
|
||||
openTradesView.Initialize(state, copyState);
|
||||
|
||||
closedTradesView.Initialize(
|
||||
services.GetRequiredService<ICopyTradeLogRepository>(), state, copyState);
|
||||
|
||||
accountSettingsView.Initialize(
|
||||
services.GetRequiredService<ICopyTradingAccountSettingsRepository>(), state, copyState);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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
|
||||
YII=
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,348 +0,0 @@
|
||||
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.colCopyPnl = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colCopyPf = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colCopyAvg = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colCopyCount = 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.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
|
||||
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.colCopyPnl,
|
||||
this.colCopyPf,
|
||||
this.colCopyAvg,
|
||||
this.colCopyCount});
|
||||
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;
|
||||
//
|
||||
// colCopyPnl
|
||||
//
|
||||
this.colCopyPnl.DataPropertyName = "CopyPnl30d";
|
||||
this.colCopyPnl.HeaderText = "Copy-PnL (30T)";
|
||||
this.colCopyPnl.Name = "colCopyPnl";
|
||||
this.colCopyPnl.ReadOnly = true;
|
||||
this.colCopyPnl.Width = 110;
|
||||
//
|
||||
// colCopyPf
|
||||
//
|
||||
this.colCopyPf.DataPropertyName = "CopyProfitFactor";
|
||||
this.colCopyPf.HeaderText = "Profit-Faktor";
|
||||
this.colCopyPf.Name = "colCopyPf";
|
||||
this.colCopyPf.ReadOnly = true;
|
||||
this.colCopyPf.Width = 100;
|
||||
//
|
||||
// colCopyAvg
|
||||
//
|
||||
this.colCopyAvg.DataPropertyName = "CopyAvgPnlPerTrade";
|
||||
this.colCopyAvg.HeaderText = "Ø PnL/Trade";
|
||||
this.colCopyAvg.Name = "colCopyAvg";
|
||||
this.colCopyAvg.ReadOnly = true;
|
||||
this.colCopyAvg.Width = 100;
|
||||
//
|
||||
// colCopyCount
|
||||
//
|
||||
this.colCopyCount.DataPropertyName = "CopyTradeCount30d";
|
||||
this.colCopyCount.HeaderText = "Copy-Trades";
|
||||
this.colCopyCount.Name = "colCopyCount";
|
||||
this.colCopyCount.ReadOnly = true;
|
||||
this.colCopyCount.Width = 90;
|
||||
//
|
||||
// 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.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.Name = "MasterTradersView";
|
||||
this.Size = new System.Drawing.Size(1180, 640);
|
||||
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.DataGridViewTextBoxColumn colCopyPnl;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colCopyPf;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colCopyAvg;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colCopyCount;
|
||||
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,152 +0,0 @@
|
||||
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>
|
||||
/// Verwaltung der Master-Trader (mod_copytrading_traders): Liste, Detail-Editor
|
||||
/// (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 partial class MasterTradersView : UserControl
|
||||
{
|
||||
private ITrackedTraderRepository? _repo;
|
||||
private TradingState? _state;
|
||||
private CopyTradingState? _copyState;
|
||||
|
||||
private BindingList<TrackedTrader> _binding = new();
|
||||
private TrackedTrader? _current;
|
||||
|
||||
// Parameterloser Konstruktor für den WinForms-Designer.
|
||||
public MasterTradersView()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
colWinrate.DefaultCellStyle.Format = "F1";
|
||||
colPnl.DefaultCellStyle.Format = "F2";
|
||||
colCopyPnl.DefaultCellStyle.Format = "F2";
|
||||
colCopyPf.DefaultCellStyle.Format = "F2";
|
||||
colCopyAvg.DefaultCellStyle.Format = "F2";
|
||||
|
||||
// Spaltenbreiten proportional (grid-weites Fill): keine überlaufenden Fixbreiten mehr,
|
||||
// die Spalten teilen sich immer exakt die verfügbare Breite (Fix des „verbuggten" Grids).
|
||||
colId.FillWeight = 40;
|
||||
colWallet.FillWeight = 150;
|
||||
colName.FillWeight = 200;
|
||||
colCategory.FillWeight = 90;
|
||||
colActive.FillWeight = 50;
|
||||
colTrades.FillWeight = 85;
|
||||
colWinrate.FillWeight = 90;
|
||||
colPnl.FillWeight = 90;
|
||||
colCopyPnl.FillWeight = 110;
|
||||
colCopyPf.FillWeight = 95;
|
||||
colCopyAvg.FillWeight = 95;
|
||||
colCopyCount.FillWeight = 95;
|
||||
|
||||
tsNew.Click += (_, _) => AddNew();
|
||||
tsSave.Click += (_, _) => SaveCurrent();
|
||||
tsDelete.Click += (_, _) => DeleteCurrent();
|
||||
tsRefresh.Click += (_, _) => LoadData();
|
||||
grid.SelectionChanged += (_, _) => OnSelectionChanged();
|
||||
}
|
||||
|
||||
/// <summary>Injiziert die Abhängigkeiten (nach der DI-Auflösung) und lädt die Trader.</summary>
|
||||
public void Initialize(ITrackedTraderRepository repo, TradingState state, CopyTradingState copyState)
|
||||
{
|
||||
_repo = repo;
|
||||
_state = state;
|
||||
_copyState = copyState;
|
||||
LoadData();
|
||||
}
|
||||
|
||||
private void LoadData()
|
||||
{
|
||||
if (_repo == null) return;
|
||||
|
||||
var traders = _repo.GetAll().OrderBy(t => t.Id).ToList();
|
||||
_binding = new BindingList<TrackedTrader>(traders);
|
||||
grid.DataSource = _binding;
|
||||
if (traders.Count > 0)
|
||||
grid.CurrentCell = grid.Rows[0].Cells[0];
|
||||
else
|
||||
ClearDetail();
|
||||
lblHint.Text = $"{traders.Count} Master-Trader geladen.";
|
||||
}
|
||||
|
||||
private void OnSelectionChanged()
|
||||
{
|
||||
if (grid.CurrentRow?.DataBoundItem is TrackedTrader t)
|
||||
BindDetail(t);
|
||||
}
|
||||
|
||||
private void BindDetail(TrackedTrader trader)
|
||||
{
|
||||
_current = trader;
|
||||
pgDetail.SelectedObject = trader;
|
||||
|
||||
clbAccounts.Items.Clear();
|
||||
if (_state == null) return;
|
||||
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 = clbAccounts.Items.Add(new AccountItem(acc.AccountId, label));
|
||||
clbAccounts.SetItemChecked(idx, trader.AssignedAccountIds.Contains(acc.AccountId));
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearDetail()
|
||||
{
|
||||
_current = null;
|
||||
pgDetail.SelectedObject = null;
|
||||
clbAccounts.Items.Clear();
|
||||
}
|
||||
|
||||
private void AddNew()
|
||||
{
|
||||
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];
|
||||
lblHint.Text = $"Neuer Master-Trader #{nextId} – Felder ausfüllen und Speichern.";
|
||||
}
|
||||
|
||||
private void SaveCurrent()
|
||||
{
|
||||
if (_current == null || _repo == null || _copyState == null) { lblHint.Text = "Kein Trader ausgewählt."; return; }
|
||||
|
||||
_current.AssignedAccountIds = clbAccounts.CheckedItems.Cast<AccountItem>().Select(a => a.Id).ToHashSet();
|
||||
|
||||
_repo.Upsert(_current);
|
||||
_copyState.Traders[_current.Id] = _current;
|
||||
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 || _repo == null || _copyState == 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)
|
||||
return;
|
||||
|
||||
_repo.Delete(id);
|
||||
_copyState.Traders.TryRemove(id, out _);
|
||||
_binding.Remove(_current);
|
||||
ClearDetail();
|
||||
lblHint.Text = $"Master-Trader #{id} gelöscht.";
|
||||
}
|
||||
|
||||
private sealed record AccountItem(int Id, string Label)
|
||||
{
|
||||
public override string ToString() => Label;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -1,241 +0,0 @@
|
||||
namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
{
|
||||
partial class OpenTradesView
|
||||
{
|
||||
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.tsRefresh = new System.Windows.Forms.ToolStripButton();
|
||||
this.dgvOpen = new System.Windows.Forms.DataGridView();
|
||||
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.colCurrent = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colSize = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colAmount = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colValue = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colUnrealized = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colUnrealizedPct = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colStatus = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.statusPanel = new System.Windows.Forms.Panel();
|
||||
this.lblSummary = new System.Windows.Forms.Label();
|
||||
this.toolbar.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgvOpen)).BeginInit();
|
||||
this.statusPanel.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// toolbar
|
||||
//
|
||||
this.toolbar.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
|
||||
this.toolbar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.tsRefresh });
|
||||
this.toolbar.Location = new System.Drawing.Point(0, 0);
|
||||
this.toolbar.Name = "toolbar";
|
||||
this.toolbar.Size = new System.Drawing.Size(1100, 25);
|
||||
this.toolbar.TabIndex = 0;
|
||||
//
|
||||
// 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";
|
||||
//
|
||||
// dgvOpen
|
||||
//
|
||||
this.dgvOpen.AllowUserToAddRows = false;
|
||||
this.dgvOpen.AllowUserToDeleteRows = false;
|
||||
this.dgvOpen.AutoGenerateColumns = false;
|
||||
this.dgvOpen.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
|
||||
this.dgvOpen.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.dgvOpen.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
||||
this.colAccount, this.colTrader, this.colMarket, this.colOutcome, this.colSide,
|
||||
this.colEntry, this.colCurrent, this.colSize, this.colAmount, this.colValue,
|
||||
this.colUnrealized, this.colUnrealizedPct, this.colStatus});
|
||||
this.dgvOpen.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.dgvOpen.Location = new System.Drawing.Point(0, 25);
|
||||
this.dgvOpen.Name = "dgvOpen";
|
||||
this.dgvOpen.ReadOnly = true;
|
||||
this.dgvOpen.RowHeadersVisible = false;
|
||||
this.dgvOpen.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
||||
this.dgvOpen.Size = new System.Drawing.Size(1100, 549);
|
||||
this.dgvOpen.TabIndex = 1;
|
||||
//
|
||||
// colAccount
|
||||
//
|
||||
this.colAccount.DataPropertyName = "AccountName";
|
||||
this.colAccount.HeaderText = "Account";
|
||||
this.colAccount.Name = "colAccount";
|
||||
this.colAccount.ReadOnly = true;
|
||||
this.colAccount.FillWeight = 120;
|
||||
//
|
||||
// colTrader
|
||||
//
|
||||
this.colTrader.DataPropertyName = "SourceTraderName";
|
||||
this.colTrader.HeaderText = "Master-Trader";
|
||||
this.colTrader.Name = "colTrader";
|
||||
this.colTrader.ReadOnly = true;
|
||||
this.colTrader.FillWeight = 120;
|
||||
//
|
||||
// colMarket
|
||||
//
|
||||
this.colMarket.DataPropertyName = "MarketQuestion";
|
||||
this.colMarket.HeaderText = "Markt";
|
||||
this.colMarket.Name = "colMarket";
|
||||
this.colMarket.ReadOnly = true;
|
||||
this.colMarket.FillWeight = 240;
|
||||
//
|
||||
// colOutcome
|
||||
//
|
||||
this.colOutcome.DataPropertyName = "Outcome";
|
||||
this.colOutcome.HeaderText = "Outcome";
|
||||
this.colOutcome.Name = "colOutcome";
|
||||
this.colOutcome.ReadOnly = true;
|
||||
this.colOutcome.FillWeight = 80;
|
||||
//
|
||||
// colSide
|
||||
//
|
||||
this.colSide.DataPropertyName = "Side";
|
||||
this.colSide.HeaderText = "Side";
|
||||
this.colSide.Name = "colSide";
|
||||
this.colSide.ReadOnly = true;
|
||||
this.colSide.FillWeight = 55;
|
||||
//
|
||||
// colEntry
|
||||
//
|
||||
this.colEntry.DataPropertyName = "EntryPrice";
|
||||
this.colEntry.HeaderText = "Entry";
|
||||
this.colEntry.Name = "colEntry";
|
||||
this.colEntry.ReadOnly = true;
|
||||
this.colEntry.FillWeight = 65;
|
||||
//
|
||||
// colCurrent
|
||||
//
|
||||
this.colCurrent.DataPropertyName = "CurrentPrice";
|
||||
this.colCurrent.HeaderText = "Aktuell";
|
||||
this.colCurrent.Name = "colCurrent";
|
||||
this.colCurrent.ReadOnly = true;
|
||||
this.colCurrent.FillWeight = 65;
|
||||
//
|
||||
// colSize
|
||||
//
|
||||
this.colSize.DataPropertyName = "Size";
|
||||
this.colSize.HeaderText = "Size";
|
||||
this.colSize.Name = "colSize";
|
||||
this.colSize.ReadOnly = true;
|
||||
this.colSize.FillWeight = 70;
|
||||
//
|
||||
// colAmount
|
||||
//
|
||||
this.colAmount.DataPropertyName = "AmountUsd";
|
||||
this.colAmount.HeaderText = "Einsatz";
|
||||
this.colAmount.Name = "colAmount";
|
||||
this.colAmount.ReadOnly = true;
|
||||
this.colAmount.FillWeight = 80;
|
||||
//
|
||||
// colValue
|
||||
//
|
||||
this.colValue.DataPropertyName = "CurrentValueUsd";
|
||||
this.colValue.HeaderText = "Wert";
|
||||
this.colValue.Name = "colValue";
|
||||
this.colValue.ReadOnly = true;
|
||||
this.colValue.FillWeight = 80;
|
||||
//
|
||||
// colUnrealized
|
||||
//
|
||||
this.colUnrealized.DataPropertyName = "UnrealizedPnl";
|
||||
this.colUnrealized.HeaderText = "Buchgewinn";
|
||||
this.colUnrealized.Name = "colUnrealized";
|
||||
this.colUnrealized.ReadOnly = true;
|
||||
this.colUnrealized.FillWeight = 90;
|
||||
//
|
||||
// colUnrealizedPct
|
||||
//
|
||||
this.colUnrealizedPct.DataPropertyName = "UnrealizedPct";
|
||||
this.colUnrealizedPct.HeaderText = "Buchgew. %";
|
||||
this.colUnrealizedPct.Name = "colUnrealizedPct";
|
||||
this.colUnrealizedPct.ReadOnly = true;
|
||||
this.colUnrealizedPct.FillWeight = 80;
|
||||
//
|
||||
// colStatus
|
||||
//
|
||||
this.colStatus.DataPropertyName = "Status";
|
||||
this.colStatus.HeaderText = "Status";
|
||||
this.colStatus.Name = "colStatus";
|
||||
this.colStatus.ReadOnly = true;
|
||||
this.colStatus.FillWeight = 90;
|
||||
//
|
||||
// statusPanel
|
||||
//
|
||||
this.statusPanel.Controls.Add(this.lblSummary);
|
||||
this.statusPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.statusPanel.Location = new System.Drawing.Point(0, 574);
|
||||
this.statusPanel.Name = "statusPanel";
|
||||
this.statusPanel.Size = new System.Drawing.Size(1100, 26);
|
||||
this.statusPanel.TabIndex = 2;
|
||||
//
|
||||
// lblSummary
|
||||
//
|
||||
this.lblSummary.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.lblSummary.Location = new System.Drawing.Point(0, 0);
|
||||
this.lblSummary.Name = "lblSummary";
|
||||
this.lblSummary.Padding = new System.Windows.Forms.Padding(8, 0, 0, 0);
|
||||
this.lblSummary.Size = new System.Drawing.Size(1100, 26);
|
||||
this.lblSummary.TabIndex = 0;
|
||||
this.lblSummary.Text = "—";
|
||||
this.lblSummary.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// OpenTradesView
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.dgvOpen);
|
||||
this.Controls.Add(this.statusPanel);
|
||||
this.Controls.Add(this.toolbar);
|
||||
this.Name = "OpenTradesView";
|
||||
this.Size = new System.Drawing.Size(1100, 600);
|
||||
this.toolbar.ResumeLayout(false);
|
||||
this.toolbar.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgvOpen)).EndInit();
|
||||
this.statusPanel.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ToolStrip toolbar;
|
||||
private System.Windows.Forms.ToolStripButton tsRefresh;
|
||||
private System.Windows.Forms.DataGridView dgvOpen;
|
||||
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 colCurrent;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colSize;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colAmount;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colValue;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colUnrealized;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colUnrealizedPct;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colStatus;
|
||||
private System.Windows.Forms.Panel statusPanel;
|
||||
private System.Windows.Forms.Label lblSummary;
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using PolyTrader.Modules.CopyTrading.Logic;
|
||||
using PolyTraderSharp;
|
||||
using PolyTraderSharp.Models;
|
||||
|
||||
namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
{
|
||||
/// <summary>
|
||||
/// Listet ALLE aktuell offenen Positionen (Portfolios der Accounts) mit Buchgewinn/-verlust.
|
||||
/// Quelle ist der Laufzeit-State (<see cref="TradingState.Accounts"/>), nicht die DB – so ist die
|
||||
/// Anzeige live. Zeilenfärbung nach Buchgewinn-% (<see cref="TradeRowColoring"/>).
|
||||
/// Layout im Designer (OpenTradesView.Designer.cs).
|
||||
/// </summary>
|
||||
public partial class OpenTradesView : UserControl
|
||||
{
|
||||
private TradingState? _state;
|
||||
private CopyTradingState? _copyState;
|
||||
|
||||
public OpenTradesView()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
colEntry.DefaultCellStyle.Format = "F3";
|
||||
colCurrent.DefaultCellStyle.Format = "F3";
|
||||
colSize.DefaultCellStyle.Format = "F2";
|
||||
colAmount.DefaultCellStyle.Format = "F2";
|
||||
colValue.DefaultCellStyle.Format = "F2";
|
||||
colUnrealized.DefaultCellStyle.Format = "F2";
|
||||
colUnrealizedPct.DefaultCellStyle.Format = "F1";
|
||||
|
||||
tsRefresh.Click += (_, _) => LoadData();
|
||||
dgvOpen.DataBindingComplete += (_, _) => ColorRows();
|
||||
}
|
||||
|
||||
public void Initialize(TradingState state, CopyTradingState copyState)
|
||||
{
|
||||
_state = state;
|
||||
_copyState = copyState;
|
||||
LoadData();
|
||||
}
|
||||
|
||||
private void LoadData()
|
||||
{
|
||||
if (_state == null) return;
|
||||
|
||||
var rows = _state.Accounts.Values
|
||||
.SelectMany(a => a.OpenPositions.Values.Select(p => (acc: a, pos: p)))
|
||||
.OrderByDescending(x => x.pos.CurrentValueUsd)
|
||||
.Select(x =>
|
||||
{
|
||||
decimal unrealized = x.pos.CurrentValueUsd - x.pos.AmountUsd;
|
||||
decimal pct = x.pos.AmountUsd > 0m ? unrealized / x.pos.AmountUsd * 100m : 0m;
|
||||
return new OpenTradeRow
|
||||
{
|
||||
AccountName = ResolveAccount(x.acc.AccountId, x.pos.IsDemo),
|
||||
SourceTraderName = ResolveTrader(x.pos.SourceTraderId, x.pos.SourceTraderName),
|
||||
MarketQuestion = x.pos.MarketQuestion,
|
||||
Outcome = x.pos.Outcome,
|
||||
Side = x.pos.Side,
|
||||
EntryPrice = x.pos.EntryPrice,
|
||||
CurrentPrice = x.pos.CurrentPrice,
|
||||
Size = x.pos.Size,
|
||||
AmountUsd = x.pos.AmountUsd,
|
||||
CurrentValueUsd = x.pos.CurrentValueUsd,
|
||||
UnrealizedPnl = unrealized,
|
||||
UnrealizedPct = pct,
|
||||
Status = x.pos.ExitPending ? "Exit läuft" : "offen"
|
||||
};
|
||||
})
|
||||
.ToList();
|
||||
|
||||
dgvOpen.DataSource = new BindingList<OpenTradeRow>(rows);
|
||||
|
||||
decimal totalValue = rows.Sum(r => r.CurrentValueUsd);
|
||||
decimal totalUnrealized = rows.Sum(r => r.UnrealizedPnl);
|
||||
lblSummary.Text = $"{rows.Count} offene Positionen | Wert: {totalValue:F2} USDC | Buchgewinn: {totalUnrealized:F2} USDC";
|
||||
}
|
||||
|
||||
private void ColorRows()
|
||||
{
|
||||
foreach (DataGridViewRow row in dgvOpen.Rows)
|
||||
if (row.DataBoundItem is OpenTradeRow r)
|
||||
row.DefaultCellStyle.BackColor = TradeRowPalette.ForPnlPercent(r.UnrealizedPct);
|
||||
}
|
||||
|
||||
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, string fallback)
|
||||
{
|
||||
if (_copyState != null && _copyState.Traders.TryGetValue(traderId, out var t) && !string.IsNullOrEmpty(t.DisplayName))
|
||||
return t.DisplayName;
|
||||
return !string.IsNullOrEmpty(fallback) ? fallback : (traderId > 0 ? $"#{traderId}" : "System");
|
||||
}
|
||||
|
||||
/// <summary>Anzeige-Zeile für offene Positionen.</summary>
|
||||
private sealed class OpenTradeRow
|
||||
{
|
||||
public string AccountName { get; set; } = string.Empty;
|
||||
public string SourceTraderName { get; set; } = string.Empty;
|
||||
public string MarketQuestion { get; set; } = string.Empty;
|
||||
public string Outcome { get; set; } = string.Empty;
|
||||
public string Side { get; set; } = string.Empty;
|
||||
public decimal EntryPrice { get; set; }
|
||||
public decimal CurrentPrice { get; set; }
|
||||
public decimal Size { get; set; }
|
||||
public decimal AmountUsd { get; set; }
|
||||
public decimal CurrentValueUsd { get; set; }
|
||||
public decimal UnrealizedPnl { get; set; }
|
||||
public decimal UnrealizedPct { get; set; }
|
||||
public string Status { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System.Drawing;
|
||||
using PolyTrader.Modules.CopyTrading.Logic;
|
||||
|
||||
namespace PolyTrader.Modules.CopyTrading.Ui
|
||||
{
|
||||
/// <summary>
|
||||
/// WinForms-Farbpalette zu den <see cref="TradeRowTint"/>-Kategorien. Die Schwellenlogik liegt
|
||||
/// (getestet) in <see cref="TradeRowColoring"/>; hier steht nur noch, wie die Kategorien aussehen.
|
||||
/// Die Avalonia-UI bekommt später ihre eigene Palette zu denselben Kategorien.
|
||||
/// </summary>
|
||||
internal static class TradeRowPalette
|
||||
{
|
||||
public static readonly Color Loss = Color.FromArgb(245, 200, 200); // rot
|
||||
public static readonly Color SmallWin = Color.FromArgb(212, 240, 212); // hellgrün
|
||||
public static readonly Color BigWin = Color.FromArgb(140, 214, 140); // grün
|
||||
|
||||
public static Color For(TradeRowTint tint) => tint switch
|
||||
{
|
||||
TradeRowTint.Loss => Loss,
|
||||
TradeRowTint.BigWin => BigWin,
|
||||
_ => SmallWin
|
||||
};
|
||||
|
||||
/// <summary>Bequemlichkeit für die Grids: PnL-Prozent direkt in die Zeilenfarbe.</summary>
|
||||
public static Color ForPnlPercent(decimal pnlPercent) => For(TradeRowColoring.ForPnlPercent(pnlPercent));
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PolyTrader.Core\PolyTrader.Core.csproj" />
|
||||
@@ -20,11 +20,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<!-- Linux-Portierung: plattformneutral. Die WinForms-UI dieses Moduls (Scanner und Ausfuehrung)
|
||||
wurde entfernt; die Avalonia-Ansicht kommt spaeter direkt hierher zurueck – Avalonia ist
|
||||
im Gegensatz zu WinForms plattformuebergreifend und braucht kein eigenes UI-Projekt. -->
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<!-- Modul trägt eigene WinForms-UI-Tabs bei. -->
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -54,22 +54,22 @@ namespace PolyTrader.Modules.ResolutionFarming
|
||||
// Live-Marktquelle, Live-Execution, On-Chain-Auto-Redeem und Kalibrierung folgen (Zielland).
|
||||
}
|
||||
|
||||
public void RegisterUi(IModuleUiHost host, System.IServiceProvider services)
|
||||
/// <summary>
|
||||
/// Aktuell ohne Ansicht: Die WinForms-UI wurde mit der Linux-Portierung entfernt, die
|
||||
/// Avalonia-Ansicht folgt (Stufe L3/L4). Die Fachlogik dieses Moduls laeuft davon
|
||||
/// unabhaengig weiter – die Shell zeigt schlicht kein Fenster fuer das Modul an.
|
||||
///
|
||||
/// <para><b>Beim Nachbau zu erhalten</b> (Spezifikation: docs/UI-SPEZIFIKATION-WinForms.md,
|
||||
/// Originalcode: Git-Tag <c>winforms-final</c>):</para>
|
||||
/// <list type="bullet">
|
||||
/// <item>View-ID <c>resolutionfarming.main</c> (stabil – Launcher-Button und Symbol haengen daran)</item>
|
||||
/// <item>Titel <c>ResolutionFarming</c>, Gruppe <c>ResolutionFarming</c>, Order <c>200</c></item>
|
||||
/// <item>Ein Fenster fuers ganze Modul: ResolutionFarmingMainForm mit Tabs: Kandidaten / Positionen / Historie+Statistik / Settings</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public void RegisterUi(IModuleUiHost host, IServiceProvider services)
|
||||
{
|
||||
// EIN Fenster fürs ganze Modul (Tabs: Kandidaten/Positionen/Historie/Settings).
|
||||
host.RegisterView(new ModuleView
|
||||
{
|
||||
Id = "resolutionfarming.main",
|
||||
Title = "ResolutionFarming",
|
||||
Group = "ResolutionFarming",
|
||||
Order = 200,
|
||||
CreateView = () =>
|
||||
{
|
||||
var form = new Ui.ResolutionFarmingMainForm();
|
||||
form.Initialize(services);
|
||||
return form;
|
||||
}
|
||||
});
|
||||
// Bewusst leer, bis die Avalonia-Ansicht steht (siehe Doku oben).
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
-379
@@ -1,379 +0,0 @@
|
||||
namespace PolyTrader.Modules.ResolutionFarming.Ui
|
||||
{
|
||||
partial class ResolutionFarmingMainForm
|
||||
{
|
||||
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()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ResolutionFarmingMainForm));
|
||||
tabControlRf = new TabControl();
|
||||
tabKandidaten = new TabPage();
|
||||
dgvCandidates = new DataGridView();
|
||||
pnlCandTop = new Panel();
|
||||
btnCandRefresh = new Button();
|
||||
cbCandAccount = new ComboBox();
|
||||
lblCandKonto = new Label();
|
||||
tabPositionen = new TabPage();
|
||||
dgvPositions = new DataGridView();
|
||||
pnlPosTop = new Panel();
|
||||
btnPosRefresh = new Button();
|
||||
tabHistorie = new TabPage();
|
||||
dgvHistory = new DataGridView();
|
||||
lblHistSummary = new Label();
|
||||
pnlHistTop = new Panel();
|
||||
btnHistRefresh = new Button();
|
||||
tabSettings = new TabPage();
|
||||
pgSettings = new PropertyGrid();
|
||||
pnlSetTop = new Panel();
|
||||
btnSettingsSave = new Button();
|
||||
cbSettingsAccount = new ComboBox();
|
||||
lblSetKonto = new Label();
|
||||
lblRfStatus = new Label();
|
||||
tabControlRf.SuspendLayout();
|
||||
tabKandidaten.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)dgvCandidates).BeginInit();
|
||||
pnlCandTop.SuspendLayout();
|
||||
tabPositionen.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)dgvPositions).BeginInit();
|
||||
pnlPosTop.SuspendLayout();
|
||||
tabHistorie.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)dgvHistory).BeginInit();
|
||||
pnlHistTop.SuspendLayout();
|
||||
tabSettings.SuspendLayout();
|
||||
pnlSetTop.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// tabControlRf
|
||||
//
|
||||
tabControlRf.Controls.Add(tabKandidaten);
|
||||
tabControlRf.Controls.Add(tabPositionen);
|
||||
tabControlRf.Controls.Add(tabHistorie);
|
||||
tabControlRf.Controls.Add(tabSettings);
|
||||
tabControlRf.Dock = DockStyle.Fill;
|
||||
tabControlRf.Location = new Point(0, 0);
|
||||
tabControlRf.Margin = new Padding(4, 5, 4, 5);
|
||||
tabControlRf.Name = "tabControlRf";
|
||||
tabControlRf.SelectedIndex = 0;
|
||||
tabControlRf.Size = new Size(1429, 993);
|
||||
tabControlRf.TabIndex = 0;
|
||||
//
|
||||
// tabKandidaten
|
||||
//
|
||||
tabKandidaten.Controls.Add(dgvCandidates);
|
||||
tabKandidaten.Controls.Add(pnlCandTop);
|
||||
tabKandidaten.Location = new Point(4, 34);
|
||||
tabKandidaten.Margin = new Padding(4, 5, 4, 5);
|
||||
tabKandidaten.Name = "tabKandidaten";
|
||||
tabKandidaten.Padding = new Padding(4, 5, 4, 5);
|
||||
tabKandidaten.Size = new Size(1421, 955);
|
||||
tabKandidaten.TabIndex = 0;
|
||||
tabKandidaten.Text = "Kandidaten";
|
||||
tabKandidaten.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// dgvCandidates
|
||||
//
|
||||
dgvCandidates.AllowUserToAddRows = false;
|
||||
dgvCandidates.AllowUserToDeleteRows = false;
|
||||
dgvCandidates.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
dgvCandidates.Dock = DockStyle.Fill;
|
||||
dgvCandidates.Location = new Point(4, 62);
|
||||
dgvCandidates.Margin = new Padding(4, 5, 4, 5);
|
||||
dgvCandidates.Name = "dgvCandidates";
|
||||
dgvCandidates.ReadOnly = true;
|
||||
dgvCandidates.RowHeadersVisible = false;
|
||||
dgvCandidates.RowHeadersWidth = 62;
|
||||
dgvCandidates.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
dgvCandidates.Size = new Size(1413, 888);
|
||||
dgvCandidates.TabIndex = 1;
|
||||
//
|
||||
// pnlCandTop
|
||||
//
|
||||
pnlCandTop.Controls.Add(btnCandRefresh);
|
||||
pnlCandTop.Controls.Add(cbCandAccount);
|
||||
pnlCandTop.Controls.Add(lblCandKonto);
|
||||
pnlCandTop.Dock = DockStyle.Top;
|
||||
pnlCandTop.Location = new Point(4, 5);
|
||||
pnlCandTop.Margin = new Padding(4, 5, 4, 5);
|
||||
pnlCandTop.Name = "pnlCandTop";
|
||||
pnlCandTop.Size = new Size(1413, 57);
|
||||
pnlCandTop.TabIndex = 0;
|
||||
//
|
||||
// btnCandRefresh
|
||||
//
|
||||
btnCandRefresh.Location = new Point(464, 7);
|
||||
btnCandRefresh.Margin = new Padding(4, 5, 4, 5);
|
||||
btnCandRefresh.Name = "btnCandRefresh";
|
||||
btnCandRefresh.Size = new Size(157, 43);
|
||||
btnCandRefresh.TabIndex = 2;
|
||||
btnCandRefresh.Text = "Aktualisieren";
|
||||
btnCandRefresh.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// cbCandAccount
|
||||
//
|
||||
cbCandAccount.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
cbCandAccount.Location = new Point(79, 8);
|
||||
cbCandAccount.Margin = new Padding(4, 5, 4, 5);
|
||||
cbCandAccount.Name = "cbCandAccount";
|
||||
cbCandAccount.Size = new Size(370, 33);
|
||||
cbCandAccount.TabIndex = 1;
|
||||
//
|
||||
// lblCandKonto
|
||||
//
|
||||
lblCandKonto.AutoSize = true;
|
||||
lblCandKonto.Location = new Point(9, 15);
|
||||
lblCandKonto.Margin = new Padding(4, 0, 4, 0);
|
||||
lblCandKonto.Name = "lblCandKonto";
|
||||
lblCandKonto.Size = new Size(64, 25);
|
||||
lblCandKonto.TabIndex = 0;
|
||||
lblCandKonto.Text = "Konto:";
|
||||
//
|
||||
// tabPositionen
|
||||
//
|
||||
tabPositionen.Controls.Add(dgvPositions);
|
||||
tabPositionen.Controls.Add(pnlPosTop);
|
||||
tabPositionen.Location = new Point(4, 34);
|
||||
tabPositionen.Margin = new Padding(4, 5, 4, 5);
|
||||
tabPositionen.Name = "tabPositionen";
|
||||
tabPositionen.Padding = new Padding(4, 5, 4, 5);
|
||||
tabPositionen.Size = new Size(1421, 955);
|
||||
tabPositionen.TabIndex = 1;
|
||||
tabPositionen.Text = "Positionen";
|
||||
tabPositionen.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// dgvPositions
|
||||
//
|
||||
dgvPositions.AllowUserToAddRows = false;
|
||||
dgvPositions.AllowUserToDeleteRows = false;
|
||||
dgvPositions.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
dgvPositions.Dock = DockStyle.Fill;
|
||||
dgvPositions.Location = new Point(4, 62);
|
||||
dgvPositions.Margin = new Padding(4, 5, 4, 5);
|
||||
dgvPositions.Name = "dgvPositions";
|
||||
dgvPositions.ReadOnly = true;
|
||||
dgvPositions.RowHeadersVisible = false;
|
||||
dgvPositions.RowHeadersWidth = 62;
|
||||
dgvPositions.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
dgvPositions.Size = new Size(1413, 888);
|
||||
dgvPositions.TabIndex = 1;
|
||||
//
|
||||
// pnlPosTop
|
||||
//
|
||||
pnlPosTop.Controls.Add(btnPosRefresh);
|
||||
pnlPosTop.Dock = DockStyle.Top;
|
||||
pnlPosTop.Location = new Point(4, 5);
|
||||
pnlPosTop.Margin = new Padding(4, 5, 4, 5);
|
||||
pnlPosTop.Name = "pnlPosTop";
|
||||
pnlPosTop.Size = new Size(1413, 57);
|
||||
pnlPosTop.TabIndex = 0;
|
||||
//
|
||||
// btnPosRefresh
|
||||
//
|
||||
btnPosRefresh.Location = new Point(9, 7);
|
||||
btnPosRefresh.Margin = new Padding(4, 5, 4, 5);
|
||||
btnPosRefresh.Name = "btnPosRefresh";
|
||||
btnPosRefresh.Size = new Size(157, 43);
|
||||
btnPosRefresh.TabIndex = 0;
|
||||
btnPosRefresh.Text = "Aktualisieren";
|
||||
btnPosRefresh.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tabHistorie
|
||||
//
|
||||
tabHistorie.Controls.Add(dgvHistory);
|
||||
tabHistorie.Controls.Add(lblHistSummary);
|
||||
tabHistorie.Controls.Add(pnlHistTop);
|
||||
tabHistorie.Location = new Point(4, 34);
|
||||
tabHistorie.Margin = new Padding(4, 5, 4, 5);
|
||||
tabHistorie.Name = "tabHistorie";
|
||||
tabHistorie.Padding = new Padding(4, 5, 4, 5);
|
||||
tabHistorie.Size = new Size(1421, 955);
|
||||
tabHistorie.TabIndex = 2;
|
||||
tabHistorie.Text = "Historie / Statistik";
|
||||
tabHistorie.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// dgvHistory
|
||||
//
|
||||
dgvHistory.AllowUserToAddRows = false;
|
||||
dgvHistory.AllowUserToDeleteRows = false;
|
||||
dgvHistory.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
dgvHistory.Dock = DockStyle.Fill;
|
||||
dgvHistory.Location = new Point(4, 142);
|
||||
dgvHistory.Margin = new Padding(4, 5, 4, 5);
|
||||
dgvHistory.Name = "dgvHistory";
|
||||
dgvHistory.ReadOnly = true;
|
||||
dgvHistory.RowHeadersVisible = false;
|
||||
dgvHistory.RowHeadersWidth = 62;
|
||||
dgvHistory.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
dgvHistory.Size = new Size(1413, 808);
|
||||
dgvHistory.TabIndex = 2;
|
||||
//
|
||||
// lblHistSummary
|
||||
//
|
||||
lblHistSummary.Dock = DockStyle.Top;
|
||||
lblHistSummary.Location = new Point(4, 62);
|
||||
lblHistSummary.Margin = new Padding(4, 0, 4, 0);
|
||||
lblHistSummary.Name = "lblHistSummary";
|
||||
lblHistSummary.Padding = new Padding(9, 10, 9, 10);
|
||||
lblHistSummary.Size = new Size(1413, 80);
|
||||
lblHistSummary.TabIndex = 1;
|
||||
//
|
||||
// pnlHistTop
|
||||
//
|
||||
pnlHistTop.Controls.Add(btnHistRefresh);
|
||||
pnlHistTop.Dock = DockStyle.Top;
|
||||
pnlHistTop.Location = new Point(4, 5);
|
||||
pnlHistTop.Margin = new Padding(4, 5, 4, 5);
|
||||
pnlHistTop.Name = "pnlHistTop";
|
||||
pnlHistTop.Size = new Size(1413, 57);
|
||||
pnlHistTop.TabIndex = 0;
|
||||
//
|
||||
// btnHistRefresh
|
||||
//
|
||||
btnHistRefresh.Location = new Point(9, 7);
|
||||
btnHistRefresh.Margin = new Padding(4, 5, 4, 5);
|
||||
btnHistRefresh.Name = "btnHistRefresh";
|
||||
btnHistRefresh.Size = new Size(157, 43);
|
||||
btnHistRefresh.TabIndex = 0;
|
||||
btnHistRefresh.Text = "Aktualisieren";
|
||||
btnHistRefresh.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tabSettings
|
||||
//
|
||||
tabSettings.Controls.Add(pgSettings);
|
||||
tabSettings.Controls.Add(pnlSetTop);
|
||||
tabSettings.Location = new Point(4, 34);
|
||||
tabSettings.Margin = new Padding(4, 5, 4, 5);
|
||||
tabSettings.Name = "tabSettings";
|
||||
tabSettings.Padding = new Padding(4, 5, 4, 5);
|
||||
tabSettings.Size = new Size(1421, 955);
|
||||
tabSettings.TabIndex = 3;
|
||||
tabSettings.Text = "Settings";
|
||||
tabSettings.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// pgSettings
|
||||
//
|
||||
pgSettings.Dock = DockStyle.Fill;
|
||||
pgSettings.Location = new Point(4, 62);
|
||||
pgSettings.Margin = new Padding(4, 5, 4, 5);
|
||||
pgSettings.Name = "pgSettings";
|
||||
pgSettings.Size = new Size(1413, 888);
|
||||
pgSettings.TabIndex = 1;
|
||||
//
|
||||
// pnlSetTop
|
||||
//
|
||||
pnlSetTop.Controls.Add(btnSettingsSave);
|
||||
pnlSetTop.Controls.Add(cbSettingsAccount);
|
||||
pnlSetTop.Controls.Add(lblSetKonto);
|
||||
pnlSetTop.Dock = DockStyle.Top;
|
||||
pnlSetTop.Location = new Point(4, 5);
|
||||
pnlSetTop.Margin = new Padding(4, 5, 4, 5);
|
||||
pnlSetTop.Name = "pnlSetTop";
|
||||
pnlSetTop.Size = new Size(1413, 57);
|
||||
pnlSetTop.TabIndex = 0;
|
||||
//
|
||||
// btnSettingsSave
|
||||
//
|
||||
btnSettingsSave.Location = new Point(464, 7);
|
||||
btnSettingsSave.Margin = new Padding(4, 5, 4, 5);
|
||||
btnSettingsSave.Name = "btnSettingsSave";
|
||||
btnSettingsSave.Size = new Size(157, 43);
|
||||
btnSettingsSave.TabIndex = 2;
|
||||
btnSettingsSave.Text = "Speichern";
|
||||
btnSettingsSave.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// cbSettingsAccount
|
||||
//
|
||||
cbSettingsAccount.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
cbSettingsAccount.Location = new Point(79, 8);
|
||||
cbSettingsAccount.Margin = new Padding(4, 5, 4, 5);
|
||||
cbSettingsAccount.Name = "cbSettingsAccount";
|
||||
cbSettingsAccount.Size = new Size(370, 33);
|
||||
cbSettingsAccount.TabIndex = 1;
|
||||
//
|
||||
// lblSetKonto
|
||||
//
|
||||
lblSetKonto.AutoSize = true;
|
||||
lblSetKonto.Location = new Point(9, 15);
|
||||
lblSetKonto.Margin = new Padding(4, 0, 4, 0);
|
||||
lblSetKonto.Name = "lblSetKonto";
|
||||
lblSetKonto.Size = new Size(64, 25);
|
||||
lblSetKonto.TabIndex = 0;
|
||||
lblSetKonto.Text = "Konto:";
|
||||
//
|
||||
// lblRfStatus
|
||||
//
|
||||
lblRfStatus.Dock = DockStyle.Bottom;
|
||||
lblRfStatus.Location = new Point(0, 993);
|
||||
lblRfStatus.Margin = new Padding(4, 0, 4, 0);
|
||||
lblRfStatus.Name = "lblRfStatus";
|
||||
lblRfStatus.Padding = new Padding(9, 3, 9, 3);
|
||||
lblRfStatus.Size = new Size(1429, 37);
|
||||
lblRfStatus.TabIndex = 1;
|
||||
//
|
||||
// ResolutionFarmingMainForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(10F, 25F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(1429, 1030);
|
||||
Controls.Add(tabControlRf);
|
||||
Controls.Add(lblRfStatus);
|
||||
Icon = (Icon)resources.GetObject("$this.Icon");
|
||||
Margin = new Padding(4, 5, 4, 5);
|
||||
Name = "ResolutionFarmingMainForm";
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Text = "ResolutionFarming";
|
||||
tabControlRf.ResumeLayout(false);
|
||||
tabKandidaten.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)dgvCandidates).EndInit();
|
||||
pnlCandTop.ResumeLayout(false);
|
||||
pnlCandTop.PerformLayout();
|
||||
tabPositionen.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)dgvPositions).EndInit();
|
||||
pnlPosTop.ResumeLayout(false);
|
||||
tabHistorie.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)dgvHistory).EndInit();
|
||||
pnlHistTop.ResumeLayout(false);
|
||||
tabSettings.ResumeLayout(false);
|
||||
pnlSetTop.ResumeLayout(false);
|
||||
pnlSetTop.PerformLayout();
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TabControl tabControlRf;
|
||||
private System.Windows.Forms.TabPage tabKandidaten;
|
||||
private System.Windows.Forms.Panel pnlCandTop;
|
||||
private System.Windows.Forms.Label lblCandKonto;
|
||||
private System.Windows.Forms.ComboBox cbCandAccount;
|
||||
private System.Windows.Forms.Button btnCandRefresh;
|
||||
private System.Windows.Forms.DataGridView dgvCandidates;
|
||||
private System.Windows.Forms.TabPage tabPositionen;
|
||||
private System.Windows.Forms.Panel pnlPosTop;
|
||||
private System.Windows.Forms.Button btnPosRefresh;
|
||||
private System.Windows.Forms.DataGridView dgvPositions;
|
||||
private System.Windows.Forms.TabPage tabHistorie;
|
||||
private System.Windows.Forms.Panel pnlHistTop;
|
||||
private System.Windows.Forms.Button btnHistRefresh;
|
||||
private System.Windows.Forms.Label lblHistSummary;
|
||||
private System.Windows.Forms.DataGridView dgvHistory;
|
||||
private System.Windows.Forms.TabPage tabSettings;
|
||||
private System.Windows.Forms.Panel pnlSetTop;
|
||||
private System.Windows.Forms.Label lblSetKonto;
|
||||
private System.Windows.Forms.ComboBox cbSettingsAccount;
|
||||
private System.Windows.Forms.Button btnSettingsSave;
|
||||
private System.Windows.Forms.PropertyGrid pgSettings;
|
||||
private System.Windows.Forms.Label lblRfStatus;
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using PolyTrader.Modules.ResolutionFarming.Models;
|
||||
using PolyTrader.Modules.ResolutionFarming.Persistence;
|
||||
using PolyTraderSharp;
|
||||
|
||||
namespace PolyTrader.Modules.ResolutionFarming.Ui
|
||||
{
|
||||
/// <summary>
|
||||
/// Hauptfenster des ResolutionFarming-Moduls: Tabs Kandidaten, Positionen, Historie/Statistik,
|
||||
/// Settings. Layout im Designer (ResolutionFarmingMainForm.Designer.cs), Verhalten/Daten hier.
|
||||
/// DB-Zugriffe defensiv (Guarded), damit die UI auch ohne angewendete rf_-Migration bedienbar bleibt.
|
||||
/// </summary>
|
||||
public partial class ResolutionFarmingMainForm : Form
|
||||
{
|
||||
private IRfCandidateRepository? _candidates;
|
||||
private IRfPositionRepository? _positions;
|
||||
private IRfClosedTradeRepository? _closed;
|
||||
private IRfSettingsRepository? _settingsRepo;
|
||||
private TradingState? _state;
|
||||
|
||||
private RfSettings? _currentSettings;
|
||||
|
||||
public ResolutionFarmingMainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
btnCandRefresh.Click += (_, _) => RefreshCandidates();
|
||||
cbCandAccount.SelectedIndexChanged += (_, _) => RefreshCandidates();
|
||||
btnPosRefresh.Click += (_, _) => RefreshPositions();
|
||||
btnHistRefresh.Click += (_, _) => RefreshHistory();
|
||||
btnSettingsSave.Click += (_, _) => SaveSettings();
|
||||
cbSettingsAccount.SelectedIndexChanged += (_, _) => LoadSettings();
|
||||
}
|
||||
|
||||
/// <summary>Injiziert Repos/State (nach DI-Auflösung) und lädt die Ansichten.</summary>
|
||||
public void Initialize(IServiceProvider services)
|
||||
{
|
||||
_candidates = services.GetRequiredService<IRfCandidateRepository>();
|
||||
_positions = services.GetRequiredService<IRfPositionRepository>();
|
||||
_closed = services.GetRequiredService<IRfClosedTradeRepository>();
|
||||
_settingsRepo = services.GetRequiredService<IRfSettingsRepository>();
|
||||
_state = services.GetRequiredService<TradingState>();
|
||||
|
||||
PopulateAccounts();
|
||||
RefreshCandidates();
|
||||
RefreshPositions();
|
||||
RefreshHistory();
|
||||
}
|
||||
|
||||
// ---------------- Daten ----------------
|
||||
|
||||
private void PopulateAccounts()
|
||||
{
|
||||
if (_state == null) return;
|
||||
var items = _state.Accounts.Values
|
||||
.OrderBy(a => a.AccountId)
|
||||
.Select(a => new AccountItem(a.AccountId, string.IsNullOrEmpty(a.Name) ? $"#{a.AccountId}" : $"{a.Name} (#{a.AccountId}){(a.IsDemo ? " · Demo" : "")}"))
|
||||
.ToList();
|
||||
|
||||
foreach (var combo in new[] { cbCandAccount, cbSettingsAccount })
|
||||
{
|
||||
combo.DisplayMember = nameof(AccountItem.Label);
|
||||
combo.ValueMember = nameof(AccountItem.Id);
|
||||
combo.DataSource = items.ToList();
|
||||
}
|
||||
|
||||
if (items.Count > 0) LoadSettings();
|
||||
else SetStatus("Keine Accounts vorhanden.");
|
||||
}
|
||||
|
||||
private int? SelectedAccountId(ComboBox combo) =>
|
||||
combo.SelectedItem is AccountItem it ? it.Id : (int?)null;
|
||||
|
||||
private void RefreshCandidates()
|
||||
{
|
||||
if (_candidates == null || SelectedAccountId(cbCandAccount) is not int accId) return;
|
||||
Guarded("Kandidaten", () => dgvCandidates.DataSource = _candidates.GetRecent(accId, 200));
|
||||
}
|
||||
|
||||
private void RefreshPositions()
|
||||
{
|
||||
if (_positions == null) return;
|
||||
Guarded("Positionen", () => dgvPositions.DataSource = _positions.GetAllOpen());
|
||||
}
|
||||
|
||||
private void RefreshHistory()
|
||||
{
|
||||
if (_closed == null) return;
|
||||
Guarded("Historie", () =>
|
||||
{
|
||||
var trades = _closed.Find(_ => true);
|
||||
dgvHistory.DataSource = trades;
|
||||
lblHistSummary.Text = BuildSummary(trades);
|
||||
});
|
||||
}
|
||||
|
||||
private static string BuildSummary(System.Collections.Generic.List<RfClosedTrade> trades)
|
||||
{
|
||||
if (trades.Count == 0) return "Noch keine abgeschlossenen Trades.";
|
||||
int wins = trades.Count(t => t.RealizedPnl > 0m);
|
||||
decimal pnl = trades.Sum(t => t.RealizedPnl);
|
||||
decimal fees = trades.Sum(t => t.TotalFees);
|
||||
double winrate = 100.0 * wins / trades.Count;
|
||||
// Winrate je Preisband (Kalibrierung: realisierte Winrate sollte > Band-Mitte liegen).
|
||||
var bands = trades
|
||||
.GroupBy(t => $"{Math.Floor(t.EntryPrice * 20m) / 20m:F2}") // 5-¢-Bänder
|
||||
.OrderBy(g => g.Key)
|
||||
.Select(g => $"{g.Key}: {100.0 * g.Count(x => x.RealizedPnl > 0m) / g.Count():F0}% ({g.Count()})");
|
||||
return $"Trades: {trades.Count} | Winrate: {winrate:F1}% | Netto-PnL: {pnl:F2} USDC | Fees: {fees:F2}\n" +
|
||||
$"Winrate je Preisband: {string.Join(" | ", bands)}";
|
||||
}
|
||||
|
||||
private void LoadSettings()
|
||||
{
|
||||
if (_settingsRepo == null || SelectedAccountId(cbSettingsAccount) is not int accId) return;
|
||||
Guarded("Settings", () =>
|
||||
{
|
||||
_currentSettings = _settingsRepo.Get(accId) ?? new RfSettings { AccountId = accId };
|
||||
pgSettings.SelectedObject = _currentSettings;
|
||||
SetStatus($"Einstellungen für Konto #{accId}.");
|
||||
});
|
||||
}
|
||||
|
||||
private void SaveSettings()
|
||||
{
|
||||
if (_settingsRepo == null || _currentSettings == null) return;
|
||||
Guarded("Speichern", () =>
|
||||
{
|
||||
_settingsRepo.Upsert(_currentSettings);
|
||||
SetStatus($"Gespeichert für Konto #{_currentSettings.AccountId} um {DateTime.Now:HH:mm:ss}.");
|
||||
});
|
||||
}
|
||||
|
||||
private void Guarded(string what, Action action)
|
||||
{
|
||||
try { action(); }
|
||||
catch (Exception ex) { SetStatus($"{what}: DB nicht bereit ({ex.Message}). Migration angewendet?"); }
|
||||
}
|
||||
|
||||
private void SetStatus(string text) => lblRfStatus.Text = text;
|
||||
|
||||
private sealed record AccountItem(int Id, string Label);
|
||||
}
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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
|
||||
RK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PolyTrader.Core\PolyTrader.Core.csproj" />
|
||||
@@ -25,11 +25,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<!-- Linux-Portierung: plattformneutral. Die WinForms-UI dieses Moduls (KI-Analyse, Dossiers, MCP-Light)
|
||||
wurde entfernt; die Avalonia-Ansicht kommt spaeter direkt hierher zurueck – Avalonia ist
|
||||
im Gegensatz zu WinForms plattformuebergreifend und braucht kein eigenes UI-Projekt. -->
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<!-- Modul trägt eigene WinForms-UI bei (Dossier-Browser, später Analyse-Chat). -->
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -54,21 +54,22 @@ namespace PolyTrader.Modules.Supervisor
|
||||
services.AddHostedService<Mcp.McpLightServer>();
|
||||
}
|
||||
|
||||
public void RegisterUi(IModuleUiHost host, System.IServiceProvider services)
|
||||
/// <summary>
|
||||
/// Aktuell ohne Ansicht: Die WinForms-UI wurde mit der Linux-Portierung entfernt, die
|
||||
/// Avalonia-Ansicht folgt (Stufe L3/L4). Die Fachlogik dieses Moduls laeuft davon
|
||||
/// unabhaengig weiter – die Shell zeigt schlicht kein Fenster fuer das Modul an.
|
||||
///
|
||||
/// <para><b>Beim Nachbau zu erhalten</b> (Spezifikation: docs/UI-SPEZIFIKATION-WinForms.md,
|
||||
/// Originalcode: Git-Tag <c>winforms-final</c>):</para>
|
||||
/// <list type="bullet">
|
||||
/// <item>View-ID <c>supervisor.main</c> (stabil – Launcher-Button und Symbol haengen daran)</item>
|
||||
/// <item>Titel <c>Supervisor</c>, Gruppe <c>Supervisor</c>, Order <c>300</c></item>
|
||||
/// <item>Ein Fenster fuers ganze Modul: SupervisorMainForm mit Tabs: Analyse (Chat) / Dossiers / Berichte / Counterfactual</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public void RegisterUi(IModuleUiHost host, IServiceProvider services)
|
||||
{
|
||||
host.RegisterView(new ModuleView
|
||||
{
|
||||
Id = "supervisor.main",
|
||||
Title = "Supervisor",
|
||||
Group = "Supervisor",
|
||||
Order = 300,
|
||||
CreateView = () =>
|
||||
{
|
||||
var form = new Ui.SupervisorMainForm();
|
||||
form.Initialize(services);
|
||||
return form;
|
||||
}
|
||||
});
|
||||
// Bewusst leer, bis die Avalonia-Ansicht steht (siehe Doku oben).
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
@@ -1,524 +0,0 @@
|
||||
namespace PolyTrader.Modules.Supervisor.Ui
|
||||
{
|
||||
partial class SupervisorMainForm
|
||||
{
|
||||
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()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SupervisorMainForm));
|
||||
tabControlSup = new TabControl();
|
||||
tabAnalyse = new TabPage();
|
||||
rtbChat = new RichTextBox();
|
||||
pnlChatInput = new Panel();
|
||||
tbChatInput = new TextBox();
|
||||
btnSend = new Button();
|
||||
toolStripChat = new ToolStrip();
|
||||
lblProfil = new ToolStripLabel();
|
||||
cbProfile = new ToolStripComboBox();
|
||||
lblModel = new ToolStripLabel();
|
||||
tbModel = new ToolStripTextBox();
|
||||
sepChat = new ToolStripSeparator();
|
||||
btnClearChat = new ToolStripButton();
|
||||
tabDossiers = new TabPage();
|
||||
splitDossiers = new SplitContainer();
|
||||
dgvSignals = new DataGridView();
|
||||
tbDossier = new TextBox();
|
||||
toolStripDossier = new ToolStrip();
|
||||
btnDossierRefresh = new ToolStripButton();
|
||||
sepDossier = new ToolStripSeparator();
|
||||
lblSignal = new ToolStripLabel();
|
||||
tbSignalId = new ToolStripTextBox();
|
||||
btnDossierOpen = new ToolStripButton();
|
||||
tabBerichte = new TabPage();
|
||||
splitReports = new SplitContainer();
|
||||
dgvReports = new DataGridView();
|
||||
tbReport = new TextBox();
|
||||
toolStripReports = new ToolStrip();
|
||||
btnReportsRefresh = new ToolStripButton();
|
||||
tabCounterfactual = new TabPage();
|
||||
dgvCounterfactuals = new DataGridView();
|
||||
toolStripCf = new ToolStrip();
|
||||
btnCfRefresh = new ToolStripButton();
|
||||
lblStatus = new Label();
|
||||
tabControlSup.SuspendLayout();
|
||||
tabAnalyse.SuspendLayout();
|
||||
pnlChatInput.SuspendLayout();
|
||||
toolStripChat.SuspendLayout();
|
||||
tabDossiers.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)splitDossiers).BeginInit();
|
||||
splitDossiers.Panel1.SuspendLayout();
|
||||
splitDossiers.Panel2.SuspendLayout();
|
||||
splitDossiers.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)dgvSignals).BeginInit();
|
||||
toolStripDossier.SuspendLayout();
|
||||
tabBerichte.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)splitReports).BeginInit();
|
||||
splitReports.Panel1.SuspendLayout();
|
||||
splitReports.Panel2.SuspendLayout();
|
||||
splitReports.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)dgvReports).BeginInit();
|
||||
toolStripReports.SuspendLayout();
|
||||
tabCounterfactual.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)dgvCounterfactuals).BeginInit();
|
||||
toolStripCf.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// tabControlSup
|
||||
//
|
||||
tabControlSup.Controls.Add(tabAnalyse);
|
||||
tabControlSup.Controls.Add(tabDossiers);
|
||||
tabControlSup.Controls.Add(tabBerichte);
|
||||
tabControlSup.Controls.Add(tabCounterfactual);
|
||||
tabControlSup.Dock = DockStyle.Fill;
|
||||
tabControlSup.Location = new Point(0, 0);
|
||||
tabControlSup.Margin = new Padding(4, 5, 4, 5);
|
||||
tabControlSup.Name = "tabControlSup";
|
||||
tabControlSup.SelectedIndex = 0;
|
||||
tabControlSup.Size = new Size(1786, 1126);
|
||||
tabControlSup.TabIndex = 0;
|
||||
//
|
||||
// tabAnalyse
|
||||
//
|
||||
tabAnalyse.Controls.Add(rtbChat);
|
||||
tabAnalyse.Controls.Add(pnlChatInput);
|
||||
tabAnalyse.Controls.Add(toolStripChat);
|
||||
tabAnalyse.Location = new Point(4, 34);
|
||||
tabAnalyse.Margin = new Padding(4, 5, 4, 5);
|
||||
tabAnalyse.Name = "tabAnalyse";
|
||||
tabAnalyse.Padding = new Padding(4, 5, 4, 5);
|
||||
tabAnalyse.Size = new Size(1778, 1088);
|
||||
tabAnalyse.TabIndex = 0;
|
||||
tabAnalyse.Text = "Analyse";
|
||||
tabAnalyse.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// rtbChat
|
||||
//
|
||||
rtbChat.BackColor = Color.White;
|
||||
rtbChat.Dock = DockStyle.Fill;
|
||||
rtbChat.Font = new Font("Segoe UI", 9.5F);
|
||||
rtbChat.Location = new Point(4, 39);
|
||||
rtbChat.Margin = new Padding(4, 5, 4, 5);
|
||||
rtbChat.Name = "rtbChat";
|
||||
rtbChat.ReadOnly = true;
|
||||
rtbChat.Size = new Size(1770, 944);
|
||||
rtbChat.TabIndex = 1;
|
||||
rtbChat.Text = "";
|
||||
//
|
||||
// pnlChatInput
|
||||
//
|
||||
pnlChatInput.Controls.Add(tbChatInput);
|
||||
pnlChatInput.Controls.Add(btnSend);
|
||||
pnlChatInput.Dock = DockStyle.Bottom;
|
||||
pnlChatInput.Location = new Point(4, 983);
|
||||
pnlChatInput.Margin = new Padding(4, 5, 4, 5);
|
||||
pnlChatInput.Name = "pnlChatInput";
|
||||
pnlChatInput.Padding = new Padding(6, 7, 6, 7);
|
||||
pnlChatInput.Size = new Size(1770, 100);
|
||||
pnlChatInput.TabIndex = 2;
|
||||
//
|
||||
// tbChatInput
|
||||
//
|
||||
tbChatInput.Dock = DockStyle.Fill;
|
||||
tbChatInput.Location = new Point(6, 7);
|
||||
tbChatInput.Margin = new Padding(4, 5, 4, 5);
|
||||
tbChatInput.Multiline = true;
|
||||
tbChatInput.Name = "tbChatInput";
|
||||
tbChatInput.PlaceholderText = "Analyse-Frage stellen … (Strg+Enter zum Senden)";
|
||||
tbChatInput.Size = new Size(1601, 86);
|
||||
tbChatInput.TabIndex = 0;
|
||||
//
|
||||
// btnSend
|
||||
//
|
||||
btnSend.Dock = DockStyle.Right;
|
||||
btnSend.Location = new Point(1607, 7);
|
||||
btnSend.Margin = new Padding(4, 5, 4, 5);
|
||||
btnSend.Name = "btnSend";
|
||||
btnSend.Size = new Size(157, 86);
|
||||
btnSend.TabIndex = 1;
|
||||
btnSend.Text = "Senden";
|
||||
btnSend.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// toolStripChat
|
||||
//
|
||||
toolStripChat.ImageScalingSize = new Size(24, 24);
|
||||
toolStripChat.Items.AddRange(new ToolStripItem[] { lblProfil, cbProfile, lblModel, tbModel, sepChat, btnClearChat });
|
||||
toolStripChat.Location = new Point(4, 5);
|
||||
toolStripChat.Name = "toolStripChat";
|
||||
toolStripChat.Padding = new Padding(0, 0, 3, 0);
|
||||
toolStripChat.Size = new Size(1770, 34);
|
||||
toolStripChat.TabIndex = 0;
|
||||
//
|
||||
// lblProfil
|
||||
//
|
||||
lblProfil.Name = "lblProfil";
|
||||
lblProfil.Size = new Size(57, 29);
|
||||
lblProfil.Text = "Profil:";
|
||||
//
|
||||
// cbProfile
|
||||
//
|
||||
cbProfile.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
cbProfile.Name = "cbProfile";
|
||||
cbProfile.Size = new Size(227, 34);
|
||||
//
|
||||
// lblModel
|
||||
//
|
||||
lblModel.Name = "lblModel";
|
||||
lblModel.Size = new Size(71, 29);
|
||||
lblModel.Text = "Modell:";
|
||||
//
|
||||
// tbModel
|
||||
//
|
||||
tbModel.AutoSize = false;
|
||||
tbModel.Name = "tbModel";
|
||||
tbModel.Size = new Size(313, 31);
|
||||
tbModel.Text = "openrouter/auto";
|
||||
//
|
||||
// sepChat
|
||||
//
|
||||
sepChat.Name = "sepChat";
|
||||
sepChat.Size = new Size(6, 34);
|
||||
//
|
||||
// btnClearChat
|
||||
//
|
||||
btnClearChat.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
||||
btnClearChat.Name = "btnClearChat";
|
||||
btnClearChat.Size = new Size(122, 29);
|
||||
btnClearChat.Text = "Verlauf leeren";
|
||||
//
|
||||
// tabDossiers
|
||||
//
|
||||
tabDossiers.Controls.Add(splitDossiers);
|
||||
tabDossiers.Controls.Add(toolStripDossier);
|
||||
tabDossiers.Location = new Point(4, 34);
|
||||
tabDossiers.Margin = new Padding(4, 5, 4, 5);
|
||||
tabDossiers.Name = "tabDossiers";
|
||||
tabDossiers.Padding = new Padding(4, 5, 4, 5);
|
||||
tabDossiers.Size = new Size(1778, 1088);
|
||||
tabDossiers.TabIndex = 1;
|
||||
tabDossiers.Text = "Dossiers";
|
||||
tabDossiers.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// splitDossiers
|
||||
//
|
||||
splitDossiers.Dock = DockStyle.Fill;
|
||||
splitDossiers.Location = new Point(4, 39);
|
||||
splitDossiers.Margin = new Padding(4, 5, 4, 5);
|
||||
splitDossiers.Name = "splitDossiers";
|
||||
//
|
||||
// splitDossiers.Panel1
|
||||
//
|
||||
splitDossiers.Panel1.Controls.Add(dgvSignals);
|
||||
//
|
||||
// splitDossiers.Panel2
|
||||
//
|
||||
splitDossiers.Panel2.Controls.Add(tbDossier);
|
||||
splitDossiers.Size = new Size(1770, 1044);
|
||||
splitDossiers.SplitterDistance = 601;
|
||||
splitDossiers.SplitterWidth = 6;
|
||||
splitDossiers.TabIndex = 1;
|
||||
//
|
||||
// dgvSignals
|
||||
//
|
||||
dgvSignals.AllowUserToAddRows = false;
|
||||
dgvSignals.AllowUserToDeleteRows = false;
|
||||
dgvSignals.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
dgvSignals.Dock = DockStyle.Fill;
|
||||
dgvSignals.Location = new Point(0, 0);
|
||||
dgvSignals.Margin = new Padding(4, 5, 4, 5);
|
||||
dgvSignals.MultiSelect = false;
|
||||
dgvSignals.Name = "dgvSignals";
|
||||
dgvSignals.ReadOnly = true;
|
||||
dgvSignals.RowHeadersVisible = false;
|
||||
dgvSignals.RowHeadersWidth = 62;
|
||||
dgvSignals.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
dgvSignals.Size = new Size(601, 1044);
|
||||
dgvSignals.TabIndex = 0;
|
||||
//
|
||||
// tbDossier
|
||||
//
|
||||
tbDossier.Dock = DockStyle.Fill;
|
||||
tbDossier.Font = new Font("Consolas", 9.5F);
|
||||
tbDossier.Location = new Point(0, 0);
|
||||
tbDossier.Margin = new Padding(4, 5, 4, 5);
|
||||
tbDossier.Multiline = true;
|
||||
tbDossier.Name = "tbDossier";
|
||||
tbDossier.ReadOnly = true;
|
||||
tbDossier.ScrollBars = ScrollBars.Both;
|
||||
tbDossier.Size = new Size(1163, 1044);
|
||||
tbDossier.TabIndex = 0;
|
||||
tbDossier.WordWrap = false;
|
||||
//
|
||||
// toolStripDossier
|
||||
//
|
||||
toolStripDossier.ImageScalingSize = new Size(24, 24);
|
||||
toolStripDossier.Items.AddRange(new ToolStripItem[] { btnDossierRefresh, sepDossier, lblSignal, tbSignalId, btnDossierOpen });
|
||||
toolStripDossier.Location = new Point(4, 5);
|
||||
toolStripDossier.Name = "toolStripDossier";
|
||||
toolStripDossier.Padding = new Padding(0, 0, 3, 0);
|
||||
toolStripDossier.Size = new Size(1770, 34);
|
||||
toolStripDossier.TabIndex = 0;
|
||||
//
|
||||
// btnDossierRefresh
|
||||
//
|
||||
btnDossierRefresh.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
||||
btnDossierRefresh.Name = "btnDossierRefresh";
|
||||
btnDossierRefresh.Size = new Size(116, 29);
|
||||
btnDossierRefresh.Text = "Aktualisieren";
|
||||
//
|
||||
// sepDossier
|
||||
//
|
||||
sepDossier.Name = "sepDossier";
|
||||
sepDossier.Size = new Size(6, 34);
|
||||
//
|
||||
// lblSignal
|
||||
//
|
||||
lblSignal.Name = "lblSignal";
|
||||
lblSignal.Size = new Size(80, 29);
|
||||
lblSignal.Text = "SignalId:";
|
||||
//
|
||||
// tbSignalId
|
||||
//
|
||||
tbSignalId.AutoSize = false;
|
||||
tbSignalId.Name = "tbSignalId";
|
||||
tbSignalId.Size = new Size(313, 31);
|
||||
//
|
||||
// btnDossierOpen
|
||||
//
|
||||
btnDossierOpen.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
||||
btnDossierOpen.Name = "btnDossierOpen";
|
||||
btnDossierOpen.Size = new Size(132, 29);
|
||||
btnDossierOpen.Text = "Dossier öffnen";
|
||||
//
|
||||
// tabBerichte
|
||||
//
|
||||
tabBerichte.Controls.Add(splitReports);
|
||||
tabBerichte.Controls.Add(toolStripReports);
|
||||
tabBerichte.Location = new Point(4, 34);
|
||||
tabBerichte.Margin = new Padding(4, 5, 4, 5);
|
||||
tabBerichte.Name = "tabBerichte";
|
||||
tabBerichte.Padding = new Padding(4, 5, 4, 5);
|
||||
tabBerichte.Size = new Size(1778, 1089);
|
||||
tabBerichte.TabIndex = 2;
|
||||
tabBerichte.Text = "Berichte";
|
||||
tabBerichte.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// splitReports
|
||||
//
|
||||
splitReports.Dock = DockStyle.Fill;
|
||||
splitReports.Location = new Point(4, 39);
|
||||
splitReports.Margin = new Padding(4, 5, 4, 5);
|
||||
splitReports.Name = "splitReports";
|
||||
//
|
||||
// splitReports.Panel1
|
||||
//
|
||||
splitReports.Panel1.Controls.Add(dgvReports);
|
||||
//
|
||||
// splitReports.Panel2
|
||||
//
|
||||
splitReports.Panel2.Controls.Add(tbReport);
|
||||
splitReports.Size = new Size(1770, 1045);
|
||||
splitReports.SplitterDistance = 744;
|
||||
splitReports.SplitterWidth = 6;
|
||||
splitReports.TabIndex = 1;
|
||||
//
|
||||
// dgvReports
|
||||
//
|
||||
dgvReports.AllowUserToAddRows = false;
|
||||
dgvReports.AllowUserToDeleteRows = false;
|
||||
dgvReports.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
dgvReports.Dock = DockStyle.Fill;
|
||||
dgvReports.Location = new Point(0, 0);
|
||||
dgvReports.Margin = new Padding(4, 5, 4, 5);
|
||||
dgvReports.MultiSelect = false;
|
||||
dgvReports.Name = "dgvReports";
|
||||
dgvReports.ReadOnly = true;
|
||||
dgvReports.RowHeadersVisible = false;
|
||||
dgvReports.RowHeadersWidth = 62;
|
||||
dgvReports.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
dgvReports.Size = new Size(744, 1045);
|
||||
dgvReports.TabIndex = 0;
|
||||
//
|
||||
// tbReport
|
||||
//
|
||||
tbReport.Dock = DockStyle.Fill;
|
||||
tbReport.Font = new Font("Segoe UI", 9.5F);
|
||||
tbReport.Location = new Point(0, 0);
|
||||
tbReport.Margin = new Padding(4, 5, 4, 5);
|
||||
tbReport.Multiline = true;
|
||||
tbReport.Name = "tbReport";
|
||||
tbReport.ReadOnly = true;
|
||||
tbReport.ScrollBars = ScrollBars.Both;
|
||||
tbReport.Size = new Size(1020, 1045);
|
||||
tbReport.TabIndex = 0;
|
||||
//
|
||||
// toolStripReports
|
||||
//
|
||||
toolStripReports.ImageScalingSize = new Size(24, 24);
|
||||
toolStripReports.Items.AddRange(new ToolStripItem[] { btnReportsRefresh });
|
||||
toolStripReports.Location = new Point(4, 5);
|
||||
toolStripReports.Name = "toolStripReports";
|
||||
toolStripReports.Padding = new Padding(0, 0, 3, 0);
|
||||
toolStripReports.Size = new Size(1770, 34);
|
||||
toolStripReports.TabIndex = 0;
|
||||
//
|
||||
// btnReportsRefresh
|
||||
//
|
||||
btnReportsRefresh.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
||||
btnReportsRefresh.Name = "btnReportsRefresh";
|
||||
btnReportsRefresh.Size = new Size(116, 29);
|
||||
btnReportsRefresh.Text = "Aktualisieren";
|
||||
//
|
||||
// tabCounterfactual
|
||||
//
|
||||
tabCounterfactual.Controls.Add(dgvCounterfactuals);
|
||||
tabCounterfactual.Controls.Add(toolStripCf);
|
||||
tabCounterfactual.Location = new Point(4, 34);
|
||||
tabCounterfactual.Margin = new Padding(4, 5, 4, 5);
|
||||
tabCounterfactual.Name = "tabCounterfactual";
|
||||
tabCounterfactual.Padding = new Padding(4, 5, 4, 5);
|
||||
tabCounterfactual.Size = new Size(1778, 1089);
|
||||
tabCounterfactual.TabIndex = 3;
|
||||
tabCounterfactual.Text = "Counterfactual";
|
||||
tabCounterfactual.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// dgvCounterfactuals
|
||||
//
|
||||
dgvCounterfactuals.AllowUserToAddRows = false;
|
||||
dgvCounterfactuals.AllowUserToDeleteRows = false;
|
||||
dgvCounterfactuals.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
dgvCounterfactuals.Dock = DockStyle.Fill;
|
||||
dgvCounterfactuals.Location = new Point(4, 39);
|
||||
dgvCounterfactuals.Margin = new Padding(4, 5, 4, 5);
|
||||
dgvCounterfactuals.MultiSelect = false;
|
||||
dgvCounterfactuals.Name = "dgvCounterfactuals";
|
||||
dgvCounterfactuals.ReadOnly = true;
|
||||
dgvCounterfactuals.RowHeadersVisible = false;
|
||||
dgvCounterfactuals.RowHeadersWidth = 62;
|
||||
dgvCounterfactuals.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
dgvCounterfactuals.Size = new Size(1770, 1045);
|
||||
dgvCounterfactuals.TabIndex = 1;
|
||||
//
|
||||
// toolStripCf
|
||||
//
|
||||
toolStripCf.ImageScalingSize = new Size(24, 24);
|
||||
toolStripCf.Items.AddRange(new ToolStripItem[] { btnCfRefresh });
|
||||
toolStripCf.Location = new Point(4, 5);
|
||||
toolStripCf.Name = "toolStripCf";
|
||||
toolStripCf.Padding = new Padding(0, 0, 3, 0);
|
||||
toolStripCf.Size = new Size(1770, 34);
|
||||
toolStripCf.TabIndex = 0;
|
||||
//
|
||||
// btnCfRefresh
|
||||
//
|
||||
btnCfRefresh.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
||||
btnCfRefresh.Name = "btnCfRefresh";
|
||||
btnCfRefresh.Size = new Size(116, 29);
|
||||
btnCfRefresh.Text = "Aktualisieren";
|
||||
//
|
||||
// lblStatus
|
||||
//
|
||||
lblStatus.Dock = DockStyle.Bottom;
|
||||
lblStatus.Location = new Point(0, 1126);
|
||||
lblStatus.Margin = new Padding(4, 0, 4, 0);
|
||||
lblStatus.Name = "lblStatus";
|
||||
lblStatus.Padding = new Padding(9, 3, 9, 3);
|
||||
lblStatus.Size = new Size(1786, 37);
|
||||
lblStatus.TabIndex = 1;
|
||||
//
|
||||
// SupervisorMainForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(10F, 25F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(1786, 1163);
|
||||
Controls.Add(tabControlSup);
|
||||
Controls.Add(lblStatus);
|
||||
Icon = (Icon)resources.GetObject("$this.Icon");
|
||||
Margin = new Padding(4, 5, 4, 5);
|
||||
Name = "SupervisorMainForm";
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Text = "Supervisor";
|
||||
tabControlSup.ResumeLayout(false);
|
||||
tabAnalyse.ResumeLayout(false);
|
||||
tabAnalyse.PerformLayout();
|
||||
pnlChatInput.ResumeLayout(false);
|
||||
pnlChatInput.PerformLayout();
|
||||
toolStripChat.ResumeLayout(false);
|
||||
toolStripChat.PerformLayout();
|
||||
tabDossiers.ResumeLayout(false);
|
||||
tabDossiers.PerformLayout();
|
||||
splitDossiers.Panel1.ResumeLayout(false);
|
||||
splitDossiers.Panel2.ResumeLayout(false);
|
||||
splitDossiers.Panel2.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)splitDossiers).EndInit();
|
||||
splitDossiers.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)dgvSignals).EndInit();
|
||||
toolStripDossier.ResumeLayout(false);
|
||||
toolStripDossier.PerformLayout();
|
||||
tabBerichte.ResumeLayout(false);
|
||||
tabBerichte.PerformLayout();
|
||||
splitReports.Panel1.ResumeLayout(false);
|
||||
splitReports.Panel2.ResumeLayout(false);
|
||||
splitReports.Panel2.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)splitReports).EndInit();
|
||||
splitReports.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)dgvReports).EndInit();
|
||||
toolStripReports.ResumeLayout(false);
|
||||
toolStripReports.PerformLayout();
|
||||
tabCounterfactual.ResumeLayout(false);
|
||||
tabCounterfactual.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)dgvCounterfactuals).EndInit();
|
||||
toolStripCf.ResumeLayout(false);
|
||||
toolStripCf.PerformLayout();
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TabControl tabControlSup;
|
||||
private System.Windows.Forms.TabPage tabAnalyse;
|
||||
private System.Windows.Forms.ToolStrip toolStripChat;
|
||||
private System.Windows.Forms.ToolStripLabel lblProfil;
|
||||
private System.Windows.Forms.ToolStripComboBox cbProfile;
|
||||
private System.Windows.Forms.ToolStripLabel lblModel;
|
||||
private System.Windows.Forms.ToolStripTextBox tbModel;
|
||||
private System.Windows.Forms.ToolStripSeparator sepChat;
|
||||
private System.Windows.Forms.ToolStripButton btnClearChat;
|
||||
private System.Windows.Forms.RichTextBox rtbChat;
|
||||
private System.Windows.Forms.Panel pnlChatInput;
|
||||
private System.Windows.Forms.TextBox tbChatInput;
|
||||
private System.Windows.Forms.Button btnSend;
|
||||
private System.Windows.Forms.TabPage tabDossiers;
|
||||
private System.Windows.Forms.ToolStrip toolStripDossier;
|
||||
private System.Windows.Forms.ToolStripButton btnDossierRefresh;
|
||||
private System.Windows.Forms.ToolStripSeparator sepDossier;
|
||||
private System.Windows.Forms.ToolStripLabel lblSignal;
|
||||
private System.Windows.Forms.ToolStripTextBox tbSignalId;
|
||||
private System.Windows.Forms.ToolStripButton btnDossierOpen;
|
||||
private System.Windows.Forms.SplitContainer splitDossiers;
|
||||
private System.Windows.Forms.DataGridView dgvSignals;
|
||||
private System.Windows.Forms.TextBox tbDossier;
|
||||
private System.Windows.Forms.TabPage tabBerichte;
|
||||
private System.Windows.Forms.ToolStrip toolStripReports;
|
||||
private System.Windows.Forms.ToolStripButton btnReportsRefresh;
|
||||
private System.Windows.Forms.SplitContainer splitReports;
|
||||
private System.Windows.Forms.DataGridView dgvReports;
|
||||
private System.Windows.Forms.TextBox tbReport;
|
||||
private System.Windows.Forms.TabPage tabCounterfactual;
|
||||
private System.Windows.Forms.ToolStrip toolStripCf;
|
||||
private System.Windows.Forms.ToolStripButton btnCfRefresh;
|
||||
private System.Windows.Forms.DataGridView dgvCounterfactuals;
|
||||
private System.Windows.Forms.Label lblStatus;
|
||||
}
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using PolyTrader.Core.Analytics;
|
||||
using PolyTrader.Modules.Supervisor.Agent;
|
||||
using PolyTrader.Modules.Supervisor.Persistence;
|
||||
using PolyTrader.Modules.Supervisor.Services;
|
||||
|
||||
namespace PolyTrader.Modules.Supervisor.Ui
|
||||
{
|
||||
/// <summary>
|
||||
/// Hauptfenster des Supervisor-Moduls: Tab „Analyse" (Chat mit Profil-/Modellwahl, Tool-Aufrufe
|
||||
/// transparent), Tab „Dossiers" (Signal-Browser), Tab „Berichte" (gespeicherte Analysen).
|
||||
/// Layout im Designer (SupervisorMainForm.Designer.cs), Verhalten/Daten hier.
|
||||
/// </summary>
|
||||
public partial class SupervisorMainForm : Form
|
||||
{
|
||||
private DossierService? _dossiers;
|
||||
private SupervisorAgent? _agent;
|
||||
private ISupervisorReportRepository? _reports;
|
||||
private ISupervisorCounterfactualRepository? _counterfactuals;
|
||||
|
||||
public SupervisorMainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
foreach (var profile in SupervisorProfiles.All)
|
||||
cbProfile.Items.Add(profile);
|
||||
cbProfile.SelectedIndex = 0;
|
||||
|
||||
btnSend.Click += async (_, _) => await SendQuestionAsync();
|
||||
tbChatInput.KeyDown += async (_, e) =>
|
||||
{
|
||||
if (e.Control && e.KeyCode == Keys.Enter) { e.SuppressKeyPress = true; await SendQuestionAsync(); }
|
||||
};
|
||||
btnClearChat.Click += (_, _) => rtbChat.Clear();
|
||||
btnDossierRefresh.Click += (_, _) => LoadSignals();
|
||||
btnDossierOpen.Click += (_, _) => OpenDossier(tbSignalId.Text.Trim());
|
||||
dgvSignals.SelectionChanged += (_, _) => OpenSelectedSignal();
|
||||
btnReportsRefresh.Click += (_, _) => LoadReports();
|
||||
dgvReports.SelectionChanged += (_, _) => ShowSelectedReport();
|
||||
btnCfRefresh.Click += (_, _) => LoadCounterfactuals();
|
||||
}
|
||||
|
||||
public void Initialize(IServiceProvider services)
|
||||
{
|
||||
_dossiers = services.GetRequiredService<DossierService>();
|
||||
_agent = services.GetRequiredService<SupervisorAgent>();
|
||||
_reports = services.GetRequiredService<ISupervisorReportRepository>();
|
||||
_counterfactuals = services.GetRequiredService<ISupervisorCounterfactualRepository>();
|
||||
LoadSignals();
|
||||
LoadReports();
|
||||
LoadCounterfactuals();
|
||||
AppendChat("System", "Supervisor bereit (read-only). API-Key: POLYTRADER_OPENROUTER_KEY oder Datei openrouter.key. " +
|
||||
"MCP-Light für externe Clients: POLYTRADER_MCP_PORT setzen.", System.Drawing.Color.Gray);
|
||||
}
|
||||
|
||||
// ===== Analyse-Chat =====
|
||||
|
||||
private async System.Threading.Tasks.Task SendQuestionAsync()
|
||||
{
|
||||
if (_agent == null) return;
|
||||
string question = tbChatInput.Text.Trim();
|
||||
if (question.Length == 0) return;
|
||||
var profile = cbProfile.SelectedItem as SupervisorProfile ?? SupervisorProfiles.Allgemein;
|
||||
|
||||
tbChatInput.Text = "";
|
||||
btnSend.Enabled = false;
|
||||
AppendChat($"Du ({profile.Name})", question, System.Drawing.Color.DarkBlue);
|
||||
lblStatus.Text = "Analyse läuft …";
|
||||
|
||||
var progress = new Progress<string>(msg => AppendChat("Tool", msg, System.Drawing.Color.DarkGoldenrod));
|
||||
try
|
||||
{
|
||||
string model = tbModel.Text;
|
||||
var result = await System.Threading.Tasks.Task.Run(() =>
|
||||
_agent.AskAsync(question, model, progress, profile));
|
||||
AppendChat("Supervisor", result.Answer, System.Drawing.Color.Black);
|
||||
lblStatus.Text = $"Fertig. {result.ToolInvocations.Count} Tool-Aufruf(e), ~{result.PromptTokens + result.CompletionTokens} Tokens.";
|
||||
SaveReport(profile, model, question, result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppendChat("Fehler", ex.Message, System.Drawing.Color.Firebrick);
|
||||
lblStatus.Text = "Fehler bei der Analyse.";
|
||||
}
|
||||
finally
|
||||
{
|
||||
btnSend.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveReport(SupervisorProfile profile, string model, string question, AgentResult result)
|
||||
{
|
||||
try
|
||||
{
|
||||
var calls = new List<object>();
|
||||
foreach (var (tool, args, _) in result.ToolInvocations)
|
||||
calls.Add(new { tool, args });
|
||||
_reports?.Insert(new SupervisorReport
|
||||
{
|
||||
Profile = profile.Name,
|
||||
Model = model,
|
||||
Question = question,
|
||||
Answer = result.Answer,
|
||||
ToolCallsJson = System.Text.Json.JsonSerializer.Serialize(calls),
|
||||
ToolCallCount = result.ToolInvocations.Count,
|
||||
PromptTokens = result.PromptTokens,
|
||||
CompletionTokens = result.CompletionTokens
|
||||
});
|
||||
LoadReports();
|
||||
}
|
||||
catch { /* Bericht-Ablage ist Beiwerk – Analyse-Ergebnis steht im Chat */ }
|
||||
}
|
||||
|
||||
private void AppendChat(string who, string text, System.Drawing.Color color)
|
||||
{
|
||||
if (InvokeRequired) { BeginInvoke(() => AppendChat(who, text, color)); return; }
|
||||
rtbChat.SelectionStart = rtbChat.TextLength;
|
||||
rtbChat.SelectionColor = color;
|
||||
rtbChat.AppendText($"[{DateTime.Now:HH:mm:ss}] {who}: {text}{Environment.NewLine}{Environment.NewLine}");
|
||||
rtbChat.ScrollToCaret();
|
||||
}
|
||||
|
||||
// ===== Dossier-Browser =====
|
||||
|
||||
private void LoadSignals()
|
||||
{
|
||||
if (_dossiers == null) return;
|
||||
try
|
||||
{
|
||||
List<SignalSummary> signals = _dossiers.RecentSignals(200);
|
||||
dgvSignals.DataSource = signals;
|
||||
lblStatus.Text = signals.Count == 0
|
||||
? "Noch keine Journal-Einträge (Entscheidungen entstehen, sobald Signale verarbeitet werden)."
|
||||
: $"{signals.Count} Signale.";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lblStatus.Text = $"Journal nicht lesbar: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenSelectedSignal()
|
||||
{
|
||||
if (dgvSignals.CurrentRow?.DataBoundItem is SignalSummary s)
|
||||
OpenDossier(s.SignalId);
|
||||
}
|
||||
|
||||
private void OpenDossier(string signalId)
|
||||
{
|
||||
if (_dossiers == null || string.IsNullOrWhiteSpace(signalId)) return;
|
||||
try
|
||||
{
|
||||
var dossier = _dossiers.BuildForSignal(signalId);
|
||||
tbDossier.Text = DossierBuilder.ToMarkdown(dossier).Replace("\n", Environment.NewLine);
|
||||
tbSignalId.Text = signalId;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
tbDossier.Text = $"Dossier konnte nicht geladen werden: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Berichte =====
|
||||
|
||||
private void LoadReports()
|
||||
{
|
||||
if (_reports == null) return;
|
||||
try
|
||||
{
|
||||
dgvReports.DataSource = _reports.GetRecent(100);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lblStatus.Text = $"Berichte nicht lesbar (sup_-Migration angewendet?): {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Counterfactuals =====
|
||||
|
||||
private void LoadCounterfactuals()
|
||||
{
|
||||
if (_counterfactuals == null) return;
|
||||
try
|
||||
{
|
||||
dgvCounterfactuals.DataSource = _counterfactuals.GetRecent(200);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lblStatus.Text = $"Counterfactuals nicht lesbar (Migration angewendet?): {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowSelectedReport()
|
||||
{
|
||||
if (dgvReports.CurrentRow?.DataBoundItem is SupervisorReport r)
|
||||
tbReport.Text =
|
||||
$"[{r.CreatedAt:dd.MM.yyyy HH:mm}] Profil {r.Profile} · Modell {r.Model} · {r.ToolCallCount} Tool-Aufrufe{Environment.NewLine}{Environment.NewLine}" +
|
||||
$"FRAGE:{Environment.NewLine}{r.Question}{Environment.NewLine}{Environment.NewLine}" +
|
||||
$"ANTWORT:{Environment.NewLine}{r.Answer.Replace("\n", Environment.NewLine)}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="toolStripChat.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="toolStripDossier.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>188, 17</value>
|
||||
</metadata>
|
||||
<metadata name="toolStripReports.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>382, 17</value>
|
||||
</metadata>
|
||||
<metadata name="toolStripCf.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>578, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
AAABAAMAEBAAAAAAIABMAwAANgAAABgYAAAAACAAMwYAAIIDAAAgIAAAAAAgAFEHAAC1CQAAiVBORw0K
|
||||
GgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADE0lEQVR4nG1TTWhUVxT+7l8mb/6nGc3YOBkJCTFG
|
||||
Y22GxBiipUGpi6jgShG6KJJdU3Xvwm1Azaagdlm6E/pDaaGh0E3FUgRbnRijkjTGxJDJ/P+8effdW+6b
|
||||
+Aeey4F3zz3f98757rmku7t7plarPVhZWbkFAPF4/HhfX9+5SCR8knMRMDEpnUqhUPxhbm7u242NjV9M
|
||||
rKOj47xlWXu53+/n6XT65uzs7Eoqlfy0t3fPxfi2bcTnawVn3ORCujJg2/WzyWTnmfn5zNWlpeXfx8bG
|
||||
bmYyma85Y6wRi0YxOjr6cyLxIShjaG21XCEEI4R4BJRREELcSDTG0unhS8lk6lIsFoPBciYEzWY3oVzt
|
||||
FEslFgkFab1aZVWt8dq0NgSMaI1isaxAqJvbzAnGGOVQCkJwrK4ViRCCIhJFrV5HrVoFowzaW0AgFEbD
|
||||
tuE0bJrP5lUy1dGsTkODc45SIY8DQ0OYODaOwtMMPp+cRL5YQC6XwxdfTsFZf47R/XswODKCXC7bJNfN
|
||||
9uDzcTiNCtoifiTiIXwyfhjdO7ejXsmjYZfQ+YEfH+3rRXp4EGGLQzpVtLRQMOKC7B08cr1zZ9fU/fsP
|
||||
pBCcB4JhWIEAsusvvd6NGTHbtrejUi6jWinDcRw5MNDPnyw+muETvausfxAY71oGF8IcQrmu900p9QiU
|
||||
UpDOY++GhBCQjoP2pB8P/95k/FD7s/nP9pfBD64xuEaVLX+fqS1nYLJG8evy+jzZBaRuzyTu9fRUouVS
|
||||
mZh6bVtDm8S3jHhaEdOWDoaCemEhkD89tfYxXQSW/vk3e4M7Fm3lRDaqCusvNJYX33UTkzUFSxBpcg3G
|
||||
YLmZkShxpuNthUNHR0JH4C+7oZQLRt9txFVQBAwWDYrf/iz88dU3zrQ3X9pUR0xh2HH7Ar8x3M8nYmGJ
|
||||
mm0EeWOWjyFX5Lj7UP50+pqcJASryhB4k/qGJHD5BM4O7aanEm0Y8XH4zLktYa9lceevR+r7Kz/iO0JQ
|
||||
2QLr5mt5pROBVs2rD3VG0NPC0GI2DReN/wpYAFCiBDDg5n+B/wES01Pdhr/66QAAAABJRU5ErkJggolQ
|
||||
TkcNChoKAAAADUlIRFIAAAAYAAAAGAgGAAAA4Hc9+AAABfpJREFUeJylVWtsVMcV/mbu3L13n96HwXmY
|
||||
x5oQJ+A62BSXBiVrUUIgDZWaihRUVVSIOj/yIz+itP9i+W+iqGqlVCJVE6WiSgQJUl4FQgKxIosUikWI
|
||||
X5BiGwXc+LFee3e93rv3zkx07tqWTdpfPdKR7p055zvnfHPODGtsbNxfqVQOjoyMPLV161azoaFBnThx
|
||||
QqIqOxrua9ibSqQO27Z9NwC9sM7K5fJ/srns68P/Hj4FoIcW9+/fbwwPD/PLly+76XT6ZCAQeItFo9G9
|
||||
TU1N/8jn86/19/c/wxiDEKK1vr7+hebm5gOrV6+GZduwrCCWi+PMwymXMTExgatXr75969atl13X7aW9
|
||||
zZs3H43FYh19fX1PiEKhYKXTaZVKpTpyudz8+Pj4+ba2bX/dtq0tpTWTUkoYwjQY4+AL4AqAIQKwLCbX
|
||||
r29AOp0+cOnSxccuXfrXkdra2szOnTs7stmsunDhgiWobMYY10o5ra2tz0npPdeypRW3x771ApYlVq2q
|
||||
pYrA+SL8QhCl4HmeMTk5hYrjeJlMeyoajb0rhOCccQcMFmFTABiGgdGRUUOYAd30g2Y2eO26SiaTorY2
|
||||
iUql4lOxSP6iMFLOQTYTE5NiYOi62tLSwr++/rUeHR01auI1vp0fgMQ0TUzncqx/YBBBy+I10SiK+QK0
|
||||
UuBCQEkJrath6Jy4YQBaY35Ogmzzs3k+OHgNxUKBJWpiS7ZieUrkqDwP3A5i5MYNCNNEMBzBXGEW0Wis
|
||||
CurTI5HPzYBxhnAsThWAcwbP9ap9xqm+qvjEamgwMHhSwnUrCIZD+PkvD6ClbTuEO49Hdu+G6ynMzc35
|
||||
6lQ8tO/bh/a9PwNzStjx8I8QT6ZQqZThehUfa0UAimoIKhnIZqewc/fj2PXow+g58SbGh77EoSNHsPa+
|
||||
jZiemsJ0dgrrNmzErw8fxlefvIeB7jN4cs9jyOza5e8rqVc0hE8R8WUFLJ/vQr6AH25pRjwaQePGDahb
|
||||
sw5xYWB9/V04O5PznRrW3oM4B+rrapHc+wTWrFmHCjNRKBZh22G/65YCEKu2JZDPF+F5ZdTEIvjjKy9j
|
||||
y9YWtO77BbRU+POrf8K5c+chRLX0M6c+glspoeHHGTpnvHHsb7jSe8X39dwSPM+BLWwQtqA7YdaxMD1b
|
||||
xNiURCQcxnun/oljx8+ChszPQggkEgkEQyH/f+zKTXx8/g80B1hsc2qCeLwGxWIRkSRDLBEAeYv7U2Ab
|
||||
EjncFZxFRBVg2S4Mg4PzxNJRaQDS86D0TPXgGIch4iv2afCknPFnZu26GURsDsIWz++Ae/DRi4g2ljjK
|
||||
E9UJ+n9EE+d5XrgWwvqbcMW7Q7iR7i8MbK9ZtcmZn5JaamMxCPG7qP9NmD/Oy9peA8xg0gomjS/6JwcI
|
||||
W3x8nQ0dup3tsdTqTdIIKKnKBjmSWhZgCoAbALsjiGaAkgDNllOuJk5qGJayFDMmb2d7CFsQUO8oPnjw
|
||||
q7GD9zfXBSulm9rgYI4LjAwD09NA2VnIdnkATd0HJBNAfT0gOCAVtB2q4/1Xx4qEST5Cvag568LpB+6d
|
||||
feeeu4O/sSJxzy3NCJrGaFiDOpOyvPNoKFuqLkjPhGKQnkYgFJfFSUdc7p9955WzOK07dZW9zgzEq71I
|
||||
v/5bfvKR7bVNHitJ5RQN06QJX3G1rBClqbuAigsYVkQKHTI+/2Kq7/Bf1FPPtmKkqxue76o12NNPwxzs
|
||||
xgMvHeJ/b3so2qRMT8tySSupqRifoaX3cvFbQzODaWGHGHcFu/hloe93b6pfPZjB0PHjcBmD9i8N+ji+
|
||||
CV7fBAZ/f0wdOtMz+/6337g6GLB4KGQygzHJGDy+oPRNa7QXClicbMmHfAmDsAhzMZkl6ewE7+qCCaDu
|
||||
mXY8+dNW1rEqgfo1dTyViDD/qSShrHJFjW/GVXYyh1sf9erXjn6GDwGMd3bC7epaMv3+WBFd7QxGN0D3
|
||||
QnRPE9p+0oRM2ERK0r1OrcjA5lxkP+1D9+k+XARQyAClzzSo0v8xNXcIkX60w6/GBhAGQG/gcqU1m2zu
|
||||
bOHl8h262pYvryzyJgAAAABJRU5ErkJggolQTkcNChoKAAAADUlIRFIAAAAgAAAAIAgGAAAAc3p69AAA
|
||||
BxhJREFUeJy1l2lsXFcVx39vG49nvMV2NmcZO3Ed2U1LKKJt7JBIjRNFiaryBb4ggbAgjYrUIhBQCnxi
|
||||
UeknUKWqqvgCUlUJWgpEaULSFDW08JVmcSIn8cx4SWzHmfHYM2/mzdvQuZ5xvYYUKVe6mnnvnnP+/3uW
|
||||
e+7TgEhXV5czNDRUA5RZY2zdurXBNM1vhWH4jTAMH5V3YRiqNU3Tqr8XNU37ved5vxsbG5tdy9ZiTA1Y
|
||||
19nZmRFjN2/eXE5C2759+w5N0/5imubunp4etmxpEzJYVmSJRdctMzY2xvj4LQYHB/E873IYhl8eGRkZ
|
||||
Fq6LwXfu3OkI6Rs3bjQLgQ0dHR2Thw8f5syZM6TT6SoJo729/TXDMI7v37+frq4uZmZyZGdy5PMFPM9f
|
||||
QsA0Derq4qxraqSpqZGhoSEuXLiA7/tvpFKp5wBRiCQSCefIkSOcPXuWZDK50RTlIAjYtWsXruty/vx5
|
||||
J51OxxOJxLVEYvs2ITY1dZdPLl6mtraWlpYW2traiNbUSAwqftIoOQ75fJ6pO9OkR0bZuGEDAwPfFKDj
|
||||
YRgeTafTuxKJROHgwYMKSzariFdjKSQy09P09/dz+vTpQl9fH93dPVy7doNiqURHezuxeEzJ+r5PwbZX
|
||||
BDYWixGPx7ELNslUikwmS3//Ya5eHdzqum5WbGczWfzAX8gfcyHYmsbwcJK6hkYGBgbQdYP/fHIR0zTp
|
||||
7OwAdEql0oLiWkPsGKahdJLJtLLxcE83O3Z0REZGxkilUvT29X4aOhYNXdO4fes2kUgNmZkZwsBn86ZN
|
||||
lB1XeeizDF3XWd/ayujoKBcvXaF1fTMTE1OKYLVqVhCQWIpiLpfDK5dpamxScXbuY+ereUJmfV092Zks
|
||||
c7N5dF3jU+jVCDCv6DiOlBE1NTXYEmsBX2AtRJbuQr0Nw9XOBWVDcsYuFObfL9Mzl4BXDAm4hCOfn8Mt
|
||||
l9F0HcM01brvy5qOaVnKWzIkPJ5bxvf8BVmhEvg+pmFgGAZlsbOKp/TlL0TR88qKdffn9vDWu+/w/A9e
|
||||
4onH9uDdTvLG23/i0Se/RCGfV0kpU/7Lu9fefYdnv/9jvvj5PQQTKd56+4/KhpDzPFfZvGcIzEhEsZYd
|
||||
2a6NlKKcd7/69leIxupwnBJR4PHeXv5x6s/UxuJKr2gXePzJXuTpleNfJRavwy2VlPG9fX38/dTfiFg1
|
||||
BFqIbhhreyAeiyn3C9OibdN/YN+8i+WduLjsUAsc2vsYtl1UuSLTLhY51PcFRQB/XtZzHaV76MA+ZUts
|
||||
Svhqo9GVHggryWMXHSzLrDzr/Pvjf7G3r5ezV1NLlD7850e4nqfcL8N1PT688BEH9u9bISs2xJZyvyS4
|
||||
660k0NDQoB5836WSV+psf/bECXU8zxNSKaqMRCxLZbesUVl5/jvPUV5F1rIsotEoQTDfOzzfXUnALjoE
|
||||
oUbZDQgJlGIYaphWFMOU3rR0yLofagTevOfCUMewokTXkg00gkqZum6gsGQuELg7FzBXssjOgmFWa3y1
|
||||
ollr3J+sOMf3YM6xmC3N578m7fjSz5ncfewoOO8t7dwPYghizVEun3qPR36GasfhxBzXW0cmH6qvayFw
|
||||
7z5QfN1qYW5yEsEUbCHg3bzDyW1TE9+L1W/Ef8AEjMhGclMTCKZgS86XXj3Hm3fHx9G1JgggXD4lLNVZ
|
||||
8eJqU42KnOgstyO2BUOwBFOwhUD5yhiTczbDmfEJMNsIfRamUgrB0MDUwfofU2REVnTUZhbbMtsQDMES
|
||||
TMGWEMhS4dVzvPBS7fDJ7iceAe4QVurVcSGVhuEkZDIwm1/R0BaG7LqhDpqboaMDursqOxcPGRZoLYxd
|
||||
vyS7f0EwBbtqSo78zW+e4LcPPxR/ZnvXJvzCzfnGK7vR52e1m65VdMr7FffL/UWm6uQS+/hORoYmuHK9
|
||||
8Nevva4I3BYPVG3Jbx3Qcf5FPkjsaG5Ztz6Kb99aqMrFu74XgcXeqMoasTayd0qkhzN3D77MU0ASyIvY
|
||||
YlvSplqAHe//iJOJjsbWda1RfGea0F96Bb/focldoKaV7HSJdDI33f9rngbkO0FKzV9tMxbQKp54/0VO
|
||||
tjZbzZsT9eDZhG7pvs8oVRVWFMwYt9NzTGfcTP/LClx2Pi39a7Esa5BI/OEEP+3cwLFNbVHqGg2VmNKa
|
||||
JbjLyShDuo4uNyfDIp/zmbhV4sYUp77+Or8A0svBF/TWILEO2PRUD7t/eIxfNsRob2zUicU0amt15F6x
|
||||
6LsEiVKxGGDbIblcwKxN6pVT/OSDQS4DE0B2Ofi9CFRzIlbJi/Xbmtn43SM83bOFQ/VR5ENhxZgrkRwc
|
||||
59xvznByNKPq/E4l3vIV4/8/bUyreEOIyIVHLg6NoC5Gy++TUvFFIAfIl7HUuQDLrtdMn8/Sc8Ujcl7I
|
||||
nUoOsOW66j4rx2vl4/a+Sue/FWVwQfGabmUAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
Reference in New Issue
Block a user