@
UI-U3: server-side min-winrate/min-copyability filters Add optional minWinRate/minCopyability params to GetTradersAsync so the leaderboard min-value filters see the full pool instead of being applied client-side to only the first page of results. Covered by a new AnalyticsService test (three traders, both filters). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> @
This commit is contained in:
@@ -101,6 +101,51 @@ public class AnalyticsServiceTests
|
||||
Assert.Equal(87.5m, deepDive.EntryQuality);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetTradersAsync_MinFilters_ExcludeBelowThreshold()
|
||||
{
|
||||
// Arrange
|
||||
using var db = CreateDbContext();
|
||||
var traderRepo = new TraderRepository(db);
|
||||
var tradeRepo = new TradeRepository(db, NullLogger<TradeRepository>.Instance);
|
||||
var discoveryMock = new Mock<IDiscoveryService>();
|
||||
var pnlEngineMock = new Mock<IPositionPnLEngine>();
|
||||
var alertRepoMock = new Mock<IAlertRepository>();
|
||||
var watchlistRepoMock = new Mock<IWatchlistRepository>();
|
||||
watchlistRepoMock.Setup(w => w.GetAllAsync(It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<WatchlistEntry>());
|
||||
var marketRepo = new MarketRepository(db);
|
||||
var providers = new List<IPlatformProvider>();
|
||||
|
||||
var svc = new AnalyticsService(
|
||||
traderRepo, tradeRepo, alertRepoMock.Object, watchlistRepoMock.Object,
|
||||
marketRepo, discoveryMock.Object, providers, pnlEngineMock.Object,
|
||||
NullLogger<AnalyticsService>.Instance);
|
||||
|
||||
// Three traders: WinRate 40 / 60 / 80, Copyability 30 / 55 / 90.
|
||||
db.Traders.Add(new Trader { Id = 1, PlatformUserId = "0xA", DisplayName = "Low", WinRate = 40m,
|
||||
Analytics = new TraderAnalytics { TraderId = 1, CopytradingCopyabilityScore = 30m } });
|
||||
db.Traders.Add(new Trader { Id = 2, PlatformUserId = "0xB", DisplayName = "Mid", WinRate = 60m,
|
||||
Analytics = new TraderAnalytics { TraderId = 2, CopytradingCopyabilityScore = 55m } });
|
||||
db.Traders.Add(new Trader { Id = 3, PlatformUserId = "0xC", DisplayName = "High", WinRate = 80m,
|
||||
Analytics = new TraderAnalytics { TraderId = 3, CopytradingCopyabilityScore = 90m } });
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
// Act — minWinRate 55 keeps Mid + High.
|
||||
var byWinRate = await svc.GetTradersAsync(minWinRate: 55m);
|
||||
// minCopyability 60 keeps only High.
|
||||
var byCopyability = await svc.GetTradersAsync(minCopyability: 60m);
|
||||
// No filter keeps all three.
|
||||
var unfiltered = await svc.GetTradersAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, byWinRate.Count);
|
||||
Assert.DoesNotContain(byWinRate, t => t.DisplayName == "Low");
|
||||
Assert.Single(byCopyability);
|
||||
Assert.Equal("High", byCopyability[0].DisplayName);
|
||||
Assert.Equal(3, unfiltered.Count);
|
||||
}
|
||||
|
||||
private class MockDiscoveryService : IDiscoveryService
|
||||
{
|
||||
public Task<int> ImportTraderAsync(PlatformType platform, string platformUserId, string displayName, bool isAutoDiscovered = true, CancellationToken ct = default)
|
||||
|
||||
Reference in New Issue
Block a user