From 16a56bd26c8e09e74c10ad9e2b86fe33f9f209f4 Mon Sep 17 00:00:00 2001 From: cryptooda Date: Sun, 28 Sep 2025 20:57:42 +0700 Subject: [PATCH] Add agent fees --- .../Controllers/DataController.cs | 3 +- .../Models/Responses/AgentSummaryViewModel.cs | 5 ++ .../Grains/IPlatformSummaryGrain.cs | 6 +++ .../AgentGrainTests.cs | 53 ++----------------- .../Bots/Grains/AgentGrain.cs | 26 ++++++--- .../Bots/Models/AgentGrainState.cs | 6 +++ .../Bots/TradingBotBase.cs | 23 ++++---- .../Grains/PlatformSummaryGrain.cs | 45 ++++++++++------ .../Commands/GetAllAgentSummariesCommand.cs | 8 +-- .../ManageBot/Commands/GetAllAgentsCommand.cs | 8 +-- .../GetAllAgentSummariesCommandHandler.cs | 23 -------- .../ManageBot/GetAllAgentsCommandHandler.cs | 24 --------- .../Handlers/OpenPositionCommandHandler.cs | 24 ++------- src/Managing.Application/Users/UserService.cs | 2 + src/Managing.Docker/docker-compose.local.yml | 4 +- .../Statistics/AgentSummary.cs | 3 ++ .../ManagingDbContextModelSnapshot.cs | 3 ++ .../PostgreSql/AgentSummaryRepository.cs | 5 +- .../PostgreSql/Entities/AgentSummaryEntity.cs | 1 + src/Managing.WebApp/package.json | 2 +- 20 files changed, 108 insertions(+), 166 deletions(-) diff --git a/src/Managing.Api/Controllers/DataController.cs b/src/Managing.Api/Controllers/DataController.cs index 7c2e42a2..5e3acfbb 100644 --- a/src/Managing.Api/Controllers/DataController.cs +++ b/src/Managing.Api/Controllers/DataController.cs @@ -391,7 +391,7 @@ public class DataController : ControllerBase try { // Get all agent summaries - var allAgentSummaries = await _mediator.Send(new GetAllAgentSummariesCommand("Total")); + var allAgentSummaries = await _mediator.Send(new GetAllAgentSummariesCommand()); // Filter agents with valid PnL data and order by PnL var agentsWithPnL = allAgentSummaries @@ -638,6 +638,7 @@ public class DataController : ControllerBase ActiveStrategiesCount = agentSummary.ActiveStrategiesCount, TotalVolume = agentSummary.TotalVolume, TotalBalance = agentSummary.TotalBalance, + TotalFees = agentSummary.TotalFees, }; agentSummaryViewModels.Add(agentSummaryViewModel); diff --git a/src/Managing.Api/Models/Responses/AgentSummaryViewModel.cs b/src/Managing.Api/Models/Responses/AgentSummaryViewModel.cs index b5c69553..98c71755 100644 --- a/src/Managing.Api/Models/Responses/AgentSummaryViewModel.cs +++ b/src/Managing.Api/Models/Responses/AgentSummaryViewModel.cs @@ -47,6 +47,11 @@ namespace Managing.Api.Models.Responses /// Total balance including USDC and open position values (without leverage, including PnL) /// public decimal TotalBalance { get; set; } + + /// + /// Total fees paid by this agent across all positions + /// + public decimal TotalFees { get; set; } } /// diff --git a/src/Managing.Application.Abstractions/Grains/IPlatformSummaryGrain.cs b/src/Managing.Application.Abstractions/Grains/IPlatformSummaryGrain.cs index 38d828a6..62ff0ea6 100644 --- a/src/Managing.Application.Abstractions/Grains/IPlatformSummaryGrain.cs +++ b/src/Managing.Application.Abstractions/Grains/IPlatformSummaryGrain.cs @@ -26,6 +26,12 @@ public interface IPlatformSummaryGrain : IGrainWithStringKey [OneWay] Task UpdateActiveStrategyCountAsync(int newActiveCount); + /// + /// Increments the total agent count when a new agent is activated + /// + [OneWay] + Task IncrementAgentCountAsync(); + [OneWay] Task OnPositionClosedAsync(PositionClosedEvent evt); diff --git a/src/Managing.Application.Tests/AgentGrainTests.cs b/src/Managing.Application.Tests/AgentGrainTests.cs index 70790e37..82ddfaa0 100644 --- a/src/Managing.Application.Tests/AgentGrainTests.cs +++ b/src/Managing.Application.Tests/AgentGrainTests.cs @@ -1,14 +1,13 @@ using Managing.Application.Abstractions; -using Managing.Application.Abstractions.Models; using Managing.Application.Abstractions.Services; using Managing.Application.Bots.Grains; using Managing.Application.Bots.Models; using Managing.Domain.Bots; using Managing.Domain.Statistics; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Moq; using Xunit; -using static Managing.Common.Enums; namespace Managing.Application.Tests; @@ -22,6 +21,7 @@ public class AgentGrainTests private readonly Mock _mockUserService; private readonly Mock _mockAccountService; private readonly Mock _mockTradingService; + private readonly Mock _mockScopeFactory; public AgentGrainTests() { @@ -33,6 +33,7 @@ public class AgentGrainTests _mockUserService = new Mock(); _mockAccountService = new Mock(); _mockTradingService = new Mock(); + _mockScopeFactory = new Mock(); // Setup default state _mockState.Setup(x => x.State).Returns(new AgentGrainState @@ -42,51 +43,6 @@ public class AgentGrainTests }); } - [Fact] - public async Task OnAgentSummaryUpdateAsync_WithValidBotId_ShouldCallUpdateSummary() - { - // Arrange - var agentGrain = CreateAgentGrain(); - var botId = _mockState.Object.State.BotIds.First(); - var updateEvent = new AgentSummaryUpdateEvent - { - BotId = botId, - EventType = NotificationEventType.PositionOpened, - Timestamp = DateTime.UtcNow - }; - - // Setup mocks - _mockBotService.Setup(x => x.GetBotsByIdsAsync(It.IsAny>())) - .ReturnsAsync(new List()); - _mockAgentService.Setup(x => x.SaveOrUpdateAgentSummary(It.IsAny())) - .Returns(Task.CompletedTask); - - // Act - await agentGrain.OnAgentSummaryUpdateAsync(updateEvent); - - // Assert - _mockAgentService.Verify(x => x.SaveOrUpdateAgentSummary(It.IsAny()), Times.Once); - } - - [Fact] - public async Task OnAgentSummaryUpdateAsync_WithInvalidBotId_ShouldNotCallUpdateSummary() - { - // Arrange - var agentGrain = CreateAgentGrain(); - var updateEvent = new AgentSummaryUpdateEvent - { - BotId = Guid.NewGuid(), // Different bot ID - EventType = NotificationEventType.PositionOpened, - Timestamp = DateTime.UtcNow - }; - - // Act - await agentGrain.OnAgentSummaryUpdateAsync(updateEvent); - - // Assert - _mockAgentService.Verify(x => x.SaveOrUpdateAgentSummary(It.IsAny()), Times.Never); - } - [Fact] public async Task RegisterBotAsync_ShouldUpdateSummary() { @@ -137,6 +93,7 @@ public class AgentGrainTests _mockExchangeService.Object, _mockUserService.Object, _mockAccountService.Object, - _mockTradingService.Object); + _mockTradingService.Object, + _mockScopeFactory.Object); } } \ No newline at end of file diff --git a/src/Managing.Application/Bots/Grains/AgentGrain.cs b/src/Managing.Application/Bots/Grains/AgentGrain.cs index fb07e3a0..010da85d 100644 --- a/src/Managing.Application/Bots/Grains/AgentGrain.cs +++ b/src/Managing.Application/Bots/Grains/AgentGrain.cs @@ -56,10 +56,10 @@ public class AgentGrain : Grain, IAgentGrain _scopeFactory = scopeFactory; } - public override Task OnActivateAsync(CancellationToken cancellationToken) + public override async Task OnActivateAsync(CancellationToken cancellationToken) { _logger.LogInformation("AgentGrain activated for user {UserId}", this.GetPrimaryKeyLong()); - return base.OnActivateAsync(cancellationToken); + await base.OnActivateAsync(cancellationToken); } public async Task InitializeAsync(int userId, string agentName) @@ -86,6 +86,14 @@ public class AgentGrain : Grain, IAgentGrain await _agentService.SaveOrUpdateAgentSummary(emptySummary); _logger.LogInformation("Agent {UserId} initialized with name {AgentName} and empty summary", userId, agentName); + + // Notify platform summary about new agent activation + await ServiceScopeHelpers.WithScopedService(_scopeFactory, async grainFactory => + { + var platformGrain = grainFactory.GetGrain("platform-summary"); + await platformGrain.IncrementAgentCountAsync(); + _logger.LogDebug("Notified platform summary about new agent activation for user {UserId}", userId); + }); } public async Task UpdateAgentNameAsync(string agentName) @@ -162,14 +170,19 @@ public class AgentGrain : Grain, IAgentGrain var totalVolume = positions.Sum(p => p.Open.Price * p.Open.Quantity * p.Open.Leverage); var collateral = positions.Sum(p => p.Open.Price * p.Open.Quantity); var totalFees = positions.Sum(p => p.CalculateTotalFees()); + + // Store total fees in grain state for caching + _state.State.TotalFees = totalFees; // Calculate wins/losses from position PnL var totalWins = positions.Count(p => (p.ProfitAndLoss?.Realized ?? 0) > 0); var totalLosses = positions.Count(p => (p.ProfitAndLoss?.Realized ?? 0) <= 0); + // Calculate ROI based on PnL minus fees + var netPnL = totalPnL - totalFees; var totalROI = collateral switch { - > 0 => (totalPnL / collateral) * 100, + > 0 => (netPnL / collateral) * 100, >= 0 => 0, _ => 0 }; @@ -223,7 +236,7 @@ public class AgentGrain : Grain, IAgentGrain { UserId = (int)this.GetPrimaryKeyLong(), AgentName = _state.State.AgentName, - TotalPnL = totalPnL, + TotalPnL = totalPnL, // Use net PnL without fees Wins = totalWins, Losses = totalLosses, TotalROI = totalROI, @@ -231,13 +244,14 @@ public class AgentGrain : Grain, IAgentGrain ActiveStrategiesCount = activeStrategiesCount, TotalVolume = totalVolume, TotalBalance = totalBalance, + TotalFees = totalFees, }; // Save summary to database await _agentService.SaveOrUpdateAgentSummary(summary); - _logger.LogDebug("Updated agent summary from position data for user {UserId}: PnL={PnL}, Volume={Volume}, Wins={Wins}, Losses={Losses}", - this.GetPrimaryKeyLong(), totalPnL, totalVolume, totalWins, totalLosses); + _logger.LogDebug("Updated agent summary from position data for user {UserId}: NetPnL={NetPnL}, TotalPnL={TotalPnL}, Fees={Fees}, Volume={Volume}, Wins={Wins}, Losses={Losses}", + this.GetPrimaryKeyLong(), netPnL, totalPnL, totalFees, totalVolume, totalWins, totalLosses); } catch (Exception ex) { diff --git a/src/Managing.Application/Bots/Models/AgentGrainState.cs b/src/Managing.Application/Bots/Models/AgentGrainState.cs index 568499f8..dd5ef2a2 100644 --- a/src/Managing.Application/Bots/Models/AgentGrainState.cs +++ b/src/Managing.Application/Bots/Models/AgentGrainState.cs @@ -24,6 +24,12 @@ namespace Managing.Application.Bots.Models /// [Id(4)] public CachedBalanceData? CachedBalanceData { get; set; } = null; + + /// + /// Total fees paid by this agent across all positions + /// + [Id(5)] + public decimal TotalFees { get; set; } = 0; } /// diff --git a/src/Managing.Application/Bots/TradingBotBase.cs b/src/Managing.Application/Bots/TradingBotBase.cs index e6279b47..063d6361 100644 --- a/src/Managing.Application/Bots/TradingBotBase.cs +++ b/src/Managing.Application/Bots/TradingBotBase.cs @@ -406,10 +406,13 @@ public class TradingBotBase : ITradingBot await UpdatePositionDatabase(internalPosition); - if (previousPositionStatus != PositionStatus.Filled && internalPosition.Status == PositionStatus.Filled) + if (previousPositionStatus != PositionStatus.Filled && + internalPosition.Status == PositionStatus.Filled) { await NotifyAgentAndPlatformGrainAsync(NotificationEventType.PositionOpened, internalPosition); - }else{ + } + else + { await NotifyAgentAndPlatformGrainAsync(NotificationEventType.PositionUpdated, internalPosition); } } @@ -750,8 +753,6 @@ public class TradingBotBase : ITradingBot currentPrice, true); } } - - } catch (Exception ex) { @@ -763,10 +764,8 @@ public class TradingBotBase : ITradingBot private async Task UpdatePositionDatabase(Position position) { - await ServiceScopeHelpers.WithScopedService(_scopeFactory, async tradingService => - { - await tradingService.UpdatePositionAsync(position); - }); + await ServiceScopeHelpers.WithScopedService(_scopeFactory, + async tradingService => { await tradingService.UpdatePositionAsync(position); }); } private async Task OpenPosition(LightSignal signal) @@ -1347,6 +1346,7 @@ public class TradingBotBase : ITradingBot // Update position in database with all trade changes if (!Config.IsForBacktest) { + position.Status = PositionStatus.Finished; await UpdatePositionDatabase(position); await NotifyAgentAndPlatformGrainAsync(NotificationEventType.PositionClosed, position); } @@ -1468,10 +1468,13 @@ public class TradingBotBase : ITradingBot { if (Positions[identifier].ProfitAndLoss == null) { - Positions[identifier].ProfitAndLoss = new ProfitAndLoss(){ + Positions[identifier].ProfitAndLoss = new ProfitAndLoss() + { Realized = realized }; - }else{ + } + else + { Positions[identifier].ProfitAndLoss.Realized = realized; } } diff --git a/src/Managing.Application/Grains/PlatformSummaryGrain.cs b/src/Managing.Application/Grains/PlatformSummaryGrain.cs index e71f2da9..bfff2253 100644 --- a/src/Managing.Application/Grains/PlatformSummaryGrain.cs +++ b/src/Managing.Application/Grains/PlatformSummaryGrain.cs @@ -76,11 +76,16 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable _state.State.DailySnapshots.Add(initialSnapshot); _state.State.LastSnapshot = initialSnapshot.Date; _state.State.LastUpdated = initialSnapshot.Date; + _logger.LogInformation("Created initial empty daily snapshot for {Date}", today); } + _state.State.TotalAgents = await _agentService.GetTotalAgentCount(); + await RefreshDataAsync(); } + + await base.OnActivateAsync(cancellationToken); } public async Task GetPlatformSummaryAsync() @@ -129,7 +134,7 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable // Calculate fees and PnL for all positions totalFees += position.CalculateTotalFees(); totalPnL += position.ProfitAndLoss?.Realized ?? 0; - + // Count all positions totalPositionCount++; @@ -142,6 +147,7 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable { _state.State.VolumeByAsset[ticker] = 0; } + _state.State.VolumeByAsset[ticker] += positionVolume; // Position count breakdown by asset - update state directly @@ -149,6 +155,7 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable { _state.State.PositionCountByAsset[ticker] = 0; } + _state.State.PositionCountByAsset[ticker]++; // Position count breakdown by direction - update state directly @@ -156,10 +163,10 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable { _state.State.PositionCountByDirection[direction] = 0; } + _state.State.PositionCountByDirection[direction]++; } - _state.State.TotalAgents = await _agentService.GetTotalAgentCount(); _state.State.TotalPlatformVolume = totalVolume; _state.State.TotalPlatformFees = totalFees; _state.State.TotalPlatformPnL = totalPnL; @@ -169,7 +176,7 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable _logger.LogDebug( "Updated position breakdown from positions: {AssetCount} assets, Long={LongPositions}, Short={ShortPositions}", - _state.State.PositionCountByAsset.Count, + _state.State.PositionCountByAsset.Count, _state.State.PositionCountByDirection.GetValueOrDefault(TradeDirection.Long, 0), _state.State.PositionCountByDirection.GetValueOrDefault(TradeDirection.Short, 0)); @@ -207,6 +214,24 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable } } + public async Task IncrementAgentCountAsync() + { + try + { + _logger.LogInformation("Incrementing agent count from {CurrentCount} to {NewCount}", + _state.State.TotalAgents, _state.State.TotalAgents + 1); + + _state.State.TotalAgents++; + await _state.WriteStateAsync(); + + _logger.LogInformation("Agent count incremented to: {NewCount}", _state.State.TotalAgents); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error incrementing agent count"); + } + } + public async Task OnPositionClosedAsync(PositionClosedEvent evt) { try @@ -282,20 +307,6 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable await _state.WriteStateAsync(); } - private async Task RefreshPnLFromDatabaseAsync() - { - try - { - var totalPnL = await _tradingService.GetGlobalPnLFromPositionsAsync(); - _state.State.TotalPlatformPnL = totalPnL; - _logger.LogDebug("Refreshed PnL from database: {TotalPnL}", totalPnL); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error refreshing PnL from database"); - } - } - private bool IsDataStale() { var timeSinceLastUpdate = DateTime.UtcNow - _state.State.LastUpdated; diff --git a/src/Managing.Application/ManageBot/Commands/GetAllAgentSummariesCommand.cs b/src/Managing.Application/ManageBot/Commands/GetAllAgentSummariesCommand.cs index f1bc8e86..cda39d2d 100644 --- a/src/Managing.Application/ManageBot/Commands/GetAllAgentSummariesCommand.cs +++ b/src/Managing.Application/ManageBot/Commands/GetAllAgentSummariesCommand.cs @@ -8,14 +8,8 @@ namespace Managing.Application.ManageBot.Commands /// public class GetAllAgentSummariesCommand : IRequest> { - /// - /// Optional time filter to apply (24H, 3D, 1W, 1M, 1Y, Total) - /// - public string TimeFilter { get; } - - public GetAllAgentSummariesCommand(string timeFilter = "Total") + public GetAllAgentSummariesCommand() { - TimeFilter = timeFilter; } } } \ No newline at end of file diff --git a/src/Managing.Application/ManageBot/Commands/GetAllAgentsCommand.cs b/src/Managing.Application/ManageBot/Commands/GetAllAgentsCommand.cs index c728cd40..368b2687 100644 --- a/src/Managing.Application/ManageBot/Commands/GetAllAgentsCommand.cs +++ b/src/Managing.Application/ManageBot/Commands/GetAllAgentsCommand.cs @@ -9,14 +9,8 @@ namespace Managing.Application.ManageBot.Commands /// public class GetAllAgentsCommand : IRequest>> { - /// - /// Optional time filter to apply (24H, 3D, 1W, 1M, 1Y, Total) - /// - public string TimeFilter { get; } - - public GetAllAgentsCommand(string timeFilter = "Total") + public GetAllAgentsCommand() { - TimeFilter = timeFilter; } } } \ No newline at end of file diff --git a/src/Managing.Application/ManageBot/GetAllAgentSummariesCommandHandler.cs b/src/Managing.Application/ManageBot/GetAllAgentSummariesCommandHandler.cs index 2d139883..528c9829 100644 --- a/src/Managing.Application/ManageBot/GetAllAgentSummariesCommandHandler.cs +++ b/src/Managing.Application/ManageBot/GetAllAgentSummariesCommandHandler.cs @@ -24,31 +24,8 @@ namespace Managing.Application.ManageBot // Get all agent summaries from the database var allAgentSummaries = await _agentService.GetAllAgentSummaries(); - if (request.TimeFilter != "Total") - { - var cutoffDate = GetCutoffDate(request.TimeFilter); - allAgentSummaries = allAgentSummaries.Where(a => - a.UpdatedAt >= cutoffDate || - (a.Runtime.HasValue && a.Runtime.Value >= cutoffDate)); - } - return allAgentSummaries; } - /// - /// Gets the cutoff date based on the time filter - /// - private DateTime GetCutoffDate(string timeFilter) - { - return timeFilter switch - { - "24H" => DateTime.UtcNow.AddHours(-24), - "3D" => DateTime.UtcNow.AddDays(-3), - "1W" => DateTime.UtcNow.AddDays(-7), - "1M" => DateTime.UtcNow.AddMonths(-1), - "1Y" => DateTime.UtcNow.AddYears(-1), - _ => DateTime.MinValue // Default to include all data - }; - } } } \ No newline at end of file diff --git a/src/Managing.Application/ManageBot/GetAllAgentsCommandHandler.cs b/src/Managing.Application/ManageBot/GetAllAgentsCommandHandler.cs index 0f4f8762..fa286798 100644 --- a/src/Managing.Application/ManageBot/GetAllAgentsCommandHandler.cs +++ b/src/Managing.Application/ManageBot/GetAllAgentsCommandHandler.cs @@ -35,35 +35,11 @@ namespace Managing.Application.ManageBot var userBots = await _botService.GetBotsByUser(user.Id); var botList = userBots.ToList(); - // Apply time filter if specified - if (request.TimeFilter != "Total") - { - var cutoffDate = GetCutoffDate(request.TimeFilter); - botList = botList.Where(bot => - bot.StartupTime >= cutoffDate || - bot.CreateDate >= cutoffDate).ToList(); - } - result[user] = botList; } return result; } - /// - /// Gets the cutoff date based on the time filter - /// - private DateTime GetCutoffDate(string timeFilter) - { - return timeFilter switch - { - "24H" => DateTime.UtcNow.AddHours(-24), - "3D" => DateTime.UtcNow.AddDays(-3), - "1W" => DateTime.UtcNow.AddDays(-7), - "1M" => DateTime.UtcNow.AddMonths(-1), - "1Y" => DateTime.UtcNow.AddYears(-1), - _ => DateTime.MinValue // Default to include all data - }; - } } } \ No newline at end of file diff --git a/src/Managing.Application/Trading/Handlers/OpenPositionCommandHandler.cs b/src/Managing.Application/Trading/Handlers/OpenPositionCommandHandler.cs index f98e1d9f..8d9d750a 100644 --- a/src/Managing.Application/Trading/Handlers/OpenPositionCommandHandler.cs +++ b/src/Managing.Application/Trading/Handlers/OpenPositionCommandHandler.cs @@ -45,25 +45,19 @@ namespace Managing.Application.Trading.Handlers } // Gas fee check for EVM exchanges - decimal gasFeeUsd = 0; if (!request.IsForPaperTrading) { if (account.Exchange == TradingExchanges.Evm || account.Exchange == TradingExchanges.GmxV2) { - gasFeeUsd = await exchangeService.GetFee(account); - if (gasFeeUsd > Constants.GMX.Config.MaximumGasFeeUsd) + var currentGasFees = await exchangeService.GetFee(account); + if (currentGasFees > Constants.GMX.Config.MaximumGasFeeUsd) { throw new InsufficientFundsException( - $"Gas fee too high for position opening: {gasFeeUsd:F2} USD (threshold: {Constants.GMX.Config.MaximumGasFeeUsd} USD). Position opening cancelled.", + $"Gas fee too high for position opening: {currentGasFees:F2} USD (threshold: {Constants.GMX.Config.MaximumGasFeeUsd} USD). Position opening cancelled.", InsufficientFundsType.InsufficientEth); } } } - else - { - gasFeeUsd = Constants.GMX.Config.GasFeePerTransaction; - } - var price = request.IsForPaperTrading && request.Price.HasValue ? request.Price.Value @@ -94,19 +88,11 @@ namespace Managing.Application.Trading.Handlers position.Open = trade; // Calculate and set fees for the position - var positionSizeUsd = (position.Open.Price * position.Open.Quantity) * position.Open.Leverage; - // Set gas fees (only for EVM exchanges) - if (account.Exchange == TradingExchanges.Evm || account.Exchange == TradingExchanges.GmxV2) - { - position.GasFees = gasFeeUsd; - } - else - { - position.GasFees = TradingHelpers.CalculateOpeningGasFees(); - } + position.GasFees = TradingHelpers.CalculateOpeningGasFees(); // Set UI fees for opening + var positionSizeUsd = TradingHelpers.GetVolumeForPosition(position); position.UiFees = TradingHelpers.CalculateOpeningUiFees(positionSizeUsd); var closeDirection = request.Direction == TradeDirection.Long diff --git a/src/Managing.Application/Users/UserService.cs b/src/Managing.Application/Users/UserService.cs index 21271250..b462335a 100644 --- a/src/Managing.Application/Users/UserService.cs +++ b/src/Managing.Application/Users/UserService.cs @@ -116,6 +116,8 @@ public class UserService : IUserService var agentGrain = _grainFactory.GetGrain(user.Id); await agentGrain.InitializeAsync(user.Id, string.Empty); _logger.LogInformation("AgentGrain initialized for new user {UserId}", user.Id); + + } catch (Exception ex) { diff --git a/src/Managing.Docker/docker-compose.local.yml b/src/Managing.Docker/docker-compose.local.yml index 039da6d8..32741e8b 100644 --- a/src/Managing.Docker/docker-compose.local.yml +++ b/src/Managing.Docker/docker-compose.local.yml @@ -55,7 +55,7 @@ services: - managing-network restart: unless-stopped environment: - - REDIS_PASSWORD=SuperSecretPassword + - REDIS_PASSWORD= command: > sh -c " if [ -n \"$$REDIS_PASSWORD\" ]; then @@ -65,4 +65,4 @@ services: redis-server --appendonly yes redis-cli fi - " \ No newline at end of file + "SuperSecretPassword \ No newline at end of file diff --git a/src/Managing.Domain/Statistics/AgentSummary.cs b/src/Managing.Domain/Statistics/AgentSummary.cs index 615987aa..086e3bdd 100644 --- a/src/Managing.Domain/Statistics/AgentSummary.cs +++ b/src/Managing.Domain/Statistics/AgentSummary.cs @@ -47,4 +47,7 @@ public class AgentSummary [Id(13)] public decimal TotalBalance { get; set; } + + [Id(14)] + public decimal TotalFees { get; set; } } \ No newline at end of file diff --git a/src/Managing.Infrastructure.Database/Migrations/ManagingDbContextModelSnapshot.cs b/src/Managing.Infrastructure.Database/Migrations/ManagingDbContextModelSnapshot.cs index a6928b7d..4de32cff 100644 --- a/src/Managing.Infrastructure.Database/Migrations/ManagingDbContextModelSnapshot.cs +++ b/src/Managing.Infrastructure.Database/Migrations/ManagingDbContextModelSnapshot.cs @@ -99,6 +99,9 @@ namespace Managing.Infrastructure.Databases.Migrations .HasPrecision(18, 8) .HasColumnType("numeric(18,8)"); + b.Property("TotalFees") + .HasColumnType("numeric"); + b.Property("TotalPnL") .HasColumnType("decimal(18,8)"); diff --git a/src/Managing.Infrastructure.Database/PostgreSql/AgentSummaryRepository.cs b/src/Managing.Infrastructure.Database/PostgreSql/AgentSummaryRepository.cs index 7f64a4cc..9b9db661 100644 --- a/src/Managing.Infrastructure.Database/PostgreSql/AgentSummaryRepository.cs +++ b/src/Managing.Infrastructure.Database/PostgreSql/AgentSummaryRepository.cs @@ -249,7 +249,8 @@ public class AgentSummaryRepository : IAgentSummaryRepository UpdatedAt = domain.UpdatedAt, ActiveStrategiesCount = domain.ActiveStrategiesCount, TotalVolume = domain.TotalVolume, - TotalBalance = domain.TotalBalance + TotalBalance = domain.TotalBalance, + TotalFees = domain.TotalFees }; } @@ -265,6 +266,7 @@ public class AgentSummaryRepository : IAgentSummaryRepository entity.ActiveStrategiesCount = domain.ActiveStrategiesCount; entity.TotalVolume = domain.TotalVolume; entity.TotalBalance = domain.TotalBalance; + entity.TotalFees = domain.TotalFees; } private static AgentSummary MapToDomain(AgentSummaryEntity entity) @@ -284,6 +286,7 @@ public class AgentSummaryRepository : IAgentSummaryRepository ActiveStrategiesCount = entity.ActiveStrategiesCount, TotalVolume = entity.TotalVolume, TotalBalance = entity.TotalBalance, + TotalFees = entity.TotalFees, User = PostgreSqlMappers.Map(entity.User) }; } diff --git a/src/Managing.Infrastructure.Database/PostgreSql/Entities/AgentSummaryEntity.cs b/src/Managing.Infrastructure.Database/PostgreSql/Entities/AgentSummaryEntity.cs index 67681afb..8445e7ad 100644 --- a/src/Managing.Infrastructure.Database/PostgreSql/Entities/AgentSummaryEntity.cs +++ b/src/Managing.Infrastructure.Database/PostgreSql/Entities/AgentSummaryEntity.cs @@ -15,6 +15,7 @@ public class AgentSummaryEntity public int ActiveStrategiesCount { get; set; } public decimal TotalVolume { get; set; } public decimal TotalBalance { get; set; } + public decimal TotalFees { get; set; } // Navigation property public UserEntity User { get; set; } diff --git a/src/Managing.WebApp/package.json b/src/Managing.WebApp/package.json index e99c67c4..9ac3ed36 100644 --- a/src/Managing.WebApp/package.json +++ b/src/Managing.WebApp/package.json @@ -82,7 +82,7 @@ "prettier-plugin-tailwind-css": "^1.5.0", "tailwindcss": "^3.0.23", "typescript": "^5.7.3", - "vite": "^6.3.5", + "vite": "^6.3.6", "whatwg-fetch": "^3.6.2" }, "msw": {