Add test and max collateral used
This commit is contained in:
@@ -655,6 +655,51 @@ public class TradingBotCalculationsTests : TradingBoxTests
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region CalculateROI Tests
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CalculateROI_WithRealTradingBotData_ReturnsCorrectROI()
|
||||||
|
{
|
||||||
|
// Arrange - Using real trading bot data from the provided JSON
|
||||||
|
var initialBalance = 50m;
|
||||||
|
var netPnL = 4.57691m; // finalBalance - initialBalance = 54.57691 - 50
|
||||||
|
|
||||||
|
// Act - Using existing GetGrowthFromInitalBalance method
|
||||||
|
var result = TradingBox.GetGrowthFromInitalBalance(initialBalance, netPnL);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
// ROI = (Final - Initial) / Initial * 100 = (54.57691 - 50) / 50 * 100 = 9.15382%
|
||||||
|
result.Should().BeApproximately(9.15382m, 0.00001m);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(100.0, 10.0, 10.0)] // 10% gain: initial=100, netPnL=10, expected=10%
|
||||||
|
[InlineData(100.0, -10.0, -10.0)] // 10% loss: initial=100, netPnL=-10, expected=-10%
|
||||||
|
[InlineData(100.0, 0.0, 0.0)] // No change: initial=100, netPnL=0, expected=0%
|
||||||
|
[InlineData(50.0, 4.57691, 9.15382)] // Real bot data: initial=50, netPnL=4.57691, expected=9.15382%
|
||||||
|
public void CalculateROI_WithVariousInputs_ReturnsCorrectPercentage(decimal initialBalance, decimal netPnL, decimal expectedROI)
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var result = TradingBox.GetGrowthFromInitalBalance(initialBalance, netPnL);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().BeApproximately(expectedROI, 0.00001m);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CalculateROI_WithZeroInitialBalance_ThrowsDivideByZeroException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var initialBalance = 0m;
|
||||||
|
var netPnL = 100m;
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.Throws<DivideByZeroException>(() =>
|
||||||
|
TradingBox.GetGrowthFromInitalBalance(initialBalance, netPnL));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Helper Methods
|
#region Helper Methods
|
||||||
|
|
||||||
private List<Position> CreateLossPositions(int count, TradeDirection direction = TradeDirection.Long)
|
private List<Position> CreateLossPositions(int count, TradeDirection direction = TradeDirection.Long)
|
||||||
@@ -733,5 +778,118 @@ public class TradingBotCalculationsTests : TradingBoxTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region CalculateAgentSummaryMetrics Tests
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CalculateAgentSummaryMetrics_WithRealTradingBotPositions_ReturnsCorrectMetrics()
|
||||||
|
{
|
||||||
|
// Arrange - Create positions based on the real trading bot JSON data
|
||||||
|
var positions = new List<Position>
|
||||||
|
{
|
||||||
|
CreateRealPosition(
|
||||||
|
direction: TradeDirection.Short,
|
||||||
|
openPrice: 2.1849m,
|
||||||
|
quantity: 22.91465209m,
|
||||||
|
leverage: 5m,
|
||||||
|
takeProfitPrice: 2.1602m,
|
||||||
|
realizedPnL: 2.66162442m,
|
||||||
|
netPnL: 2.38787384m,
|
||||||
|
gasFees: 0.15m
|
||||||
|
),
|
||||||
|
CreateRealPosition(
|
||||||
|
direction: TradeDirection.Long,
|
||||||
|
openPrice: 2.104m,
|
||||||
|
quantity: 24.69722156m,
|
||||||
|
leverage: 5m,
|
||||||
|
takeProfitPrice: 2.127m,
|
||||||
|
realizedPnL: 2.71702395m,
|
||||||
|
netPnL: 2.43569648m,
|
||||||
|
gasFees: 0.15m
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var metrics = TradingBox.CalculateAgentSummaryMetrics(positions);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
// Total PnL: 2.66162442 + 2.71702395 = 5.37864837
|
||||||
|
metrics.TotalPnL.Should().BeApproximately(5.37864837m, 0.00000001m);
|
||||||
|
|
||||||
|
// Total Fees: 2 positions * 0.15 gas fees = 0.3 (no UI fees since positions are closed)
|
||||||
|
metrics.TotalFees.Should().Be(0.3m);
|
||||||
|
|
||||||
|
// Net PnL: 5.37864837 - 0.3 = 5.07864837
|
||||||
|
metrics.NetPnL.Should().BeApproximately(5.07864837m, 0.00000001m);
|
||||||
|
|
||||||
|
// Wins: 2, Losses: 0
|
||||||
|
metrics.Wins.Should().Be(2);
|
||||||
|
metrics.Losses.Should().Be(0);
|
||||||
|
|
||||||
|
// Collateral: max of (openPrice * quantity) = max(2.1849 * 22.91465209, 2.104 * 24.69722156)
|
||||||
|
// = max(50.083, 51.96295416224) = 51.96295416224
|
||||||
|
metrics.Collateral.Should().BeApproximately(51.96295416224m, 0.00000000001m);
|
||||||
|
|
||||||
|
// ROI: (netPnL / collateral) * 100 = (5.07864837 / 51.96295416224) * 100 ≈ 9.774%
|
||||||
|
metrics.TotalROI.Should().BeApproximately(9.774m, 0.001m);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private static Position CreateRealPosition(
|
||||||
|
TradeDirection direction,
|
||||||
|
decimal openPrice,
|
||||||
|
decimal quantity,
|
||||||
|
decimal leverage,
|
||||||
|
decimal takeProfitPrice,
|
||||||
|
decimal realizedPnL,
|
||||||
|
decimal netPnL,
|
||||||
|
decimal gasFees)
|
||||||
|
{
|
||||||
|
// Create position using the existing test helper
|
||||||
|
var position = CreateTestPosition(
|
||||||
|
openPrice: openPrice,
|
||||||
|
quantity: quantity,
|
||||||
|
direction: direction,
|
||||||
|
leverage: leverage,
|
||||||
|
positionStatus: PositionStatus.Finished,
|
||||||
|
includeTrades: true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Override ticker to XRP
|
||||||
|
position.Ticker = Ticker.XRP;
|
||||||
|
|
||||||
|
// Update trades to match real data
|
||||||
|
position.Open.TradeType = TradeType.Limit;
|
||||||
|
position.Open.Ticker = Ticker.XRP;
|
||||||
|
position.Open.ExchangeOrderId = Guid.NewGuid().ToString();
|
||||||
|
|
||||||
|
// Set TakeProfit1 to filled with the correct price
|
||||||
|
position.TakeProfit1.Status = TradeStatus.Filled;
|
||||||
|
position.TakeProfit1.Date = TestDate.AddHours(1);
|
||||||
|
position.TakeProfit1.Ticker = Ticker.XRP;
|
||||||
|
position.TakeProfit1.Price = takeProfitPrice;
|
||||||
|
position.TakeProfit1.ExchangeOrderId = Guid.NewGuid().ToString();
|
||||||
|
position.TakeProfit1.Message = "EmptyTrade";
|
||||||
|
|
||||||
|
// Set StopLoss to cancelled
|
||||||
|
position.StopLoss.Status = TradeStatus.Cancelled;
|
||||||
|
position.StopLoss.Ticker = Ticker.XRP;
|
||||||
|
position.StopLoss.ExchangeOrderId = Guid.NewGuid().ToString();
|
||||||
|
position.StopLoss.Message = "EmptyTrade";
|
||||||
|
|
||||||
|
// Set Profit and Loss
|
||||||
|
position.ProfitAndLoss = new ProfitAndLoss
|
||||||
|
{
|
||||||
|
Realized = realizedPnL,
|
||||||
|
Net = netPnL
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set fees
|
||||||
|
position.UiFees = 0;
|
||||||
|
position.GasFees = gasFees;
|
||||||
|
|
||||||
|
return position;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -601,7 +601,7 @@ public static class TradingBox
|
|||||||
var totalVolume = GetTotalVolumeTraded(validPositions);
|
var totalVolume = GetTotalVolumeTraded(validPositions);
|
||||||
var wins = validPositions.Count(p => (p.ProfitAndLoss?.Net ?? 0m) > 0m);
|
var wins = validPositions.Count(p => (p.ProfitAndLoss?.Net ?? 0m) > 0m);
|
||||||
var losses = validPositions.Count(p => (p.ProfitAndLoss?.Net ?? 0m) <= 0m);
|
var losses = validPositions.Count(p => (p.ProfitAndLoss?.Net ?? 0m) <= 0m);
|
||||||
var collateral = validPositions.Sum(p => (p.Open?.Price ?? 0m) * (p.Open?.Quantity ?? 0m));
|
var collateral = validPositions.Max(p => (p.Open?.Price ?? 0m) * (p.Open?.Quantity ?? 0m));
|
||||||
var totalROI = collateral > 0m ? (netPnL / collateral) * 100m : 0m;
|
var totalROI = collateral > 0m ? (netPnL / collateral) * 100m : 0m;
|
||||||
|
|
||||||
return new AgentSummaryMetrics(totalPnL, netPnL, totalROI, totalVolume, wins, losses, totalFees,
|
return new AgentSummaryMetrics(totalPnL, netPnL, totalROI, totalVolume, wins, losses, totalFees,
|
||||||
|
|||||||
Reference in New Issue
Block a user