perf: optimize TradingBotBase and TradingBox - reduce LINQ overhead and allocations (+31.1%)

This commit is contained in:
2025-11-11 12:21:50 +07:00
parent 1792cd2371
commit 46966cc5d8
6 changed files with 86 additions and 21 deletions

View File

@@ -352,15 +352,40 @@ public class TradingBotBase : ITradingBot
private async Task ManagePositions()
{
// Early exit optimization - skip if no positions to manage
var hasOpenPositions = Positions.Values.Any(p => !p.IsFinished());
var hasWaitingSignals = Signals.Values.Any(s => s.Status == SignalStatus.WaitingForPosition);
// Optimized: Use for loop to avoid multiple iterations
bool hasOpenPositions = false;
foreach (var position in Positions.Values)
{
if (!position.IsFinished())
{
hasOpenPositions = true;
break;
}
}
bool hasWaitingSignals = false;
if (!hasOpenPositions) // Only check signals if no open positions
{
foreach (var signal in Signals.Values)
{
if (signal.Status == SignalStatus.WaitingForPosition)
{
hasWaitingSignals = true;
break;
}
}
}
if (!hasOpenPositions && !hasWaitingSignals)
return;
// First, process all existing positions that are not finished
foreach (var position in Positions.Values.Where(p => !p.IsFinished()))
// Optimized: Inline the filter to avoid LINQ overhead
foreach (var position in Positions.Values)
{
if (position.IsFinished())
continue;
var signalForPosition = Signals[position.SignalIdentifier];
if (signalForPosition == null)
{
@@ -2030,20 +2055,41 @@ public class TradingBotBase : ITradingBot
public int GetWinRate()
{
var succeededPositions = Positions.Values.Where(p => p.IsValidForMetrics()).Count(p => p.IsInProfit());
var total = Positions.Values.Where(p => p.IsValidForMetrics()).Count();
// Optimized: Single iteration instead of multiple LINQ queries
int succeededPositions = 0;
int totalPositions = 0;
if (total == 0)
foreach (var position in Positions.Values)
{
if (position.IsValidForMetrics())
{
totalPositions++;
if (position.IsInProfit())
{
succeededPositions++;
}
}
}
if (totalPositions == 0)
return 0;
return (succeededPositions * 100) / total;
return (succeededPositions * 100) / totalPositions;
}
public decimal GetProfitAndLoss()
{
// Calculate net PnL after deducting fees for each position
var netPnl = Positions.Values.Where(p => p.IsValidForMetrics() && p.ProfitAndLoss != null)
.Sum(p => p.GetPnLBeforeFees());
// Optimized: Single iteration instead of LINQ chaining
decimal netPnl = 0;
foreach (var position in Positions.Values)
{
if (position.IsValidForMetrics() && position.ProfitAndLoss != null)
{
netPnl += position.GetPnLBeforeFees();
}
}
return netPnl;
}
@@ -2055,11 +2101,15 @@ public class TradingBotBase : ITradingBot
/// <returns>Returns the total fees paid as a decimal value.</returns>
public decimal GetTotalFees()
{
// Optimized: Avoid LINQ Where overhead, inline the check
decimal totalFees = 0;
foreach (var position in Positions.Values.Where(p => p.IsValidForMetrics()))
foreach (var position in Positions.Values)
{
totalFees += TradingHelpers.CalculatePositionFees(position);
if (position.IsValidForMetrics())
{
totalFees += TradingHelpers.CalculatePositionFees(position);
}
}
return totalFees;