using System; using System.Collections.Generic; using System.Linq; using PolyTrader.Core.Analytics; using PolyTraderSharp.Models; using Xunit; namespace PolyTrader.Tests { /// Sicherheitsnetz für die Dashboard-/Launcher-Auswertungen (KPIs, Equity-Kurve, Gruppierungen). 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()); 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); } } }