Update clamping for backtest

This commit is contained in:
2025-07-18 13:51:10 +07:00
parent bb3891c95e
commit 13aa681c2b
2 changed files with 21 additions and 23 deletions

View File

@@ -364,7 +364,7 @@ namespace Managing.Application.Backtesting
{ {
try try
{ {
if (backtest.Score > 50) if (backtest.Score > 60)
{ {
await _messengerService.SendBacktestNotification(backtest); await _messengerService.SendBacktestNotification(backtest);
} }

View File

@@ -422,7 +422,8 @@ public class GeneticService : IGeneticService
} }
catch (Exception notificationEx) catch (Exception notificationEx)
{ {
_logger.LogWarning(notificationEx, "Failed to send genetic algorithm notification for request {RequestId}", request.RequestId); _logger.LogWarning(notificationEx,
"Failed to send genetic algorithm notification for request {RequestId}", request.RequestId);
} }
return new GeneticAlgorithmResult return new GeneticAlgorithmResult
@@ -531,7 +532,10 @@ public class TradingBotChromosome : ChromosomeBase
return geneIndex switch return geneIndex switch
{ {
0 => new Gene(GetRandomInRange((0.9, _maxTakeProfit))), // Take profit (0.9% to max TP) 0 => new Gene(GetRandomInRange((0.9, _maxTakeProfit))), // Take profit (0.9% to max TP)
1 => new Gene(GetRandomInRange(GeneticService.ParameterRanges["stopLoss"])), // Stop loss (will be constrained during initialization) 1 => new Gene(
GetRandomInRange(
GeneticService.ParameterRanges
["stopLoss"])), // Stop loss (will be constrained during initialization)
2 => new Gene(GetRandomIntInRange(GeneticService.ParameterRanges["cooldownPeriod"])), // Cooldown period 2 => new Gene(GetRandomIntInRange(GeneticService.ParameterRanges["cooldownPeriod"])), // Cooldown period
3 => new Gene(GetRandomIntInRange(GeneticService.ParameterRanges["maxLossStreak"])), // Max loss streak 3 => new Gene(GetRandomIntInRange(GeneticService.ParameterRanges["maxLossStreak"])), // Max loss streak
_ => new Gene(0) _ => new Gene(0)
@@ -550,7 +554,7 @@ public class TradingBotChromosome : ChromosomeBase
{ {
GenerateIndicatorSelectionPattern(); GenerateIndicatorSelectionPattern();
} }
return new Gene(_indicatorSelectionPattern![geneIndex - 5]); return new Gene(_indicatorSelectionPattern![geneIndex - 5]);
} }
else else
@@ -614,6 +618,7 @@ public class TradingBotChromosome : ChromosomeBase
{ {
clone._indicatorSelectionPattern = (int[])_indicatorSelectionPattern.Clone(); clone._indicatorSelectionPattern = (int[])_indicatorSelectionPattern.Clone();
} }
return clone; return clone;
} }
@@ -700,15 +705,12 @@ public class TradingBotChromosome : ChromosomeBase
// Get take profit from chromosome (gene 0) // Get take profit from chromosome (gene 0)
var takeProfit = Convert.ToDouble(genes[0].Value); var takeProfit = Convert.ToDouble(genes[0].Value);
// Get stop loss from chromosome (gene 1) and enforce constraints at phenotype level // Get stop loss from chromosome (gene 1)
var stopLoss = Convert.ToDouble(genes[1].Value); var stopLoss = Convert.ToDouble(genes[1].Value);
// Enforce 1.1:1 risk-reward ratio constraint at phenotype level // Only enforce minimum stop loss to cover fees, allow any risk-reward ratio above that
var minStopLoss = Math.Max(0.2, takeProfit / 1.1); // Minimum 0.2% to cover fees var minStopLoss = 0.2; // Minimum 0.2% to cover fees
var maxStopLoss = takeProfit - 0.1; // Ensure SL is less than TP with some buffer stopLoss = Math.Max(minStopLoss, stopLoss);
// Clamp stop loss to valid range (this maintains genotype-phenotype mapping)
stopLoss = Math.Max(minStopLoss, Math.Min(maxStopLoss, stopLoss));
// Get loopback period from gene 4 // Get loopback period from gene 4
var loopbackPeriod = Convert.ToInt32(genes[4].Value); var loopbackPeriod = Convert.ToInt32(genes[4].Value);
@@ -809,13 +811,13 @@ public class TradingBotChromosome : ChromosomeBase
// Generate a random combination of up to 4 indicators // Generate a random combination of up to 4 indicators
var selectedCount = _random.Next(1, Math.Min(5, _eligibleIndicators.Count + 1)); // 1 to 4 indicators var selectedCount = _random.Next(1, Math.Min(5, _eligibleIndicators.Count + 1)); // 1 to 4 indicators
var selectedIndices = new HashSet<int>(); var selectedIndices = new HashSet<int>();
// Randomly select indices // Randomly select indices
while (selectedIndices.Count < selectedCount) while (selectedIndices.Count < selectedCount)
{ {
selectedIndices.Add(_random.Next(_eligibleIndicators.Count)); selectedIndices.Add(_random.Next(_eligibleIndicators.Count));
} }
// Create the selection pattern // Create the selection pattern
_indicatorSelectionPattern = new int[_eligibleIndicators.Count]; _indicatorSelectionPattern = new int[_eligibleIndicators.Count];
for (int i = 0; i < _eligibleIndicators.Count; i++) for (int i = 0; i < _eligibleIndicators.Count; i++)
@@ -832,21 +834,17 @@ public class TradingBotChromosome : ChromosomeBase
// Generate take profit first (gene 0) // Generate take profit first (gene 0)
var takeProfit = GetRandomInRange((0.9, _maxTakeProfit)); var takeProfit = GetRandomInRange((0.9, _maxTakeProfit));
ReplaceGene(0, new Gene(takeProfit)); ReplaceGene(0, new Gene(takeProfit));
// Generate stop loss with constraints based on take profit (gene 1) // Generate stop loss independently (gene 1) - only enforce minimum to cover fees
var minStopLoss = Math.Max(0.2, takeProfit / 1.1); // Minimum 0.2% to cover fees var stopLoss = GetRandomInRange(GeneticService.ParameterRanges["stopLoss"]);
var maxStopLoss = takeProfit - 0.1; // Ensure SL is less than TP with some buffer
var stopLoss = GetRandomInRange((minStopLoss, maxStopLoss));
ReplaceGene(1, new Gene(stopLoss)); ReplaceGene(1, new Gene(stopLoss));
// Initialize remaining genes normally // Initialize remaining genes normally
for (int i = 2; i < Length; i++) for (int i = 2; i < Length; i++)
{ {
ReplaceGene(i, GenerateGene(i)); ReplaceGene(i, GenerateGene(i));
} }
} }
} }
/// <summary> /// <summary>
@@ -934,7 +932,7 @@ public class TradingBotFitness : IFitness
// Calculate base fitness from backtest score // Calculate base fitness from backtest score
var baseFitness = backtest.Score; var baseFitness = backtest.Score;
// Return base fitness (no penalty for now) // Return base fitness (no penalty for now)
return baseFitness; return baseFitness;
} }