Trading bot grain (#33)
* Trading bot Grain * Fix a bit more of the trading bot * Advance on the tradingbot grain * Fix build * Fix db script * Fix user login * Fix a bit backtest * Fix cooldown and backtest * start fixing bot start * Fix startup * Setup local db * Fix build and update candles and scenario * Add bot registry * Add reminder * Updateing the grains * fix bootstraping * Save stats on tick * Save bot data every tick * Fix serialization * fix save bot stats * Fix get candles * use dict instead of list for position * Switch hashset to dict * Fix a bit * Fix bot launch and bot view * add migrations * Remove the tolist * Add agent grain * Save agent summary * clean * Add save bot * Update get bots * Add get bots * Fix stop/restart * fix Update config * Update scanner table on new backtest saved * Fix backtestRowDetails.tsx * Fix agentIndex * Update agentIndex * Fix more things * Update user cache * Fix * Fix account load/start/restart/run
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Managing.Api.Authorization;
|
||||
|
||||
|
||||
public class JwtMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
@@ -14,7 +13,21 @@ public class JwtMiddleware
|
||||
|
||||
public async Task Invoke(HttpContext context, IUserService userService, IJwtUtils jwtUtils)
|
||||
{
|
||||
if (context.Request.Path.StartsWithSegments("/User/create-token") ||
|
||||
context.Request.Path.StartsWithSegments("/swagger") ||
|
||||
context.Request.Path.StartsWithSegments("/health"))
|
||||
{
|
||||
await _next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
|
||||
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
throw new UnauthorizedAccessException("Authorization token is missing");
|
||||
}
|
||||
|
||||
var userId = jwtUtils.ValidateJwtToken(token);
|
||||
if (userId != null)
|
||||
{
|
||||
|
||||
@@ -340,7 +340,7 @@ public class BacktestController : BaseController
|
||||
// Convert IndicatorRequest objects to Indicator domain objects
|
||||
foreach (var indicatorRequest in request.Config.Scenario.Indicators)
|
||||
{
|
||||
var indicator = new Indicator(indicatorRequest.Name, indicatorRequest.Type)
|
||||
var indicator = new IndicatorBase(indicatorRequest.Name, indicatorRequest.Type)
|
||||
{
|
||||
SignalType = indicatorRequest.SignalType,
|
||||
MinimumHistory = indicatorRequest.MinimumHistory,
|
||||
@@ -706,7 +706,6 @@ public class BacktestController : BaseController
|
||||
}
|
||||
|
||||
|
||||
|
||||
public MoneyManagement Map(MoneyManagementRequest moneyManagementRequest)
|
||||
{
|
||||
return new MoneyManagement
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
||||
using Managing.Api.Models.Requests;
|
||||
using Managing.Api.Models.Responses;
|
||||
using Managing.Application.Abstractions;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Application.Hubs;
|
||||
using Managing.Application.ManageBot.Commands;
|
||||
@@ -8,7 +7,6 @@ using Managing.Domain.Backtests;
|
||||
using Managing.Domain.Bots;
|
||||
using Managing.Domain.Candles;
|
||||
using Managing.Domain.Scenarios;
|
||||
using Managing.Domain.Shared.Helpers;
|
||||
using Managing.Domain.Statistics;
|
||||
using Managing.Domain.Strategies;
|
||||
using Managing.Domain.Strategies.Base;
|
||||
@@ -244,7 +242,7 @@ public class DataController : ControllerBase
|
||||
{
|
||||
return Ok(new CandlesWithIndicatorsResponse
|
||||
{
|
||||
Candles = new List<Candle>(),
|
||||
Candles = new HashSet<Candle>(),
|
||||
IndicatorsValues = new Dictionary<IndicatorType, IndicatorsResultBase>()
|
||||
});
|
||||
}
|
||||
@@ -290,8 +288,8 @@ public class DataController : ControllerBase
|
||||
}
|
||||
|
||||
// Get active bots
|
||||
var activeBots = await _mediator.Send(new GetActiveBotsCommand());
|
||||
var currentCount = activeBots.Count;
|
||||
var activeBots = await _mediator.Send(new GetBotsByStatusCommand(BotStatus.Up));
|
||||
var currentCount = activeBots.Count();
|
||||
|
||||
// Get previous count from cache
|
||||
var previousCount = _cacheService.GetValue<int>(previousCountKey);
|
||||
@@ -343,11 +341,11 @@ public class DataController : ControllerBase
|
||||
}
|
||||
|
||||
// Get active bots
|
||||
var activeBots = await _mediator.Send(new GetActiveBotsCommand());
|
||||
var activeBots = await _mediator.Send(new GetBotsByStatusCommand(BotStatus.Up));
|
||||
|
||||
// Calculate PnL for each bot once and store in a list of tuples
|
||||
var botsWithPnL = activeBots
|
||||
.Select(bot => new { Bot = bot, PnL = bot.GetProfitAndLoss() })
|
||||
.Select(bot => new { Bot = bot, PnL = bot.Pnl })
|
||||
.OrderByDescending(item => item.PnL)
|
||||
.Take(3)
|
||||
.ToList();
|
||||
@@ -441,55 +439,42 @@ public class DataController : ControllerBase
|
||||
/// </summary>
|
||||
/// <param name="strategy">The trading bot to map</param>
|
||||
/// <returns>A view model with detailed strategy information</returns>
|
||||
private UserStrategyDetailsViewModel MapStrategyToViewModel(ITradingBot strategy)
|
||||
private UserStrategyDetailsViewModel MapStrategyToViewModel(Bot strategy)
|
||||
{
|
||||
// Get the runtime directly from the bot
|
||||
TimeSpan runtimeSpan = strategy.GetRuntime();
|
||||
|
||||
// Get the startup time from the bot's internal property
|
||||
// If bot is not running, we use MinValue as a placeholder
|
||||
DateTime startupTime = DateTime.MinValue;
|
||||
if (strategy is Bot bot && bot.StartupTime != DateTime.MinValue)
|
||||
{
|
||||
startupTime = bot.StartupTime;
|
||||
}
|
||||
|
||||
// Calculate ROI percentage based on PnL relative to account value
|
||||
decimal pnl = strategy.GetProfitAndLoss();
|
||||
decimal pnl = strategy.Pnl;
|
||||
|
||||
// If we had initial investment amount, we could calculate ROI like:
|
||||
decimal initialInvestment = 1000; // Example placeholder, ideally should come from the account
|
||||
decimal roi = pnl != 0 ? (pnl / initialInvestment) * 100 : 0;
|
||||
|
||||
// Calculate volume statistics
|
||||
decimal totalVolume = TradingBox.GetTotalVolumeTraded(strategy.Positions);
|
||||
decimal volumeLast24h = TradingBox.GetLast24HVolumeTraded(strategy.Positions);
|
||||
decimal totalVolume = strategy.Volume;
|
||||
decimal volumeLast24h = strategy.Volume;
|
||||
|
||||
// Calculate win/loss statistics
|
||||
(int wins, int losses) = TradingBox.GetWinLossCount(strategy.Positions);
|
||||
(int wins, int losses) = (strategy.TradeWins, strategy.TradeLosses);
|
||||
|
||||
int winRate = wins + losses > 0 ? (wins * 100) / (wins + losses) : 0;
|
||||
// Calculate ROI for last 24h
|
||||
decimal roiLast24h = TradingBox.GetLast24HROI(strategy.Positions);
|
||||
decimal roiLast24h = strategy.Roi;
|
||||
|
||||
return new UserStrategyDetailsViewModel
|
||||
{
|
||||
Name = strategy.Name,
|
||||
ScenarioName = strategy.Config.ScenarioName,
|
||||
State = strategy.GetStatus() == BotStatus.Up.ToString() ? "RUNNING" :
|
||||
strategy.GetStatus() == BotStatus.Down.ToString() ? "STOPPED" : "UNUSED",
|
||||
State = strategy.Status.ToString(),
|
||||
PnL = pnl,
|
||||
ROIPercentage = roi,
|
||||
ROILast24H = roiLast24h,
|
||||
Runtime = startupTime,
|
||||
WinRate = strategy.GetWinRate(),
|
||||
Runtime = strategy.StartupTime,
|
||||
WinRate = winRate,
|
||||
TotalVolumeTraded = totalVolume,
|
||||
VolumeLast24H = volumeLast24h,
|
||||
Wins = wins,
|
||||
Losses = losses,
|
||||
Positions = strategy.Positions.OrderByDescending(p => p.Date)
|
||||
.ToList(), // Include sorted positions with most recent first
|
||||
Identifier = strategy.Identifier,
|
||||
WalletBalances = strategy.WalletBalances,
|
||||
Positions = new Dictionary<Guid, Position>(),
|
||||
Identifier = strategy.Identifier.ToString(),
|
||||
WalletBalances = new Dictionary<DateTime, decimal>(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -544,18 +529,17 @@ public class DataController : ControllerBase
|
||||
continue; // Skip agents with no strategies
|
||||
}
|
||||
|
||||
// Combine all positions from all strategies
|
||||
var allPositions = strategies.SelectMany<ITradingBot, Position>(s => s.Positions).ToList();
|
||||
// TODO: Add this calculation into repository for better performance
|
||||
|
||||
var globalPnL = strategies.Sum(s => s.Pnl);
|
||||
var globalVolume = strategies.Sum(s => s.Volume);
|
||||
var globalVolumeLast24h = strategies.Sum(s => s.Volume);
|
||||
|
||||
// Calculate agent metrics for platform totals
|
||||
decimal totalPnL = TradingBox.GetPnLInTimeRange(allPositions, timeFilter);
|
||||
decimal totalVolume = TradingBox.GetTotalVolumeTraded(allPositions);
|
||||
decimal volumeLast24h = TradingBox.GetLast24HVolumeTraded(allPositions);
|
||||
|
||||
// Add to platform totals
|
||||
totalPlatformPnL += totalPnL;
|
||||
totalPlatformVolume += totalVolume;
|
||||
totalPlatformVolumeLast24h += volumeLast24h;
|
||||
totalPlatformPnL += globalPnL;
|
||||
totalPlatformVolume += globalVolume;
|
||||
totalPlatformVolumeLast24h += globalVolumeLast24h;
|
||||
}
|
||||
|
||||
// Set the platform totals
|
||||
@@ -569,128 +553,25 @@ public class DataController : ControllerBase
|
||||
return Ok(summary);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a list of agent summaries for the agent index page
|
||||
/// </summary>
|
||||
/// <param name="timeFilter">Time filter to apply (24H, 3D, 1W, 1M, 1Y, Total)</param>
|
||||
/// <returns>A list of agent summaries sorted by performance</returns>
|
||||
[HttpGet("GetAgentIndex")]
|
||||
public async Task<ActionResult<AgentIndexViewModel>> GetAgentIndex(string timeFilter = "Total")
|
||||
{
|
||||
// Validate time filter
|
||||
var validTimeFilters = new[] { "24H", "3D", "1W", "1M", "1Y", "Total" };
|
||||
if (!validTimeFilters.Contains(timeFilter))
|
||||
{
|
||||
timeFilter = "Total"; // Default to Total if invalid
|
||||
}
|
||||
|
||||
string cacheKey = $"AgentIndex_{timeFilter}";
|
||||
|
||||
// Check if the agent index is already cached
|
||||
var cachedIndex = _cacheService.GetValue<AgentIndexViewModel>(cacheKey);
|
||||
|
||||
if (cachedIndex != null)
|
||||
{
|
||||
return Ok(cachedIndex);
|
||||
}
|
||||
|
||||
// Get all agents and their strategies
|
||||
var agentsWithStrategies = await _mediator.Send(new GetAllAgentsCommand(timeFilter));
|
||||
|
||||
// Create the agent index response
|
||||
var agentIndex = new AgentIndexViewModel
|
||||
{
|
||||
TimeFilter = timeFilter
|
||||
};
|
||||
|
||||
// Create summaries for each agent
|
||||
foreach (var agent in agentsWithStrategies)
|
||||
{
|
||||
var user = agent.Key;
|
||||
var strategies = agent.Value;
|
||||
|
||||
if (strategies.Count == 0)
|
||||
{
|
||||
continue; // Skip agents with no strategies
|
||||
}
|
||||
|
||||
// Combine all positions from all strategies
|
||||
var allPositions = strategies.SelectMany<ITradingBot, Position>(s => s.Positions).ToList();
|
||||
|
||||
// Calculate agent metrics
|
||||
decimal totalPnL = TradingBox.GetPnLInTimeRange(allPositions, timeFilter);
|
||||
decimal pnlLast24h = TradingBox.GetPnLInTimeRange(allPositions, "24H");
|
||||
|
||||
decimal totalROI = TradingBox.GetROIInTimeRange(allPositions, timeFilter);
|
||||
decimal roiLast24h = TradingBox.GetROIInTimeRange(allPositions, "24H");
|
||||
|
||||
(int wins, int losses) = TradingBox.GetWinLossCountInTimeRange(allPositions, timeFilter);
|
||||
|
||||
// Calculate trading volumes
|
||||
decimal totalVolume = TradingBox.GetTotalVolumeTraded(allPositions);
|
||||
decimal volumeLast24h = TradingBox.GetLast24HVolumeTraded(allPositions);
|
||||
|
||||
// Calculate win rate
|
||||
int averageWinRate = 0;
|
||||
if (wins + losses > 0)
|
||||
{
|
||||
averageWinRate = (wins * 100) / (wins + losses);
|
||||
}
|
||||
|
||||
// Add to agent summaries
|
||||
var agentSummary = new AgentSummaryViewModel
|
||||
{
|
||||
AgentName = user.AgentName,
|
||||
TotalPnL = totalPnL,
|
||||
PnLLast24h = pnlLast24h,
|
||||
TotalROI = totalROI,
|
||||
ROILast24h = roiLast24h,
|
||||
Wins = wins,
|
||||
Losses = losses,
|
||||
AverageWinRate = averageWinRate,
|
||||
ActiveStrategiesCount = strategies.Count,
|
||||
TotalVolume = totalVolume,
|
||||
VolumeLast24h = volumeLast24h
|
||||
};
|
||||
|
||||
agentIndex.AgentSummaries.Add(agentSummary);
|
||||
}
|
||||
|
||||
// Sort agent summaries by total PnL (highest first)
|
||||
agentIndex.AgentSummaries = agentIndex.AgentSummaries.OrderByDescending(a => a.TotalPnL).ToList();
|
||||
|
||||
// Cache the results for 5 minutes
|
||||
_cacheService.SaveValue(cacheKey, agentIndex, TimeSpan.FromMinutes(5));
|
||||
|
||||
return Ok(agentIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a paginated list of agent summaries for the agent index page
|
||||
/// </summary>
|
||||
/// <param name="timeFilter">Time filter to apply (24H, 3D, 1W, 1M, 1Y, Total)</param>
|
||||
/// <param name="page">Page number (defaults to 1)</param>
|
||||
/// <param name="pageSize">Number of items per page (defaults to 10, max 100)</param>
|
||||
/// <param name="sortBy">Field to sort by (TotalPnL, PnLLast24h, TotalROI, ROILast24h, Wins, Losses, AverageWinRate, ActiveStrategiesCount, TotalVolume, VolumeLast24h)</param>
|
||||
/// <param name="sortBy">Field to sort by (TotalPnL, TotalROI, Wins, Losses, AgentName, CreatedAt, UpdatedAt)</param>
|
||||
/// <param name="sortOrder">Sort order - "asc" or "desc" (defaults to "desc")</param>
|
||||
/// <param name="agentNames">Optional comma-separated list of agent names to filter by</param>
|
||||
/// <returns>A paginated list of agent summaries sorted by the specified field</returns>
|
||||
[HttpGet("GetAgentIndexPaginated")]
|
||||
public async Task<ActionResult<PaginatedAgentIndexResponse>> GetAgentIndexPaginated(
|
||||
string timeFilter = "Total",
|
||||
int page = 1,
|
||||
int pageSize = 10,
|
||||
string sortBy = "TotalPnL",
|
||||
SortableFields sortBy = SortableFields.TotalPnL,
|
||||
string sortOrder = "desc",
|
||||
string? agentNames = null)
|
||||
{
|
||||
// Validate time filter
|
||||
var validTimeFilters = new[] { "24H", "3D", "1W", "1M", "1Y", "Total" };
|
||||
if (!validTimeFilters.Contains(timeFilter))
|
||||
{
|
||||
timeFilter = "Total"; // Default to Total if invalid
|
||||
}
|
||||
|
||||
// Validate pagination parameters
|
||||
if (page < 1)
|
||||
{
|
||||
@@ -708,177 +589,59 @@ public class DataController : ControllerBase
|
||||
return BadRequest("Sort order must be 'asc' or 'desc'");
|
||||
}
|
||||
|
||||
// Validate sort by field
|
||||
var validSortFields = new[]
|
||||
{
|
||||
"TotalPnL", "PnLLast24h", "TotalROI", "ROILast24h", "Wins", "Losses", "AverageWinRate",
|
||||
"ActiveStrategiesCount", "TotalVolume", "VolumeLast24h"
|
||||
};
|
||||
if (!validSortFields.Contains(sortBy))
|
||||
{
|
||||
sortBy = "TotalPnL"; // Default to TotalPnL if invalid
|
||||
}
|
||||
|
||||
// Create cache key that includes agent names filter
|
||||
var agentNamesForCache = !string.IsNullOrWhiteSpace(agentNames)
|
||||
? string.Join("_", agentNames.Split(',', StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(name => name.Trim())
|
||||
.Where(name => !string.IsNullOrWhiteSpace(name))
|
||||
.OrderBy(name => name))
|
||||
: "all";
|
||||
string cacheKey = $"AgentIndex_{timeFilter}_{agentNamesForCache}";
|
||||
|
||||
// Check if the agent index is already cached
|
||||
var cachedIndex = _cacheService.GetValue<AgentIndexViewModel>(cacheKey);
|
||||
|
||||
List<AgentSummaryViewModel> allAgentSummaries;
|
||||
|
||||
if (cachedIndex != null)
|
||||
{
|
||||
allAgentSummaries = cachedIndex.AgentSummaries.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get all agents and their strategies
|
||||
var agentsWithStrategies = await _mediator.Send(new GetAllAgentsCommand(timeFilter));
|
||||
|
||||
allAgentSummaries = new List<AgentSummaryViewModel>();
|
||||
|
||||
// Create summaries for each agent
|
||||
foreach (var agent in agentsWithStrategies)
|
||||
{
|
||||
var user = agent.Key;
|
||||
var strategies = agent.Value;
|
||||
|
||||
if (strategies.Count == 0)
|
||||
{
|
||||
continue; // Skip agents with no strategies
|
||||
}
|
||||
|
||||
// Combine all positions from all strategies
|
||||
var allPositions = strategies.SelectMany<ITradingBot, Position>(s => s.Positions).ToList();
|
||||
|
||||
// Calculate agent metrics
|
||||
decimal totalPnL = TradingBox.GetPnLInTimeRange(allPositions, timeFilter);
|
||||
decimal pnlLast24h = TradingBox.GetPnLInTimeRange(allPositions, "24H");
|
||||
|
||||
decimal totalROI = TradingBox.GetROIInTimeRange(allPositions, timeFilter);
|
||||
decimal roiLast24h = TradingBox.GetROIInTimeRange(allPositions, "24H");
|
||||
|
||||
(int wins, int losses) = TradingBox.GetWinLossCountInTimeRange(allPositions, timeFilter);
|
||||
|
||||
// Calculate trading volumes
|
||||
decimal totalVolume = TradingBox.GetTotalVolumeTraded(allPositions);
|
||||
decimal volumeLast24h = TradingBox.GetLast24HVolumeTraded(allPositions);
|
||||
|
||||
// Calculate win rate
|
||||
int averageWinRate = 0;
|
||||
if (wins + losses > 0)
|
||||
{
|
||||
averageWinRate = (wins * 100) / (wins + losses);
|
||||
}
|
||||
|
||||
// Add to agent summaries
|
||||
var agentSummary = new AgentSummaryViewModel
|
||||
{
|
||||
AgentName = user.AgentName,
|
||||
TotalPnL = totalPnL,
|
||||
PnLLast24h = pnlLast24h,
|
||||
TotalROI = totalROI,
|
||||
ROILast24h = roiLast24h,
|
||||
Wins = wins,
|
||||
Losses = losses,
|
||||
AverageWinRate = averageWinRate,
|
||||
ActiveStrategiesCount = strategies.Count,
|
||||
TotalVolume = totalVolume,
|
||||
VolumeLast24h = volumeLast24h
|
||||
};
|
||||
|
||||
allAgentSummaries.Add(agentSummary);
|
||||
}
|
||||
|
||||
// Cache the results for 5 minutes
|
||||
var agentIndex = new AgentIndexViewModel
|
||||
{
|
||||
TimeFilter = timeFilter,
|
||||
AgentSummaries = allAgentSummaries
|
||||
};
|
||||
_cacheService.SaveValue(cacheKey, agentIndex, TimeSpan.FromMinutes(5));
|
||||
}
|
||||
|
||||
// Apply agent name filtering if specified
|
||||
// Parse agent names filter
|
||||
IEnumerable<string>? agentNamesList = null;
|
||||
if (!string.IsNullOrWhiteSpace(agentNames))
|
||||
{
|
||||
var agentNameList = agentNames.Split(',', StringSplitOptions.RemoveEmptyEntries)
|
||||
agentNamesList = agentNames.Split(',', StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(name => name.Trim())
|
||||
.Where(name => !string.IsNullOrWhiteSpace(name))
|
||||
.ToList();
|
||||
|
||||
if (agentNameList.Any())
|
||||
{
|
||||
allAgentSummaries = allAgentSummaries
|
||||
.Where(agent => agentNameList.Contains(agent.AgentName, StringComparer.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
// Apply sorting
|
||||
var sortedSummaries = sortBy switch
|
||||
// Get paginated results from database
|
||||
var command = new GetPaginatedAgentSummariesCommand(page, pageSize, sortBy, sortOrder, agentNamesList);
|
||||
var result = await _mediator.Send(command);
|
||||
var agentSummaries = result.Results;
|
||||
var totalCount = result.TotalCount;
|
||||
|
||||
// Map to view models
|
||||
var agentSummaryViewModels = new List<AgentSummaryViewModel>();
|
||||
foreach (var agentSummary in agentSummaries)
|
||||
{
|
||||
"TotalPnL" => sortOrder == "desc"
|
||||
? allAgentSummaries.OrderByDescending(a => a.TotalPnL)
|
||||
: allAgentSummaries.OrderBy(a => a.TotalPnL),
|
||||
"PnLLast24h" => sortOrder == "desc"
|
||||
? allAgentSummaries.OrderByDescending(a => a.PnLLast24h)
|
||||
: allAgentSummaries.OrderBy(a => a.PnLLast24h),
|
||||
"TotalROI" => sortOrder == "desc"
|
||||
? allAgentSummaries.OrderByDescending(a => a.TotalROI)
|
||||
: allAgentSummaries.OrderBy(a => a.TotalROI),
|
||||
"ROILast24h" => sortOrder == "desc"
|
||||
? allAgentSummaries.OrderByDescending(a => a.ROILast24h)
|
||||
: allAgentSummaries.OrderBy(a => a.ROILast24h),
|
||||
"Wins" => sortOrder == "desc"
|
||||
? allAgentSummaries.OrderByDescending(a => a.Wins)
|
||||
: allAgentSummaries.OrderBy(a => a.Wins),
|
||||
"Losses" => sortOrder == "desc"
|
||||
? allAgentSummaries.OrderByDescending(a => a.Losses)
|
||||
: allAgentSummaries.OrderBy(a => a.Losses),
|
||||
"AverageWinRate" => sortOrder == "desc"
|
||||
? allAgentSummaries.OrderByDescending(a => a.AverageWinRate)
|
||||
: allAgentSummaries.OrderBy(a => a.AverageWinRate),
|
||||
"ActiveStrategiesCount" => sortOrder == "desc"
|
||||
? allAgentSummaries.OrderByDescending(a => a.ActiveStrategiesCount)
|
||||
: allAgentSummaries.OrderBy(a => a.ActiveStrategiesCount),
|
||||
"TotalVolume" => sortOrder == "desc"
|
||||
? allAgentSummaries.OrderByDescending(a => a.TotalVolume)
|
||||
: allAgentSummaries.OrderBy(a => a.TotalVolume),
|
||||
"VolumeLast24h" => sortOrder == "desc"
|
||||
? allAgentSummaries.OrderByDescending(a => a.VolumeLast24h)
|
||||
: allAgentSummaries.OrderBy(a => a.VolumeLast24h),
|
||||
_ => sortOrder == "desc"
|
||||
? allAgentSummaries.OrderByDescending(a => a.TotalPnL)
|
||||
: allAgentSummaries.OrderBy(a => a.TotalPnL)
|
||||
};
|
||||
// Calculate win rate
|
||||
int averageWinRate = 0;
|
||||
if (agentSummary.Wins + agentSummary.Losses > 0)
|
||||
{
|
||||
averageWinRate = (agentSummary.Wins * 100) / (agentSummary.Wins + agentSummary.Losses);
|
||||
}
|
||||
|
||||
// Map to view model
|
||||
var agentSummaryViewModel = new AgentSummaryViewModel
|
||||
{
|
||||
AgentName = agentSummary.AgentName,
|
||||
TotalPnL = agentSummary.TotalPnL,
|
||||
TotalROI = agentSummary.TotalROI,
|
||||
Wins = agentSummary.Wins,
|
||||
Losses = agentSummary.Losses,
|
||||
ActiveStrategiesCount = agentSummary.ActiveStrategiesCount,
|
||||
TotalVolume = agentSummary.TotalVolume,
|
||||
};
|
||||
|
||||
agentSummaryViewModels.Add(agentSummaryViewModel);
|
||||
}
|
||||
|
||||
var totalCount = allAgentSummaries.Count;
|
||||
var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize);
|
||||
|
||||
// Apply pagination
|
||||
var paginatedSummaries = sortedSummaries
|
||||
.Skip((page - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToList();
|
||||
|
||||
var response = new PaginatedAgentIndexResponse
|
||||
{
|
||||
AgentSummaries = paginatedSummaries,
|
||||
AgentSummaries = agentSummaryViewModels,
|
||||
TotalCount = totalCount,
|
||||
CurrentPage = page,
|
||||
PageSize = pageSize,
|
||||
TotalPages = totalPages,
|
||||
HasNextPage = page < totalPages,
|
||||
HasPreviousPage = page > 1,
|
||||
TimeFilter = timeFilter,
|
||||
SortBy = sortBy,
|
||||
SortOrder = sortOrder,
|
||||
FilteredAgentNames = agentNames
|
||||
@@ -970,7 +733,7 @@ public class DataController : ControllerBase
|
||||
|
||||
foreach (var indicatorRequest in scenarioRequest.Indicators)
|
||||
{
|
||||
var indicator = new Indicator(indicatorRequest.Name, indicatorRequest.Type)
|
||||
var indicator = new IndicatorBase(indicatorRequest.Name, indicatorRequest.Type)
|
||||
{
|
||||
SignalType = indicatorRequest.SignalType,
|
||||
MinimumHistory = indicatorRequest.MinimumHistory,
|
||||
|
||||
@@ -197,23 +197,23 @@ public class ScenarioController : BaseController
|
||||
};
|
||||
}
|
||||
|
||||
private static IndicatorViewModel MapToIndicatorViewModel(Indicator indicator)
|
||||
private static IndicatorViewModel MapToIndicatorViewModel(IndicatorBase indicatorBase)
|
||||
{
|
||||
return new IndicatorViewModel
|
||||
{
|
||||
Name = indicator.Name,
|
||||
Type = indicator.Type,
|
||||
SignalType = indicator.SignalType,
|
||||
MinimumHistory = indicator.MinimumHistory,
|
||||
Period = indicator.Period,
|
||||
FastPeriods = indicator.FastPeriods,
|
||||
SlowPeriods = indicator.SlowPeriods,
|
||||
SignalPeriods = indicator.SignalPeriods,
|
||||
Multiplier = indicator.Multiplier,
|
||||
SmoothPeriods = indicator.SmoothPeriods,
|
||||
StochPeriods = indicator.StochPeriods,
|
||||
CyclePeriods = indicator.CyclePeriods,
|
||||
UserName = indicator.User?.Name
|
||||
Name = indicatorBase.Name,
|
||||
Type = indicatorBase.Type,
|
||||
SignalType = indicatorBase.SignalType,
|
||||
MinimumHistory = indicatorBase.MinimumHistory,
|
||||
Period = indicatorBase.Period,
|
||||
FastPeriods = indicatorBase.FastPeriods,
|
||||
SlowPeriods = indicatorBase.SlowPeriods,
|
||||
SignalPeriods = indicatorBase.SignalPeriods,
|
||||
Multiplier = indicatorBase.Multiplier,
|
||||
SmoothPeriods = indicatorBase.SmoothPeriods,
|
||||
StochPeriods = indicatorBase.StochPeriods,
|
||||
CyclePeriods = indicatorBase.CyclePeriods,
|
||||
UserName = indicatorBase.User?.Name
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ public class TradingController : BaseController
|
||||
/// <param name="identifier">The unique identifier of the position to close.</param>
|
||||
/// <returns>The closed position.</returns>
|
||||
[HttpPost("ClosePosition")]
|
||||
public async Task<ActionResult<Position>> ClosePosition(string identifier)
|
||||
public async Task<ActionResult<Position>> ClosePosition(Guid identifier)
|
||||
{
|
||||
var position = await _tradingService.GetPositionByIdentifierAsync(identifier);
|
||||
var result = await _closeTradeCommandHandler.Handle(new ClosePositionCommand(position));
|
||||
|
||||
@@ -26,7 +26,8 @@ public class UserController : BaseController
|
||||
/// <param name="userService">Service for user-related operations.</param>
|
||||
/// <param name="jwtUtils">Utility for JWT token operations.</param>
|
||||
/// <param name="webhookService">Service for webhook operations.</param>
|
||||
public UserController(IConfiguration config, IUserService userService, IJwtUtils jwtUtils, IWebhookService webhookService)
|
||||
public UserController(IConfiguration config, IUserService userService, IJwtUtils jwtUtils,
|
||||
IWebhookService webhookService)
|
||||
: base(userService)
|
||||
{
|
||||
_config = config;
|
||||
@@ -40,7 +41,7 @@ public class UserController : BaseController
|
||||
/// <param name="login">The login request containing user credentials.</param>
|
||||
/// <returns>A JWT token if authentication is successful; otherwise, an Unauthorized result.</returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost]
|
||||
[HttpPost("create-token")]
|
||||
public async Task<ActionResult<string>> CreateToken([FromBody] LoginRequest login)
|
||||
{
|
||||
var user = await _userService.Authenticate(login.Name, login.Address, login.Message, login.Signature);
|
||||
@@ -52,16 +53,18 @@ public class UserController : BaseController
|
||||
}
|
||||
|
||||
return Unauthorized();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current user's information.
|
||||
/// </summary>
|
||||
/// <returns>The current user's information.</returns>
|
||||
[Authorize]
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<User>> GetCurrentUser()
|
||||
{
|
||||
var user = await base.GetUser();
|
||||
user = await _userService.GetUserByName(user.Name);
|
||||
return Ok(user);
|
||||
}
|
||||
|
||||
@@ -70,6 +73,7 @@ public class UserController : BaseController
|
||||
/// </summary>
|
||||
/// <param name="agentName">The new agent name to set.</param>
|
||||
/// <returns>The updated user with the new agent name.</returns>
|
||||
[Authorize]
|
||||
[HttpPut("agent-name")]
|
||||
public async Task<ActionResult<User>> UpdateAgentName([FromBody] string agentName)
|
||||
{
|
||||
@@ -83,6 +87,7 @@ public class UserController : BaseController
|
||||
/// </summary>
|
||||
/// <param name="avatarUrl">The new avatar URL to set.</param>
|
||||
/// <returns>The updated user with the new avatar URL.</returns>
|
||||
[Authorize]
|
||||
[HttpPut("avatar")]
|
||||
public async Task<ActionResult<User>> UpdateAvatarUrl([FromBody] string avatarUrl)
|
||||
{
|
||||
@@ -96,35 +101,37 @@ public class UserController : BaseController
|
||||
/// </summary>
|
||||
/// <param name="telegramChannel">The new Telegram channel to set.</param>
|
||||
/// <returns>The updated user with the new Telegram channel.</returns>
|
||||
[Authorize]
|
||||
[HttpPut("telegram-channel")]
|
||||
public async Task<ActionResult<User>> UpdateTelegramChannel([FromBody] string telegramChannel)
|
||||
{
|
||||
var user = await GetUser();
|
||||
var updatedUser = await _userService.UpdateTelegramChannel(user, telegramChannel);
|
||||
|
||||
|
||||
// Send welcome message to the newly configured telegram channel
|
||||
if (!string.IsNullOrEmpty(telegramChannel))
|
||||
{
|
||||
try
|
||||
{
|
||||
var welcomeMessage = $"🎉 **Trading Bot - Welcome!**\n\n" +
|
||||
$"🎯 **Agent:** {user.Name}\n" +
|
||||
$"📡 **Channel ID:** {telegramChannel}\n" +
|
||||
$"⏰ **Setup Time:** {DateTime.UtcNow:MMM dd, yyyy • HH:mm:ss} UTC\n\n" +
|
||||
$"🔔 **Notification Types:**\n" +
|
||||
$"• 📈 Position Opens & Closes\n" +
|
||||
$"• 🤖 Bot configuration changes\n\n" +
|
||||
$"🚀 **Welcome aboard!** Your trading notifications are now live.";
|
||||
$"🎯 **Agent:** {user.Name}\n" +
|
||||
$"📡 **Channel ID:** {telegramChannel}\n" +
|
||||
$"⏰ **Setup Time:** {DateTime.UtcNow:MMM dd, yyyy • HH:mm:ss} UTC\n\n" +
|
||||
$"🔔 **Notification Types:**\n" +
|
||||
$"• 📈 Position Opens & Closes\n" +
|
||||
$"• 🤖 Bot configuration changes\n\n" +
|
||||
$"🚀 **Welcome aboard!** Your trading notifications are now live.";
|
||||
|
||||
await _webhookService.SendMessage(welcomeMessage, telegramChannel);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log the error but don't fail the update operation
|
||||
Console.WriteLine($"Failed to send welcome message to telegram channel {telegramChannel}: {ex.Message}");
|
||||
Console.WriteLine(
|
||||
$"Failed to send welcome message to telegram channel {telegramChannel}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return Ok(updatedUser);
|
||||
}
|
||||
|
||||
@@ -132,11 +139,12 @@ public class UserController : BaseController
|
||||
/// Tests the Telegram channel configuration by sending a test message.
|
||||
/// </summary>
|
||||
/// <returns>A message indicating the test result.</returns>
|
||||
[Authorize]
|
||||
[HttpPost("telegram-channel/test")]
|
||||
public async Task<ActionResult<string>> TestTelegramChannel()
|
||||
{
|
||||
var user = await GetUser();
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(user.TelegramChannel))
|
||||
{
|
||||
return BadRequest("No Telegram channel configured for this user. Please set a Telegram channel first.");
|
||||
@@ -144,7 +152,7 @@ public class UserController : BaseController
|
||||
|
||||
try
|
||||
{
|
||||
var testMessage = $"🚀 **Trading Bot - Channel Test**\n\n" +
|
||||
var testMessage = $"🚀 **Trading Bot - Channel Test**\n\n" +
|
||||
$"🎯 **Agent:** {user.Name}\n" +
|
||||
$"📡 **Channel ID:** {user.TelegramChannel}\n" +
|
||||
$"⏰ **Test Time:** {DateTime.UtcNow:MMM dd, yyyy • HH:mm:ss} UTC\n\n" +
|
||||
@@ -154,13 +162,13 @@ public class UserController : BaseController
|
||||
$"🎉 **Ready to trade!** Your notifications are now active.";
|
||||
|
||||
await _webhookService.SendMessage(testMessage, user.TelegramChannel);
|
||||
|
||||
return Ok($"Test message sent successfully to Telegram channel {user.TelegramChannel}. Please check your Telegram to verify delivery.");
|
||||
|
||||
return Ok(
|
||||
$"Test message sent successfully to Telegram channel {user.TelegramChannel}. Please check your Telegram to verify delivery.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return StatusCode(500, $"Failed to send test message: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
55
src/Managing.Api/Models/Requests/GetBotsPaginatedRequest.cs
Normal file
55
src/Managing.Api/Models/Requests/GetBotsPaginatedRequest.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Api.Models.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Request model for getting paginated bots with filtering and sorting
|
||||
/// </summary>
|
||||
public class GetBotsPaginatedRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Page number (1-based). Default is 1.
|
||||
/// </summary>
|
||||
public int PageNumber { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Number of items per page. Default is 10, maximum is 100.
|
||||
/// </summary>
|
||||
public int PageSize { get; set; } = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Filter by bot status. If null, returns bots of all statuses.
|
||||
/// </summary>
|
||||
public BotStatus? Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Filter by user ID. If null, returns bots for all users.
|
||||
/// </summary>
|
||||
public int? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Filter by bot name (partial match, case-insensitive). If null, no name filtering is applied.
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Filter by ticker (partial match, case-insensitive). If null, no ticker filtering is applied.
|
||||
/// </summary>
|
||||
public string? Ticker { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Filter by agent name (partial match, case-insensitive). If null, no agent name filtering is applied.
|
||||
/// </summary>
|
||||
public string? AgentName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sort field. Valid values: "Name", "Ticker", "Status", "CreateDate", "StartupTime", "Pnl", "WinRate", "AgentName".
|
||||
/// Default is "CreateDate".
|
||||
/// </summary>
|
||||
public string SortBy { get; set; } = "CreateDate";
|
||||
|
||||
/// <summary>
|
||||
/// Sort direction. Default is "Desc" (descending).
|
||||
/// </summary>
|
||||
public string SortDirection { get; set; } = "Desc";
|
||||
}
|
||||
@@ -13,7 +13,7 @@ public class UpdateBotConfigRequest
|
||||
/// The unique identifier of the bot to update
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Identifier { get; set; }
|
||||
public Guid Identifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The new trading bot configuration request
|
||||
|
||||
@@ -15,21 +15,11 @@ namespace Managing.Api.Models.Responses
|
||||
/// </summary>
|
||||
public decimal TotalPnL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Profit and loss in the last 24 hours in USD
|
||||
/// </summary>
|
||||
public decimal PnLLast24h { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total return on investment as a percentage
|
||||
/// </summary>
|
||||
public decimal TotalROI { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Return on investment in the last 24 hours as a percentage
|
||||
/// </summary>
|
||||
public decimal ROILast24h { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of winning trades
|
||||
/// </summary>
|
||||
@@ -40,10 +30,6 @@ namespace Managing.Api.Models.Responses
|
||||
/// </summary>
|
||||
public int Losses { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Average win rate as a percentage
|
||||
/// </summary>
|
||||
public int AverageWinRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of active strategies for this agent
|
||||
@@ -54,11 +40,6 @@ namespace Managing.Api.Models.Responses
|
||||
/// Total volume traded by this agent in USD
|
||||
/// </summary>
|
||||
public decimal TotalVolume { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Volume traded in the last 24 hours in USD
|
||||
/// </summary>
|
||||
public decimal VolumeLast24h { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -12,10 +12,11 @@ public class CandlesWithIndicatorsResponse
|
||||
/// <summary>
|
||||
/// The list of candles.
|
||||
/// </summary>
|
||||
public List<Candle> Candles { get; set; } = new List<Candle>();
|
||||
public HashSet<Candle> Candles { get; set; } = new HashSet<Candle>();
|
||||
|
||||
/// <summary>
|
||||
/// The calculated indicators values.
|
||||
/// </summary>
|
||||
public Dictionary<IndicatorType, IndicatorsResultBase> IndicatorsValues { get; set; } = new Dictionary<IndicatorType, IndicatorsResultBase>();
|
||||
}
|
||||
public Dictionary<IndicatorType, IndicatorsResultBase> IndicatorsValues { get; set; } =
|
||||
new Dictionary<IndicatorType, IndicatorsResultBase>();
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Api.Models.Responses;
|
||||
|
||||
/// <summary>
|
||||
@@ -48,7 +50,7 @@ public class PaginatedAgentIndexResponse
|
||||
/// <summary>
|
||||
/// Field used for sorting
|
||||
/// </summary>
|
||||
public string SortBy { get; set; } = "TotalPnL";
|
||||
public SortableFields SortBy { get; set; } = SortableFields.TotalPnL;
|
||||
|
||||
/// <summary>
|
||||
/// Sort order (asc or desc)
|
||||
|
||||
43
src/Managing.Api/Models/Responses/PaginatedResponse.cs
Normal file
43
src/Managing.Api/Models/Responses/PaginatedResponse.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
namespace Managing.Api.Models.Responses;
|
||||
|
||||
/// <summary>
|
||||
/// Generic pagination response model
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of items in the response</typeparam>
|
||||
public class PaginatedResponse<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// The items for the current page
|
||||
/// </summary>
|
||||
public List<T> Items { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Total number of items across all pages
|
||||
/// </summary>
|
||||
public int TotalCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current page number (1-based)
|
||||
/// </summary>
|
||||
public int PageNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of items per page
|
||||
/// </summary>
|
||||
public int PageSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total number of pages
|
||||
/// </summary>
|
||||
public int TotalPages { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether there is a previous page
|
||||
/// </summary>
|
||||
public bool HasPreviousPage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether there is a next page
|
||||
/// </summary>
|
||||
public bool HasNextPage { get; set; }
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Managing.Domain.Bots;
|
||||
using Managing.Domain.Candles;
|
||||
using Managing.Domain.Indicators;
|
||||
using Managing.Domain.Trades;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Api.Models.Responses
|
||||
{
|
||||
@@ -14,16 +15,16 @@ namespace Managing.Api.Models.Responses
|
||||
public string Status { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of signals generated by the bot
|
||||
/// Dictionary of signals generated by the bot, keyed by signal identifier
|
||||
/// </summary>
|
||||
[Required]
|
||||
public List<LightSignal> Signals { get; internal set; }
|
||||
public Dictionary<string, LightSignal> Signals { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of positions opened by the bot
|
||||
/// Dictionary of positions opened by the bot, keyed by position identifier
|
||||
/// </summary>
|
||||
[Required]
|
||||
public List<Position> Positions { get; internal set; }
|
||||
public Dictionary<Guid, Position> Positions { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Candles used by the bot for analysis
|
||||
@@ -55,12 +56,6 @@ namespace Managing.Api.Models.Responses
|
||||
[Required]
|
||||
public string AgentName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The full trading bot configuration
|
||||
/// </summary>
|
||||
[Required]
|
||||
public TradingBotConfig Config { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The time when the bot was created
|
||||
/// </summary>
|
||||
@@ -72,5 +67,13 @@ namespace Managing.Api.Models.Responses
|
||||
/// </summary>
|
||||
[Required]
|
||||
public DateTime StartupTime { get; internal set; }
|
||||
|
||||
[Required] public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ticker/symbol being traded by this bot
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Ticker Ticker { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -63,16 +63,12 @@ namespace Managing.Api.Models.Responses
|
||||
public int Losses { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of all positions executed by this strategy
|
||||
/// Dictionary of all positions executed by this strategy, keyed by position identifier
|
||||
/// </summary>
|
||||
public List<Position> Positions { get; set; } = new List<Position>();
|
||||
public Dictionary<Guid, Position> Positions { get; set; } = new Dictionary<Guid, Position>();
|
||||
|
||||
public string Identifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the scenario used by this strategy
|
||||
/// </summary>
|
||||
public string ScenarioName { get; set; }
|
||||
public Dictionary<DateTime, decimal> WalletBalances { get; set; }
|
||||
public Dictionary<DateTime, decimal> WalletBalances { get; set; } = new Dictionary<DateTime, decimal>();
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ using Managing.Api.Authorization;
|
||||
using Managing.Api.Filters;
|
||||
using Managing.Api.HealthChecks;
|
||||
using Managing.Application.Hubs;
|
||||
using Managing.Application.Workers;
|
||||
using Managing.Bootstrap;
|
||||
using Managing.Common;
|
||||
using Managing.Core.Middleawares;
|
||||
@@ -170,7 +169,7 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJw
|
||||
ValidateIssuerSigningKey = true
|
||||
};
|
||||
});
|
||||
builder.Services.AddAuthorization();
|
||||
|
||||
builder.Services.AddCors(o => o.AddPolicy("CorsPolicy", builder =>
|
||||
{
|
||||
builder
|
||||
@@ -233,12 +232,6 @@ builder.Services.AddSwaggerGen(options =>
|
||||
});
|
||||
|
||||
builder.WebHost.SetupDiscordBot();
|
||||
if (builder.Configuration.GetValue<bool>("EnableBotManager", false))
|
||||
{
|
||||
builder.Services.AddHostedService<BotManagerWorker>();
|
||||
}
|
||||
|
||||
// Workers are now registered in ApiBootstrap.cs
|
||||
|
||||
// App
|
||||
var app = builder.Build();
|
||||
@@ -288,5 +281,4 @@ app.UseEndpoints(endpoints =>
|
||||
});
|
||||
|
||||
|
||||
|
||||
app.Run();
|
||||
@@ -5,7 +5,8 @@
|
||||
"Token": "Fw2FPL2OwTzDHzSbR2Sd5xs0EKQYy00Q-hYKYAhr9cC1_q5YySONpxuf_Ck0PTjyUiF13xXmi__bu_pXH-H9zA=="
|
||||
},
|
||||
"PostgreSql": {
|
||||
"ConnectionString": "Host=localhost;Port=5432;Database=managing;Username=postgres;Password=postgres"
|
||||
"ConnectionString": "Host=localhost;Port=5432;Database=managing;Username=postgres;Password=postgres",
|
||||
"Orleans": "Host=localhost;Port=5432;Database=orleans;Username=postgres;Password=postgres"
|
||||
},
|
||||
"Privy": {
|
||||
"AppId": "cm6f47n1l003jx7mjwaembhup",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"PostgreSql": {
|
||||
"ConnectionString": "Host=apps.prod.live;Port=5432;Database=managing;Username=postgres;Password=postgres"
|
||||
"ConnectionString": "Host=managing-postgre.apps.managing.live;Port=5432;Database=managing;Username=postgres;Password=29032b13a5bc4d37",
|
||||
"Orleans": "Host=managing-postgre.apps.managing.live;Port=5432;Database=orleans;Username=postgres;Password=29032b13a5bc4d37"
|
||||
},
|
||||
"InfluxDb": {
|
||||
"Url": "https://influx-db.apps.managing.live",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"PostgreSql": {
|
||||
"ConnectionString": "Host=managing-postgre.apps.managing.live;Port=5432;Database=managing;Username=postgres;Password=29032b13a5bc4d37"
|
||||
"ConnectionString": "Host=managing-postgre.apps.managing.live;Port=5432;Database=managing;Username=postgres;Password=29032b13a5bc4d37",
|
||||
"Orleans": "Host=managing-postgre.apps.managing.live;Port=5432;Database=orleans;Username=postgres;Password=29032b13a5bc4d37"
|
||||
},
|
||||
"InfluxDb": {
|
||||
"Url": "http://srv-captain--influx-db:8086/",
|
||||
|
||||
Reference in New Issue
Block a user