Fix test for trading metrics
This commit is contained in:
@@ -1,14 +1,5 @@
|
||||
using FluentAssertions;
|
||||
using Managing.Common;
|
||||
using Managing.Domain.Accounts;
|
||||
using Managing.Domain.Candles;
|
||||
using Managing.Domain.Indicators;
|
||||
using Managing.Domain.MoneyManagements;
|
||||
using Managing.Domain.Scenarios;
|
||||
using Managing.Domain.Shared.Helpers;
|
||||
using Managing.Domain.Statistics;
|
||||
using Managing.Domain.Strategies;
|
||||
using Managing.Domain.Strategies.Base;
|
||||
using Managing.Domain.Trades;
|
||||
using Xunit;
|
||||
using static Managing.Common.Enums;
|
||||
@@ -63,7 +54,7 @@ public class ProfitLossTests : TradingBoxTests
|
||||
// Arrange
|
||||
var validPosition = CreateTestPosition();
|
||||
var invalidPosition = CreateTestPosition();
|
||||
invalidPosition.Status = Enums.PositionStatus.New; // Invalid for metrics
|
||||
invalidPosition.Status = PositionStatus.New; // Invalid for metrics
|
||||
|
||||
validPosition.ProfitAndLoss = new ProfitAndLoss { Realized = 100m };
|
||||
invalidPosition.ProfitAndLoss = new ProfitAndLoss { Realized = -50m };
|
||||
@@ -156,19 +147,23 @@ public class ProfitLossTests : TradingBoxTests
|
||||
[Fact]
|
||||
public void GetWinRate_WithMixedResults_CalculatesCorrectPercentage()
|
||||
{
|
||||
// Arrange
|
||||
var winningPosition1 = CreateTestPosition();
|
||||
var winningPosition2 = CreateTestPosition();
|
||||
var losingPosition1 = CreateTestPosition();
|
||||
var losingPosition2 = CreateTestPosition();
|
||||
var invalidPosition = CreateTestPosition();
|
||||
invalidPosition.Status = Enums.PositionStatus.New; // Invalid for metrics
|
||||
// Arrange - Win rate only considers Finished positions (closed trades)
|
||||
var winningPosition1 = CreateFinishedPosition();
|
||||
var winningPosition2 = CreateFinishedPosition();
|
||||
var losingPosition1 = CreateFinishedPosition();
|
||||
var losingPosition2 = CreateFinishedPosition();
|
||||
var openFilledPosition = CreateFilledPosition(); // Open position (Filled status) - should NOT count towards win rate
|
||||
openFilledPosition.ProfitAndLoss = new ProfitAndLoss(new List<Tuple<decimal, decimal>>(), TradeDirection.Long)
|
||||
{ Realized = 100m, Net = 100m }; // Has unrealized P&L but should not count
|
||||
|
||||
winningPosition1.ProfitAndLoss = new ProfitAndLoss { Realized = 50m };
|
||||
winningPosition2.ProfitAndLoss = new ProfitAndLoss { Realized = 25m };
|
||||
losingPosition1.ProfitAndLoss = new ProfitAndLoss { Realized = -30m };
|
||||
losingPosition2.ProfitAndLoss = new ProfitAndLoss { Realized = -10m };
|
||||
invalidPosition.ProfitAndLoss = new ProfitAndLoss { Realized = 100m };
|
||||
winningPosition1.ProfitAndLoss = new ProfitAndLoss(new List<Tuple<decimal, decimal>>(), TradeDirection.Long)
|
||||
{ Realized = 50m, Net = 50m };
|
||||
winningPosition2.ProfitAndLoss = new ProfitAndLoss(new List<Tuple<decimal, decimal>>(), TradeDirection.Long)
|
||||
{ Realized = 25m, Net = 25m };
|
||||
losingPosition1.ProfitAndLoss = new ProfitAndLoss(new List<Tuple<decimal, decimal>>(), TradeDirection.Long)
|
||||
{ Realized = -30m, Net = -30m };
|
||||
losingPosition2.ProfitAndLoss = new ProfitAndLoss(new List<Tuple<decimal, decimal>>(), TradeDirection.Long)
|
||||
{ Realized = -10m, Net = -10m };
|
||||
|
||||
var positions = new Dictionary<Guid, Position>
|
||||
{
|
||||
@@ -176,25 +171,27 @@ public class ProfitLossTests : TradingBoxTests
|
||||
{ winningPosition2.Identifier, winningPosition2 },
|
||||
{ losingPosition1.Identifier, losingPosition1 },
|
||||
{ losingPosition2.Identifier, losingPosition2 },
|
||||
{ invalidPosition.Identifier, invalidPosition }
|
||||
{ openFilledPosition.Identifier, openFilledPosition } // Open position excluded from win rate
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = TradingBox.GetWinRate(positions);
|
||||
|
||||
// Assert
|
||||
result.Should().Be(50); // 2 wins out of 4 valid positions = 50%
|
||||
result.Should().Be(50); // 2 wins out of 4 finished positions = 50% (open Filled position excluded)
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetWinRate_WithAllWinningPositions_Returns100()
|
||||
{
|
||||
// Arrange
|
||||
var position1 = CreateTestPosition();
|
||||
var position2 = CreateTestPosition();
|
||||
// Arrange - Win rate only considers Finished positions (closed trades)
|
||||
var position1 = CreateFinishedPosition();
|
||||
var position2 = CreateFinishedPosition();
|
||||
|
||||
position1.ProfitAndLoss = new ProfitAndLoss { Realized = 50m };
|
||||
position2.ProfitAndLoss = new ProfitAndLoss { Realized = 25m };
|
||||
position1.ProfitAndLoss = new ProfitAndLoss(new List<Tuple<decimal, decimal>>(), TradeDirection.Long)
|
||||
{ Realized = 50m, Net = 50m };
|
||||
position2.ProfitAndLoss = new ProfitAndLoss(new List<Tuple<decimal, decimal>>(), TradeDirection.Long)
|
||||
{ Realized = 25m, Net = 25m };
|
||||
|
||||
var positions = new Dictionary<Guid, Position>
|
||||
{
|
||||
@@ -206,18 +203,20 @@ public class ProfitLossTests : TradingBoxTests
|
||||
var result = TradingBox.GetWinRate(positions);
|
||||
|
||||
// Assert
|
||||
result.Should().Be(100);
|
||||
result.Should().Be(100); // 2 wins out of 2 finished positions = 100%
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetWinRate_WithAllLosingPositions_Returns0()
|
||||
{
|
||||
// Arrange
|
||||
var position1 = CreateTestPosition();
|
||||
var position2 = CreateTestPosition();
|
||||
// Arrange - Win rate only considers Finished positions (closed trades)
|
||||
var position1 = CreateFinishedPosition();
|
||||
var position2 = CreateFinishedPosition();
|
||||
|
||||
position1.ProfitAndLoss = new ProfitAndLoss { Realized = -50m };
|
||||
position2.ProfitAndLoss = new ProfitAndLoss { Realized = -25m };
|
||||
position1.ProfitAndLoss = new ProfitAndLoss(new List<Tuple<decimal, decimal>>(), TradeDirection.Long)
|
||||
{ Realized = -50m, Net = -50m };
|
||||
position2.ProfitAndLoss = new ProfitAndLoss(new List<Tuple<decimal, decimal>>(), TradeDirection.Long)
|
||||
{ Realized = -25m, Net = -25m };
|
||||
|
||||
var positions = new Dictionary<Guid, Position>
|
||||
{
|
||||
@@ -229,7 +228,7 @@ public class ProfitLossTests : TradingBoxTests
|
||||
var result = TradingBox.GetWinRate(positions);
|
||||
|
||||
// Assert
|
||||
result.Should().Be(0);
|
||||
result.Should().Be(0); // 0 wins out of 2 finished positions = 0%
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -309,7 +308,7 @@ public class ProfitLossTests : TradingBoxTests
|
||||
public void GetProfitAndLoss_CalculatesLongPositionCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var position = CreateTestPosition(openPrice: 100m, quantity: 1m, direction: Enums.TradeDirection.Long,
|
||||
var position = CreateTestPosition(openPrice: 100m, quantity: 1m, direction: TradeDirection.Long,
|
||||
leverage: 1m);
|
||||
var quantity = 1m;
|
||||
var closePrice = 110m; // 10% profit
|
||||
@@ -328,7 +327,7 @@ public class ProfitLossTests : TradingBoxTests
|
||||
public void GetProfitAndLoss_CalculatesShortPositionCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var position = CreateTestPosition(openPrice: 100m, quantity: 1m, direction: Enums.TradeDirection.Short,
|
||||
var position = CreateTestPosition(openPrice: 100m, quantity: 1m, direction: TradeDirection.Short,
|
||||
leverage: 1m);
|
||||
var quantity = 1m;
|
||||
var closePrice = 90m; // 10% profit
|
||||
@@ -347,7 +346,7 @@ public class ProfitLossTests : TradingBoxTests
|
||||
public void GetProfitAndLoss_WithLeverage_AppliesLeverageMultiplier()
|
||||
{
|
||||
// Arrange
|
||||
var position = CreateTestPosition(openPrice: 100m, quantity: 1m, direction: Enums.TradeDirection.Long,
|
||||
var position = CreateTestPosition(openPrice: 100m, quantity: 1m, direction: TradeDirection.Long,
|
||||
leverage: 1m);
|
||||
var quantity = 1m;
|
||||
var closePrice = 105m; // 5% profit
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
using FluentAssertions;
|
||||
using Managing.Common;
|
||||
using Managing.Domain.Accounts;
|
||||
using Managing.Domain.Candles;
|
||||
using Managing.Domain.Indicators;
|
||||
using Managing.Domain.MoneyManagements;
|
||||
using Managing.Domain.Scenarios;
|
||||
using Managing.Domain.Shared.Helpers;
|
||||
using Managing.Domain.Statistics;
|
||||
using Managing.Domain.Strategies;
|
||||
using Managing.Domain.Strategies.Base;
|
||||
using Managing.Domain.Trades;
|
||||
using Xunit;
|
||||
using static Managing.Common.Enums;
|
||||
@@ -513,6 +506,7 @@ public class TradingMetricsTests : TradingBoxTests
|
||||
public void GetTotalVolumeTraded_WithMixedPositionStatuses_IncludesOnlyValidPositions()
|
||||
{
|
||||
// Arrange - Mix of different position statuses
|
||||
// IsValidForMetrics() returns true for: Filled (open), Finished (closed), and Flipped positions
|
||||
var finishedPosition = CreateFinishedPosition(openPrice: 50000m, quantity: 0.001m, leverage: 1m);
|
||||
var filledPosition = CreateFilledPosition(openPrice: 60000m, quantity: 0.002m, leverage: 1m);
|
||||
var newPosition = CreateNewPosition(openPrice: 40000m, quantity: 0.001m, leverage: 1m);
|
||||
@@ -523,13 +517,13 @@ public class TradingMetricsTests : TradingBoxTests
|
||||
// Act
|
||||
var result = TradingBox.GetTotalVolumeTraded(positions);
|
||||
|
||||
// Assert - Should include finished + filled positions, exclude new + canceled
|
||||
// Finished: 50000 * 0.001 * 1 + 52000 * 0.001 * 1 = 102
|
||||
// Filled: 60000 * 0.002 * 1 = 120
|
||||
// New: excluded
|
||||
// Canceled: excluded
|
||||
// Assert - GetTotalVolumeTraded only includes valid positions (uses IsValidForMetrics)
|
||||
// Finished (valid): 50000 * 0.001 * 1 (open) + 52000 * 0.001 * 1 (TP1) = 102
|
||||
// Filled (valid): 60000 * 0.002 * 1 = 120
|
||||
// New (EXCLUDED - not valid for metrics): excluded
|
||||
// Canceled (EXCLUDED - not valid for metrics): excluded
|
||||
// Total: 102 + 120 = 222
|
||||
result.Should().Be(317m); // Actual calculation gives 317
|
||||
result.Should().Be(222m);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -568,11 +562,11 @@ public class TradingMetricsTests : TradingBoxTests
|
||||
// Arrange - Mix of positions with different statuses and outcomes
|
||||
var winningFinished = CreateFinishedPosition();
|
||||
winningFinished.ProfitAndLoss = new ProfitAndLoss(new List<Tuple<decimal, decimal>>(), TradeDirection.Long)
|
||||
{ Net = 100m };
|
||||
{ Net = 100m };
|
||||
|
||||
var losingFinished = CreateFinishedPosition();
|
||||
losingFinished.ProfitAndLoss = new ProfitAndLoss(new List<Tuple<decimal, decimal>>(), TradeDirection.Long)
|
||||
{ Net = -50m };
|
||||
{ Net = -50m };
|
||||
|
||||
var openFilled = CreateFilledPosition(); // Open position - should not count towards win rate
|
||||
var newPosition = CreateNewPosition(); // Not valid for metrics
|
||||
|
||||
@@ -487,6 +487,7 @@ public static class TradingBox
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the total volume traded across all positions
|
||||
/// Only includes valid positions (Filled, Finished, Flipped) - excludes New, Canceled, Rejected
|
||||
/// </summary>
|
||||
/// <param name="positions">List of positions to analyze</param>
|
||||
/// <returns>The total volume traded in decimal</returns>
|
||||
@@ -496,6 +497,12 @@ public static class TradingBox
|
||||
|
||||
foreach (var position in positions)
|
||||
{
|
||||
// Only count volume for valid positions (Filled, Finished, Flipped)
|
||||
if (!position.IsValidForMetrics())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add entry volume
|
||||
totalVolume += position.Open.Quantity * position.Open.Price * position.Open.Leverage;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user