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

@@ -102,13 +102,13 @@ namespace Managing.Api.Controllers
{
var user = await GetUser();
var result = await _AccountService.SwapGmxTokensAsync(
user,
name,
request.FromTicker,
request.ToTicker,
request.Amount,
request.OrderType,
request.TriggerRatio,
user,
name,
request.FromTicker,
request.ToTicker,
request.Amount,
request.OrderType,
request.TriggerRatio,
request.AllowedSlippage
);
return Ok(result);
@@ -126,11 +126,11 @@ namespace Managing.Api.Controllers
{
var user = await GetUser();
var result = await _AccountService.SendTokenAsync(
user,
name,
request.RecipientAddress,
request.Ticker,
request.Amount,
user,
name,
request.RecipientAddress,
request.Ticker,
request.Amount,
request.ChainId
);
return Ok(result);
@@ -142,9 +142,9 @@ namespace Managing.Api.Controllers
/// <param name="name">The name of the account to delete.</param>
/// <returns>An ActionResult indicating the outcome of the operation.</returns>
[HttpDelete]
public ActionResult DeleteAccount(string name)
public async Task<ActionResult> DeleteAccount(string name)
{
var user = GetUser().Result;
var user = await GetUser();
return Ok(_AccountService.DeleteAccount(user, name));
}
}

View File

@@ -70,7 +70,8 @@ public class BacktestController : BaseController
public async Task<ActionResult<IEnumerable<Backtest>>> Backtests()
{
var user = await GetUser();
return Ok(_backtester.GetBacktestsByUser(user));
var backtests = await _backtester.GetBacktestsByUserAsync(user);
return Ok(backtests);
}
/// <summary>
@@ -84,7 +85,7 @@ public class BacktestController : BaseController
public async Task<ActionResult<Backtest>> Backtest(string id)
{
var user = await GetUser();
var backtest = _backtester.GetBacktestByIdForUser(user, id);
var backtest = await _backtester.GetBacktestByIdForUserAsync(user, id);
if (backtest == null)
{
@@ -103,7 +104,8 @@ public class BacktestController : BaseController
public async Task<ActionResult> DeleteBacktest(string id)
{
var user = await GetUser();
return Ok(_backtester.DeleteBacktestByUser(user, id));
var result = await _backtester.DeleteBacktestByUserAsync(user, id);
return Ok(result);
}
/// <summary>
@@ -115,7 +117,7 @@ public class BacktestController : BaseController
public async Task<ActionResult> DeleteBacktests([FromBody] DeleteBacktestsRequest request)
{
var user = await GetUser();
return Ok(_backtester.DeleteBacktestsByIdsForUser(user, request.BacktestIds));
return Ok(await _backtester.DeleteBacktestsByIdsForUserAsync(user, request.BacktestIds));
}
/// <summary>
@@ -133,7 +135,7 @@ public class BacktestController : BaseController
return BadRequest("Request ID is required");
}
var backtests = _backtester.GetBacktestsByRequestId(requestId);
var backtests = await _backtester.GetBacktestsByRequestIdAsync(requestId);
return Ok(backtests);
}
@@ -177,7 +179,7 @@ public class BacktestController : BaseController
}
var (backtests, totalCount) =
_backtester.GetBacktestsByRequestIdPaginated(requestId, page, pageSize, sortBy, sortOrder);
await _backtester.GetBacktestsByRequestIdPaginatedAsync(requestId, page, pageSize, sortBy, sortOrder);
var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize);
@@ -243,7 +245,7 @@ public class BacktestController : BaseController
return BadRequest("Sort order must be 'asc' or 'desc'");
}
var (backtests, totalCount) = _backtester.GetBacktestsByUserPaginated(user, page, pageSize, sortBy, sortOrder);
var (backtests, totalCount) = await _backtester.GetBacktestsByUserPaginatedAsync(user, page, pageSize, sortBy, sortOrder);
var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize);
var response = new PaginatedBacktestsResponse
@@ -528,7 +530,7 @@ public class BacktestController : BaseController
_backtester.DeleteBundleBacktestRequestByIdForUser(user, id);
// Then, delete all related backtests
var backtestsDeleted = _backtester.DeleteBacktestsByRequestId(id);
var backtestsDeleted = await _backtester.DeleteBacktestsByRequestIdAsync(id);
return Ok(new
{
@@ -693,7 +695,7 @@ public class BacktestController : BaseController
_geneticService.DeleteGeneticRequestByIdForUser(user, id);
// Then, delete all related backtests
var backtestsDeleted = _backtester.DeleteBacktestsByRequestId(id);
var backtestsDeleted = await _backtester.DeleteBacktestsByRequestIdAsync(id);
return Ok(new
{

View File

@@ -22,17 +22,16 @@ public abstract class BaseController : ControllerBase
var identity = HttpContext?.User.Identity as ClaimsIdentity;
if (identity != null)
{
var address = identity.Claims.FirstOrDefault(c => c.Type == "address").Value;
var user = await _userService.GetUserByAddressAsync(address);
if (user != null)
var address = identity.Claims.FirstOrDefault(c => c.Type == "address")?.Value;
if (address != null)
{
var user = await _userService.GetUserByAddressAsync(address);
return user;
}
throw new Exception("User not found for this token");
}
throw new Exception("Not identity assigned to this token");
}
}

View File

@@ -128,8 +128,14 @@ public class BotController : BaseController
var user = await GetUser();
if (string.IsNullOrEmpty(user.AgentName))
{
return BadRequest(
"Agent name is required to start a bot. Please configure your agent name in the user profile.");
}
// Get money management - either by name lookup or use provided object
MoneyManagement moneyManagement;
LightMoneyManagement moneyManagement;
if (!string.IsNullOrEmpty(request.Config.MoneyManagementName))
{
moneyManagement =
@@ -144,12 +150,6 @@ public class BotController : BaseController
moneyManagement = Map(request.Config.MoneyManagement);
// Format percentage values if using custom money management
moneyManagement?.FormatPercentage();
// Ensure user is set for custom money management
if (moneyManagement != null)
{
moneyManagement.User = user;
}
}
// Validate initialTradingBalance
@@ -425,7 +425,7 @@ public class BotController : BaseController
new StopBotCommand(bot.Identifier));
// Get the saved bot backup
var backup = _botService.GetBotBackup(bot.Identifier);
var backup = await _botService.GetBotBackup(bot.Identifier);
if (backup != null)
{
_botService.StartBotFromBackup(backup);
@@ -564,7 +564,8 @@ public class BotController : BaseController
catch (Exception ex)
{
_logger.LogError(ex, "Error opening position manually");
return StatusCode(500, $"Error opening position: {ex.Message}");
return StatusCode(500,
$"Error opening position: {ex.Message}, {ex.InnerException?.Message} or {ex.StackTrace}");
}
}
@@ -699,20 +700,31 @@ public class BotController : BaseController
}
// Validate and get the money management
MoneyManagement moneyManagement = null;
LightMoneyManagement moneyManagement = null;
if (!string.IsNullOrEmpty(request.MoneyManagementName))
{
// Load money management by name
moneyManagement = await _moneyManagementService.GetMoneyMangement(user, request.MoneyManagementName);
if (moneyManagement == null)
var fullMoneyManagement =
await _moneyManagementService.GetMoneyMangement(user, request.MoneyManagementName);
if (fullMoneyManagement == null)
{
return BadRequest($"Money management '{request.MoneyManagementName}' not found");
}
if (moneyManagement.User?.Name != user.Name)
if (fullMoneyManagement.User?.Name != user.Name)
{
return Forbid("You don't have permission to use this money management");
}
// Convert to LightMoneyManagement
moneyManagement = new LightMoneyManagement
{
Name = fullMoneyManagement.Name,
Timeframe = fullMoneyManagement.Timeframe,
StopLoss = fullMoneyManagement.StopLoss,
TakeProfit = fullMoneyManagement.TakeProfit,
Leverage = fullMoneyManagement.Leverage
};
}
else if (request.MoneyManagement != null)
{
@@ -720,9 +732,6 @@ public class BotController : BaseController
moneyManagement = request.MoneyManagement;
// Format percentage values if using custom money management
moneyManagement.FormatPercentage();
// Ensure user is set for custom money management
moneyManagement.User = user;
}
else
{

View File

@@ -206,14 +206,14 @@ public class DataController : ControllerBase
/// <returns>A <see cref="SpotlightOverview"/> object containing spotlight data.</returns>
[Authorize]
[HttpGet("Spotlight")]
public ActionResult<SpotlightOverview> GetSpotlight()
public async Task<ActionResult<SpotlightOverview>> GetSpotlight()
{
var overview = _cacheService.GetOrSave(nameof(SpotlightOverview),
() => { return _statisticService.GetLastSpotlight(DateTime.Now.AddDays(-2)); }, TimeSpan.FromMinutes(2));
if (overview?.Spotlights.Count < overview?.ScenarioCount || overview == null)
var cacheKey = $"Spotlight_{DateTime.Now.AddDays(-2).ToString("yyyy-MM-dd")}";
var overview = _cacheService.GetValue<SpotlightOverview>(cacheKey);
if (overview == null)
{
overview = _statisticService.GetLastSpotlight(DateTime.Now.AddDays(-2));
overview = await _statisticService.GetLastSpotlight(DateTime.Now.AddDays(-2));
_cacheService.SaveValue(cacheKey, overview, TimeSpan.FromMinutes(2));
}
return Ok(overview);
@@ -256,7 +256,7 @@ public class DataController : ControllerBase
{
// Map ScenarioRequest to domain Scenario object
var domainScenario = MapScenarioRequestToScenario(request.Scenario);
indicatorsValues = await _tradingService.CalculateIndicatorsValuesAsync(domainScenario, candles);
indicatorsValues = _tradingService.CalculateIndicatorsValuesAsync(domainScenario, candles);
}
return Ok(new CandlesWithIndicatorsResponse

View File

@@ -40,8 +40,16 @@ public class MoneyManagementController : BaseController
[HttpPost]
public async Task<ActionResult<MoneyManagement>> PostMoneyManagement(MoneyManagement moneyManagement)
{
var user = await GetUser();
return Ok(await _moneyManagementService.CreateOrUpdateMoneyManagement(user, moneyManagement));
try
{
var user = await GetUser();
var result = await _moneyManagementService.CreateOrUpdateMoneyManagement(user, moneyManagement);
return Ok(result);
}
catch (Exception ex)
{
return StatusCode(500, $"Error creating/updating money management: {ex.Message}");
}
}
/// <summary>
@@ -52,8 +60,16 @@ public class MoneyManagementController : BaseController
[Route("moneymanagements")]
public async Task<ActionResult<IEnumerable<MoneyManagement>>> GetMoneyManagements()
{
var user = await GetUser();
return Ok(_moneyManagementService.GetMoneyMangements(user));
try
{
var user = await GetUser();
var moneyManagements = await _moneyManagementService.GetMoneyMangements(user);
return Ok(moneyManagements);
}
catch (Exception ex)
{
return StatusCode(500, $"Error retrieving money managements: {ex.Message}");
}
}
/// <summary>
@@ -64,8 +80,22 @@ public class MoneyManagementController : BaseController
[HttpGet]
public async Task<ActionResult<MoneyManagement>> GetMoneyManagement(string name)
{
var user = await GetUser();
return Ok(await _moneyManagementService.GetMoneyMangement(user, name));
try
{
var user = await GetUser();
var result = await _moneyManagementService.GetMoneyMangement(user, name);
if (result == null)
{
return NotFound($"Money management strategy '{name}' not found");
}
return Ok(result);
}
catch (Exception ex)
{
return StatusCode(500, $"Error retrieving money management: {ex.Message}");
}
}
/// <summary>
@@ -76,7 +106,21 @@ public class MoneyManagementController : BaseController
[HttpDelete]
public async Task<ActionResult> DeleteMoneyManagement(string name)
{
var user = await GetUser();
return Ok(_moneyManagementService.DeleteMoneyManagement(user, name));
try
{
var user = await GetUser();
var result = await _moneyManagementService.DeleteMoneyManagement(user, name);
if (!result)
{
return NotFound($"Money management strategy '{name}' not found or could not be deleted");
}
return Ok(new { success = true, message = $"Money management strategy '{name}' deleted successfully" });
}
catch (Exception ex)
{
return StatusCode(500, $"Error deleting money management: {ex.Message}");
}
}
}

View File

@@ -43,7 +43,7 @@ public class ScenarioController : BaseController
public async Task<ActionResult<IEnumerable<ScenarioViewModel>>> GetScenarios()
{
var user = await GetUser();
var scenarios = _scenarioService.GetScenariosByUser(user);
var scenarios = await _scenarioService.GetScenariosByUserAsync(user);
var scenarioViewModels = scenarios.Select(MapToScenarioViewModel);
return Ok(scenarioViewModels);
}
@@ -59,7 +59,7 @@ public class ScenarioController : BaseController
int? loopbackPeriod = null)
{
var user = await GetUser();
var scenario = _scenarioService.CreateScenarioForUser(user, name, strategies, loopbackPeriod);
var scenario = await _scenarioService.CreateScenarioForUser(user, name, strategies, loopbackPeriod);
var scenarioViewModel = MapToScenarioViewModel(scenario);
return Ok(scenarioViewModel);
}
@@ -73,7 +73,7 @@ public class ScenarioController : BaseController
public async Task<ActionResult> DeleteScenario(string name)
{
var user = await GetUser();
return Ok(_scenarioService.DeleteScenarioByUser(user, name));
return Ok(await _scenarioService.DeleteScenarioByUser(user, name));
}
// Update scenario
@@ -81,7 +81,7 @@ public class ScenarioController : BaseController
public async Task<ActionResult> UpdateScenario(string name, List<string> strategies, int? loopbackPeriod = null)
{
var user = await GetUser();
return Ok(_scenarioService.UpdateScenarioByUser(user, name, strategies, loopbackPeriod));
return Ok(await _scenarioService.UpdateScenarioByUser(user, name, strategies, loopbackPeriod));
}
/// <summary>
@@ -93,7 +93,7 @@ public class ScenarioController : BaseController
public async Task<ActionResult<IEnumerable<IndicatorViewModel>>> GetIndicators()
{
var user = await GetUser();
var indicators = _scenarioService.GetIndicatorsByUser(user);
var indicators = await _scenarioService.GetIndicatorsAsync();
var indicatorViewModels = indicators.Select(MapToIndicatorViewModel);
return Ok(indicatorViewModels);
}
@@ -127,7 +127,7 @@ public class ScenarioController : BaseController
int? cyclePeriods = null)
{
var user = await GetUser();
var indicator = _scenarioService.CreateIndicatorForUser(
var indicator = await _scenarioService.CreateIndicatorForUser(
user,
indicatorType,
name,
@@ -153,7 +153,7 @@ public class ScenarioController : BaseController
public async Task<ActionResult> DeleteIndicator(string name)
{
var user = await GetUser();
return Ok(_scenarioService.DeleteIndicatorByUser(user, name));
return Ok(await _scenarioService.DeleteIndicatorByUser(user, name));
}
// Update indicator
@@ -172,7 +172,7 @@ public class ScenarioController : BaseController
int? cyclePeriods = null)
{
var user = await GetUser();
return Ok(_scenarioService.UpdateIndicatorByUser(
return Ok(await _scenarioService.UpdateIndicatorByUser(
user,
indicatorType,
name,

View File

@@ -1,19 +1,15 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Domain.MoneyManagements;
using Managing.Domain.Strategies;
using Managing.Domain.Scenarios;
using Managing.Domain.Users;
using static Managing.Common.Enums;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Managing.Api.Controllers;
/// <summary>
/// Controller for managing application settings and configurations.
/// Provides endpoints for setting up default configurations and resetting settings.
/// Requires authorization for access and produces JSON responses.
/// </summary>
[ApiController]
[Authorize]
[Route("[controller]")]
@@ -22,28 +18,58 @@ public class SettingsController : BaseController
{
private readonly ISettingsService _settingsService;
/// <summary>
/// Initializes a new instance of the <see cref="SettingsController"/> class.
/// </summary>
/// <param name="settingsService">The service for managing application settings.</param>
/// <param name="userService">The service for user-related operations.</param>
public SettingsController(ISettingsService settingsService, IUserService userService)
: base(userService)
{
_settingsService = settingsService;
}
/// <summary>
/// Sets up initial application settings.
/// </summary>
/// <returns>A result indicating if the setup was successful.</returns>
[HttpPost]
public ActionResult SetupSettings()
public async Task<ActionResult<bool>> SetupSettings()
{
return Ok(_settingsService.SetupSettings());
try
{
var result = await _settingsService.SetupSettings();
return Ok(result);
}
catch (Exception ex)
{
return StatusCode(500, $"Error setting up settings: {ex.Message}");
}
}
/// <summary>
/// Resets all application settings to their default values.
/// </summary>
/// <returns>A result indicating if the reset was successful.</returns>
[HttpDelete]
public async Task<ActionResult<bool>> ResetSettings()
{
return Ok(await _settingsService.ResetSettings());
try
{
var result = await _settingsService.ResetSettings();
return Ok(result);
}
catch (Exception ex)
{
return StatusCode(500, $"Error resetting settings: {ex.Message}");
}
}
/// <summary>
/// Creates default configuration for backtesting including Money Management, Strategy, and Scenario
/// for the authenticated user.
/// </summary>
/// <returns>A result indicating if the default configuration was created successfully</returns>
/// <returns>A result indicating if the default configuration was created successfully.</returns>
[HttpPost]
[Route("create-default-config")]
public async Task<ActionResult<bool>> CreateDefaultConfiguration()
@@ -52,9 +78,12 @@ public class SettingsController : BaseController
{
var user = await GetUser();
if (user == null)
return Unauthorized("User not found");
{
return Unauthorized("User not found or authentication failed");
}
return Ok(await _settingsService.CreateDefaultConfiguration(user));
var result = await _settingsService.CreateDefaultConfiguration(user);
return Ok(result);
}
catch (Exception ex)
{

View File

@@ -51,17 +51,6 @@ public class TradingController : BaseController
_moneyManagementService = moneyManagementService;
}
/// <summary>
/// Retrieves a list of positions based on the initiator type.
/// </summary>
/// <param name="positionInitiator">The initiator of the position (e.g., User, System).</param>
/// <returns>A list of positions.</returns>
[HttpGet("GetPositions")]
public async Task<ActionResult<List<Position>>> GetPositions(PositionInitiator positionInitiator)
{
var result = await _mediator.Send(new GetPositionsCommand(positionInitiator));
return Ok(result);
}
/// <summary>
/// Retrieves a specific trade by account name, ticker, and exchange order ID.
@@ -98,7 +87,7 @@ public class TradingController : BaseController
[HttpPost("ClosePosition")]
public async Task<ActionResult<Position>> ClosePosition(string identifier)
{
var position = _tradingService.GetPositionByIdentifier(identifier);
var position = await _tradingService.GetPositionByIdentifierAsync(identifier);
var result = await _closeTradeCommandHandler.Handle(new ClosePositionCommand(position));
return Ok(result);
}