Add more test for the daily volumes and add button to set the UIFee Factor

This commit is contained in:
2025-11-14 18:04:58 +07:00
parent d27df5de51
commit 479fcca662
3 changed files with 453 additions and 1 deletions

View File

@@ -800,4 +800,179 @@ public class PlatformSummaryMetricsTests
result.PositionCountByAsset.Should().HaveCount(1);
result.TotalPlatformVolume.Should().BeGreaterThan(0);
}
[Fact]
public void CalculateDailySnapshotFromPositions_WithDateFiltering_CalculatesCumulativeMetricsCorrectly()
{
// Arrange - Create positions with different dates spanning multiple days
var baseDate = TestDate.Date;
var positions = new List<Position>
{
// Day 1: Two positions (one finished, one filled)
CreateFinishedPosition(50000m, 0.1m, TradeDirection.Long, 1m, 51000m, false),
CreateFilledPosition(40000m, 0.2m, TradeDirection.Short, 1m),
// Day 2: One finished position
CreateFinishedPosition(60000m, 0.05m, TradeDirection.Long, 2m, 61200m, false),
// Day 3: Two positions (future dates - should be excluded)
};
// Set specific dates for positions
positions[0].Date = baseDate.AddHours(10); // Day 1, 10 AM
positions[1].Date = baseDate.AddHours(14); // Day 1, 2 PM
positions[2].Date = baseDate.AddDays(1).AddHours(11); // Day 2, 11 AM
// Future positions (should be excluded)
var futurePositions = new List<Position>
{
CreateFinishedPosition(30000m, 0.15m, TradeDirection.Short, 1m, 29100m, false),
CreateFilledPosition(70000m, 0.08m, TradeDirection.Long, 1m)
};
futurePositions[0].Date = baseDate.AddDays(2).AddHours(9); // Day 3, 9 AM
futurePositions[1].Date = baseDate.AddDays(2).AddHours(16); // Day 3, 4 PM
var allPositions = positions.Concat(futurePositions).ToList();
// Act - Calculate snapshot for Day 2 (should include Day 1 and Day 2 positions only)
var targetDate = baseDate.AddDays(1); // Day 2
var filteredPositions = allPositions.Where(p => p.Date.Date <= targetDate).ToList();
var metrics = TradingBox.CalculatePlatformSummaryMetrics(filteredPositions);
// Assert - Should include positions from Day 1 and Day 2 only
metrics.TotalLifetimePositionCount.Should().Be(3); // 2 from Day 1 + 1 from Day 2
// Calculate expected volume: Day 1 positions + Day 2 position
// Default takeProfitPercentage is 0.04m (4%)
var day1Volume = (50000m * 0.1m * 1m + 52000m * 0.1m * 1m) + // Finished long: 5000 + 5200 = 10200
(40000m * 0.2m * 1m); // Open short: 8000 (not finished, no close volume)
var day2Volume = (60000m * 0.05m * 2m + 62400m * 0.05m * 2m); // Finished long with 2x leverage: 6000 + 6240 = 12240
var expectedTotalVolume = day1Volume + day2Volume; // 10200 + 8000 + 12240 = 30440
metrics.TotalPlatformVolume.Should().Be(expectedTotalVolume);
metrics.OpenInterest.Should().Be(40000m * 0.2m * 1m); // Only the open short position from Day 1
// Should have both BTC and position counts
metrics.VolumeByAsset.Should().ContainKey("BTC");
metrics.PositionCountByAsset["BTC"].Should().Be(3);
}
[Fact]
public void CalculateDailySnapshotFromPositions_WithNoPositionsForDate_ReturnsEmptyMetrics()
{
// Arrange - Create positions all after the target date
var baseDate = TestDate.Date;
var positions = new List<Position>
{
CreateFinishedPosition(50000m, 0.1m, TradeDirection.Long, 1m, 51000m, false),
CreateFilledPosition(40000m, 0.2m, TradeDirection.Short, 1m)
};
// Set dates after target date
positions[0].Date = baseDate.AddDays(1).AddHours(10);
positions[1].Date = baseDate.AddDays(2).AddHours(14);
// Act - Calculate snapshot for a date before all positions
var targetDate = baseDate; // Today, before all positions
var filteredPositions = positions.Where(p => p.Date.Date <= targetDate).ToList();
var metrics = TradingBox.CalculatePlatformSummaryMetrics(filteredPositions);
// Assert - Should have no positions for this date
metrics.TotalLifetimePositionCount.Should().Be(0);
metrics.TotalPlatformVolume.Should().Be(0);
metrics.TotalPlatformFees.Should().Be(0);
metrics.TotalPlatformPnL.Should().Be(0);
metrics.NetPnL.Should().Be(0);
metrics.OpenInterest.Should().Be(0);
metrics.VolumeByAsset.Should().BeEmpty();
metrics.PositionCountByAsset.Should().BeEmpty();
metrics.PositionCountByDirection.Should().BeEmpty();
}
[Fact]
public void CalculateDailySnapshotFromPositions_WithMixedAssetsAndDirections_CalculatesAssetBreakdownsCorrectly()
{
// Arrange - Create positions with different assets and directions over multiple days
var baseDate = TestDate.Date;
var positions = new List<Position>
{
// Day 1: BTC Long (finished) and ETH Short (open)
CreateFinishedPosition(50000m, 0.1m, TradeDirection.Long, 1m, 51000m, false), // BTC finished
CreateFilledPosition(3000m, 1m, TradeDirection.Short, 1m), // ETH open
// Day 2: BTC Short (finished) and ETH Long (finished)
CreateFinishedPosition(40000m, 0.2m, TradeDirection.Short, 2m, 39200m, false), // BTC finished
CreateFinishedPosition(3100m, 0.5m, TradeDirection.Long, 1m, 3180m, false) // ETH finished
};
// Set dates
positions[0].Date = baseDate.AddHours(10); // Day 1 BTC
positions[1].Date = baseDate.AddHours(14); // Day 1 ETH
positions[2].Date = baseDate.AddDays(1).AddHours(11); // Day 2 BTC
positions[3].Date = baseDate.AddDays(1).AddHours(15); // Day 2 ETH
// Set ETH tickers for ETH positions
positions[1].Ticker = Ticker.ETH;
positions[3].Ticker = Ticker.ETH;
// Act - Calculate snapshot for Day 2 (includes all positions)
var targetDate = baseDate.AddDays(1);
var filteredPositions = positions.Where(p => p.Date.Date <= targetDate).ToList();
var metrics = TradingBox.CalculatePlatformSummaryMetrics(filteredPositions);
// Assert - Should include all 4 positions
metrics.TotalLifetimePositionCount.Should().Be(4);
metrics.VolumeByAsset.Should().HaveCount(2); // BTC and ETH
metrics.PositionCountByAsset.Should().HaveCount(2);
metrics.PositionCountByAsset["BTC"].Should().Be(2);
metrics.PositionCountByAsset["ETH"].Should().Be(2);
// Should have only one direction (one open short ETH, rest are finished)
metrics.PositionCountByDirection.Should().HaveCount(1);
metrics.PositionCountByDirection[TradeDirection.Short].Should().Be(1); // Only the open ETH short position
// Open interest should only include the open ETH short position
metrics.OpenInterest.Should().Be(3000m * 1m * 1m); // ETH open short: 3000
}
[Fact]
public void CalculateDailySnapshotFromPositions_WithPositionSpanningMultipleDays_CalculatesVolumePerDayCorrectly()
{
// Arrange - Create positions representing the same position at different stages
var baseDate = TestDate.Date;
// Position as it appears on Day 1 (still open)
var positionDay1 = CreateFilledPosition(50000m, 0.1m, TradeDirection.Long, 1m);
positionDay1.Date = baseDate.AddHours(12); // Day 1, noon
// Position as it appears on Day 2 (now closed)
var positionDay2 = CreateFinishedPosition(50000m, 0.1m, TradeDirection.Long, 1m, 52000m, false);
positionDay2.Date = baseDate.AddHours(12); // Same open date
positionDay2.TakeProfit1.Date = baseDate.AddDays(1).AddHours(10); // Closed on Day 2
// Act - Calculate snapshot for Day 1 (position opened but not closed yet)
var day1Positions = new List<Position> { positionDay1 };
var day1Metrics = TradingBox.CalculatePlatformSummaryMetrics(day1Positions);
// Calculate snapshot for Day 2 (position opened and closed)
var day2Positions = new List<Position> { positionDay2 };
var day2Metrics = TradingBox.CalculatePlatformSummaryMetrics(day2Positions);
// Assert - Day 1: Only opening volume (position still open)
var expectedDay1Volume = 50000m * 0.1m * 1m; // Open: 5000
day1Metrics.TotalPlatformVolume.Should().Be(expectedDay1Volume);
day1Metrics.TotalLifetimePositionCount.Should().Be(1);
day1Metrics.OpenInterest.Should().Be(expectedDay1Volume); // Position still open
// Assert - Day 2: Opening volume + closing volume (position now closed)
var expectedDay2Volume = 50000m * 0.1m * 1m + 52000m * 0.1m * 1m; // Open: 5000 + Close: 5200 = 10200
day2Metrics.TotalPlatformVolume.Should().Be(expectedDay2Volume);
day2Metrics.TotalLifetimePositionCount.Should().Be(1);
day2Metrics.OpenInterest.Should().Be(0m); // Position now closed
// Assert - Volume increased from Day 1 to Day 2 (closing volume added)
day2Metrics.TotalPlatformVolume.Should().BeGreaterThan(day1Metrics.TotalPlatformVolume);
var volumeIncrease = day2Metrics.TotalPlatformVolume - day1Metrics.TotalPlatformVolume;
volumeIncrease.Should().Be(5200m); // The closing volume added on Day 2
}
}