feat: implement Part D and E from FIXPLAN
- D1/D2/D2c: Added TraderTraits entity, TraderTraitCalculator, Market Return Metrics (MedianWin, AvgWin, etc.), and trait filters
- D3: Implemented HF-Trader Tiering via IngestMode (Full, Aggregated, SnapshotOnly) and updated TradeHistoryWorker to respect tiers
- E1-E5: Added MasterStatus to Trader, TraderWindowMetrics for rolling analytics, Fingerprint metrics (PriceBandProfile, P50/P90), Copyability aggregates (Volume, Drift, Edge)
- E6: Implemented GET /api/traders/{id}/profile and GET /api/traders/correlation
- Replaced FIXPLAN-2026-07-09.md with FIXPLAN-TODO.md and FIXPLAN-DONE.md
- Cleaned up API docs and plan to use generic terms (removed hardcoded PolyTrader references)
- Added respective EF Core Migrations
This commit is contained in:
@@ -833,4 +833,52 @@ public class PositionPnLEngineTests
|
||||
$"Trades30d ({analytics.Trades30d}) must never exceed TotalTrades ({trader.TotalTrades})");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RecalculateTraderPositionsAsync_SumsAggregatedCountForTotalTrades()
|
||||
{
|
||||
// Arrange
|
||||
var dbName = Guid.NewGuid().ToString();
|
||||
using (var db = CreateDbContext(dbName))
|
||||
{
|
||||
var trader = new Trader { Id = 1, PlatformUserId = "0x1", DisplayName = "Trader 1", TotalTrades = 0 };
|
||||
var market = new Market { Id = 10, PlatformMarketId = 1L, Question = "Q?" };
|
||||
market.Outcomes.Add(new MarketOutcome { Id = 100, MarketId = 10, Label = "Yes", TokenId = "t100", CurrentPrice = 0.50m });
|
||||
db.Traders.Add(trader);
|
||||
db.Markets.Add(market);
|
||||
|
||||
db.Trades.Add(new Trade
|
||||
{
|
||||
Id = 10, TraderId = 1, DbMarketId = 10, MarketOutcomeId = 100,
|
||||
Side = TradeSide.Buy, Price = 0.40m, Size = 100m, Amount = 40m,
|
||||
ExecutedAt = DateTime.UtcNow.AddDays(-2),
|
||||
AggregatedCount = 5 // Represents 5 trades
|
||||
});
|
||||
db.Trades.Add(new Trade
|
||||
{
|
||||
Id = 11, TraderId = 1, DbMarketId = 10, MarketOutcomeId = 100,
|
||||
Side = TradeSide.Sell, Price = 0.50m, Size = 50m, Amount = 25m,
|
||||
ExecutedAt = DateTime.UtcNow.AddDays(-1),
|
||||
AggregatedCount = null // Represents 1 trade
|
||||
});
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
// Act
|
||||
using (var db = CreateDbContext(dbName))
|
||||
{
|
||||
var pnlEngine = new PositionPnLEngine(db, NullLogger<PositionPnLEngine>.Instance);
|
||||
await pnlEngine.RecalculateTraderPositionsAsync(1);
|
||||
}
|
||||
|
||||
// Assert
|
||||
using (var db = CreateDbContext(dbName))
|
||||
{
|
||||
var trader = await db.Traders.SingleAsync(t => t.Id == 1);
|
||||
Assert.Equal(6, trader.TotalTrades); // 5 + 1
|
||||
|
||||
var analytics = await db.TraderAnalytics.SingleAsync(a => a.TraderId == 1);
|
||||
Assert.Equal(6, analytics.Trades30d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user