Add agentbalance
This commit is contained in:
@@ -345,7 +345,7 @@ public class DataController : ControllerBase
|
|||||||
|
|
||||||
// Calculate PnL for each bot once and store in a list of tuples
|
// Calculate PnL for each bot once and store in a list of tuples
|
||||||
var botsWithPnL = activeBots
|
var botsWithPnL = activeBots
|
||||||
.Select(bot => new { Bot = bot, PnL = bot.Pnl })
|
.Select(bot => new { Bot = bot, PnL = bot.Pnl, agentName = bot.User.AgentName })
|
||||||
.OrderByDescending(item => item.PnL)
|
.OrderByDescending(item => item.PnL)
|
||||||
.Take(3)
|
.Take(3)
|
||||||
.ToList();
|
.ToList();
|
||||||
@@ -357,7 +357,8 @@ public class DataController : ControllerBase
|
|||||||
.Select(item => new StrategyPerformance
|
.Select(item => new StrategyPerformance
|
||||||
{
|
{
|
||||||
StrategyName = item.Bot.Name,
|
StrategyName = item.Bot.Name,
|
||||||
PnL = item.PnL
|
PnL = item.PnL,
|
||||||
|
AgentName = item.agentName,
|
||||||
})
|
})
|
||||||
.ToList()
|
.ToList()
|
||||||
};
|
};
|
||||||
@@ -452,7 +453,8 @@ public class DataController : ControllerBase
|
|||||||
/// <param name="strategy">The trading bot to map</param>
|
/// <param name="strategy">The trading bot to map</param>
|
||||||
/// <param name="positionsByIdentifier">Pre-fetched positions grouped by initiator identifier</param>
|
/// <param name="positionsByIdentifier">Pre-fetched positions grouped by initiator identifier</param>
|
||||||
/// <returns>A view model with detailed strategy information</returns>
|
/// <returns>A view model with detailed strategy information</returns>
|
||||||
private UserStrategyDetailsViewModel MapStrategyToViewModel(Bot strategy, Dictionary<Guid, List<Position>> positionsByIdentifier)
|
private UserStrategyDetailsViewModel MapStrategyToViewModel(Bot strategy,
|
||||||
|
Dictionary<Guid, List<Position>> positionsByIdentifier)
|
||||||
{
|
{
|
||||||
// Calculate ROI percentage based on PnL relative to account value
|
// Calculate ROI percentage based on PnL relative to account value
|
||||||
decimal pnl = strategy.Pnl;
|
decimal pnl = strategy.Pnl;
|
||||||
@@ -473,8 +475,8 @@ public class DataController : ControllerBase
|
|||||||
decimal roiLast24h = strategy.Roi;
|
decimal roiLast24h = strategy.Roi;
|
||||||
|
|
||||||
// Get positions for this strategy from pre-fetched data
|
// Get positions for this strategy from pre-fetched data
|
||||||
var positions = positionsByIdentifier.TryGetValue(strategy.Identifier, out var strategyPositions)
|
var positions = positionsByIdentifier.TryGetValue(strategy.Identifier, out var strategyPositions)
|
||||||
? strategyPositions
|
? strategyPositions
|
||||||
: new List<Position>();
|
: new List<Position>();
|
||||||
|
|
||||||
return new UserStrategyDetailsViewModel
|
return new UserStrategyDetailsViewModel
|
||||||
@@ -645,6 +647,7 @@ public class DataController : ControllerBase
|
|||||||
Losses = agentSummary.Losses,
|
Losses = agentSummary.Losses,
|
||||||
ActiveStrategiesCount = agentSummary.ActiveStrategiesCount,
|
ActiveStrategiesCount = agentSummary.ActiveStrategiesCount,
|
||||||
TotalVolume = agentSummary.TotalVolume,
|
TotalVolume = agentSummary.TotalVolume,
|
||||||
|
TotalBalance = agentSummary.TotalBalance,
|
||||||
};
|
};
|
||||||
|
|
||||||
agentSummaryViewModels.Add(agentSummaryViewModel);
|
agentSummaryViewModels.Add(agentSummaryViewModel);
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ namespace Managing.Api.Models.Responses
|
|||||||
/// Total volume traded by this agent in USD
|
/// Total volume traded by this agent in USD
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public decimal TotalVolume { get; set; }
|
public decimal TotalVolume { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total balance including USDC and open position values (without leverage, including PnL)
|
||||||
|
/// </summary>
|
||||||
|
public decimal TotalBalance { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ namespace Managing.Api.Models.Responses
|
|||||||
/// Name of the strategy bot
|
/// Name of the strategy bot
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string StrategyName { get; set; }
|
public string StrategyName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Profit and Loss value of the strategy
|
/// Profit and Loss value of the strategy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public decimal PnL { get; set; }
|
public decimal PnL { get; set; }
|
||||||
|
|
||||||
|
public string AgentName { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -25,17 +27,17 @@ namespace Managing.Api.Models.Responses
|
|||||||
/// Name of the strategy bot
|
/// Name of the strategy bot
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string StrategyName { get; set; }
|
public string StrategyName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Return on Investment percentage of the strategy
|
/// Return on Investment percentage of the strategy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public decimal Roi { get; set; }
|
public decimal Roi { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Profit and Loss value of the strategy
|
/// Profit and Loss value of the strategy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public decimal PnL { get; set; }
|
public decimal PnL { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Volume traded by the strategy
|
/// Volume traded by the strategy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -52,7 +54,7 @@ namespace Managing.Api.Models.Responses
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public List<StrategyPerformance> TopStrategies { get; set; } = new List<StrategyPerformance>();
|
public List<StrategyPerformance> TopStrategies { get; set; } = new List<StrategyPerformance>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// View model containing the top performing strategies by ROI
|
/// View model containing the top performing strategies by ROI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -63,4 +65,4 @@ namespace Managing.Api.Models.Responses
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public List<StrategyRoiPerformance> TopStrategiesByRoi { get; set; } = new List<StrategyRoiPerformance>();
|
public List<StrategyRoiPerformance> TopStrategiesByRoi { get; set; } = new List<StrategyRoiPerformance>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,13 +9,13 @@ public interface IAccountService
|
|||||||
Task<Account> CreateAccount(User user, Account account);
|
Task<Account> CreateAccount(User user, Account account);
|
||||||
bool DeleteAccount(User user, string name);
|
bool DeleteAccount(User user, string name);
|
||||||
IEnumerable<Account> GetAccountsByUser(User user, bool hideSecrets = true);
|
IEnumerable<Account> GetAccountsByUser(User user, bool hideSecrets = true);
|
||||||
Task<IEnumerable<Account>> GetAccountsByUserAsync(User user, bool hideSecrets = true);
|
Task<IEnumerable<Account>> GetAccountsByUserAsync(User user, bool hideSecrets = true, bool getBalance = false);
|
||||||
Task<IEnumerable<Account>> GetAccounts(bool hideSecrets, bool getBalance);
|
Task<IEnumerable<Account>> GetAccounts(bool hideSecrets, bool getBalance);
|
||||||
Task<IEnumerable<Account>> GetAccountsAsync(bool hideSecrets, bool getBalance);
|
Task<IEnumerable<Account>> GetAccountsAsync(bool hideSecrets, bool getBalance);
|
||||||
Task<Account> GetAccount(string name, bool hideSecrets, bool getBalance);
|
Task<Account> GetAccount(string name, bool hideSecrets, bool getBalance);
|
||||||
public Task<Account> GetAccountByUser(User user, string name, bool hideSecrets, bool getBalance);
|
public Task<Account> GetAccountByUser(User user, string name, bool hideSecrets, bool getBalance);
|
||||||
public Task<Account> GetAccountByKey(string key, bool hideSecrets, bool getBalance);
|
public Task<Account> GetAccountByKey(string key, bool hideSecrets, bool getBalance);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets an account by name directly from the repository.
|
/// Gets an account by name directly from the repository.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -24,7 +24,7 @@ public interface IAccountService
|
|||||||
/// <param name="getBalance">Whether to fetch the current balance</param>
|
/// <param name="getBalance">Whether to fetch the current balance</param>
|
||||||
/// <returns>The found account or null if not found</returns>
|
/// <returns>The found account or null if not found</returns>
|
||||||
Task<Account> GetAccountByAccountName(string accountName, bool hideSecrets = true, bool getBalance = false);
|
Task<Account> GetAccountByAccountName(string accountName, bool hideSecrets = true, bool getBalance = false);
|
||||||
|
|
||||||
IEnumerable<Account> GetAccountsBalancesByUser(User user, bool hideSecrets = true);
|
IEnumerable<Account> GetAccountsBalancesByUser(User user, bool hideSecrets = true);
|
||||||
Task<IEnumerable<Account>> GetAccountsBalancesByUserAsync(User user, bool hideSecrets = true);
|
Task<IEnumerable<Account>> GetAccountsBalancesByUserAsync(User user, bool hideSecrets = true);
|
||||||
Task<GmxClaimableSummary> GetGmxClaimableSummaryAsync(User user, string accountName);
|
Task<GmxClaimableSummary> GetGmxClaimableSummaryAsync(User user, string accountName);
|
||||||
|
|||||||
@@ -11,5 +11,6 @@ public interface IUserService
|
|||||||
Task<User> UpdateTelegramChannel(User user, string telegramChannel);
|
Task<User> UpdateTelegramChannel(User user, string telegramChannel);
|
||||||
Task<User> GetUserByName(string name);
|
Task<User> GetUserByName(string name);
|
||||||
Task<User> GetUserByAgentName(string agentName);
|
Task<User> GetUserByAgentName(string agentName);
|
||||||
|
Task<User> GetUserByIdAsync(int userId);
|
||||||
Task<IEnumerable<User>> GetAllUsersAsync();
|
Task<IEnumerable<User>> GetAllUsersAsync();
|
||||||
}
|
}
|
||||||
@@ -173,13 +173,14 @@ public class AccountService : IAccountService
|
|||||||
return GetAccountsByUserAsync(user, hideSecrets).Result;
|
return GetAccountsByUserAsync(user, hideSecrets).Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<Account>> GetAccountsByUserAsync(User user, bool hideSecrets = true)
|
public async Task<IEnumerable<Account>> GetAccountsByUserAsync(User user, bool hideSecrets = true,
|
||||||
|
bool getBalance = false)
|
||||||
{
|
{
|
||||||
var cacheKey = $"user-account-{user.Name}";
|
var cacheKey = $"user-account-{user.Name}";
|
||||||
|
|
||||||
// For now, we'll get fresh data since caching async operations requires more complex logic
|
// For now, we'll get fresh data since caching async operations requires more complex logic
|
||||||
// This can be optimized later with proper async caching
|
// This can be optimized later with proper async caching
|
||||||
return await GetAccountsAsync(user, hideSecrets, false);
|
return await GetAccountsAsync(user, hideSecrets, getBalance);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IEnumerable<Account>> GetAccountsAsync(User user, bool hideSecrets, bool getBalance)
|
private async Task<IEnumerable<Account>> GetAccountsAsync(User user, bool hideSecrets, bool getBalance)
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ public class AgentGrain : Grain, IAgentGrain, IRemindable
|
|||||||
private readonly ILogger<AgentGrain> _logger;
|
private readonly ILogger<AgentGrain> _logger;
|
||||||
private readonly IBotService _botService;
|
private readonly IBotService _botService;
|
||||||
private readonly IAgentService _agentService;
|
private readonly IAgentService _agentService;
|
||||||
|
private readonly IExchangeService _exchangeService;
|
||||||
|
private readonly IUserService _userService;
|
||||||
|
private readonly IAccountService _accountService;
|
||||||
|
private readonly ITradingService _tradingService;
|
||||||
private const string _updateSummaryReminderName = "UpdateAgentSummary";
|
private const string _updateSummaryReminderName = "UpdateAgentSummary";
|
||||||
|
|
||||||
public AgentGrain(
|
public AgentGrain(
|
||||||
@@ -21,12 +25,20 @@ public class AgentGrain : Grain, IAgentGrain, IRemindable
|
|||||||
IPersistentState<AgentGrainState> state,
|
IPersistentState<AgentGrainState> state,
|
||||||
ILogger<AgentGrain> logger,
|
ILogger<AgentGrain> logger,
|
||||||
IBotService botService,
|
IBotService botService,
|
||||||
IAgentService agentService)
|
IAgentService agentService,
|
||||||
|
IExchangeService exchangeService,
|
||||||
|
IUserService userService,
|
||||||
|
IAccountService accountService,
|
||||||
|
ITradingService tradingService)
|
||||||
{
|
{
|
||||||
_state = state;
|
_state = state;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_botService = botService;
|
_botService = botService;
|
||||||
_agentService = agentService;
|
_agentService = agentService;
|
||||||
|
_exchangeService = exchangeService;
|
||||||
|
_userService = userService;
|
||||||
|
_accountService = accountService;
|
||||||
|
_tradingService = tradingService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task OnActivateAsync(CancellationToken cancellationToken)
|
public override Task OnActivateAsync(CancellationToken cancellationToken)
|
||||||
@@ -122,6 +134,43 @@ public class AgentGrain : Grain, IAgentGrain, IRemindable
|
|||||||
runtime = bots.Max(b => b.StartupTime);
|
runtime = bots.Max(b => b.StartupTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate total balance (USDC + open positions value)
|
||||||
|
decimal totalBalance = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var userId = (int)this.GetPrimaryKeyLong();
|
||||||
|
var user = await _userService.GetUserByIdAsync(userId);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
var userAccounts = await _accountService.GetAccountsByUserAsync(user, hideSecrets: true, true);
|
||||||
|
|
||||||
|
foreach (var account in userAccounts)
|
||||||
|
{
|
||||||
|
// Get USDC balance
|
||||||
|
var usdcBalances = await _exchangeService.GetBalances(account);
|
||||||
|
var usdcBalance = usdcBalances.FirstOrDefault(b => b.TokenName?.ToUpper() == "USDC")?.Amount ??
|
||||||
|
0;
|
||||||
|
totalBalance += usdcBalance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get positions for all bots using their GUIDs as InitiatorIdentifier
|
||||||
|
var botPositions =
|
||||||
|
await _tradingService.GetPositionsByInitiatorIdentifiersAsync(_state.State.BotIds);
|
||||||
|
|
||||||
|
foreach (var position in botPositions.Where(p => !p.IsFinished()))
|
||||||
|
{
|
||||||
|
totalBalance += position.Open.Price * position.Open.Quantity;
|
||||||
|
totalBalance += position.ProfitAndLoss?.Realized ?? 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error calculating total balance for agent {UserId}", this.GetPrimaryKeyLong());
|
||||||
|
totalBalance = 0; // Set to 0 if calculation fails
|
||||||
|
}
|
||||||
|
|
||||||
var summary = new AgentSummary
|
var summary = new AgentSummary
|
||||||
{
|
{
|
||||||
UserId = (int)this.GetPrimaryKeyLong(),
|
UserId = (int)this.GetPrimaryKeyLong(),
|
||||||
@@ -133,6 +182,7 @@ public class AgentGrain : Grain, IAgentGrain, IRemindable
|
|||||||
Runtime = runtime,
|
Runtime = runtime,
|
||||||
ActiveStrategiesCount = bots.Count(b => b.Status == BotStatus.Running),
|
ActiveStrategiesCount = bots.Count(b => b.Status == BotStatus.Running),
|
||||||
TotalVolume = totalVolume,
|
TotalVolume = totalVolume,
|
||||||
|
TotalBalance = totalBalance,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Save summary to database
|
// Save summary to database
|
||||||
|
|||||||
@@ -251,4 +251,17 @@ public class UserService : IUserService
|
|||||||
{
|
{
|
||||||
return await _userRepository.GetAllUsersAsync();
|
return await _userRepository.GetAllUsersAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<User> GetUserByIdAsync(int userId)
|
||||||
|
{
|
||||||
|
var allUsers = await _userRepository.GetAllUsersAsync();
|
||||||
|
var user = allUsers.FirstOrDefault(u => u.Id == userId);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"User with ID {userId} not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -44,4 +44,7 @@ public class AgentSummary
|
|||||||
|
|
||||||
[Id(12)]
|
[Id(12)]
|
||||||
public decimal TotalVolume { get; set; }
|
public decimal TotalVolume { get; set; }
|
||||||
|
|
||||||
|
[Id(13)]
|
||||||
|
public decimal TotalBalance { get; set; }
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,8 @@ public class AgentSummaryRepository : IAgentSummaryRepository
|
|||||||
CreatedAt = domain.CreatedAt,
|
CreatedAt = domain.CreatedAt,
|
||||||
UpdatedAt = domain.UpdatedAt,
|
UpdatedAt = domain.UpdatedAt,
|
||||||
ActiveStrategiesCount = domain.ActiveStrategiesCount,
|
ActiveStrategiesCount = domain.ActiveStrategiesCount,
|
||||||
TotalVolume = domain.TotalVolume
|
TotalVolume = domain.TotalVolume,
|
||||||
|
TotalBalance = domain.TotalBalance
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +209,7 @@ public class AgentSummaryRepository : IAgentSummaryRepository
|
|||||||
entity.Runtime = domain.Runtime;
|
entity.Runtime = domain.Runtime;
|
||||||
entity.ActiveStrategiesCount = domain.ActiveStrategiesCount;
|
entity.ActiveStrategiesCount = domain.ActiveStrategiesCount;
|
||||||
entity.TotalVolume = domain.TotalVolume;
|
entity.TotalVolume = domain.TotalVolume;
|
||||||
|
entity.TotalBalance = domain.TotalBalance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AgentSummary MapToDomain(AgentSummaryEntity entity)
|
private static AgentSummary MapToDomain(AgentSummaryEntity entity)
|
||||||
@@ -226,6 +228,7 @@ public class AgentSummaryRepository : IAgentSummaryRepository
|
|||||||
UpdatedAt = entity.UpdatedAt,
|
UpdatedAt = entity.UpdatedAt,
|
||||||
ActiveStrategiesCount = entity.ActiveStrategiesCount,
|
ActiveStrategiesCount = entity.ActiveStrategiesCount,
|
||||||
TotalVolume = entity.TotalVolume,
|
TotalVolume = entity.TotalVolume,
|
||||||
|
TotalBalance = entity.TotalBalance,
|
||||||
User = PostgreSqlMappers.Map(entity.User)
|
User = PostgreSqlMappers.Map(entity.User)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public class AgentSummaryEntity
|
|||||||
public DateTime UpdatedAt { get; set; }
|
public DateTime UpdatedAt { get; set; }
|
||||||
public int ActiveStrategiesCount { get; set; }
|
public int ActiveStrategiesCount { get; set; }
|
||||||
public decimal TotalVolume { get; set; }
|
public decimal TotalVolume { get; set; }
|
||||||
|
public decimal TotalBalance { get; set; }
|
||||||
|
|
||||||
// Navigation property
|
// Navigation property
|
||||||
public UserEntity User { get; set; }
|
public UserEntity User { get; set; }
|
||||||
|
|||||||
Reference in New Issue
Block a user