Start impl for genetic
This commit is contained in:
@@ -30,6 +30,7 @@ public class BacktestController : BaseController
|
|||||||
private readonly IScenarioService _scenarioService;
|
private readonly IScenarioService _scenarioService;
|
||||||
private readonly IAccountService _accountService;
|
private readonly IAccountService _accountService;
|
||||||
private readonly IMoneyManagementService _moneyManagementService;
|
private readonly IMoneyManagementService _moneyManagementService;
|
||||||
|
private readonly IGeneticService _geneticService;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BacktestController"/> class.
|
/// Initializes a new instance of the <see cref="BacktestController"/> class.
|
||||||
@@ -39,12 +40,14 @@ public class BacktestController : BaseController
|
|||||||
/// <param name="scenarioService">The service for managing scenarios.</param>
|
/// <param name="scenarioService">The service for managing scenarios.</param>
|
||||||
/// <param name="accountService">The service for account management.</param>
|
/// <param name="accountService">The service for account management.</param>
|
||||||
/// <param name="moneyManagementService">The service for money management strategies.</param>
|
/// <param name="moneyManagementService">The service for money management strategies.</param>
|
||||||
|
/// <param name="geneticService">The service for genetic algorithm operations.</param>
|
||||||
public BacktestController(
|
public BacktestController(
|
||||||
IHubContext<BotHub> hubContext,
|
IHubContext<BotHub> hubContext,
|
||||||
IBacktester backtester,
|
IBacktester backtester,
|
||||||
IScenarioService scenarioService,
|
IScenarioService scenarioService,
|
||||||
IAccountService accountService,
|
IAccountService accountService,
|
||||||
IMoneyManagementService moneyManagementService,
|
IMoneyManagementService moneyManagementService,
|
||||||
|
IGeneticService geneticService,
|
||||||
IUserService userService) : base(userService)
|
IUserService userService) : base(userService)
|
||||||
{
|
{
|
||||||
_hubContext = hubContext;
|
_hubContext = hubContext;
|
||||||
@@ -52,6 +55,7 @@ public class BacktestController : BaseController
|
|||||||
_scenarioService = scenarioService;
|
_scenarioService = scenarioService;
|
||||||
_accountService = accountService;
|
_accountService = accountService;
|
||||||
_moneyManagementService = moneyManagementService;
|
_moneyManagementService = moneyManagementService;
|
||||||
|
_geneticService = geneticService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -266,8 +270,8 @@ public class BacktestController : BaseController
|
|||||||
{
|
{
|
||||||
var user = await GetUser();
|
var user = await GetUser();
|
||||||
|
|
||||||
// Create genetic request using the Backtester service
|
// Create genetic request using the GeneticService directly
|
||||||
var geneticRequest = _backtester.CreateGeneticRequest(
|
var geneticRequest = _geneticService.CreateGeneticRequest(
|
||||||
user,
|
user,
|
||||||
request.Ticker,
|
request.Ticker,
|
||||||
request.Timeframe,
|
request.Timeframe,
|
||||||
@@ -302,7 +306,7 @@ public class BacktestController : BaseController
|
|||||||
public async Task<ActionResult<IEnumerable<GeneticRequest>>> GetGeneticRequests()
|
public async Task<ActionResult<IEnumerable<GeneticRequest>>> GetGeneticRequests()
|
||||||
{
|
{
|
||||||
var user = await GetUser();
|
var user = await GetUser();
|
||||||
var geneticRequests = _backtester.GetGeneticRequestsByUser(user);
|
var geneticRequests = _geneticService.GetGeneticRequestsByUser(user);
|
||||||
return Ok(geneticRequests);
|
return Ok(geneticRequests);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,7 +320,7 @@ public class BacktestController : BaseController
|
|||||||
public async Task<ActionResult<GeneticRequest>> GetGeneticRequest(string id)
|
public async Task<ActionResult<GeneticRequest>> GetGeneticRequest(string id)
|
||||||
{
|
{
|
||||||
var user = await GetUser();
|
var user = await GetUser();
|
||||||
var geneticRequest = _backtester.GetGeneticRequestByIdForUser(user, id);
|
var geneticRequest = _geneticService.GetGeneticRequestByIdForUser(user, id);
|
||||||
|
|
||||||
if (geneticRequest == null)
|
if (geneticRequest == null)
|
||||||
{
|
{
|
||||||
@@ -336,7 +340,7 @@ public class BacktestController : BaseController
|
|||||||
public async Task<ActionResult> DeleteGeneticRequest(string id)
|
public async Task<ActionResult> DeleteGeneticRequest(string id)
|
||||||
{
|
{
|
||||||
var user = await GetUser();
|
var user = await GetUser();
|
||||||
_backtester.DeleteGeneticRequestByIdForUser(user, id);
|
_geneticService.DeleteGeneticRequestByIdForUser(user, id);
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using Managing.Domain.Bots;
|
using Managing.Domain.Bots;
|
||||||
using Managing.Domain.Candles;
|
using Managing.Domain.Candles;
|
||||||
using Managing.Domain.Users;
|
using Managing.Domain.Users;
|
||||||
using static Managing.Common.Enums;
|
|
||||||
|
|
||||||
namespace Managing.Application.Abstractions.Services
|
namespace Managing.Application.Abstractions.Services
|
||||||
{
|
{
|
||||||
@@ -50,25 +49,6 @@ namespace Managing.Application.Abstractions.Services
|
|||||||
bool DeleteBacktestByUser(User user, string id);
|
bool DeleteBacktestByUser(User user, string id);
|
||||||
bool DeleteBacktestsByUser(User user);
|
bool DeleteBacktestsByUser(User user);
|
||||||
|
|
||||||
// Genetic algorithm request methods
|
|
||||||
GeneticRequest CreateGeneticRequest(
|
|
||||||
User user,
|
|
||||||
Ticker ticker,
|
|
||||||
Timeframe timeframe,
|
|
||||||
DateTime startDate,
|
|
||||||
DateTime endDate,
|
|
||||||
decimal balance,
|
|
||||||
int populationSize,
|
|
||||||
int generations,
|
|
||||||
double mutationRate,
|
|
||||||
string selectionMethod,
|
|
||||||
int elitismPercentage,
|
|
||||||
double maxTakeProfit,
|
|
||||||
List<IndicatorType> eligibleIndicators);
|
|
||||||
|
|
||||||
IEnumerable<GeneticRequest> GetGeneticRequestsByUser(User user);
|
|
||||||
GeneticRequest GetGeneticRequestByIdForUser(User user, string id);
|
|
||||||
void UpdateGeneticRequest(GeneticRequest geneticRequest);
|
|
||||||
void DeleteGeneticRequestByIdForUser(User user, string id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,4 +74,11 @@ public interface IGeneticService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Collection of pending genetic requests</returns>
|
/// <returns>Collection of pending genetic requests</returns>
|
||||||
IEnumerable<GeneticRequest> GetPendingGeneticRequests();
|
IEnumerable<GeneticRequest> GetPendingGeneticRequests();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runs the genetic algorithm for a specific request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">The genetic request to process</param>
|
||||||
|
/// <returns>The genetic algorithm result</returns>
|
||||||
|
Task<GeneticAlgorithmResult> RunGeneticAlgorithm(GeneticRequest request);
|
||||||
}
|
}
|
||||||
@@ -69,8 +69,8 @@ public class GeneticAlgorithmWorker : BaseWorker<GeneticAlgorithmWorker>
|
|||||||
request.Status = GeneticRequestStatus.Running;
|
request.Status = GeneticRequestStatus.Running;
|
||||||
_geneticService.UpdateGeneticRequest(request);
|
_geneticService.UpdateGeneticRequest(request);
|
||||||
|
|
||||||
// Run genetic algorithm
|
// Run genetic algorithm using the service
|
||||||
var results = await RunGeneticAlgorithm(request, cancellationToken);
|
var results = await _geneticService.RunGeneticAlgorithm(request);
|
||||||
|
|
||||||
// Update request with results
|
// Update request with results
|
||||||
request.Status = GeneticRequestStatus.Completed;
|
request.Status = GeneticRequestStatus.Completed;
|
||||||
@@ -101,31 +101,5 @@ public class GeneticAlgorithmWorker : BaseWorker<GeneticAlgorithmWorker>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<GeneticAlgorithmResult> RunGeneticAlgorithm(GeneticRequest request, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
// TODO: Implement the actual genetic algorithm
|
|
||||||
// This is where the genetic algorithm logic will be implemented
|
|
||||||
|
|
||||||
_logger.LogInformation("[GeneticAlgorithm] Placeholder: Would run genetic algorithm for request {RequestId}", request.RequestId);
|
|
||||||
|
|
||||||
// Simulate some processing time
|
|
||||||
await Task.Delay(1000, cancellationToken);
|
|
||||||
|
|
||||||
return new GeneticAlgorithmResult
|
|
||||||
{
|
|
||||||
BestFitness = 0.85,
|
|
||||||
BestIndividual = "placeholder_individual",
|
|
||||||
ProgressInfo = "{\"generation\": 10, \"best_fitness\": 0.85}"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Result of a genetic algorithm run
|
|
||||||
/// </summary>
|
|
||||||
public class GeneticAlgorithmResult
|
|
||||||
{
|
|
||||||
public double BestFitness { get; set; }
|
|
||||||
public string BestIndividual { get; set; } = string.Empty;
|
|
||||||
public string ProgressInfo { get; set; } = string.Empty;
|
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,6 @@ namespace Managing.Application.Backtesting
|
|||||||
private readonly IScenarioService _scenarioService;
|
private readonly IScenarioService _scenarioService;
|
||||||
private readonly IAccountService _accountService;
|
private readonly IAccountService _accountService;
|
||||||
private readonly IMessengerService _messengerService;
|
private readonly IMessengerService _messengerService;
|
||||||
private readonly IGeneticService _geneticService;
|
|
||||||
|
|
||||||
public Backtester(
|
public Backtester(
|
||||||
IExchangeService exchangeService,
|
IExchangeService exchangeService,
|
||||||
@@ -36,8 +35,7 @@ namespace Managing.Application.Backtesting
|
|||||||
ILogger<Backtester> logger,
|
ILogger<Backtester> logger,
|
||||||
IScenarioService scenarioService,
|
IScenarioService scenarioService,
|
||||||
IAccountService accountService,
|
IAccountService accountService,
|
||||||
IMessengerService messengerService,
|
IMessengerService messengerService)
|
||||||
IGeneticService geneticService)
|
|
||||||
{
|
{
|
||||||
_exchangeService = exchangeService;
|
_exchangeService = exchangeService;
|
||||||
_botFactory = botFactory;
|
_botFactory = botFactory;
|
||||||
@@ -46,7 +44,6 @@ namespace Managing.Application.Backtesting
|
|||||||
_scenarioService = scenarioService;
|
_scenarioService = scenarioService;
|
||||||
_accountService = accountService;
|
_accountService = accountService;
|
||||||
_messengerService = messengerService;
|
_messengerService = messengerService;
|
||||||
_geneticService = geneticService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Backtest RunSimpleBotBacktest(Workflow workflow, bool save = false)
|
public Backtest RunSimpleBotBacktest(Workflow workflow, bool save = false)
|
||||||
@@ -460,82 +457,6 @@ namespace Managing.Application.Backtesting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new genetic algorithm request
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="user">The user creating the request</param>
|
|
||||||
/// <param name="ticker">The ticker to optimize for</param>
|
|
||||||
/// <param name="timeframe">The timeframe to use</param>
|
|
||||||
/// <param name="startDate">The start date for the backtest period</param>
|
|
||||||
/// <param name="endDate">The end date for the backtest period</param>
|
|
||||||
/// <param name="balance">The starting balance</param>
|
|
||||||
/// <param name="populationSize">The population size for the genetic algorithm</param>
|
|
||||||
/// <param name="generations">The number of generations to evolve</param>
|
|
||||||
/// <param name="mutationRate">The mutation rate (0.0 - 1.0)</param>
|
|
||||||
/// <param name="selectionMethod">The selection method to use</param>
|
|
||||||
/// <param name="elitismPercentage">The percentage of elite individuals to preserve</param>
|
|
||||||
/// <param name="maxTakeProfit">The maximum take profit percentage</param>
|
|
||||||
/// <param name="eligibleIndicators">The list of eligible indicators</param>
|
|
||||||
/// <returns>The created genetic request</returns>
|
|
||||||
public GeneticRequest CreateGeneticRequest(
|
|
||||||
User user,
|
|
||||||
Ticker ticker,
|
|
||||||
Timeframe timeframe,
|
|
||||||
DateTime startDate,
|
|
||||||
DateTime endDate,
|
|
||||||
decimal balance,
|
|
||||||
int populationSize,
|
|
||||||
int generations,
|
|
||||||
double mutationRate,
|
|
||||||
string selectionMethod,
|
|
||||||
int elitismPercentage,
|
|
||||||
double maxTakeProfit,
|
|
||||||
List<IndicatorType> eligibleIndicators)
|
|
||||||
{
|
|
||||||
return _geneticService.CreateGeneticRequest(
|
|
||||||
user, ticker, timeframe, startDate, endDate, balance,
|
|
||||||
populationSize, generations, mutationRate, selectionMethod,
|
|
||||||
elitismPercentage, maxTakeProfit, eligibleIndicators);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets all genetic requests for a user
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="user">The user to get requests for</param>
|
|
||||||
/// <returns>Collection of genetic requests</returns>
|
|
||||||
public IEnumerable<GeneticRequest> GetGeneticRequestsByUser(User user)
|
|
||||||
{
|
|
||||||
return _geneticService.GetGeneticRequestsByUser(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a specific genetic request by ID for a user
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="user">The user</param>
|
|
||||||
/// <param name="id">The request ID</param>
|
|
||||||
/// <returns>The genetic request or null if not found</returns>
|
|
||||||
public GeneticRequest GetGeneticRequestByIdForUser(User user, string id)
|
|
||||||
{
|
|
||||||
return _geneticService.GetGeneticRequestByIdForUser(user, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates a genetic request
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="geneticRequest">The genetic request to update</param>
|
|
||||||
public void UpdateGeneticRequest(GeneticRequest geneticRequest)
|
|
||||||
{
|
|
||||||
_geneticService.UpdateGeneticRequest(geneticRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deletes a genetic request by ID for a user
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="user">The user</param>
|
|
||||||
/// <param name="id">The request ID</param>
|
|
||||||
public void DeleteGeneticRequestByIdForUser(User user, string id)
|
|
||||||
{
|
|
||||||
_geneticService.DeleteGeneticRequestByIdForUser(user, id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,13 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using GeneticSharp;
|
||||||
using Managing.Application.Abstractions.Repositories;
|
using Managing.Application.Abstractions.Repositories;
|
||||||
using Managing.Application.Abstractions.Services;
|
using Managing.Application.Abstractions.Services;
|
||||||
using Managing.Domain.Backtests;
|
using Managing.Domain.Backtests;
|
||||||
|
using Managing.Domain.Bots;
|
||||||
|
using Managing.Domain.MoneyManagements;
|
||||||
|
using Managing.Domain.Risk;
|
||||||
using Managing.Domain.Users;
|
using Managing.Domain.Users;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
|
|
||||||
namespace Managing.Application;
|
namespace Managing.Application;
|
||||||
@@ -12,10 +18,17 @@ namespace Managing.Application;
|
|||||||
public class GeneticService : IGeneticService
|
public class GeneticService : IGeneticService
|
||||||
{
|
{
|
||||||
private readonly IGeneticRepository _geneticRepository;
|
private readonly IGeneticRepository _geneticRepository;
|
||||||
|
private readonly IBacktester _backtester;
|
||||||
|
private readonly ILogger<GeneticService> _logger;
|
||||||
|
|
||||||
public GeneticService(IGeneticRepository geneticRepository)
|
public GeneticService(
|
||||||
|
IGeneticRepository geneticRepository,
|
||||||
|
IBacktester backtester,
|
||||||
|
ILogger<GeneticService> logger)
|
||||||
{
|
{
|
||||||
_geneticRepository = geneticRepository;
|
_geneticRepository = geneticRepository;
|
||||||
|
_backtester = backtester;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GeneticRequest CreateGeneticRequest(
|
public GeneticRequest CreateGeneticRequest(
|
||||||
@@ -79,4 +92,245 @@ public class GeneticService : IGeneticService
|
|||||||
{
|
{
|
||||||
return _geneticRepository.GetPendingGeneticRequests();
|
return _geneticRepository.GetPendingGeneticRequests();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runs the genetic algorithm for a specific request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">The genetic request to process</param>
|
||||||
|
/// <returns>The genetic algorithm result</returns>
|
||||||
|
public async Task<GeneticAlgorithmResult> RunGeneticAlgorithm(GeneticRequest request)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Starting genetic algorithm for request {RequestId}", request.RequestId);
|
||||||
|
|
||||||
|
// Create chromosome for trading bot configuration
|
||||||
|
var chromosome = new TradingBotChromosome(request.EligibleIndicators);
|
||||||
|
|
||||||
|
// Create fitness function
|
||||||
|
var fitness = new TradingBotFitness(_backtester, request);
|
||||||
|
|
||||||
|
// Create genetic algorithm
|
||||||
|
var ga = new GeneticAlgorithm(
|
||||||
|
new Population(request.PopulationSize, request.PopulationSize, chromosome),
|
||||||
|
fitness,
|
||||||
|
GetSelection(request.SelectionMethod),
|
||||||
|
new UniformCrossover(),
|
||||||
|
GetMutation(request.MutationRate))
|
||||||
|
{
|
||||||
|
Termination = new GenerationNumberTermination(request.Generations)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run the genetic algorithm
|
||||||
|
ga.Start();
|
||||||
|
|
||||||
|
// Get the best chromosome
|
||||||
|
var bestChromosome = ga.BestChromosome as TradingBotChromosome;
|
||||||
|
var bestFitness = ga.BestChromosome.Fitness.Value;
|
||||||
|
|
||||||
|
_logger.LogInformation("Genetic algorithm completed for request {RequestId}. Best fitness: {Fitness}",
|
||||||
|
request.RequestId, bestFitness);
|
||||||
|
|
||||||
|
return new GeneticAlgorithmResult
|
||||||
|
{
|
||||||
|
BestFitness = bestFitness,
|
||||||
|
BestIndividual = bestChromosome?.ToString() ?? "unknown",
|
||||||
|
ProgressInfo = JsonSerializer.Serialize(new
|
||||||
|
{
|
||||||
|
generation = ga.GenerationsNumber,
|
||||||
|
best_fitness = bestFitness,
|
||||||
|
population_size = request.PopulationSize,
|
||||||
|
generations = request.Generations
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error running genetic algorithm for request {RequestId}", request.RequestId);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ISelection GetSelection(string selectionMethod)
|
||||||
|
{
|
||||||
|
return selectionMethod.ToLower() switch
|
||||||
|
{
|
||||||
|
"tournament" => new TournamentSelection(),
|
||||||
|
"roulette" => new RouletteWheelSelection(),
|
||||||
|
"rank" => new RankSelection(),
|
||||||
|
_ => new TournamentSelection()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private IMutation GetMutation(double mutationRate)
|
||||||
|
{
|
||||||
|
return new UniformMutation(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Chromosome representing a trading bot configuration
|
||||||
|
/// </summary>
|
||||||
|
public class TradingBotChromosome : ChromosomeBase
|
||||||
|
{
|
||||||
|
private readonly List<IndicatorType> _eligibleIndicators;
|
||||||
|
private readonly Random _random = new Random();
|
||||||
|
|
||||||
|
public TradingBotChromosome(List<IndicatorType> eligibleIndicators) : base(eligibleIndicators.Count + 5)
|
||||||
|
{
|
||||||
|
_eligibleIndicators = eligibleIndicators;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Gene GenerateGene(int geneIndex)
|
||||||
|
{
|
||||||
|
if (geneIndex < _eligibleIndicators.Count)
|
||||||
|
{
|
||||||
|
// Gene represents whether an indicator is selected (0 or 1)
|
||||||
|
return new Gene(_random.Next(2));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Additional genes for other parameters
|
||||||
|
return geneIndex switch
|
||||||
|
{
|
||||||
|
var i when i == _eligibleIndicators.Count => new Gene(_random.Next(1, 11)), // Stop loss percentage
|
||||||
|
var i when i == _eligibleIndicators.Count + 1 => new Gene(_random.Next(1, 21)), // Take profit percentage
|
||||||
|
var i when i == _eligibleIndicators.Count + 2 => new Gene(_random.Next(1, 101)), // Position size percentage
|
||||||
|
var i when i == _eligibleIndicators.Count + 3 => new Gene(_random.Next(1, 51)), // Max positions
|
||||||
|
var i when i == _eligibleIndicators.Count + 4 => new Gene(_random.Next(1, 11)), // Risk level
|
||||||
|
_ => new Gene(0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IChromosome CreateNew()
|
||||||
|
{
|
||||||
|
return new TradingBotChromosome(_eligibleIndicators);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IChromosome Clone()
|
||||||
|
{
|
||||||
|
var clone = new TradingBotChromosome(_eligibleIndicators);
|
||||||
|
clone.ReplaceGenes(0, GetGenes());
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IndicatorType> GetSelectedIndicators()
|
||||||
|
{
|
||||||
|
var selected = new List<IndicatorType>();
|
||||||
|
for (int i = 0; i < _eligibleIndicators.Count; i++)
|
||||||
|
{
|
||||||
|
if (GetGene(i).Value.ToString() == "1")
|
||||||
|
{
|
||||||
|
selected.Add(_eligibleIndicators[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TradingBotConfig GetTradingBotConfig(GeneticRequest request)
|
||||||
|
{
|
||||||
|
var selectedIndicators = GetSelectedIndicators();
|
||||||
|
var genes = GetGenes();
|
||||||
|
|
||||||
|
return new TradingBotConfig
|
||||||
|
{
|
||||||
|
Name = $"Genetic_{request.RequestId}",
|
||||||
|
AccountName = "genetic_account",
|
||||||
|
Ticker = request.Ticker,
|
||||||
|
Timeframe = request.Timeframe,
|
||||||
|
BotTradingBalance = request.Balance,
|
||||||
|
IsForBacktest = true,
|
||||||
|
IsForWatchingOnly = false,
|
||||||
|
CooldownPeriod = 0,
|
||||||
|
MaxLossStreak = 3,
|
||||||
|
FlipPosition = false,
|
||||||
|
FlipOnlyWhenInProfit = true,
|
||||||
|
MoneyManagement = new MoneyManagement
|
||||||
|
{
|
||||||
|
Name = $"Genetic_{request.RequestId}_MM",
|
||||||
|
Timeframe = request.Timeframe,
|
||||||
|
StopLoss = Convert.ToDecimal(genes[_eligibleIndicators.Count].Value),
|
||||||
|
TakeProfit = Convert.ToDecimal(genes[_eligibleIndicators.Count + 1].Value),
|
||||||
|
Leverage = 1.0m
|
||||||
|
},
|
||||||
|
RiskManagement = new RiskManagement
|
||||||
|
{
|
||||||
|
RiskTolerance = (RiskToleranceLevel)Convert.ToInt32(genes[_eligibleIndicators.Count + 4].Value)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fitness function for trading bot optimization
|
||||||
|
/// </summary>
|
||||||
|
public class TradingBotFitness : IFitness
|
||||||
|
{
|
||||||
|
private readonly IBacktester _backtester;
|
||||||
|
private readonly GeneticRequest _request;
|
||||||
|
|
||||||
|
public TradingBotFitness(IBacktester backtester, GeneticRequest request)
|
||||||
|
{
|
||||||
|
_backtester = backtester;
|
||||||
|
_request = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Evaluate(IChromosome chromosome)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var tradingBotChromosome = chromosome as TradingBotChromosome;
|
||||||
|
if (tradingBotChromosome == null)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var config = tradingBotChromosome.GetTradingBotConfig(_request);
|
||||||
|
|
||||||
|
// Run backtest
|
||||||
|
var backtest = _backtester.RunTradingBotBacktest(
|
||||||
|
config,
|
||||||
|
_request.StartDate,
|
||||||
|
_request.EndDate,
|
||||||
|
_request.User,
|
||||||
|
false, // Don't save individual backtests
|
||||||
|
false // Don't include candles
|
||||||
|
).Result;
|
||||||
|
|
||||||
|
// Calculate fitness based on backtest results
|
||||||
|
var fitness = CalculateFitness(backtest);
|
||||||
|
|
||||||
|
return fitness;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// Return low fitness for failed backtests
|
||||||
|
return 0.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double CalculateFitness(Backtest backtest)
|
||||||
|
{
|
||||||
|
if (backtest == null || backtest.Score == null)
|
||||||
|
return 0.1;
|
||||||
|
|
||||||
|
// Use the backtest score as the primary fitness metric
|
||||||
|
var baseFitness = backtest.Score;
|
||||||
|
|
||||||
|
// Apply additional factors
|
||||||
|
var tradeCount = backtest.Positions?.Count ?? 0;
|
||||||
|
var winRate = backtest.WinRate;
|
||||||
|
var finalPnl = backtest.FinalPnl;
|
||||||
|
|
||||||
|
// Penalize if no trades were made
|
||||||
|
if (tradeCount == 0)
|
||||||
|
return 0.1;
|
||||||
|
|
||||||
|
// Bonus for good win rate
|
||||||
|
var winRateBonus = winRate > 0.6 ? 10 : 0;
|
||||||
|
|
||||||
|
// Bonus for positive PnL
|
||||||
|
var pnlBonus = finalPnl > 0 ? 20 : 0;
|
||||||
|
|
||||||
|
return baseFitness + winRateBonus + pnlBonus;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentValidation" Version="11.9.1" />
|
<PackageReference Include="FluentValidation" Version="11.9.1" />
|
||||||
|
<PackageReference Include="GeneticSharp" Version="3.1.4" />
|
||||||
<PackageReference Include="MediatR" Version="12.2.0" />
|
<PackageReference Include="MediatR" Version="12.2.0" />
|
||||||
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="11.1.0" />
|
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="11.1.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.1.0" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.1.0" />
|
||||||
|
|||||||
27
src/Managing.Domain/Backtests/GeneticAlgorithmResult.cs
Normal file
27
src/Managing.Domain/Backtests/GeneticAlgorithmResult.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
namespace Managing.Domain.Backtests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the result of a genetic algorithm run
|
||||||
|
/// </summary>
|
||||||
|
public class GeneticAlgorithmResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The best fitness score achieved
|
||||||
|
/// </summary>
|
||||||
|
public double BestFitness { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The best individual (chromosome) found
|
||||||
|
/// </summary>
|
||||||
|
public string BestIndividual { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Progress information as JSON string
|
||||||
|
/// </summary>
|
||||||
|
public string ProgressInfo { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When the algorithm completed
|
||||||
|
/// </summary>
|
||||||
|
public DateTime CompletedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user