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:
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.MongoDb" Version="8.1.0"/>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Npgsql" Version="8.1.0"/>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="9.0.0"/>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="9.0.0"/>
|
||||
<PackageReference Include="Essential.LoggerProvider.Elasticsearch" Version="1.3.2"/>
|
||||
@@ -52,8 +52,4 @@
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Workers\"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Managing.Domain.Bots;
|
||||
using Managing.Domain.Candles;
|
||||
using Managing.Domain.Strategies;
|
||||
using Managing.Domain.Trades;
|
||||
|
||||
namespace Managing.Api.Models.Responses
|
||||
@@ -11,56 +10,67 @@ namespace Managing.Api.Models.Responses
|
||||
/// <summary>
|
||||
/// Current status of the bot (Up, Down, etc.)
|
||||
/// </summary>
|
||||
[Required] public string Status { get; internal set; }
|
||||
|
||||
[Required]
|
||||
public string Status { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of signals generated by the bot
|
||||
/// </summary>
|
||||
[Required] public List<Signal> Signals { get; internal set; }
|
||||
|
||||
[Required]
|
||||
public List<LightSignal> Signals { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of positions opened by the bot
|
||||
/// </summary>
|
||||
[Required] public List<Position> Positions { get; internal set; }
|
||||
|
||||
[Required]
|
||||
public List<Position> Positions { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Candles used by the bot for analysis
|
||||
/// </summary>
|
||||
[Required] public List<Candle> Candles { get; internal set; }
|
||||
|
||||
[Required]
|
||||
public List<Candle> Candles { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current win rate percentage
|
||||
/// </summary>
|
||||
[Required] public int WinRate { get; internal set; }
|
||||
|
||||
[Required]
|
||||
public int WinRate { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current profit and loss
|
||||
/// </summary>
|
||||
[Required] public decimal ProfitAndLoss { get; internal set; }
|
||||
|
||||
[Required]
|
||||
public decimal ProfitAndLoss { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique identifier for the bot
|
||||
/// </summary>
|
||||
[Required] public string Identifier { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Identifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Agent name associated with the bot
|
||||
/// </summary>
|
||||
[Required] public string AgentName { get; set; }
|
||||
|
||||
[Required]
|
||||
public string AgentName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The full trading bot configuration
|
||||
/// </summary>
|
||||
[Required] public TradingBotConfig Config { get; internal set; }
|
||||
|
||||
[Required]
|
||||
public TradingBotConfig Config { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The time when the bot was created
|
||||
/// </summary>
|
||||
[Required] public DateTime CreateDate { get; internal set; }
|
||||
|
||||
[Required]
|
||||
public DateTime CreateDate { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The time when the bot was started
|
||||
/// </summary>
|
||||
[Required] public DateTime StartupTime { get; internal set; }
|
||||
[Required]
|
||||
public DateTime StartupTime { get; internal set; }
|
||||
}
|
||||
}
|
||||
@@ -10,11 +10,12 @@ using Managing.Bootstrap;
|
||||
using Managing.Common;
|
||||
using Managing.Core.Middleawares;
|
||||
using Managing.Infrastructure.Databases.InfluxDb.Models;
|
||||
using Managing.Infrastructure.Databases.MongoDb;
|
||||
using Managing.Infrastructure.Databases.MongoDb.Configurations;
|
||||
using Managing.Infrastructure.Databases.PostgreSql;
|
||||
using Managing.Infrastructure.Databases.PostgreSql.Configurations;
|
||||
using Managing.Infrastructure.Evm.Models.Privy;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.OpenApi.Models;
|
||||
@@ -71,7 +72,7 @@ builder.Services.AddServiceDiscovery();
|
||||
builder.Services.AddHealthChecks()
|
||||
.AddCheck("self", () => HealthCheckResult.Healthy(), ["api"]);
|
||||
|
||||
var mongoConnectionString = builder.Configuration.GetSection(Constants.Databases.MongoDb)["ConnectionString"];
|
||||
var postgreSqlConnectionString = builder.Configuration.GetSection(Constants.Databases.PostgreSql)["ConnectionString"];
|
||||
var influxUrl = builder.Configuration.GetSection(Constants.Databases.InfluxDb)["Url"];
|
||||
var web3ProxyUrl = builder.Configuration.GetSection("Web3Proxy")["BaseUrl"];
|
||||
|
||||
@@ -87,9 +88,38 @@ builder.Services.AddHttpClient("GmxHealthCheck")
|
||||
builder.Services.AddSingleton<Web3ProxyHealthCheck>(sp =>
|
||||
new Web3ProxyHealthCheck(sp.GetRequiredService<IHttpClientFactory>(), web3ProxyUrl));
|
||||
|
||||
// Add PostgreSQL DbContext with improved concurrency and connection management
|
||||
builder.Services.AddDbContext<ManagingDbContext>(options =>
|
||||
{
|
||||
options.UseNpgsql(postgreSqlConnectionString, npgsqlOptions =>
|
||||
{
|
||||
// Configure connection pooling and timeout settings for better concurrency
|
||||
npgsqlOptions.CommandTimeout(60); // Increase command timeout for complex queries
|
||||
npgsqlOptions.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(10),
|
||||
errorCodesToAdd: null);
|
||||
});
|
||||
|
||||
// Enable detailed errors in development
|
||||
if (builder.Environment.IsDevelopment())
|
||||
{
|
||||
options.EnableDetailedErrors();
|
||||
options.EnableSensitiveDataLogging();
|
||||
options.EnableThreadSafetyChecks(); // Enable thread safety checks in development
|
||||
}
|
||||
|
||||
// Configure query tracking behavior for better performance
|
||||
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); // Default to no tracking for better performance
|
||||
|
||||
// Enable service provider caching for better performance
|
||||
options.EnableServiceProviderCaching();
|
||||
|
||||
// Enable connection resiliency for backtest and high-load scenarios
|
||||
options.LogTo(msg => Console.WriteLine(msg), LogLevel.Warning); // Log warnings for connection issues
|
||||
}, ServiceLifetime.Scoped); // Explicitly specify scoped lifetime for proper request isolation
|
||||
|
||||
// Add specific health checks for databases and other services
|
||||
builder.Services.AddHealthChecks()
|
||||
.AddMongoDb(mongoConnectionString, name: "mongodb", tags: ["database"])
|
||||
.AddNpgSql(postgreSqlConnectionString, name: "postgresql", tags: ["database"])
|
||||
.AddUrlGroup(new Uri($"{influxUrl}/health"), name: "influxdb", tags: ["database"])
|
||||
.AddCheck<Web3ProxyHealthCheck>("web3proxy", tags: ["api", "external"])
|
||||
.AddCheck<CandleDataHealthCheck>("candle-data", tags: ["database", "candles"])
|
||||
@@ -120,7 +150,7 @@ builder.Host.UseSerilog((hostBuilder, loggerConfiguration) =>
|
||||
});
|
||||
|
||||
builder.Services.AddOptions();
|
||||
builder.Services.Configure<ManagingDatabaseSettings>(builder.Configuration.GetSection(Constants.Databases.MongoDb));
|
||||
builder.Services.Configure<PostgreSqlSettings>(builder.Configuration.GetSection(Constants.Databases.PostgreSql));
|
||||
builder.Services.Configure<InfluxDbSettings>(builder.Configuration.GetSection(Constants.Databases.InfluxDb));
|
||||
builder.Services.Configure<PrivySettings>(builder.Configuration.GetSection(Constants.ThirdParty.Privy));
|
||||
builder.Services.AddControllers().AddJsonOptions(options =>
|
||||
@@ -209,25 +239,6 @@ if (builder.Configuration.GetValue<bool>("EnableBotManager", false))
|
||||
// App
|
||||
var app = builder.Build();
|
||||
app.UseSerilogRequestLogging();
|
||||
|
||||
// Create MongoDB indexes on startup
|
||||
try
|
||||
{
|
||||
var indexService = app.Services.GetRequiredService<IndexService>();
|
||||
await indexService.CreateIndexesAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log the error but don't fail the application startup
|
||||
var logger = app.Services.GetRequiredService<ILogger<Program>>();
|
||||
logger.LogError(ex, "Failed to create MongoDB indexes on startup. The application will continue without indexes.");
|
||||
}
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.UseOpenApi();
|
||||
app.UseSwaggerUI(c =>
|
||||
{
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"DetailedErrors": true,
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"System": "Error",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"ElasticConfiguration": {
|
||||
"Uri": "http://elasticsearch:9200/"
|
||||
},
|
||||
"Sentry": {
|
||||
"Debug": true,
|
||||
"TracesSampleRate": 1.0,
|
||||
"SendDefaultPii": true,
|
||||
"DiagnosticLevel": "Debug"
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
{
|
||||
"ManagingDatabase": {
|
||||
"ConnectionString": "mongodb://managingdb:27017",
|
||||
"DatabaseName": "ManagingDb"
|
||||
},
|
||||
"InfluxDb": {
|
||||
"Url": "http://influxdb:8086/",
|
||||
"Organization": "",
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
{
|
||||
"ManagingDatabase": {
|
||||
"ConnectionString": "mongodb://managingdb:27017",
|
||||
"DatabaseName": "ManagingDb",
|
||||
"UserName": "admin",
|
||||
"Password": "!MotdepasseFort11"
|
||||
},
|
||||
"InfluxDb": {
|
||||
"Url": "http://influxdb:8086/",
|
||||
"Organization": "managing-org",
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
{
|
||||
"ManagingDatabase": {
|
||||
"ConnectionString": "mongodb://localhost:27017",
|
||||
"DatabaseName": "ManagingDb"
|
||||
},
|
||||
"InfluxDb": {
|
||||
"Url": "http://localhost:8086/",
|
||||
"Organization": "managing-org",
|
||||
"Token": "Fw2FPL2OwTzDHzSbR2Sd5xs0EKQYy00Q-hYKYAhr9cC1_q5YySONpxuf_Ck0PTjyUiF13xXmi__bu_pXH-H9zA=="
|
||||
},
|
||||
"PostgreSql": {
|
||||
"ConnectionString": "Host=localhost;Port=5432;Database=managing;Username=postgres;Password=postgres"
|
||||
},
|
||||
"Privy": {
|
||||
"AppId": "cm6f47n1l003jx7mjwaembhup",
|
||||
"AppSecret": "63Chz2z5M8TgR5qc8dznSLRAGTHTyPU4cjdQobrBF1Cx5tszZpTuFgyrRd7hZ2k6HpwDz3GEwQZzsCqHb8Z311bF"
|
||||
@@ -39,5 +38,6 @@
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"WorkerBotManager": true,
|
||||
"WorkerBalancesTracking": true
|
||||
"WorkerBalancesTracking": false,
|
||||
"WorkerNotifyBundleBacktest": true
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"ManagingDatabase": {
|
||||
"ConnectionString": "mongodb://admin:vgRehYTdhghDR@srv-captain--mongo:27017/?authMechanism=SCRAM-SHA-256",
|
||||
"DatabaseName": "ManagingDb"
|
||||
"PostgreSql": {
|
||||
"ConnectionString": "Host=apps.prod.live;Port=5432;Database=managing;Username=postgres;Password=postgres"
|
||||
},
|
||||
"InfluxDb": {
|
||||
"Url": "https://influx-db.apps.managing.live",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"ManagingDatabase": {
|
||||
"ConnectionString": "mongodb://admin:r8oJiDIKbsEi@srv-captain--mongo-db:27017/?authMechanism=SCRAM-SHA-256",
|
||||
"DatabaseName": "ManagingDb"
|
||||
"PostgreSql": {
|
||||
"ConnectionString": "Host=managing-postgre.apps.managing.live;Port=5432;Database=managing;Username=postgres;Password=29032b13a5bc4d37"
|
||||
},
|
||||
"InfluxDb": {
|
||||
"Url": "http://srv-captain--influx-db:8086/",
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
{
|
||||
"ManagingDatabase": {
|
||||
"ConnectionString": "mongodb://admin:r8oJiDIKbsEi@mongo-db.apps.managing.live:27017/?authMechanism=SCRAM-SHA-256",
|
||||
"DatabaseName": "ManagingDb"
|
||||
},
|
||||
"InfluxDb": {
|
||||
"Url": "https://influx-db.apps.managing.live",
|
||||
"Organization": "managing-org",
|
||||
@@ -12,6 +8,9 @@
|
||||
"AppId": "cm6f47n1l003jx7mjwaembhup",
|
||||
"AppSecret": "63Chz2z5M8TgR5qc8dznSLRAGTHTyPU4cjdQobrBF1Cx5tszZpTuFgyrRd7hZ2k6HpwDz3GEwQZzsCqHb8Z311bF"
|
||||
},
|
||||
"PostgreSql": {
|
||||
"ConnectionString": "Host=managing-postgre.apps.managing.live;Port=5432;Database=managing;Username=postgres;Password=29032b13a5bc4d37"
|
||||
},
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
|
||||
@@ -12,9 +12,8 @@
|
||||
"Jwt": {
|
||||
"Secret": "2ed5f490-b6c1-4cad-8824-840c911f1fe6"
|
||||
},
|
||||
"ManagingDatabase": {
|
||||
"ConnectionString": "mongodb://managingdb",
|
||||
"DatabaseName": "ManagingDb"
|
||||
"PostgreSql": {
|
||||
"ConnectionString": "Host=localhost;Port=5432;Database=managing;Username=postgres;Password=postgres"
|
||||
},
|
||||
"InfluxDb": {
|
||||
"Url": "http://influxdb:8086/",
|
||||
|
||||
Reference in New Issue
Block a user