Add progression and new method of selection/mutation/crossover
This commit is contained in:
@@ -314,6 +314,8 @@ public class BacktestController : BaseController
|
|||||||
request.Generations,
|
request.Generations,
|
||||||
request.MutationRate,
|
request.MutationRate,
|
||||||
request.SelectionMethod,
|
request.SelectionMethod,
|
||||||
|
request.CrossoverMethod,
|
||||||
|
request.MutationMethod,
|
||||||
request.ElitismPercentage,
|
request.ElitismPercentage,
|
||||||
request.MaxTakeProfit,
|
request.MaxTakeProfit,
|
||||||
request.EligibleIndicators);
|
request.EligibleIndicators);
|
||||||
|
|||||||
@@ -52,6 +52,16 @@ public class RunGeneticRequest
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public GeneticSelectionMethod SelectionMethod { get; set; }
|
public GeneticSelectionMethod SelectionMethod { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The crossover method to use
|
||||||
|
/// </summary>
|
||||||
|
public GeneticCrossoverMethod CrossoverMethod { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The mutation method to use
|
||||||
|
/// </summary>
|
||||||
|
public GeneticMutationMethod MutationMethod { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The percentage of elite individuals to preserve (1-50)
|
/// The percentage of elite individuals to preserve (1-50)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ public interface IGeneticService
|
|||||||
/// <param name="generations">The number of generations to evolve</param>
|
/// <param name="generations">The number of generations to evolve</param>
|
||||||
/// <param name="mutationRate">The mutation rate (0.0 - 1.0)</param>
|
/// <param name="mutationRate">The mutation rate (0.0 - 1.0)</param>
|
||||||
/// <param name="selectionMethod">The selection method to use</param>
|
/// <param name="selectionMethod">The selection method to use</param>
|
||||||
|
/// <param name="crossoverMethod">The crossover method to use</param>
|
||||||
|
/// <param name="mutationMethod">The mutation method to use</param>
|
||||||
/// <param name="elitismPercentage">The percentage of elite individuals to preserve</param>
|
/// <param name="elitismPercentage">The percentage of elite individuals to preserve</param>
|
||||||
/// <param name="maxTakeProfit">The maximum take profit percentage</param>
|
/// <param name="maxTakeProfit">The maximum take profit percentage</param>
|
||||||
/// <param name="eligibleIndicators">The list of eligible indicators</param>
|
/// <param name="eligibleIndicators">The list of eligible indicators</param>
|
||||||
@@ -37,6 +39,8 @@ public interface IGeneticService
|
|||||||
int generations,
|
int generations,
|
||||||
double mutationRate,
|
double mutationRate,
|
||||||
GeneticSelectionMethod selectionMethod,
|
GeneticSelectionMethod selectionMethod,
|
||||||
|
GeneticCrossoverMethod crossoverMethod,
|
||||||
|
GeneticMutationMethod mutationMethod,
|
||||||
int elitismPercentage,
|
int elitismPercentage,
|
||||||
double maxTakeProfit,
|
double maxTakeProfit,
|
||||||
List<IndicatorType> eligibleIndicators);
|
List<IndicatorType> eligibleIndicators);
|
||||||
|
|||||||
@@ -24,4 +24,5 @@ public interface IMessengerService
|
|||||||
Task SendNewTopFundingRate(FundingRate newRate);
|
Task SendNewTopFundingRate(FundingRate newRate);
|
||||||
Task SendFundingRateUpdate(FundingRate oldRate, FundingRate newRate);
|
Task SendFundingRateUpdate(FundingRate oldRate, FundingRate newRate);
|
||||||
Task SendBacktestNotification(Backtest backtest);
|
Task SendBacktestNotification(Backtest backtest);
|
||||||
|
Task SendGeneticAlgorithmNotification(GeneticRequest request, double bestFitness, object? bestChromosome);
|
||||||
}
|
}
|
||||||
@@ -21,6 +21,7 @@ public class GeneticService : IGeneticService
|
|||||||
private readonly IGeneticRepository _geneticRepository;
|
private readonly IGeneticRepository _geneticRepository;
|
||||||
private readonly IBacktester _backtester;
|
private readonly IBacktester _backtester;
|
||||||
private readonly ILogger<GeneticService> _logger;
|
private readonly ILogger<GeneticService> _logger;
|
||||||
|
private readonly IMessengerService _messengerService;
|
||||||
|
|
||||||
// Predefined parameter ranges for each indicator (matching backtestGenetic.tsx)
|
// Predefined parameter ranges for each indicator (matching backtestGenetic.tsx)
|
||||||
public static readonly Dictionary<string, (double min, double max)> ParameterRanges = new()
|
public static readonly Dictionary<string, (double min, double max)> ParameterRanges = new()
|
||||||
@@ -186,11 +187,13 @@ public class GeneticService : IGeneticService
|
|||||||
public GeneticService(
|
public GeneticService(
|
||||||
IGeneticRepository geneticRepository,
|
IGeneticRepository geneticRepository,
|
||||||
IBacktester backtester,
|
IBacktester backtester,
|
||||||
ILogger<GeneticService> logger)
|
ILogger<GeneticService> logger,
|
||||||
|
IMessengerService messengerService)
|
||||||
{
|
{
|
||||||
_geneticRepository = geneticRepository;
|
_geneticRepository = geneticRepository;
|
||||||
_backtester = backtester;
|
_backtester = backtester;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_messengerService = messengerService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GeneticRequest CreateGeneticRequest(
|
public GeneticRequest CreateGeneticRequest(
|
||||||
@@ -204,6 +207,8 @@ public class GeneticService : IGeneticService
|
|||||||
int generations,
|
int generations,
|
||||||
double mutationRate,
|
double mutationRate,
|
||||||
GeneticSelectionMethod selectionMethod,
|
GeneticSelectionMethod selectionMethod,
|
||||||
|
GeneticCrossoverMethod crossoverMethod,
|
||||||
|
GeneticMutationMethod mutationMethod,
|
||||||
int elitismPercentage,
|
int elitismPercentage,
|
||||||
double maxTakeProfit,
|
double maxTakeProfit,
|
||||||
List<IndicatorType> eligibleIndicators)
|
List<IndicatorType> eligibleIndicators)
|
||||||
@@ -220,6 +225,8 @@ public class GeneticService : IGeneticService
|
|||||||
Generations = generations,
|
Generations = generations,
|
||||||
MutationRate = mutationRate,
|
MutationRate = mutationRate,
|
||||||
SelectionMethod = selectionMethod,
|
SelectionMethod = selectionMethod,
|
||||||
|
CrossoverMethod = crossoverMethod,
|
||||||
|
MutationMethod = mutationMethod,
|
||||||
ElitismPercentage = elitismPercentage,
|
ElitismPercentage = elitismPercentage,
|
||||||
MaxTakeProfit = maxTakeProfit,
|
MaxTakeProfit = maxTakeProfit,
|
||||||
EligibleIndicators = eligibleIndicators,
|
EligibleIndicators = eligibleIndicators,
|
||||||
@@ -307,8 +314,8 @@ public class GeneticService : IGeneticService
|
|||||||
population,
|
population,
|
||||||
fitness,
|
fitness,
|
||||||
GetSelection(request.SelectionMethod),
|
GetSelection(request.SelectionMethod),
|
||||||
new UniformCrossover(),
|
GetCrossover(request.CrossoverMethod),
|
||||||
GetMutation(request.MutationRate))
|
GetMutation(request.MutationMethod))
|
||||||
{
|
{
|
||||||
Termination = new GenerationNumberTermination(request.Generations),
|
Termination = new GenerationNumberTermination(request.Generations),
|
||||||
MutationProbability = (float)request.MutationRate,
|
MutationProbability = (float)request.MutationRate,
|
||||||
@@ -330,9 +337,7 @@ public class GeneticService : IGeneticService
|
|||||||
{
|
{
|
||||||
generationCount = ga.GenerationsNumber;
|
generationCount = ga.GenerationsNumber;
|
||||||
|
|
||||||
// Update progress every 5 generations
|
// Update progress every generation
|
||||||
if (generationCount % 5 == 0)
|
|
||||||
{
|
|
||||||
var bestFitness = ga.BestChromosome?.Fitness ?? 0;
|
var bestFitness = ga.BestChromosome?.Fitness ?? 0;
|
||||||
request.CurrentGeneration = generationCount;
|
request.CurrentGeneration = generationCount;
|
||||||
request.BestFitnessSoFar = bestFitness;
|
request.BestFitnessSoFar = bestFitness;
|
||||||
@@ -350,7 +355,6 @@ public class GeneticService : IGeneticService
|
|||||||
}
|
}
|
||||||
|
|
||||||
UpdateGeneticRequest(request);
|
UpdateGeneticRequest(request);
|
||||||
}
|
|
||||||
|
|
||||||
// Check for cancellation
|
// Check for cancellation
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
@@ -403,6 +407,16 @@ public class GeneticService : IGeneticService
|
|||||||
|
|
||||||
UpdateGeneticRequest(request);
|
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
|
return new GeneticAlgorithmResult
|
||||||
{
|
{
|
||||||
BestFitness = bestFitness,
|
BestFitness = bestFitness,
|
||||||
@@ -429,16 +443,48 @@ public class GeneticService : IGeneticService
|
|||||||
{
|
{
|
||||||
return selectionMethod switch
|
return selectionMethod switch
|
||||||
{
|
{
|
||||||
GeneticSelectionMethod.Tournament => new TournamentSelection(),
|
GeneticSelectionMethod.Elite => new EliteSelection(),
|
||||||
GeneticSelectionMethod.Roulette => new RouletteWheelSelection(),
|
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()
|
_ => 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)
|
private string BuildBacktestConfigMessage(Backtest backtest)
|
||||||
{
|
{
|
||||||
var config = backtest.Config;
|
var config = backtest.Config;
|
||||||
@@ -263,4 +276,42 @@ public class MessengerService : IMessengerService
|
|||||||
|
|
||||||
return message;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -422,8 +422,43 @@ public static class Enums
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public enum GeneticSelectionMethod
|
public enum GeneticSelectionMethod
|
||||||
{
|
{
|
||||||
Tournament,
|
Elite,
|
||||||
Roulette,
|
Roulette,
|
||||||
FitnessWeighted
|
StochasticUniversalSampling,
|
||||||
|
Tournament,
|
||||||
|
Truncation
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Crossover methods for genetic algorithm optimization
|
||||||
|
/// </summary>
|
||||||
|
public enum GeneticCrossoverMethod
|
||||||
|
{
|
||||||
|
AlternatingPosition,
|
||||||
|
CutAndSplice,
|
||||||
|
Cycle,
|
||||||
|
OnePoint,
|
||||||
|
OrderBased,
|
||||||
|
Ordered,
|
||||||
|
PartiallyMapped,
|
||||||
|
PositionBased,
|
||||||
|
ThreeParent,
|
||||||
|
TwoPoint,
|
||||||
|
Uniform,
|
||||||
|
VotingRecombination
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mutation methods for genetic algorithm optimization
|
||||||
|
/// </summary>
|
||||||
|
public enum GeneticMutationMethod
|
||||||
|
{
|
||||||
|
Displacement,
|
||||||
|
FlipBit,
|
||||||
|
Insertion,
|
||||||
|
PartialShuffle,
|
||||||
|
ReverseSequence,
|
||||||
|
Twors,
|
||||||
|
Uniform
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,6 +112,18 @@ public class GeneticRequest
|
|||||||
[Required]
|
[Required]
|
||||||
public GeneticSelectionMethod SelectionMethod { get; set; } = GeneticSelectionMethod.Tournament;
|
public GeneticSelectionMethod SelectionMethod { get; set; } = GeneticSelectionMethod.Tournament;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The crossover method to use
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public GeneticCrossoverMethod CrossoverMethod { get; set; } = GeneticCrossoverMethod.Uniform;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The mutation method to use
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public GeneticMutationMethod MutationMethod { get; set; } = GeneticMutationMethod.Uniform;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The percentage of elite individuals to preserve (1-50)
|
/// The percentage of elite individuals to preserve (1-50)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ namespace Managing.Infrastructure.Databases.MongoDb.Collections
|
|||||||
public int Generations { get; set; }
|
public int Generations { get; set; }
|
||||||
public double MutationRate { get; set; }
|
public double MutationRate { get; set; }
|
||||||
public GeneticSelectionMethod SelectionMethod { get; set; }
|
public GeneticSelectionMethod SelectionMethod { get; set; }
|
||||||
|
public GeneticCrossoverMethod CrossoverMethod { get; set; }
|
||||||
|
public GeneticMutationMethod MutationMethod { get; set; }
|
||||||
public int ElitismPercentage { get; set; }
|
public int ElitismPercentage { get; set; }
|
||||||
public double MaxTakeProfit { get; set; }
|
public double MaxTakeProfit { get; set; }
|
||||||
public List<IndicatorType> EligibleIndicators { get; set; } = new();
|
public List<IndicatorType> EligibleIndicators { get; set; } = new();
|
||||||
|
|||||||
@@ -209,13 +209,18 @@ public static class MongoMappers
|
|||||||
Generations = dto.Generations,
|
Generations = dto.Generations,
|
||||||
MutationRate = dto.MutationRate,
|
MutationRate = dto.MutationRate,
|
||||||
SelectionMethod = dto.SelectionMethod,
|
SelectionMethod = dto.SelectionMethod,
|
||||||
|
CrossoverMethod = dto.CrossoverMethod,
|
||||||
|
MutationMethod = dto.MutationMethod,
|
||||||
ElitismPercentage = dto.ElitismPercentage,
|
ElitismPercentage = dto.ElitismPercentage,
|
||||||
MaxTakeProfit = dto.MaxTakeProfit,
|
MaxTakeProfit = dto.MaxTakeProfit,
|
||||||
EligibleIndicators = dto.EligibleIndicators,
|
EligibleIndicators = dto.EligibleIndicators,
|
||||||
BestFitness = dto.BestFitness,
|
BestFitness = dto.BestFitness,
|
||||||
BestIndividual = dto.BestIndividual,
|
BestIndividual = dto.BestIndividual,
|
||||||
ErrorMessage = dto.ErrorMessage,
|
ErrorMessage = dto.ErrorMessage,
|
||||||
ProgressInfo = dto.ProgressInfo
|
ProgressInfo = dto.ProgressInfo,
|
||||||
|
BestChromosome = dto.BestChromosome,
|
||||||
|
BestFitnessSoFar = dto.BestFitnessSoFar,
|
||||||
|
CurrentGeneration = dto.CurrentGeneration
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,13 +244,18 @@ public static class MongoMappers
|
|||||||
Generations = geneticRequest.Generations,
|
Generations = geneticRequest.Generations,
|
||||||
MutationRate = geneticRequest.MutationRate,
|
MutationRate = geneticRequest.MutationRate,
|
||||||
SelectionMethod = geneticRequest.SelectionMethod,
|
SelectionMethod = geneticRequest.SelectionMethod,
|
||||||
|
CrossoverMethod = geneticRequest.CrossoverMethod,
|
||||||
|
MutationMethod = geneticRequest.MutationMethod,
|
||||||
ElitismPercentage = geneticRequest.ElitismPercentage,
|
ElitismPercentage = geneticRequest.ElitismPercentage,
|
||||||
MaxTakeProfit = geneticRequest.MaxTakeProfit,
|
MaxTakeProfit = geneticRequest.MaxTakeProfit,
|
||||||
EligibleIndicators = geneticRequest.EligibleIndicators,
|
EligibleIndicators = geneticRequest.EligibleIndicators,
|
||||||
BestFitness = geneticRequest.BestFitness,
|
BestFitness = geneticRequest.BestFitness,
|
||||||
BestIndividual = geneticRequest.BestIndividual,
|
BestIndividual = geneticRequest.BestIndividual,
|
||||||
ErrorMessage = geneticRequest.ErrorMessage,
|
ErrorMessage = geneticRequest.ErrorMessage,
|
||||||
ProgressInfo = geneticRequest.ProgressInfo
|
ProgressInfo = geneticRequest.ProgressInfo,
|
||||||
|
BestChromosome = geneticRequest.BestChromosome,
|
||||||
|
BestFitnessSoFar = geneticRequest.BestFitnessSoFar,
|
||||||
|
CurrentGeneration = geneticRequest.CurrentGeneration
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3771,6 +3771,8 @@ export interface GeneticRequest {
|
|||||||
generations: number;
|
generations: number;
|
||||||
mutationRate: number;
|
mutationRate: number;
|
||||||
selectionMethod: GeneticSelectionMethod;
|
selectionMethod: GeneticSelectionMethod;
|
||||||
|
crossoverMethod: GeneticCrossoverMethod;
|
||||||
|
mutationMethod: GeneticMutationMethod;
|
||||||
elitismPercentage: number;
|
elitismPercentage: number;
|
||||||
maxTakeProfit: number;
|
maxTakeProfit: number;
|
||||||
eligibleIndicators: IndicatorType[];
|
eligibleIndicators: IndicatorType[];
|
||||||
@@ -3793,9 +3795,36 @@ export enum GeneticRequestStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum GeneticSelectionMethod {
|
export enum GeneticSelectionMethod {
|
||||||
Tournament = "Tournament",
|
Elite = "Elite",
|
||||||
Roulette = "Roulette",
|
Roulette = "Roulette",
|
||||||
FitnessWeighted = "FitnessWeighted",
|
StochasticUniversalSampling = "StochasticUniversalSampling",
|
||||||
|
Tournament = "Tournament",
|
||||||
|
Truncation = "Truncation",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum GeneticCrossoverMethod {
|
||||||
|
AlternatingPosition = "AlternatingPosition",
|
||||||
|
CutAndSplice = "CutAndSplice",
|
||||||
|
Cycle = "Cycle",
|
||||||
|
OnePoint = "OnePoint",
|
||||||
|
OrderBased = "OrderBased",
|
||||||
|
Ordered = "Ordered",
|
||||||
|
PartiallyMapped = "PartiallyMapped",
|
||||||
|
PositionBased = "PositionBased",
|
||||||
|
ThreeParent = "ThreeParent",
|
||||||
|
TwoPoint = "TwoPoint",
|
||||||
|
Uniform = "Uniform",
|
||||||
|
VotingRecombination = "VotingRecombination",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum GeneticMutationMethod {
|
||||||
|
Displacement = "Displacement",
|
||||||
|
FlipBit = "FlipBit",
|
||||||
|
Insertion = "Insertion",
|
||||||
|
PartialShuffle = "PartialShuffle",
|
||||||
|
ReverseSequence = "ReverseSequence",
|
||||||
|
Twors = "Twors",
|
||||||
|
Uniform = "Uniform",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RunGeneticRequest {
|
export interface RunGeneticRequest {
|
||||||
@@ -3808,6 +3837,8 @@ export interface RunGeneticRequest {
|
|||||||
generations?: number;
|
generations?: number;
|
||||||
mutationRate?: number;
|
mutationRate?: number;
|
||||||
selectionMethod?: GeneticSelectionMethod;
|
selectionMethod?: GeneticSelectionMethod;
|
||||||
|
crossoverMethod?: GeneticCrossoverMethod;
|
||||||
|
mutationMethod?: GeneticMutationMethod;
|
||||||
elitismPercentage?: number;
|
elitismPercentage?: number;
|
||||||
maxTakeProfit?: number;
|
maxTakeProfit?: number;
|
||||||
eligibleIndicators?: IndicatorType[] | null;
|
eligibleIndicators?: IndicatorType[] | null;
|
||||||
|
|||||||
@@ -674,6 +674,8 @@ export interface GeneticRequest {
|
|||||||
generations: number;
|
generations: number;
|
||||||
mutationRate: number;
|
mutationRate: number;
|
||||||
selectionMethod: GeneticSelectionMethod;
|
selectionMethod: GeneticSelectionMethod;
|
||||||
|
crossoverMethod: GeneticCrossoverMethod;
|
||||||
|
mutationMethod: GeneticMutationMethod;
|
||||||
elitismPercentage: number;
|
elitismPercentage: number;
|
||||||
maxTakeProfit: number;
|
maxTakeProfit: number;
|
||||||
eligibleIndicators: IndicatorType[];
|
eligibleIndicators: IndicatorType[];
|
||||||
@@ -696,9 +698,36 @@ export enum GeneticRequestStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum GeneticSelectionMethod {
|
export enum GeneticSelectionMethod {
|
||||||
Tournament = "Tournament",
|
Elite = "Elite",
|
||||||
Roulette = "Roulette",
|
Roulette = "Roulette",
|
||||||
FitnessWeighted = "FitnessWeighted",
|
StochasticUniversalSampling = "StochasticUniversalSampling",
|
||||||
|
Tournament = "Tournament",
|
||||||
|
Truncation = "Truncation",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum GeneticCrossoverMethod {
|
||||||
|
AlternatingPosition = "AlternatingPosition",
|
||||||
|
CutAndSplice = "CutAndSplice",
|
||||||
|
Cycle = "Cycle",
|
||||||
|
OnePoint = "OnePoint",
|
||||||
|
OrderBased = "OrderBased",
|
||||||
|
Ordered = "Ordered",
|
||||||
|
PartiallyMapped = "PartiallyMapped",
|
||||||
|
PositionBased = "PositionBased",
|
||||||
|
ThreeParent = "ThreeParent",
|
||||||
|
TwoPoint = "TwoPoint",
|
||||||
|
Uniform = "Uniform",
|
||||||
|
VotingRecombination = "VotingRecombination",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum GeneticMutationMethod {
|
||||||
|
Displacement = "Displacement",
|
||||||
|
FlipBit = "FlipBit",
|
||||||
|
Insertion = "Insertion",
|
||||||
|
PartialShuffle = "PartialShuffle",
|
||||||
|
ReverseSequence = "ReverseSequence",
|
||||||
|
Twors = "Twors",
|
||||||
|
Uniform = "Uniform",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RunGeneticRequest {
|
export interface RunGeneticRequest {
|
||||||
@@ -711,6 +740,8 @@ export interface RunGeneticRequest {
|
|||||||
generations?: number;
|
generations?: number;
|
||||||
mutationRate?: number;
|
mutationRate?: number;
|
||||||
selectionMethod?: GeneticSelectionMethod;
|
selectionMethod?: GeneticSelectionMethod;
|
||||||
|
crossoverMethod?: GeneticCrossoverMethod;
|
||||||
|
mutationMethod?: GeneticMutationMethod;
|
||||||
elitismPercentage?: number;
|
elitismPercentage?: number;
|
||||||
maxTakeProfit?: number;
|
maxTakeProfit?: number;
|
||||||
eligibleIndicators?: IndicatorType[] | null;
|
eligibleIndicators?: IndicatorType[] | null;
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import useApiUrlStore from '../../app/store/apiStore'
|
|||||||
import {
|
import {
|
||||||
type Backtest,
|
type Backtest,
|
||||||
BacktestClient,
|
BacktestClient,
|
||||||
|
GeneticCrossoverMethod,
|
||||||
|
GeneticMutationMethod,
|
||||||
type GeneticRequest,
|
type GeneticRequest,
|
||||||
GeneticSelectionMethod,
|
GeneticSelectionMethod,
|
||||||
IndicatorType,
|
IndicatorType,
|
||||||
@@ -52,6 +54,8 @@ interface GeneticBundleFormData {
|
|||||||
generations: number
|
generations: number
|
||||||
mutationRate: number
|
mutationRate: number
|
||||||
selectionMethod: GeneticSelectionMethod
|
selectionMethod: GeneticSelectionMethod
|
||||||
|
crossoverMethod: GeneticCrossoverMethod
|
||||||
|
mutationMethod: GeneticMutationMethod
|
||||||
elitismPercentage: number
|
elitismPercentage: number
|
||||||
maxTakeProfit: number
|
maxTakeProfit: number
|
||||||
eligibleIndicators: IndicatorType[]
|
eligibleIndicators: IndicatorType[]
|
||||||
@@ -70,6 +74,7 @@ const BacktestGeneticBundle: React.FC = () => {
|
|||||||
const [isViewModalOpen, setIsViewModalOpen] = useState(false)
|
const [isViewModalOpen, setIsViewModalOpen] = useState(false)
|
||||||
const [backtests, setBacktests] = useState<Backtest[]>([])
|
const [backtests, setBacktests] = useState<Backtest[]>([])
|
||||||
const [isLoadingBacktests, setIsLoadingBacktests] = useState(false)
|
const [isLoadingBacktests, setIsLoadingBacktests] = useState(false)
|
||||||
|
const [isFormCollapsed, setIsFormCollapsed] = useState(false)
|
||||||
|
|
||||||
// Form setup
|
// Form setup
|
||||||
const {register, handleSubmit, watch, setValue, formState: {errors}} = useForm<GeneticBundleFormData>({
|
const {register, handleSubmit, watch, setValue, formState: {errors}} = useForm<GeneticBundleFormData>({
|
||||||
@@ -83,6 +88,8 @@ const BacktestGeneticBundle: React.FC = () => {
|
|||||||
generations: 5,
|
generations: 5,
|
||||||
mutationRate: 0.3,
|
mutationRate: 0.3,
|
||||||
selectionMethod: GeneticSelectionMethod.Tournament,
|
selectionMethod: GeneticSelectionMethod.Tournament,
|
||||||
|
crossoverMethod: GeneticCrossoverMethod.Uniform,
|
||||||
|
mutationMethod: GeneticMutationMethod.Uniform,
|
||||||
elitismPercentage: 10,
|
elitismPercentage: 10,
|
||||||
maxTakeProfit: 2.0,
|
maxTakeProfit: 2.0,
|
||||||
eligibleIndicators: ALL_INDICATORS,
|
eligibleIndicators: ALL_INDICATORS,
|
||||||
@@ -139,6 +146,8 @@ const BacktestGeneticBundle: React.FC = () => {
|
|||||||
generations: data.generations,
|
generations: data.generations,
|
||||||
mutationRate: data.mutationRate,
|
mutationRate: data.mutationRate,
|
||||||
selectionMethod: data.selectionMethod,
|
selectionMethod: data.selectionMethod,
|
||||||
|
crossoverMethod: data.crossoverMethod,
|
||||||
|
mutationMethod: data.mutationMethod,
|
||||||
elitismPercentage: data.elitismPercentage,
|
elitismPercentage: data.elitismPercentage,
|
||||||
maxTakeProfit: data.maxTakeProfit,
|
maxTakeProfit: data.maxTakeProfit,
|
||||||
eligibleIndicators: selectedIndicators,
|
eligibleIndicators: selectedIndicators,
|
||||||
@@ -161,6 +170,8 @@ const BacktestGeneticBundle: React.FC = () => {
|
|||||||
setValue('generations', 5)
|
setValue('generations', 5)
|
||||||
setValue('mutationRate', 0.3)
|
setValue('mutationRate', 0.3)
|
||||||
setValue('selectionMethod', GeneticSelectionMethod.Tournament)
|
setValue('selectionMethod', GeneticSelectionMethod.Tournament)
|
||||||
|
setValue('crossoverMethod', GeneticCrossoverMethod.Uniform)
|
||||||
|
setValue('mutationMethod', GeneticMutationMethod.Uniform)
|
||||||
setValue('elitismPercentage', 10)
|
setValue('elitismPercentage', 10)
|
||||||
setValue('maxTakeProfit', 2.0)
|
setValue('maxTakeProfit', 2.0)
|
||||||
setSelectedIndicators(ALL_INDICATORS)
|
setSelectedIndicators(ALL_INDICATORS)
|
||||||
@@ -228,13 +239,6 @@ const BacktestGeneticBundle: React.FC = () => {
|
|||||||
|
|
||||||
// Table columns for genetic requests
|
// Table columns for genetic requests
|
||||||
const geneticRequestsColumns = useMemo(() => [
|
const geneticRequestsColumns = useMemo(() => [
|
||||||
{
|
|
||||||
Header: 'ID',
|
|
||||||
accessor: 'requestId',
|
|
||||||
Cell: ({value}: { value: string }) => (
|
|
||||||
<span className="font-mono text-xs">{value.slice(0, 8)}...</span>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Header: 'Ticker',
|
Header: 'Ticker',
|
||||||
accessor: 'ticker',
|
accessor: 'ticker',
|
||||||
@@ -243,6 +247,49 @@ const BacktestGeneticBundle: React.FC = () => {
|
|||||||
Header: 'Timeframe',
|
Header: 'Timeframe',
|
||||||
accessor: 'timeframe',
|
accessor: 'timeframe',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Header: 'Progress',
|
||||||
|
accessor: 'currentGeneration',
|
||||||
|
Cell: ({value, row}: { value: number, row: any }) => {
|
||||||
|
const generations = row.original.generations
|
||||||
|
const currentGen = value || 0
|
||||||
|
const percentage = generations > 0 ? Math.round((currentGen / generations) * 100) : 0
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<div className="text-xs">
|
||||||
|
{currentGen} / {generations}
|
||||||
|
</div>
|
||||||
|
<progress
|
||||||
|
className="progress progress-primary w-full h-2"
|
||||||
|
value={percentage}
|
||||||
|
max="100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: 'Selection',
|
||||||
|
accessor: 'selectionMethod',
|
||||||
|
Cell: ({value}: { value: string }) => (
|
||||||
|
<span className="text-xs">{value}</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: 'Crossover',
|
||||||
|
accessor: 'crossoverMethod',
|
||||||
|
Cell: ({value}: { value: string }) => (
|
||||||
|
<span className="text-xs">{value}</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: 'Mutation',
|
||||||
|
accessor: 'mutationMethod',
|
||||||
|
Cell: ({value}: { value: string }) => (
|
||||||
|
<span className="text-xs">{value}</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Header: 'Status',
|
Header: 'Status',
|
||||||
accessor: 'status',
|
accessor: 'status',
|
||||||
@@ -252,20 +299,6 @@ const BacktestGeneticBundle: React.FC = () => {
|
|||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Header: 'Created',
|
|
||||||
accessor: 'createdAt',
|
|
||||||
Cell: ({value}: { value: string }) => (
|
|
||||||
<span>{new Date(value).toLocaleDateString()}</span>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: 'Completed',
|
|
||||||
accessor: 'completedAt',
|
|
||||||
Cell: ({value}: { value: string | null }) => (
|
|
||||||
<span>{value ? new Date(value).toLocaleDateString() : '-'}</span>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Header: 'Actions',
|
Header: 'Actions',
|
||||||
accessor: 'actions',
|
accessor: 'actions',
|
||||||
@@ -301,14 +334,52 @@ const BacktestGeneticBundle: React.FC = () => {
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="card bg-base-100 shadow-xl">
|
<div className="card bg-base-100 shadow-xl">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
|
<div className="flex justify-between items-center mb-4">
|
||||||
|
<div>
|
||||||
<h2 className="card-title">Genetic Algorithm Bundle</h2>
|
<h2 className="card-title">Genetic Algorithm Bundle</h2>
|
||||||
<p className="text-sm text-gray-600 mb-4">
|
<p className="text-sm text-gray-600">
|
||||||
Create a genetic algorithm request that will be processed in the background.
|
Create a genetic algorithm request that will be processed in the background.
|
||||||
The algorithm will optimize trading parameters and indicator combinations.
|
The algorithm will optimize trading parameters and indicator combinations.
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setIsFormCollapsed(!isFormCollapsed)}
|
||||||
|
className="btn btn-sm btn-outline"
|
||||||
|
>
|
||||||
|
{isFormCollapsed ? 'Show Form' : 'Hide Form'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
<form onSubmit={handleSubmit(onSubmit)} className={`space-y-4 ${isFormCollapsed ? 'hidden' : ''}`}>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
{isFormCollapsed && (
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="bg-base-200 p-4 rounded-lg">
|
||||||
|
<h4 className="font-semibold mb-2">Current Settings</h4>
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-2 text-sm">
|
||||||
|
<div><strong>Ticker:</strong> {formValues.ticker}</div>
|
||||||
|
<div><strong>Timeframe:</strong> {formValues.timeframe}</div>
|
||||||
|
<div><strong>Population:</strong> {formValues.populationSize}</div>
|
||||||
|
<div><strong>Generations:</strong> {formValues.generations}</div>
|
||||||
|
<div><strong>Selection:</strong> {formValues.selectionMethod}</div>
|
||||||
|
<div><strong>Crossover:</strong> {formValues.crossoverMethod}</div>
|
||||||
|
<div><strong>Mutation:</strong> {formValues.mutationMethod}</div>
|
||||||
|
<div><strong>Indicators:</strong> {selectedIndicators.length}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleSubmit(onSubmit)}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
className="btn btn-primary"
|
||||||
|
>
|
||||||
|
{isSubmitting ? 'Creating...' : 'Create Request with Current Settings'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
<div className="form-control">
|
<div className="form-control">
|
||||||
<label className="label">
|
<label className="label">
|
||||||
<span className="label-text">Ticker</span>
|
<span className="label-text">Ticker</span>
|
||||||
@@ -418,9 +489,52 @@ const BacktestGeneticBundle: React.FC = () => {
|
|||||||
className="select select-bordered w-full"
|
className="select select-bordered w-full"
|
||||||
{...register('selectionMethod')}
|
{...register('selectionMethod')}
|
||||||
>
|
>
|
||||||
<option value={GeneticSelectionMethod.Tournament}>Tournament Selection</option>
|
<option value={GeneticSelectionMethod.Elite}>Elite Selection</option>
|
||||||
<option value={GeneticSelectionMethod.Roulette}>Roulette Wheel</option>
|
<option value={GeneticSelectionMethod.Roulette}>Roulette Wheel</option>
|
||||||
<option value={GeneticSelectionMethod.FitnessWeighted}>Fitness Weighted</option>
|
<option value={GeneticSelectionMethod.StochasticUniversalSampling}>Stochastic Universal Sampling</option>
|
||||||
|
<option value={GeneticSelectionMethod.Tournament}>Tournament Selection</option>
|
||||||
|
<option value={GeneticSelectionMethod.Truncation}>Truncation Selection</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-control">
|
||||||
|
<label className="label">
|
||||||
|
<span className="label-text">Crossover Method</span>
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
className="select select-bordered w-full"
|
||||||
|
{...register('crossoverMethod')}
|
||||||
|
>
|
||||||
|
<option value={GeneticCrossoverMethod.AlternatingPosition}>Alternating Position (AP)</option>
|
||||||
|
<option value={GeneticCrossoverMethod.CutAndSplice}>Cut and Splice</option>
|
||||||
|
<option value={GeneticCrossoverMethod.Cycle}>Cycle (CX)</option>
|
||||||
|
<option value={GeneticCrossoverMethod.OnePoint}>One-Point (C1)</option>
|
||||||
|
<option value={GeneticCrossoverMethod.OrderBased}>Order-based (OX2)</option>
|
||||||
|
<option value={GeneticCrossoverMethod.Ordered}>Ordered (OX1)</option>
|
||||||
|
<option value={GeneticCrossoverMethod.PartiallyMapped}>Partially Mapped (PMX)</option>
|
||||||
|
<option value={GeneticCrossoverMethod.PositionBased}>Position-based (POS)</option>
|
||||||
|
<option value={GeneticCrossoverMethod.ThreeParent}>Three Parent</option>
|
||||||
|
<option value={GeneticCrossoverMethod.TwoPoint}>Two-Point (C2)</option>
|
||||||
|
<option value={GeneticCrossoverMethod.Uniform}>Uniform</option>
|
||||||
|
<option value={GeneticCrossoverMethod.VotingRecombination}>Voting Recombination (VR)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-control">
|
||||||
|
<label className="label">
|
||||||
|
<span className="label-text">Mutation Method</span>
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
className="select select-bordered w-full"
|
||||||
|
{...register('mutationMethod')}
|
||||||
|
>
|
||||||
|
<option value={GeneticMutationMethod.Displacement}>Displacement</option>
|
||||||
|
<option value={GeneticMutationMethod.FlipBit}>Flip Bit</option>
|
||||||
|
<option value={GeneticMutationMethod.Insertion}>Insertion</option>
|
||||||
|
<option value={GeneticMutationMethod.PartialShuffle}>Partial Shuffle (PSM)</option>
|
||||||
|
<option value={GeneticMutationMethod.ReverseSequence}>Reverse Sequence (RSM)</option>
|
||||||
|
<option value={GeneticMutationMethod.Twors}>Twors</option>
|
||||||
|
<option value={GeneticMutationMethod.Uniform}>Uniform</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -535,6 +649,15 @@ const BacktestGeneticBundle: React.FC = () => {
|
|||||||
<div>
|
<div>
|
||||||
<strong>Timeframe:</strong> {selectedRequest.timeframe}
|
<strong>Timeframe:</strong> {selectedRequest.timeframe}
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong>Selection Method:</strong> {selectedRequest.selectionMethod}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong>Crossover Method:</strong> {selectedRequest.crossoverMethod}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong>Mutation Method:</strong> {selectedRequest.mutationMethod}
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Status:</strong>
|
<strong>Status:</strong>
|
||||||
<span className={`badge ${getStatusBadgeColor(selectedRequest.status)} ml-2`}>
|
<span className={`badge ${getStatusBadgeColor(selectedRequest.status)} ml-2`}>
|
||||||
@@ -549,6 +672,23 @@ const BacktestGeneticBundle: React.FC = () => {
|
|||||||
<strong>Completed:</strong> {new Date(selectedRequest.completedAt).toLocaleString()}
|
<strong>Completed:</strong> {new Date(selectedRequest.completedAt).toLocaleString()}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<div>
|
||||||
|
<strong>Progress:</strong> {selectedRequest.currentGeneration || 0} / {selectedRequest.generations}
|
||||||
|
{selectedRequest.currentGeneration && selectedRequest.generations > 0 && (
|
||||||
|
<div className="mt-1">
|
||||||
|
<progress
|
||||||
|
className="progress progress-primary w-full h-2"
|
||||||
|
value={Math.round(((selectedRequest.currentGeneration || 0) / selectedRequest.generations) * 100)}
|
||||||
|
max="100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{selectedRequest.bestFitnessSoFar && (
|
||||||
|
<div>
|
||||||
|
<strong>Best Fitness:</strong> {selectedRequest.bestFitnessSoFar.toFixed(4)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
|
|||||||
Reference in New Issue
Block a user