Add progression and new method of selection/mutation/crossover
This commit is contained in:
@@ -21,6 +21,7 @@ public class GeneticService : IGeneticService
|
||||
private readonly IGeneticRepository _geneticRepository;
|
||||
private readonly IBacktester _backtester;
|
||||
private readonly ILogger<GeneticService> _logger;
|
||||
private readonly IMessengerService _messengerService;
|
||||
|
||||
// Predefined parameter ranges for each indicator (matching backtestGenetic.tsx)
|
||||
public static readonly Dictionary<string, (double min, double max)> ParameterRanges = new()
|
||||
@@ -186,11 +187,13 @@ public class GeneticService : IGeneticService
|
||||
public GeneticService(
|
||||
IGeneticRepository geneticRepository,
|
||||
IBacktester backtester,
|
||||
ILogger<GeneticService> logger)
|
||||
ILogger<GeneticService> logger,
|
||||
IMessengerService messengerService)
|
||||
{
|
||||
_geneticRepository = geneticRepository;
|
||||
_backtester = backtester;
|
||||
_logger = logger;
|
||||
_messengerService = messengerService;
|
||||
}
|
||||
|
||||
public GeneticRequest CreateGeneticRequest(
|
||||
@@ -204,6 +207,8 @@ public class GeneticService : IGeneticService
|
||||
int generations,
|
||||
double mutationRate,
|
||||
GeneticSelectionMethod selectionMethod,
|
||||
GeneticCrossoverMethod crossoverMethod,
|
||||
GeneticMutationMethod mutationMethod,
|
||||
int elitismPercentage,
|
||||
double maxTakeProfit,
|
||||
List<IndicatorType> eligibleIndicators)
|
||||
@@ -220,6 +225,8 @@ public class GeneticService : IGeneticService
|
||||
Generations = generations,
|
||||
MutationRate = mutationRate,
|
||||
SelectionMethod = selectionMethod,
|
||||
CrossoverMethod = crossoverMethod,
|
||||
MutationMethod = mutationMethod,
|
||||
ElitismPercentage = elitismPercentage,
|
||||
MaxTakeProfit = maxTakeProfit,
|
||||
EligibleIndicators = eligibleIndicators,
|
||||
@@ -307,8 +314,8 @@ public class GeneticService : IGeneticService
|
||||
population,
|
||||
fitness,
|
||||
GetSelection(request.SelectionMethod),
|
||||
new UniformCrossover(),
|
||||
GetMutation(request.MutationRate))
|
||||
GetCrossover(request.CrossoverMethod),
|
||||
GetMutation(request.MutationMethod))
|
||||
{
|
||||
Termination = new GenerationNumberTermination(request.Generations),
|
||||
MutationProbability = (float)request.MutationRate,
|
||||
@@ -330,28 +337,25 @@ public class GeneticService : IGeneticService
|
||||
{
|
||||
generationCount = ga.GenerationsNumber;
|
||||
|
||||
// Update progress every 5 generations
|
||||
if (generationCount % 5 == 0)
|
||||
// Update progress every generation
|
||||
var bestFitness = ga.BestChromosome?.Fitness ?? 0;
|
||||
request.CurrentGeneration = generationCount;
|
||||
request.BestFitnessSoFar = bestFitness;
|
||||
|
||||
if (ga.BestChromosome is TradingBotChromosome bestChromosome)
|
||||
{
|
||||
var bestFitness = ga.BestChromosome?.Fitness ?? 0;
|
||||
request.CurrentGeneration = generationCount;
|
||||
request.BestFitnessSoFar = bestFitness;
|
||||
|
||||
if (ga.BestChromosome is TradingBotChromosome bestChromosome)
|
||||
var genes = bestChromosome.GetGenes();
|
||||
var geneValues = genes.Select(g =>
|
||||
{
|
||||
var genes = bestChromosome.GetGenes();
|
||||
var geneValues = genes.Select(g =>
|
||||
{
|
||||
if (g.Value is double doubleValue) return doubleValue;
|
||||
if (g.Value is int intValue) return (double)intValue;
|
||||
return Convert.ToDouble(g.Value.ToString());
|
||||
}).ToArray();
|
||||
request.BestChromosome = JsonSerializer.Serialize(geneValues);
|
||||
}
|
||||
|
||||
UpdateGeneticRequest(request);
|
||||
if (g.Value is double doubleValue) return doubleValue;
|
||||
if (g.Value is int intValue) return (double)intValue;
|
||||
return Convert.ToDouble(g.Value.ToString());
|
||||
}).ToArray();
|
||||
request.BestChromosome = JsonSerializer.Serialize(geneValues);
|
||||
}
|
||||
|
||||
UpdateGeneticRequest(request);
|
||||
|
||||
// Check for cancellation
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -403,6 +407,16 @@ public class GeneticService : IGeneticService
|
||||
|
||||
UpdateGeneticRequest(request);
|
||||
|
||||
// Send notification about the completed genetic algorithm
|
||||
try
|
||||
{
|
||||
await _messengerService.SendGeneticAlgorithmNotification(request, bestFitness, bestChromosome);
|
||||
}
|
||||
catch (Exception notificationEx)
|
||||
{
|
||||
_logger.LogWarning(notificationEx, "Failed to send genetic algorithm notification for request {RequestId}", request.RequestId);
|
||||
}
|
||||
|
||||
return new GeneticAlgorithmResult
|
||||
{
|
||||
BestFitness = bestFitness,
|
||||
@@ -429,16 +443,48 @@ public class GeneticService : IGeneticService
|
||||
{
|
||||
return selectionMethod switch
|
||||
{
|
||||
GeneticSelectionMethod.Tournament => new TournamentSelection(),
|
||||
GeneticSelectionMethod.Elite => new EliteSelection(),
|
||||
GeneticSelectionMethod.Roulette => new RouletteWheelSelection(),
|
||||
GeneticSelectionMethod.FitnessWeighted => new RankSelection(), // Use rank selection as approximation
|
||||
GeneticSelectionMethod.StochasticUniversalSampling => new StochasticUniversalSamplingSelection(),
|
||||
GeneticSelectionMethod.Tournament => new TournamentSelection(),
|
||||
GeneticSelectionMethod.Truncation => new TruncationSelection(),
|
||||
_ => new TournamentSelection()
|
||||
};
|
||||
}
|
||||
|
||||
private IMutation GetMutation(double mutationRate)
|
||||
private ICrossover GetCrossover(GeneticCrossoverMethod crossoverMethod)
|
||||
{
|
||||
return new UniformMutation(true);
|
||||
return crossoverMethod switch
|
||||
{
|
||||
GeneticCrossoverMethod.AlternatingPosition => new AlternatingPositionCrossover(),
|
||||
GeneticCrossoverMethod.CutAndSplice => new CutAndSpliceCrossover(),
|
||||
GeneticCrossoverMethod.Cycle => new CycleCrossover(),
|
||||
GeneticCrossoverMethod.OnePoint => new OnePointCrossover(),
|
||||
GeneticCrossoverMethod.OrderBased => new OrderBasedCrossover(),
|
||||
GeneticCrossoverMethod.Ordered => new OrderedCrossover(),
|
||||
GeneticCrossoverMethod.PartiallyMapped => new PartiallyMappedCrossover(),
|
||||
GeneticCrossoverMethod.PositionBased => new PositionBasedCrossover(),
|
||||
GeneticCrossoverMethod.ThreeParent => new ThreeParentCrossover(),
|
||||
GeneticCrossoverMethod.TwoPoint => new TwoPointCrossover(),
|
||||
GeneticCrossoverMethod.Uniform => new UniformCrossover(),
|
||||
GeneticCrossoverMethod.VotingRecombination => new VotingRecombinationCrossover(),
|
||||
_ => new UniformCrossover()
|
||||
};
|
||||
}
|
||||
|
||||
private IMutation GetMutation(GeneticMutationMethod mutationMethod)
|
||||
{
|
||||
return mutationMethod switch
|
||||
{
|
||||
GeneticMutationMethod.Displacement => new DisplacementMutation(),
|
||||
GeneticMutationMethod.FlipBit => new FlipBitMutation(),
|
||||
GeneticMutationMethod.Insertion => new InsertionMutation(),
|
||||
GeneticMutationMethod.PartialShuffle => new PartialShuffleMutation(),
|
||||
GeneticMutationMethod.ReverseSequence => new ReverseSequenceMutation(),
|
||||
GeneticMutationMethod.Twors => new TworsMutation(),
|
||||
GeneticMutationMethod.Uniform => new UniformMutation(true),
|
||||
_ => new UniformMutation(true)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -176,6 +176,19 @@ public class MessengerService : IMessengerService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SendGeneticAlgorithmNotification(GeneticRequest request, double bestFitness, object? bestChromosome)
|
||||
{
|
||||
try
|
||||
{
|
||||
var message = BuildGeneticAlgorithmMessage(request, bestFitness, bestChromosome);
|
||||
await _webhookService.SendMessage(message, "2775292276");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"Failed to send genetic algorithm notification: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private string BuildBacktestConfigMessage(Backtest backtest)
|
||||
{
|
||||
var config = backtest.Config;
|
||||
@@ -263,4 +276,42 @@ public class MessengerService : IMessengerService
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
private string BuildGeneticAlgorithmMessage(GeneticRequest request, double bestFitness, object? bestChromosome)
|
||||
{
|
||||
var duration = request.CompletedAt.HasValue
|
||||
? request.CompletedAt.Value - request.CreatedAt
|
||||
: TimeSpan.Zero;
|
||||
|
||||
var indicators = request.EligibleIndicators.Any()
|
||||
? string.Join(", ", request.EligibleIndicators.Select(i => i.ToString()))
|
||||
: "N/A";
|
||||
|
||||
if (request.EligibleIndicators.Count > 5)
|
||||
{
|
||||
indicators += $" (+{request.EligibleIndicators.Count - 5} more)";
|
||||
}
|
||||
|
||||
var message = $"🧬 Genetic Algorithm Completed! 🧬\n\n" +
|
||||
$"🔹 Symbol: {request.Ticker}\n" +
|
||||
$"⏱️ Timeframe: {request.Timeframe}\n" +
|
||||
$"👥 Population: {request.PopulationSize}\n" +
|
||||
$"🔄 Generations: {request.Generations}\n" +
|
||||
$"🎯 Selection: {request.SelectionMethod}\n" +
|
||||
$"🔀 Crossover: {request.CrossoverMethod}\n" +
|
||||
$"🧬 Mutation: {request.MutationMethod}\n" +
|
||||
$"🧩 Indicators: {indicators}\n" +
|
||||
$"📅 Period: {request.StartDate:yyyy-MM-dd} to {request.EndDate:yyyy-MM-dd}\n" +
|
||||
$"📈 Results:\n" +
|
||||
$"⭐ Best Fitness: {bestFitness:F4}\n" +
|
||||
$"⏱️ Duration: {duration.TotalMinutes:F1} minutes\n" +
|
||||
$"🆔 Request ID: {request.RequestId[..8]}...";
|
||||
|
||||
if (request.BestFitnessSoFar.HasValue && request.BestFitnessSoFar.Value > 0)
|
||||
{
|
||||
message += $"\n🏆 Best Fitness So Far: {request.BestFitnessSoFar.Value:F4}";
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user