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:
Oda
2025-07-27 15:42:17 +02:00
committed by GitHub
parent 361bfbf6e8
commit 422fecea7b
294 changed files with 23953 additions and 7272 deletions

View File

@@ -121,6 +121,12 @@ namespace Managing.Application.Backtesting
result.StartDate = startDate;
result.EndDate = endDate;
// Ensure RequestId is set - required for PostgreSQL NOT NULL constraint
if (string.IsNullOrEmpty(result.RequestId))
{
result.RequestId = Guid.NewGuid().ToString();
}
if (save && user != null)
{
_backtestRepository.InsertBacktestForUser(user, result);
@@ -138,8 +144,9 @@ namespace Managing.Application.Backtesting
var refundSuccess = await _kaigenService.RefundUserCreditsAsync(creditRequestId, user);
if (refundSuccess)
{
_logger.LogInformation(
"Successfully refunded credits for user {UserName} after backtest failure", user.Name);
_logger.LogError(
"Successfully refunded credits for user {UserName} after backtest failure: {message}",
user.Name, ex.Message);
}
else
{
@@ -188,7 +195,7 @@ namespace Managing.Application.Backtesting
string requestId = null,
object metadata = null)
{
var tradingBot = _botFactory.CreateBacktestTradingBot(config);
var tradingBot = await _botFactory.CreateBacktestTradingBot(config);
// Scenario and indicators should already be loaded in constructor by BotService
// This is just a validation check to ensure everything loaded properly
@@ -215,26 +222,7 @@ namespace Managing.Application.Backtesting
private async Task<Account> GetAccountFromConfig(TradingBotConfig config)
{
var accounts = _accountService.GetAccounts(false, false).ToArray();
var account = accounts.FirstOrDefault(a =>
a.Name.Equals(config.AccountName, StringComparison.OrdinalIgnoreCase) &&
a.Exchange == TradingExchanges.GmxV2);
if (account == null && accounts.Any())
{
account = accounts.First();
}
if (account != null)
{
return account;
}
return new Account
{
Name = config.AccountName,
Exchange = TradingExchanges.GmxV2
};
return await _accountService.GetAccountByAccountName(config.AccountName, false, false);
}
private List<Candle> GetCandles(Ticker ticker, Timeframe timeframe,
@@ -270,13 +258,13 @@ namespace Managing.Application.Backtesting
_logger.LogInformation("Starting backtest with {TotalCandles} candles for {Ticker} on {Timeframe}",
totalCandles, config.Ticker, config.Timeframe);
bot.WalletBalances.Add(candles.FirstOrDefault().Date, config.BotTradingBalance);
bot.WalletBalances.Add(candles.FirstOrDefault()!.Date, config.BotTradingBalance);
foreach (var candle in candles)
{
bot.OptimizedCandles.Enqueue(candle);
bot.Candles.Add(candle);
bot.Run();
await bot.Run();
currentCandle++;
@@ -318,8 +306,6 @@ namespace Managing.Application.Backtesting
var finalPnl = bot.GetProfitAndLoss();
var winRate = bot.GetWinRate();
var optimizedMoneyManagement =
TradingBox.GetBestMoneyManagement(candles, bot.Positions, config.MoneyManagement);
var stats = TradingHelpers.GetStatistics(bot.WalletBalances);
var growthPercentage =
TradingHelpers.GetGrowthFromInitalBalance(bot.WalletBalances.FirstOrDefault().Value, finalPnl);
@@ -357,7 +343,6 @@ namespace Managing.Application.Backtesting
Fees = fees,
WalletBalances = bot.WalletBalances.ToList(),
Statistics = stats,
OptimizedMoneyManagement = optimizedMoneyManagement,
IndicatorsValues = withCandles
? AggregateValues(indicatorsValues, bot.IndicatorsValues)
: new Dictionary<IndicatorType, IndicatorsResultBase>(),
@@ -442,11 +427,11 @@ namespace Managing.Application.Backtesting
return indicatorsValues;
}
public bool DeleteBacktest(string id)
public async Task<bool> DeleteBacktestAsync(string id)
{
try
{
_backtestRepository.DeleteBacktestByIdForUser(null, id);
await _backtestRepository.DeleteBacktestByIdForUserAsync(null, id);
return true;
}
catch (Exception ex)
@@ -476,12 +461,24 @@ namespace Managing.Application.Backtesting
return backtests;
}
public async Task<IEnumerable<Backtest>> GetBacktestsByUserAsync(User user)
{
var backtests = await _backtestRepository.GetBacktestsByUserAsync(user);
return backtests;
}
public IEnumerable<Backtest> GetBacktestsByRequestId(string requestId)
{
var backtests = _backtestRepository.GetBacktestsByRequestId(requestId).ToList();
return backtests;
}
public async Task<IEnumerable<Backtest>> GetBacktestsByRequestIdAsync(string requestId)
{
var backtests = await _backtestRepository.GetBacktestsByRequestIdAsync(requestId);
return backtests;
}
public (IEnumerable<LightBacktest> Backtests, int TotalCount) GetBacktestsByRequestIdPaginated(string requestId,
int page, int pageSize, string sortBy = "score", string sortOrder = "desc")
{
@@ -490,9 +487,19 @@ namespace Managing.Application.Backtesting
return (backtests, totalCount);
}
public Backtest GetBacktestByIdForUser(User user, string id)
public async Task<(IEnumerable<LightBacktest> Backtests, int TotalCount)> GetBacktestsByRequestIdPaginatedAsync(
string requestId, int page, int pageSize, string sortBy = "score", string sortOrder = "desc")
{
var backtest = _backtestRepository.GetBacktestByIdForUser(user, id);
var (backtests, totalCount) =
await _backtestRepository.GetBacktestsByRequestIdPaginatedAsync(requestId, page, pageSize, sortBy,
sortOrder);
return (backtests, totalCount);
}
public async Task<Backtest> GetBacktestByIdForUserAsync(User user, string id)
{
var backtest = await _backtestRepository.GetBacktestByIdForUserAsync(user, id);
if (backtest == null)
return null;
@@ -504,12 +511,12 @@ namespace Managing.Application.Backtesting
var account = new Account
{ Name = backtest.Config.AccountName, Exchange = TradingExchanges.Evm };
var candles = _exchangeService.GetCandlesInflux(
var candles = await _exchangeService.GetCandlesInflux(
account.Exchange,
backtest.Config.Ticker,
backtest.StartDate,
backtest.Config.Timeframe,
backtest.EndDate).Result;
backtest.EndDate);
if (candles != null && candles.Count > 0)
{
@@ -525,11 +532,11 @@ namespace Managing.Application.Backtesting
return backtest;
}
public bool DeleteBacktestByUser(User user, string id)
public async Task<bool> DeleteBacktestByUserAsync(User user, string id)
{
try
{
_backtestRepository.DeleteBacktestByIdForUser(user, id);
await _backtestRepository.DeleteBacktestByIdForUserAsync(user, id);
return true;
}
catch (Exception ex)
@@ -539,11 +546,11 @@ namespace Managing.Application.Backtesting
}
}
public bool DeleteBacktestsByIdsForUser(User user, IEnumerable<string> ids)
public async Task<bool> DeleteBacktestsByIdsForUserAsync(User user, IEnumerable<string> ids)
{
try
{
_backtestRepository.DeleteBacktestsByIdsForUser(user, ids);
await _backtestRepository.DeleteBacktestsByIdsForUserAsync(user, ids);
return true;
}
catch (Exception ex)
@@ -567,11 +574,11 @@ namespace Managing.Application.Backtesting
}
}
public bool DeleteBacktestsByRequestId(string requestId)
public async Task<bool> DeleteBacktestsByRequestIdAsync(string requestId)
{
try
{
_backtestRepository.DeleteBacktestsByRequestId(requestId);
await _backtestRepository.DeleteBacktestsByRequestIdAsync(requestId);
return true;
}
catch (Exception ex)
@@ -589,6 +596,14 @@ namespace Managing.Application.Backtesting
return (backtests, totalCount);
}
public async Task<(IEnumerable<LightBacktest> Backtests, int TotalCount)> GetBacktestsByUserPaginatedAsync(
User user, int page, int pageSize, string sortBy = "score", string sortOrder = "desc")
{
var (backtests, totalCount) =
await _backtestRepository.GetBacktestsByUserPaginatedAsync(user, page, pageSize, sortBy, sortOrder);
return (backtests, totalCount);
}
// Bundle backtest methods
public void InsertBundleBacktestRequestForUser(User user, BundleBacktestRequest bundleRequest)
{
@@ -600,27 +615,53 @@ namespace Managing.Application.Backtesting
return _backtestRepository.GetBundleBacktestRequestsByUser(user);
}
public async Task<IEnumerable<BundleBacktestRequest>> GetBundleBacktestRequestsByUserAsync(User user)
{
return await _backtestRepository.GetBundleBacktestRequestsByUserAsync(user);
}
public BundleBacktestRequest? GetBundleBacktestRequestByIdForUser(User user, string id)
{
return _backtestRepository.GetBundleBacktestRequestByIdForUser(user, id);
}
public async Task<BundleBacktestRequest?> GetBundleBacktestRequestByIdForUserAsync(User user, string id)
{
return await _backtestRepository.GetBundleBacktestRequestByIdForUserAsync(user, id);
}
public void UpdateBundleBacktestRequest(BundleBacktestRequest bundleRequest)
{
_backtestRepository.UpdateBundleBacktestRequest(bundleRequest);
}
public async Task UpdateBundleBacktestRequestAsync(BundleBacktestRequest bundleRequest)
{
await _backtestRepository.UpdateBundleBacktestRequestAsync(bundleRequest);
}
public void DeleteBundleBacktestRequestByIdForUser(User user, string id)
{
_backtestRepository.DeleteBundleBacktestRequestByIdForUser(user, id);
}
public async Task DeleteBundleBacktestRequestByIdForUserAsync(User user, string id)
{
await _backtestRepository.DeleteBundleBacktestRequestByIdForUserAsync(user, id);
}
public IEnumerable<BundleBacktestRequest> GetBundleBacktestRequestsByStatus(BundleBacktestRequestStatus status)
{
// Use the repository method to get all bundles, then filter by status
return _backtestRepository.GetBundleBacktestRequestsByStatus(status);
}
public async Task<IEnumerable<BundleBacktestRequest>> GetBundleBacktestRequestsByStatusAsync(
BundleBacktestRequestStatus status)
{
return await _backtestRepository.GetBundleBacktestRequestsByStatusAsync(status);
}
/// <summary>
/// Sends a LightBacktestResponse to all SignalR subscribers of a bundle request.
/// </summary>