using FluentAssertions;
using Managing.Domain.Accounts;
using Managing.Domain.Shared.Helpers;
using Managing.Domain.Statistics;
using Xunit;
namespace Managing.Domain.Tests;
///
/// Tests for trader analysis methods in TradingBox.
/// Covers trader evaluation, filtering, and analysis methods.
///
public class TraderAnalysisTests : TradingBoxTests
{
[Fact]
public void IsAGoodTrader_WithAllCriteriaMet_ReturnsTrue()
{
// Arrange
var trader = new Trader
{
Winrate = 35, // > 30
TradeCount = 10, // > 8
AverageWin = 100m,
AverageLoss = -50m, // |AverageLoss| < AverageWin
Pnl = 250m // > 0
};
// Act
var result = TradingBox.IsAGoodTrader(trader);
// Assert
result.Should().BeTrue();
}
[Fact]
public void IsAGoodTrader_WithLowWinrate_ReturnsFalse()
{
// Arrange
var trader = new Trader
{
Winrate = 25, // < 30
TradeCount = 10,
AverageWin = 100m,
AverageLoss = -50m,
Pnl = 250m
};
// Act
var result = TradingBox.IsAGoodTrader(trader);
// Assert
result.Should().BeFalse();
}
[Fact]
public void IsAGoodTrader_WithInsufficientTrades_ReturnsFalse()
{
// Arrange
var trader = new Trader
{
Winrate = 35,
TradeCount = 5, // < 8
AverageWin = 100m,
AverageLoss = -50m,
Pnl = 250m
};
// Act
var result = TradingBox.IsAGoodTrader(trader);
// Assert
result.Should().BeFalse();
}
[Fact]
public void IsAGoodTrader_WithPoorRiskReward_ReturnsFalse()
{
// Arrange
var trader = new Trader
{
Winrate = 35,
TradeCount = 10,
AverageWin = 50m,
AverageLoss = -100m, // |AverageLoss| > AverageWin
Pnl = 250m
};
// Act
var result = TradingBox.IsAGoodTrader(trader);
// Assert
result.Should().BeFalse();
}
[Fact]
public void IsAGoodTrader_WithNegativePnL_ReturnsFalse()
{
// Arrange
var trader = new Trader
{
Winrate = 35,
TradeCount = 10,
AverageWin = 100m,
AverageLoss = -50m,
Pnl = -50m // < 0
};
// Act
var result = TradingBox.IsAGoodTrader(trader);
// Assert
result.Should().BeFalse();
}
[Fact]
public void IsABadTrader_WithAllCriteriaMet_ReturnsTrue()
{
// Arrange
var trader = new Trader
{
Winrate = 25, // < 30
TradeCount = 10, // > 8
AverageWin = 50m,
AverageLoss = -200m, // |AverageLoss| * 3 > AverageWin
Pnl = -500m // < 0
};
// Act
var result = TradingBox.IsABadTrader(trader);
// Assert
result.Should().BeTrue();
}
[Fact]
public void IsABadTrader_WithGoodWinrate_ReturnsFalse()
{
// Arrange
var trader = new Trader
{
Winrate = 35, // > 30
TradeCount = 10,
AverageWin = 50m,
AverageLoss = -200m,
Pnl = -500m
};
// Act
var result = TradingBox.IsABadTrader(trader);
// Assert
result.Should().BeFalse();
}
[Fact]
public void IsABadTrader_WithInsufficientTrades_ReturnsFalse()
{
// Arrange
var trader = new Trader
{
Winrate = 25,
TradeCount = 5, // < 8
AverageWin = 50m,
AverageLoss = -200m,
Pnl = -500m
};
// Act
var result = TradingBox.IsABadTrader(trader);
// Assert
result.Should().BeFalse();
}
[Fact]
public void IsABadTrader_WithGoodRiskReward_ReturnsFalse()
{
// Arrange
var trader = new Trader
{
Winrate = 25,
TradeCount = 10,
AverageWin = 200m, // AverageWin > |AverageLoss| * 3
AverageLoss = -50m,
Pnl = -500m
};
// Act
var result = TradingBox.IsABadTrader(trader);
// Assert
result.Should().BeFalse();
}
[Fact]
public void IsABadTrader_WithPositivePnL_ReturnsFalse()
{
// Arrange
var trader = new Trader
{
Winrate = 25,
TradeCount = 10,
AverageWin = 50m,
AverageLoss = -200m,
Pnl = 100m // > 0
};
// Act
var result = TradingBox.IsABadTrader(trader);
// Assert
result.Should().BeFalse();
}
[Fact]
public void FindBadTrader_WithEmptyList_ReturnsEmptyList()
{
// Arrange
var traders = new List();
// Act
var result = traders.FindBadTrader();
// Assert
result.Should().BeEmpty();
}
[Fact]
public void FindBadTrader_WithOnlyGoodTraders_ReturnsEmptyList()
{
// Arrange
var traders = new List
{
new Trader { Winrate = 35, TradeCount = 10, AverageWin = 100m, AverageLoss = -50m, Pnl = 250m },
new Trader { Winrate = 40, TradeCount = 15, AverageWin = 150m, AverageLoss = -75m, Pnl = 500m }
};
// Act
var result = traders.FindBadTrader();
// Assert
result.Should().BeEmpty();
}
[Fact]
public void FindBadTrader_WithMixedTraders_ReturnsOnlyBadTraders()
{
// Arrange
var goodTrader = new Trader
{
Winrate = 35,
TradeCount = 10,
AverageWin = 100m,
AverageLoss = -50m,
Pnl = 250m
};
var badTrader1 = new Trader
{
Winrate = 25,
TradeCount = 10,
AverageWin = 50m,
AverageLoss = -200m,
Pnl = -500m
};
var badTrader2 = new Trader
{
Winrate = 20,
TradeCount = 12,
AverageWin = 30m,
AverageLoss = -150m,
Pnl = -300m
};
var traders = new List { goodTrader, badTrader1, badTrader2 };
// Act
var result = traders.FindBadTrader();
// Assert
result.Should().HaveCount(2);
result.Should().Contain(badTrader1);
result.Should().Contain(badTrader2);
result.Should().NotContain(goodTrader);
}
[Fact]
public void FindGoodTrader_WithEmptyList_ReturnsEmptyList()
{
// Arrange
var traders = new List();
// Act
var result = traders.FindGoodTrader();
// Assert
result.Should().BeEmpty();
}
[Fact]
public void FindGoodTrader_WithOnlyBadTraders_ReturnsEmptyList()
{
// Arrange
var traders = new List
{
new Trader { Winrate = 25, TradeCount = 10, AverageWin = 50m, AverageLoss = -200m, Pnl = -500m },
new Trader { Winrate = 20, TradeCount = 12, AverageWin = 30m, AverageLoss = -150m, Pnl = -300m }
};
// Act
var result = traders.FindGoodTrader();
// Assert
result.Should().BeEmpty();
}
[Fact]
public void FindGoodTrader_WithMixedTraders_ReturnsOnlyGoodTraders()
{
// Arrange
var badTrader = new Trader
{
Winrate = 25,
TradeCount = 10,
AverageWin = 50m,
AverageLoss = -200m,
Pnl = -500m
};
var goodTrader1 = new Trader
{
Winrate = 35,
TradeCount = 10,
AverageWin = 100m,
AverageLoss = -50m,
Pnl = 250m
};
var goodTrader2 = new Trader
{
Winrate = 40,
TradeCount = 15,
AverageWin = 150m,
AverageLoss = -75m,
Pnl = 500m
};
var traders = new List { badTrader, goodTrader1, goodTrader2 };
// Act
var result = traders.FindGoodTrader();
// Assert
result.Should().HaveCount(2);
result.Should().Contain(goodTrader1);
result.Should().Contain(goodTrader2);
result.Should().NotContain(badTrader);
}
[Fact]
public void MapToTraders_WithAccounts_CreatesTradersWithCorrectAddresses()
{
// Arrange
var account1 = new Account { Key = "0x123", Name = "Account1" };
var account2 = new Account { Key = "0x456", Name = "Account2" };
var accounts = new List { account1, account2 };
// Act
var result = accounts.MapToTraders();
// Assert
result.Should().HaveCount(2);
result[0].Address.Should().Be("0x123");
result[1].Address.Should().Be("0x456");
}
[Fact]
public void MapToTraders_WithEmptyList_ReturnsEmptyList()
{
// Arrange
var accounts = new List();
// Act
var result = accounts.MapToTraders();
// Assert
result.Should().BeEmpty();
}
[Theory]
[InlineData(35, 10, 100, -50, 250, true)] // Good trader
[InlineData(25, 10, 50, -200, -500, false)] // Bad trader
[InlineData(29, 9, 50, -150, -100, false)] // Boundary bad trader
[InlineData(32, 7, 100, -50, 200, false)] // Insufficient trades
[InlineData(28, 10, 200, -50, -100, false)] // Good RR but low winrate
public void TraderEvaluation_TheoryTests(int winrate, int tradeCount, decimal avgWin, decimal avgLoss, decimal pnl,
bool expectedGood)
{
// Arrange
var trader = new Trader
{
Winrate = winrate,
TradeCount = tradeCount,
AverageWin = avgWin,
AverageLoss = avgLoss,
Pnl = pnl
};
// Act & Assert
if (expectedGood)
{
TradingBox.IsAGoodTrader(trader).Should().BeTrue();
TradingBox.IsABadTrader(trader).Should().BeFalse();
}
else
{
TradingBox.IsAGoodTrader(trader).Should().BeFalse();
// Bad trader evaluation depends on multiple criteria
}
}
[Fact]
public void TraderAnalysis_MethodsAreConsistent()
{
// Arrange
var trader = new Trader
{
Winrate = 35,
TradeCount = 10,
AverageWin = 100m,
AverageLoss = -50m,
Pnl = 250m
};
// Act
var isGood = TradingBox.IsAGoodTrader(trader);
var isBad = TradingBox.IsABadTrader(trader);
// Assert
// A trader cannot be both good and bad
(isGood && isBad).Should().BeFalse();
}
[Fact]
public void FindMethods_WorkTogetherCorrectly()
{
// Arrange
var traders = new List
{
new Trader { Winrate = 35, TradeCount = 10, AverageWin = 100m, AverageLoss = -50m, Pnl = 250m }, // Good
new Trader { Winrate = 25, TradeCount = 10, AverageWin = 50m, AverageLoss = -200m, Pnl = -500m }, // Bad
new Trader { Winrate = 32, TradeCount = 5, AverageWin = 75m, AverageLoss = -75m, Pnl = 0m } // Neither
};
// Act
var goodTraders = traders.FindGoodTrader();
var badTraders = traders.FindBadTrader();
// Assert
goodTraders.Should().HaveCount(1);
badTraders.Should().HaveCount(1);
goodTraders.First().Should().NotBe(badTraders.First());
}
}