Add more test for the daily volumes and add button to set the UIFee Factor
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user