UI: Launcher-Account-Uebersicht + pure TradeAnalytics-Fundament
- TradeAnalytics (Core, pur/testbar): KPIs (Netto-PnL/Winrate/Ø/Profit-Faktor), Equity-Kurve, PnL je Modul/Account/Tag, Window-Summary. Speist Dashboard + Launcher. 7 Tests. - Launcher dgv_accountlist: Spalten via Designer (Account, Module, Polymarket-Button, Wallet-USDC, 3T-PnL, 3T-Winrate, Overall P/L). Daten je Account aus dem Core-Trade-Log via TradeAnalytics; Auto-Refresh alle 30 s; Polymarket-Button oeffnet das Wallet-Profil. DB-Abfragen fehlertolerant. Build 0 Fehler, 331 Tests gruen, --smoke-ui ok (Launcher laedt Uebersicht). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
0aedddabe8
commit
7d63791e38
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using PolyTrader.Core.Analytics;
|
||||
using PolyTraderSharp.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace PolyTrader.Tests
|
||||
{
|
||||
/// <summary>Sicherheitsnetz für die Dashboard-/Launcher-Auswertungen (KPIs, Equity-Kurve, Gruppierungen).</summary>
|
||||
public class TradeAnalyticsTests
|
||||
{
|
||||
private static TradeRecord Rec(decimal pnl, DateTime closedAt, string module = "M", int account = 1) =>
|
||||
new() { RealizedPnl = pnl, ClosedAt = closedAt, ModuleName = module, AccountId = account };
|
||||
|
||||
private static readonly DateTime T0 = new(2026, 7, 1, 12, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
[Fact]
|
||||
public void ComputeKpis_basic_set()
|
||||
{
|
||||
var k = TradeAnalytics.ComputeKpis(new[]
|
||||
{
|
||||
Rec(10m, T0), Rec(-4m, T0), Rec(6m, T0), Rec(-2m, T0)
|
||||
});
|
||||
|
||||
Assert.Equal(4, k.TradeCount);
|
||||
Assert.Equal(10m, k.NetPnl);
|
||||
Assert.Equal(50m, k.WinRatePct);
|
||||
Assert.Equal(2.5m, k.AvgPnlPerTrade);
|
||||
Assert.Equal(2.6667m, Math.Round(k.ProfitFactor, 4)); // 16 / 6
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComputeKpis_no_losses_uses_sentinel_profitfactor()
|
||||
{
|
||||
var k = TradeAnalytics.ComputeKpis(new[] { Rec(5m, T0), Rec(3m, T0) });
|
||||
Assert.Equal(100m, k.WinRatePct);
|
||||
Assert.Equal(TradeAnalytics.NoLossProfitFactor, k.ProfitFactor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComputeKpis_empty_is_zero()
|
||||
{
|
||||
var k = TradeAnalytics.ComputeKpis(Array.Empty<TradeRecord>());
|
||||
Assert.Equal(0, k.TradeCount);
|
||||
Assert.Equal(0m, k.NetPnl);
|
||||
Assert.Equal(0m, k.ProfitFactor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EquityCurve_is_cumulative_and_time_ordered()
|
||||
{
|
||||
var curve = TradeAnalytics.EquityCurve(new[]
|
||||
{
|
||||
Rec(5m, T0.AddMinutes(2)),
|
||||
Rec(10m, T0.AddMinutes(1)),
|
||||
Rec(-3m, T0.AddMinutes(3))
|
||||
});
|
||||
|
||||
Assert.Equal(3, curve.Count);
|
||||
Assert.Equal(10m, curve[0].Cumulative); // frühester zuerst
|
||||
Assert.Equal(15m, curve[1].Cumulative);
|
||||
Assert.Equal(12m, curve[2].Cumulative);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PnlByKey_groups_and_orders_desc()
|
||||
{
|
||||
var byModule = TradeAnalytics.PnlByKey(new[]
|
||||
{
|
||||
Rec(10m, T0, module: "A"), Rec(-2m, T0, module: "A"), Rec(5m, T0, module: "B")
|
||||
}, t => t.ModuleName);
|
||||
|
||||
Assert.Equal(2, byModule.Count);
|
||||
Assert.Equal("A", byModule[0].Key); // 8 vor 5
|
||||
Assert.Equal(8m, byModule[0].Pnl);
|
||||
Assert.Equal(2, byModule[0].Count);
|
||||
Assert.Equal("B", byModule[1].Key);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PnlByDay_groups_by_calendar_day()
|
||||
{
|
||||
var byDay = TradeAnalytics.PnlByDay(new[]
|
||||
{
|
||||
Rec(4m, T0), Rec(6m, T0.AddHours(2)), Rec(-1m, T0.AddDays(1))
|
||||
});
|
||||
|
||||
Assert.Equal(2, byDay.Count);
|
||||
Assert.Equal(10m, byDay[0].Pnl); // Tag 1: 4+6
|
||||
Assert.Equal(-1m, byDay[1].Pnl); // Tag 2
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WindowSummary_pnl_winrate_count()
|
||||
{
|
||||
var (pnl, winRate, count) = TradeAnalytics.WindowSummary(new[]
|
||||
{
|
||||
Rec(3m, T0), Rec(-1m, T0), Rec(2m, T0), Rec(-4m, T0)
|
||||
});
|
||||
|
||||
Assert.Equal(0m, pnl);
|
||||
Assert.Equal(50m, winRate);
|
||||
Assert.Equal(4, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user