Postgres (#30)
* Add postgres * Migrate users * Migrate geneticRequest * Try to fix Concurrent call * Fix asyncawait * Fix async and concurrent * Migrate backtests * Add cache for user by address * Fix backtest migration * Fix not open connection * Fix backtest command error * Fix concurrent * Fix all concurrency * Migrate TradingRepo * Fix scenarios * Migrate statistic repo * Save botbackup * Add settings et moneymanagement * Add bot postgres * fix a bit more backups * Fix bot model * Fix loading backup * Remove cache market for read positions * Add workers to postgre * Fix workers api * Reduce get Accounts for workers * Migrate synth to postgre * Fix backtest saved * Remove mongodb * botservice decorrelation * Fix tradingbot scope call * fix tradingbot * fix concurrent * Fix scope for genetics * Fix account over requesting * Fix bundle backtest worker * fix a lot of things * fix tab backtest * Remove optimized moneymanagement * Add light signal to not use User and too much property * Make money management lighter * insert indicators to awaitable * Migrate add strategies to await * Refactor scenario and indicator retrieval to use asynchronous methods throughout the application * add more async await * Add services * Fix and clean * Fix bot a bit * Fix bot and add message for cooldown * Remove fees * Add script to deploy db * Update dfeeploy script * fix script * Add idempotent script and backup * finish script migration * Fix did user and agent name on start bot
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
using System.Text.Json;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Application.Workers.Abstractions;
|
||||
using Managing.Domain.Backtests;
|
||||
using Managing.Domain.Bots;
|
||||
using Managing.Domain.MoneyManagements;
|
||||
using Managing.Domain.Scenarios;
|
||||
using Managing.Domain.Strategies;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
@@ -16,22 +16,20 @@ namespace Managing.Application.Workers;
|
||||
/// </summary>
|
||||
public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
||||
{
|
||||
// Removed direct repository usage for bundle requests
|
||||
private readonly IBacktester _backtester;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IMessengerService _messengerService;
|
||||
private static readonly WorkerType _workerType = WorkerType.BundleBacktest;
|
||||
|
||||
public BundleBacktestWorker(
|
||||
IBacktester backtester,
|
||||
IServiceProvider serviceProvider,
|
||||
IMessengerService messengerService,
|
||||
ILogger<BundleBacktestWorker> logger,
|
||||
IWorkerService workerService) : base(
|
||||
ILogger<BundleBacktestWorker> logger) : base(
|
||||
_workerType,
|
||||
logger,
|
||||
TimeSpan.FromMinutes(1),
|
||||
workerService)
|
||||
serviceProvider)
|
||||
{
|
||||
_backtester = backtester;
|
||||
_serviceProvider = serviceProvider;
|
||||
_messengerService = messengerService;
|
||||
}
|
||||
|
||||
@@ -42,8 +40,13 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
||||
var processingTasks = new List<Task>();
|
||||
try
|
||||
{
|
||||
// Create a new service scope to get fresh instances of services with scoped DbContext
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var backtester = scope.ServiceProvider.GetRequiredService<IBacktester>();
|
||||
|
||||
// Get pending bundle backtest requests
|
||||
var pendingRequests = _backtester.GetBundleBacktestRequestsByStatus(BundleBacktestRequestStatus.Pending);
|
||||
var pendingRequests =
|
||||
await backtester.GetBundleBacktestRequestsByStatusAsync(BundleBacktestRequestStatus.Pending);
|
||||
|
||||
foreach (var bundleRequest in pendingRequests)
|
||||
{
|
||||
@@ -64,9 +67,10 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
||||
}, cancellationToken);
|
||||
processingTasks.Add(task);
|
||||
}
|
||||
|
||||
await Task.WhenAll(processingTasks);
|
||||
|
||||
await RetryUnfinishedBacktestsInFailedBundles(cancellationToken);
|
||||
await RetryUnfinishedBacktestsInFailedBundles(backtester, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -77,13 +81,17 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
||||
|
||||
private async Task ProcessBundleRequest(BundleBacktestRequest bundleRequest, CancellationToken cancellationToken)
|
||||
{
|
||||
// Create a new service scope for this task to avoid DbContext concurrency issues
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var backtester = scope.ServiceProvider.GetRequiredService<IBacktester>();
|
||||
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Starting to process bundle backtest request {RequestId}", bundleRequest.RequestId);
|
||||
|
||||
// Update status to running
|
||||
bundleRequest.Status = BundleBacktestRequestStatus.Running;
|
||||
_backtester.UpdateBundleBacktestRequest(bundleRequest);
|
||||
await backtester.UpdateBundleBacktestRequestAsync(bundleRequest);
|
||||
|
||||
// Deserialize the backtest requests as strongly-typed objects
|
||||
var backtestRequests =
|
||||
@@ -105,10 +113,11 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
||||
var runBacktestRequest = backtestRequests[i];
|
||||
// Update current backtest being processed
|
||||
bundleRequest.CurrentBacktest = $"Backtest {i + 1} of {backtestRequests.Count}";
|
||||
_backtester.UpdateBundleBacktestRequest(bundleRequest);
|
||||
await backtester.UpdateBundleBacktestRequestAsync(bundleRequest);
|
||||
|
||||
// Run the backtest directly with the strongly-typed request
|
||||
var backtestId = await RunSingleBacktest(runBacktestRequest, bundleRequest, i, cancellationToken);
|
||||
var backtestId = await RunSingleBacktest(backtester, runBacktestRequest, bundleRequest, i,
|
||||
cancellationToken);
|
||||
if (!string.IsNullOrEmpty(backtestId))
|
||||
{
|
||||
bundleRequest.Results.Add(backtestId);
|
||||
@@ -116,7 +125,7 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
||||
|
||||
// Update progress
|
||||
bundleRequest.CompletedBacktests++;
|
||||
_backtester.UpdateBundleBacktestRequest(bundleRequest);
|
||||
await backtester.UpdateBundleBacktestRequestAsync(bundleRequest);
|
||||
|
||||
_logger.LogInformation("Completed backtest {Index} for bundle request {RequestId}",
|
||||
i + 1, bundleRequest.RequestId);
|
||||
@@ -126,20 +135,16 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
||||
_logger.LogError(ex, "Error processing backtest {Index} for bundle request {RequestId}",
|
||||
i + 1, bundleRequest.RequestId);
|
||||
bundleRequest.FailedBacktests++;
|
||||
_backtester.UpdateBundleBacktestRequest(bundleRequest);
|
||||
await backtester.UpdateBundleBacktestRequestAsync(bundleRequest);
|
||||
}
|
||||
}
|
||||
|
||||
// Update final status
|
||||
// Update final status and send notifications
|
||||
if (bundleRequest.FailedBacktests == 0)
|
||||
{
|
||||
bundleRequest.Status = BundleBacktestRequestStatus.Completed;
|
||||
// Send Telegram message to the user's channelId
|
||||
if (bundleRequest.User?.TelegramChannel != null)
|
||||
{
|
||||
var message = $"✅ Bundle backtest '{bundleRequest.Name}' (ID: {bundleRequest.RequestId}) is completed.";
|
||||
await _messengerService.SendMessage(message, bundleRequest.User.TelegramChannel);
|
||||
}
|
||||
await NotifyUser(bundleRequest);
|
||||
}
|
||||
else if (bundleRequest.CompletedBacktests == 0)
|
||||
{
|
||||
@@ -150,11 +155,13 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
||||
{
|
||||
bundleRequest.Status = BundleBacktestRequestStatus.Completed;
|
||||
bundleRequest.ErrorMessage = $"{bundleRequest.FailedBacktests} backtests failed";
|
||||
// Send Telegram message to the user's channelId even with partial failures
|
||||
await NotifyUser(bundleRequest);
|
||||
}
|
||||
|
||||
bundleRequest.CompletedAt = DateTime.UtcNow;
|
||||
bundleRequest.CurrentBacktest = null;
|
||||
_backtester.UpdateBundleBacktestRequest(bundleRequest);
|
||||
await backtester.UpdateBundleBacktestRequestAsync(bundleRequest);
|
||||
|
||||
_logger.LogInformation("Completed processing bundle backtest request {RequestId} with status {Status}",
|
||||
bundleRequest.RequestId, bundleRequest.Status);
|
||||
@@ -166,12 +173,22 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
||||
bundleRequest.Status = BundleBacktestRequestStatus.Failed;
|
||||
bundleRequest.ErrorMessage = ex.Message;
|
||||
bundleRequest.CompletedAt = DateTime.UtcNow;
|
||||
_backtester.UpdateBundleBacktestRequest(bundleRequest);
|
||||
await backtester.UpdateBundleBacktestRequestAsync(bundleRequest);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task NotifyUser(BundleBacktestRequest bundleRequest)
|
||||
{
|
||||
if (bundleRequest.User?.TelegramChannel != null)
|
||||
{
|
||||
var message =
|
||||
$"⚠️ Bundle backtest '{bundleRequest.Name}' (ID: {bundleRequest.RequestId}) completed with {bundleRequest.FailedBacktests} failed backtests.";
|
||||
await _messengerService.SendMessage(message, bundleRequest.User.TelegramChannel);
|
||||
}
|
||||
}
|
||||
|
||||
// Change RunSingleBacktest to accept RunBacktestRequest directly
|
||||
private async Task<string> RunSingleBacktest(RunBacktestRequest runBacktestRequest,
|
||||
private async Task<string> RunSingleBacktest(IBacktester backtester, RunBacktestRequest runBacktestRequest,
|
||||
BundleBacktestRequest bundleRequest,
|
||||
int index, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -259,7 +276,7 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
||||
};
|
||||
|
||||
// Run the backtest (no user context)
|
||||
var result = await _backtester.RunTradingBotBacktest(
|
||||
var result = await backtester.RunTradingBotBacktest(
|
||||
backtestConfig,
|
||||
runBacktestRequest.StartDate,
|
||||
runBacktestRequest.EndDate,
|
||||
@@ -275,9 +292,10 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
||||
return result.Id;
|
||||
}
|
||||
|
||||
private async Task RetryUnfinishedBacktestsInFailedBundles(CancellationToken cancellationToken)
|
||||
private async Task RetryUnfinishedBacktestsInFailedBundles(IBacktester backtester,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var failedBundles = _backtester.GetBundleBacktestRequestsByStatus(BundleBacktestRequestStatus.Failed);
|
||||
var failedBundles = await backtester.GetBundleBacktestRequestsByStatusAsync(BundleBacktestRequestStatus.Failed);
|
||||
foreach (var failedBundle in failedBundles)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
@@ -292,20 +310,39 @@ public class BundleBacktestWorker : BaseWorker<BundleBacktestWorker>
|
||||
.Deserialize<List<RunBacktestRequest>>(failedBundle.BacktestRequestsJson);
|
||||
if (originalRequests == null) continue;
|
||||
|
||||
for (int i = 0; i < originalRequests.Count; i++)
|
||||
for (int i = failedBundle.CompletedBacktests; i < originalRequests.Count; i++)
|
||||
{
|
||||
var expectedId = /* logic to compute expected backtest id for this request */ string.Empty;
|
||||
// If this backtest was not run or did not succeed, re-run it
|
||||
if (!succeededIds.Contains(expectedId))
|
||||
{
|
||||
var backtestId = await RunSingleBacktest(originalRequests[i], failedBundle, i, cancellationToken);
|
||||
var backtestId = await RunSingleBacktest(backtester, originalRequests[i], failedBundle, i,
|
||||
cancellationToken);
|
||||
if (!string.IsNullOrEmpty(backtestId))
|
||||
{
|
||||
failedBundle.Results?.Add(backtestId);
|
||||
_backtester.UpdateBundleBacktestRequest(failedBundle);
|
||||
failedBundle.CompletedBacktests++;
|
||||
await backtester.UpdateBundleBacktestRequestAsync(failedBundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If all backtests succeeded, update the bundle status
|
||||
if (failedBundle.CompletedBacktests == originalRequests.Count)
|
||||
{
|
||||
failedBundle.Status = BundleBacktestRequestStatus.Completed;
|
||||
failedBundle.ErrorMessage = null; // Clear any previous error
|
||||
failedBundle.CompletedAt = DateTime.UtcNow;
|
||||
await backtester.UpdateBundleBacktestRequestAsync(failedBundle);
|
||||
|
||||
// Notify user about successful retry
|
||||
await NotifyUser(failedBundle);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Bundle {RequestId} still has unfinished backtests after retry",
|
||||
failedBundle.RequestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user