Files
managing-apps/src/Managing.Application.Tests/ProfitAndLossTests.cs
2024-05-03 16:39:25 +05:00

252 lines
11 KiB
C#

using Managing.Domain.Trades;
using Xunit;
using static Managing.Common.Enums;
namespace Managing.Application.Tests
{
public class ProfitAndLossTests
{
[Theory]
[InlineData(1, 100, 110, 10)]
[InlineData(2, 100, 110, 20)]
public void Should_Return_Correct_ProfitAndLoss_Amount(decimal quantity, decimal price, decimal exitPrice, decimal expectedResult)
{
// Arrange
var init = new List<Tuple<decimal, decimal>>();
init.Add(new Tuple<decimal, decimal>(quantity, price));
var pnl = new ProfitAndLoss(init, TradeDirection.Long);
// Act
var result = pnl.FloatingForTheoriticalExit(exitPrice);
// Assert
Assert.Equal(expectedResult, result);
}
[Fact]
public void Should_Return_Correct_Pnl_For_Short_failed_Position_After_Took_One_Profit()
{
// Arrange
var position = GetFakeShortPosition();
// Setup Open and first take profit
var orders = new List<Tuple<decimal, decimal>>
{
new Tuple<decimal, decimal>(position.Open.Quantity, position.Open.Price),
new Tuple<decimal, decimal>(-position.TakeProfit1.Quantity, position.TakeProfit1.Price)
};
// Act
position.ProfitAndLoss = new ProfitAndLoss(orders, position.OriginDirection);
// Trigger Stop Loss
position.ProfitAndLoss.AddFill(-position.TakeProfit2.Quantity, position.StopLoss.Price, position.OriginDirection);
// Assert
Assert.Equal(20, position.ProfitAndLoss.Realized);
}
[Fact]
public void Should_Return_Correct_Pnl_For_Long_Solana_failed_Position_After_Took_One_Profit()
{
// Arrange
var position = GetSolanaLongPosition();
// Setup Open and first take profit
var orders = new List<Tuple<decimal, decimal>>
{
new Tuple<decimal, decimal>(position.Open.Quantity, position.Open.Price),
new Tuple<decimal, decimal>(-position.TakeProfit1.Quantity, position.TakeProfit1.Price)
};
// Act
position.ProfitAndLoss = new ProfitAndLoss(orders, position.OriginDirection);
// Trigger Stop Loss
position.ProfitAndLoss.AddFill(-position.TakeProfit2.Quantity, position.StopLoss.Price, position.OriginDirection);
// Assert
Assert.Equal(3.97005582759999752M, position.ProfitAndLoss.Realized);
}
[Fact]
public void Should_Return_Correct_Pnl_For_Long_Solana_failed_Position_After_Took_One_Profit2()
{
// Arrange
var position = GetSolanaLongPosition();
// Setup Open and first take profit
var orders = new List<Tuple<decimal, decimal>>
{
new Tuple<decimal, decimal>(position.Open.Quantity, position.Open.Price),
new Tuple<decimal, decimal>(-position.TakeProfit1.Quantity, position.TakeProfit1.Price),
new Tuple<decimal, decimal>(-position.TakeProfit2.Quantity, position.StopLoss.Price)
};
// Act
position.ProfitAndLoss = new ProfitAndLoss(orders, position.OriginDirection);
// Assert
Assert.Equal(3.97005582759999752M, position.ProfitAndLoss.Realized);
}
[Fact]
public void Should_Return_Correct_Pnl_For_Short_failed_Position_After_Took_One_Profit2()
{
// Arrange
var position = GetFakeShortPosition();
// Setup Open and first take profit
var orders = new List<Tuple<decimal, decimal>>
{
new Tuple<decimal, decimal>(position.Open.Quantity, position.Open.Price),
new Tuple<decimal, decimal>(-position.TakeProfit1.Quantity, position.TakeProfit1.Price),
new Tuple<decimal, decimal>(-position.TakeProfit2.Quantity, position.StopLoss.Price)
};
// Act
position.ProfitAndLoss = new ProfitAndLoss(orders, position.OriginDirection);
// Assert
Assert.Equal(20, position.ProfitAndLoss.Realized);
}
[Fact]
public void Should_Return_Correct_Pnl_For_Short_failed_Position_After_Took_One_Profit3()
{
// Arrange
var position = GetFakeShortPosition();
// Setup Open and first take profit
var orders = new List<Tuple<decimal, decimal>>
{
new Tuple<decimal, decimal>(position.Open.Quantity, position.Open.Price)
};
// Act
position.ProfitAndLoss = new ProfitAndLoss(orders, position.OriginDirection);
position.ProfitAndLoss.AddFill(-position.TakeProfit1.Quantity, position.TakeProfit1.Price, TradeDirection.Short);
position.ProfitAndLoss.AddFill(-position.TakeProfit2.Quantity, position.StopLoss.Price, TradeDirection.Short);
// Assert
Assert.Equal(20, position.ProfitAndLoss.Realized);
}
[Fact]
public void Should_Return_Correct_Pnl_For_Short_Succeeded_Position_After_Two_Take_Profit()
{
// Arrange
var position = GetFakeShortPosition();
// Setup Open and first take profit
var orders = new List<Tuple<decimal, decimal>>
{
new Tuple<decimal, decimal>(position.Open.Quantity, position.Open.Price),
new Tuple<decimal, decimal>(-position.TakeProfit1.Quantity, position.TakeProfit1.Price)
};
// Act
position.ProfitAndLoss = new ProfitAndLoss(orders, position.OriginDirection);
// Trigger Stop Loss
position.ProfitAndLoss.AddFill(-position.TakeProfit2.Quantity, position.TakeProfit2.Price, TradeDirection.Short);
// Assert
Assert.Equal(120, position.ProfitAndLoss.Realized);
}
[Fact]
public void Should_Return_Correct_Pnl_For_Long_failed_Position_After_Took_One_Profit()
{
// Arrange
var position = GetFakeLongPosition();
// Setup Open and first take profit
var orders = new List<Tuple<decimal, decimal>>
{
new Tuple<decimal, decimal>(position.Open.Quantity, position.Open.Price),
new Tuple<decimal, decimal>(-position.TakeProfit1.Quantity, position.TakeProfit1.Price)
};
// Act
position.ProfitAndLoss = new ProfitAndLoss(orders, position.OriginDirection);
// Trigger Stop Loss
position.ProfitAndLoss.AddFill(-position.TakeProfit2.Quantity, position.StopLoss.Price, TradeDirection.Long);
// Assert
Assert.Equal(20, position.ProfitAndLoss.Realized);
}
[Fact]
public void Should_Return_Correct_Pnl_For_Long_Succeeded_Position_After_Two_Take_Profit()
{
// Arrange
var position = GetFakeLongPosition();
// Setup Open and first take profit
var orders = new List<Tuple<decimal, decimal>>
{
new Tuple<decimal, decimal>(position.Open.Quantity, position.Open.Price),
new Tuple<decimal, decimal>(-position.TakeProfit1.Quantity, position.TakeProfit1.Price)
};
// Act
position.ProfitAndLoss = new ProfitAndLoss(orders, position.OriginDirection);
// Trigger Stop Loss
position.ProfitAndLoss.AddFill(-position.TakeProfit2.Quantity, position.TakeProfit2.Price, TradeDirection.Long);
// Assert
Assert.Equal(120, position.ProfitAndLoss.Realized);
}
private static Position GetFakeShortPosition()
{
return new Position("FakeAccount", TradeDirection.Short, Ticker.BTC, null, PositionInitiator.PaperTrading, DateTime.UtcNow)
{
Open = new Trade(DateTime.Now, TradeDirection.Short, TradeStatus.Filled,
TradeType.Market, Ticker.ADA, 10, 100, 1, "OpenOrderId", ""),
StopLoss = new Trade(DateTime.Now, TradeDirection.Long, TradeStatus.PendingOpen,
TradeType.StopMarket, Ticker.ADA, 10, 110, 1, "StopLossOrderId", ""),
TakeProfit1 = new Trade(DateTime.Now, TradeDirection.Long, TradeStatus.PendingOpen,
TradeType.TakeProfitLimit, Ticker.ADA, 6, 90, 1, "TakeProfit1OrderId", ""),
TakeProfit2 = new Trade(DateTime.Now, TradeDirection.Long, TradeStatus.PendingOpen,
TradeType.TakeProfitLimit, Ticker.ADA, 4, 85, 1, "TakeProfit1OrderId", "")
};
}
private static Position GetSolanaLongPosition()
{
return new Position("FakeAccount", TradeDirection.Long, Ticker.BTC, null, PositionInitiator.PaperTrading, DateTime.UtcNow)
{
Open = new Trade(DateTime.Now, TradeDirection.Long, TradeStatus.Filled,
TradeType.Market, Ticker.ADA, (decimal)6.0800904000245037980887037491, (decimal)81.6200, 1, "OpenOrderId", ""),
StopLoss = new Trade(DateTime.Now, TradeDirection.Short, TradeStatus.PendingOpen,
TradeType.StopMarket, Ticker.ADA, (decimal)3.6480542400147022788532222495, (decimal)79.987600, 1, "StopLossOrderId", ""),
TakeProfit1 = new Trade(DateTime.Now, TradeDirection.Short, TradeStatus.PendingOpen,
TradeType.TakeProfitLimit, Ticker.ADA, (decimal)2.4320361600098015192354814996, (decimal)85.701000, 1, "TakeProfit1OrderId", ""),
TakeProfit2 = new Trade(DateTime.Now, TradeDirection.Short, TradeStatus.PendingOpen,
TradeType.TakeProfitLimit, Ticker.ADA, (decimal)3.6480542400147022788532222495, (decimal)89.782000, 1, "TakeProfit1OrderId", "")
};
}
private static Position GetFakeLongPosition()
{
return new Position("FakeAccount", TradeDirection.Long, Ticker.BTC, null, PositionInitiator.PaperTrading, DateTime.UtcNow)
{
Open = new Trade(DateTime.Now, TradeDirection.Short, TradeStatus.Filled,
TradeType.Market, Ticker.ADA, 10, 100, 1, "OpenOrderId", ""),
StopLoss = new Trade(DateTime.Now, TradeDirection.Long, TradeStatus.PendingOpen,
TradeType.StopMarket, Ticker.ADA, 10, 90, 1, "StopLossOrderId", ""),
TakeProfit1 = new Trade(DateTime.Now, TradeDirection.Long, TradeStatus.PendingOpen,
TradeType.TakeProfitLimit, Ticker.ADA, 6, 110, 1, "TakeProfit1OrderId", ""),
TakeProfit2 = new Trade(DateTime.Now, TradeDirection.Long, TradeStatus.PendingOpen,
TradeType.TakeProfitLimit, Ticker.ADA, 4, 115, 1, "TakeProfit1OrderId", "")
};
}
}
}