using System.Linq; using PolyTrader.Modules.CopyTrading.Logic; using Xunit; using static PolyTrader.Modules.CopyTrading.Logic.TraderScore; namespace PolyTrader.Tests { /// /// Sicherheitsnetz für die Copy-Score-Kennzahlen und den Auto-Pause-Kill-Switch (Phase 3). /// public class TraderScoreTests { [Fact] public void Compute_metrics_from_mixed_pnls() { var m = Compute(new[] { 10m, -3m, 5m, -2m }); Assert.Equal(4, m.TradeCount); Assert.Equal(10m, m.CopyPnl); Assert.Equal(3.0m, m.ProfitFactor); // grossProfit 15 / grossLoss 5 Assert.Equal(2.5m, m.AvgPnlPerTrade); // 10 / 4 } [Fact] public void Compute_empty_is_all_zero() { var m = Compute(Enumerable.Empty()); Assert.Equal(0, m.TradeCount); Assert.Equal(0m, m.CopyPnl); Assert.Equal(0m, m.ProfitFactor); Assert.Equal(0m, m.AvgPnlPerTrade); } [Fact] public void Compute_all_wins_uses_no_loss_sentinel() { var m = Compute(new[] { 5m, 5m }); Assert.Equal(NoLossProfitFactor, m.ProfitFactor); Assert.Equal(10m, m.CopyPnl); } [Fact] public void Compute_all_losses_profit_factor_zero() { var m = Compute(new[] { -5m, -5m }); Assert.Equal(0m, m.ProfitFactor); Assert.Equal(-10m, m.CopyPnl); Assert.Equal(-5m, m.AvgPnlPerTrade); } [Theory] [InlineData(false, 20, -50, 10, 10, false)] // deaktiviert [InlineData(true, 5, -50, 10, 10, false)] // zu wenige Trades [InlineData(true, 12, -15, 10, 10, true)] // Verlust über Schwelle [InlineData(true, 12, -5, 10, 10, false)] // Verlust unter Schwelle [InlineData(true, 12, 20, 10, 10, false)] // im Plus [InlineData(true, 12, -10, 10, 10, true)] // genau auf der Schwelle public void ShouldAutoPause_rules(bool enabled, int count, double pnl, int minTrades, double threshold, bool expected) { Assert.Equal(expected, ShouldAutoPause(enabled, count, (decimal)pnl, minTrades, (decimal)threshold)); } } }