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

@@ -6,8 +6,8 @@ using Managing.Application.Bots;
using Managing.Domain.Bots;
using Managing.Domain.Users;
using Managing.Domain.Workflows;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using static Managing.Common.Enums;
namespace Managing.Application.ManageBot
@@ -22,13 +22,16 @@ namespace Managing.Application.ManageBot
private readonly ITradingService _tradingService;
private readonly IMoneyManagementService _moneyManagementService;
private readonly IUserService _userService;
private readonly IBackupBotService _backupBotService;
private readonly IServiceScopeFactory _scopeFactory;
private ConcurrentDictionary<string, BotTaskWrapper> _botTasks =
new ConcurrentDictionary<string, BotTaskWrapper>();
public BotService(IBotRepository botRepository, IExchangeService exchangeService,
IMessengerService messengerService, IAccountService accountService, ILogger<TradingBot> tradingBotLogger,
ITradingService tradingService, IMoneyManagementService moneyManagementService, IUserService userService)
ITradingService tradingService, IMoneyManagementService moneyManagementService, IUserService userService,
IBackupBotService backupBotService, IServiceScopeFactory scopeFactory)
{
_botRepository = botRepository;
_exchangeService = exchangeService;
@@ -38,35 +41,8 @@ namespace Managing.Application.ManageBot
_tradingService = tradingService;
_moneyManagementService = moneyManagementService;
_userService = userService;
}
public BotBackup GetBotBackup(string identifier)
{
return _botRepository.GetBots().FirstOrDefault(b => b.Identifier == identifier);
}
public void SaveOrUpdateBotBackup(User user, string identifier, BotStatus status, string data)
{
var backup = GetBotBackup(identifier);
if (backup != null)
{
backup.LastStatus = status;
backup.Data = data;
_botRepository.UpdateBackupBot(backup);
}
else
{
var botBackup = new BotBackup
{
LastStatus = status,
User = user,
Identifier = identifier,
Data = data
};
_botRepository.InsertBotAsync(botBackup);
}
_backupBotService = backupBotService;
_scopeFactory = scopeFactory;
}
public class BotTaskWrapper
@@ -96,6 +72,27 @@ namespace Managing.Application.ManageBot
_botTasks.AddOrUpdate(bot.Identifier, botTask, (key, existingVal) => botTask);
}
private async Task InitBot(ITradingBot bot, BotBackup backupBot)
{
var user = await _userService.GetUser(backupBot.User.Name);
bot.User = user;
// Config is already set correctly from backup data, so we only need to restore signals, positions, etc.
bot.LoadBackup(backupBot);
// Only start the bot if the backup status is Up
if (backupBot.LastStatus == BotStatus.Up)
{
// Start the bot asynchronously without waiting for completion
_ = Task.Run(() => bot.Start());
}
else
{
// Keep the bot in Down status if it was originally Down
bot.Stop();
}
}
public List<ITradingBot> GetActiveBots()
{
var bots = _botTasks.Values
@@ -107,17 +104,17 @@ namespace Managing.Application.ManageBot
return bots;
}
public IEnumerable<BotBackup> GetSavedBots()
public async Task<IEnumerable<BotBackup>> GetSavedBotsAsync()
{
return _botRepository.GetBots();
return await _botRepository.GetBotsAsync();
}
public void StartBotFromBackup(BotBackup backupBot)
public async Task StartBotFromBackup(BotBackup backupBot)
{
object bot = null;
Task botTask = null;
var scalpingBotData = JsonConvert.DeserializeObject<TradingBotBackup>(backupBot.Data);
var scalpingBotData = backupBot.Data;
// Get the config directly from the backup
var scalpingConfig = scalpingBotData.Config;
@@ -137,7 +134,7 @@ namespace Managing.Application.ManageBot
// Ensure the scenario is properly loaded from database if needed
if (scalpingConfig.Scenario == null && !string.IsNullOrEmpty(scalpingConfig.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(scalpingConfig.ScenarioName);
var scenario = await _tradingService.GetScenarioByNameAsync(scalpingConfig.ScenarioName);
if (scenario != null)
{
scalpingConfig.Scenario = scenario;
@@ -158,7 +155,7 @@ namespace Managing.Application.ManageBot
// Ensure critical properties are set correctly for restored bots
scalpingConfig.IsForBacktest = false;
bot = CreateTradingBot(scalpingConfig);
bot = await CreateTradingBot(scalpingConfig);
botTask = Task.Run(() => InitBot((ITradingBot)bot, backupBot));
if (bot != null && botTask != null)
@@ -168,29 +165,38 @@ namespace Managing.Application.ManageBot
}
}
private void InitBot(ITradingBot bot, BotBackup backupBot)
public async Task<BotBackup> GetBotBackup(string identifier)
{
var user = _userService.GetUser(backupBot.User.Name);
bot.User = user;
// Config is already set correctly from backup data, so we only need to restore signals, positions, etc.
bot.LoadBackup(backupBot);
return await _botRepository.GetBotByIdentifierAsync(identifier);
}
// Only start the bot if the backup status is Up
if (backupBot.LastStatus == BotStatus.Up)
public async Task SaveOrUpdateBotBackup(User user, string identifier, BotStatus status, TradingBotBackup data)
{
var backup = await GetBotBackup(identifier);
if (backup != null)
{
// Start the bot asynchronously without waiting for completion
_ = Task.Run(() => bot.Start());
backup.LastStatus = status;
backup.Data = data;
await _botRepository.UpdateBackupBot(backup);
}
else
{
// Keep the bot in Down status if it was originally Down
bot.Stop();
var botBackup = new BotBackup
{
LastStatus = status,
User = user,
Identifier = identifier,
Data = data
};
await _botRepository.InsertBotAsync(botBackup);
}
}
public IBot CreateSimpleBot(string botName, Workflow workflow)
{
return new SimpleBot(botName, _tradingBotLogger, workflow, this);
return new SimpleBot(botName, _tradingBotLogger, workflow, this, _backupBotService);
}
public async Task<string> StopBot(string identifier)
@@ -263,7 +269,7 @@ namespace Managing.Application.ManageBot
// Restart the bot (this will update StartupTime)
bot.Restart();
// Start the bot asynchronously without waiting for completion
_ = Task.Run(() => bot.Start());
@@ -282,12 +288,12 @@ namespace Managing.Application.ManageBot
return BotStatus.Down.ToString();
}
public void ToggleIsForWatchingOnly(string identifier)
public async Task ToggleIsForWatchingOnly(string identifier)
{
if (_botTasks.TryGetValue(identifier, out var botTaskWrapper) &&
botTaskWrapper.BotInstance is ITradingBot tradingBot)
{
tradingBot.ToggleIsForWatchOnly().Wait();
await tradingBot.ToggleIsForWatchOnly();
}
}
@@ -305,7 +311,7 @@ namespace Managing.Application.ManageBot
// Ensure the scenario is properly loaded from database if needed
if (newConfig.Scenario == null && !string.IsNullOrEmpty(newConfig.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(newConfig.ScenarioName);
var scenario = await _tradingService.GetScenarioByNameAsync(newConfig.ScenarioName);
if (scenario != null)
{
newConfig.Scenario = scenario;
@@ -365,12 +371,12 @@ namespace Managing.Application.ManageBot
}
public ITradingBot CreateTradingBot(TradingBotConfig config)
public async Task<ITradingBot> CreateTradingBot(TradingBotConfig config)
{
// Ensure the scenario is properly loaded from database if needed
if (config.Scenario == null && !string.IsNullOrEmpty(config.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(config.ScenarioName);
var scenario = await _tradingService.GetScenarioByNameAsync(config.ScenarioName);
if (scenario != null)
{
config.Scenario = scenario;
@@ -386,22 +392,15 @@ namespace Managing.Application.ManageBot
throw new ArgumentException("Scenario object must be provided or ScenarioName must be valid");
}
return new TradingBot(
_exchangeService,
_tradingBotLogger,
_tradingService,
_accountService,
_messengerService,
this,
config);
return new TradingBot(_tradingBotLogger, _scopeFactory, config);
}
public ITradingBot CreateBacktestTradingBot(TradingBotConfig config)
public async Task<ITradingBot> CreateBacktestTradingBot(TradingBotConfig config)
{
// Ensure the scenario is properly loaded from database if needed
if (config.Scenario == null && !string.IsNullOrEmpty(config.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(config.ScenarioName);
var scenario = await _tradingService.GetScenarioByNameAsync(config.ScenarioName);
if (scenario != null)
{
config.Scenario = scenario;
@@ -418,22 +417,15 @@ namespace Managing.Application.ManageBot
}
config.IsForBacktest = true;
return new TradingBot(
_exchangeService,
_tradingBotLogger,
_tradingService,
_accountService,
_messengerService,
this,
config);
return new TradingBot(_tradingBotLogger, _scopeFactory, config);
}
public ITradingBot CreateScalpingBot(TradingBotConfig config)
public async Task<ITradingBot> CreateScalpingBot(TradingBotConfig config)
{
// Ensure the scenario is properly loaded from database if needed
if (config.Scenario == null && !string.IsNullOrEmpty(config.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(config.ScenarioName);
var scenario = await _tradingService.GetScenarioByNameAsync(config.ScenarioName);
if (scenario != null)
{
config.Scenario = scenario;
@@ -450,22 +442,15 @@ namespace Managing.Application.ManageBot
}
config.FlipPosition = false;
return new TradingBot(
_exchangeService,
_tradingBotLogger,
_tradingService,
_accountService,
_messengerService,
this,
config);
return new TradingBot(_tradingBotLogger, _scopeFactory, config);
}
public ITradingBot CreateBacktestScalpingBot(TradingBotConfig config)
public async Task<ITradingBot> CreateBacktestScalpingBot(TradingBotConfig config)
{
// Ensure the scenario is properly loaded from database if needed
if (config.Scenario == null && !string.IsNullOrEmpty(config.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(config.ScenarioName);
var scenario = await _tradingService.GetScenarioByNameAsync(config.ScenarioName);
if (scenario != null)
{
config.Scenario = scenario;
@@ -483,22 +468,15 @@ namespace Managing.Application.ManageBot
config.IsForBacktest = true;
config.FlipPosition = false;
return new TradingBot(
_exchangeService,
_tradingBotLogger,
_tradingService,
_accountService,
_messengerService,
this,
config);
return new TradingBot(_tradingBotLogger, _scopeFactory, config);
}
public ITradingBot CreateFlippingBot(TradingBotConfig config)
public async Task<ITradingBot> CreateFlippingBot(TradingBotConfig config)
{
// Ensure the scenario is properly loaded from database if needed
if (config.Scenario == null && !string.IsNullOrEmpty(config.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(config.ScenarioName);
var scenario = await _tradingService.GetScenarioByNameAsync(config.ScenarioName);
if (scenario != null)
{
config.Scenario = scenario;
@@ -515,22 +493,15 @@ namespace Managing.Application.ManageBot
}
config.FlipPosition = true;
return new TradingBot(
_exchangeService,
_tradingBotLogger,
_tradingService,
_accountService,
_messengerService,
this,
config);
return new TradingBot(_tradingBotLogger, _scopeFactory, config);
}
public ITradingBot CreateBacktestFlippingBot(TradingBotConfig config)
public async Task<ITradingBot> CreateBacktestFlippingBot(TradingBotConfig config)
{
// Ensure the scenario is properly loaded from database if needed
if (config.Scenario == null && !string.IsNullOrEmpty(config.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(config.ScenarioName);
var scenario = await _tradingService.GetScenarioByNameAsync(config.ScenarioName);
if (scenario != null)
{
config.Scenario = scenario;
@@ -548,14 +519,7 @@ namespace Managing.Application.ManageBot
config.IsForBacktest = true;
config.FlipPosition = true;
return new TradingBot(
_exchangeService,
_tradingBotLogger,
_tradingService,
_accountService,
_messengerService,
this,
config);
return new TradingBot(_tradingBotLogger, _scopeFactory, config);
}
}
}