Add Agent tracking balance

This commit is contained in:
2025-05-16 22:30:18 +07:00
parent b34e3aa886
commit 1cfb83f0b1
34 changed files with 764 additions and 115 deletions

View File

@@ -1,52 +1,67 @@
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Repositories;
using Managing.Application.Abstractions.Services;
using Managing.Application.ManageBot.Commands;
using Managing.Application.Workers.Abstractions;
using Managing.Domain.Statistics;
using MediatR;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using static Managing.Common.Enums;
namespace Managing.Application.Workers;
public class BalanceTrackingWorker : BackgroundService
public class BalanceTrackingWorker : BaseWorker<BalanceTrackingWorker>
{
private readonly ILogger<BalanceTrackingWorker> _logger;
private readonly IMediator _mediator;
private readonly IAccountService _accountService;
private readonly TimeSpan _interval = TimeSpan.FromMinutes(1);
private readonly IAgentBalanceRepository _agentBalanceRepository;
private bool _isInitialized;
public BalanceTrackingWorker(
ILogger<BalanceTrackingWorker> logger,
IMediator mediator,
IAccountService accountService)
IAccountService accountService,
IAgentBalanceRepository agentBalanceRepository,
IWorkerService workerService)
: base(
WorkerType.BalanceTracking,
logger,
TimeSpan.FromHours(1),
workerService)
{
_logger = logger;
_mediator = mediator;
_accountService = accountService;
_agentBalanceRepository = agentBalanceRepository;
_isInitialized = false;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
protected override async Task Run(CancellationToken cancellationToken)
{
while (!stoppingToken.IsCancellationRequested)
if (!_isInitialized)
{
try
{
_logger.LogInformation("Starting balance tracking...");
await TrackBalances();
_logger.LogInformation("Completed balance tracking");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occurred while tracking balances");
}
await Task.Delay(_interval, stoppingToken);
_logger.LogInformation("Waiting 5 minutes for bots to initialize before starting balance tracking...");
await Task.Delay(TimeSpan.FromMinutes(3), cancellationToken);
_isInitialized = true;
}
}
private async Task TrackBalances()
{
_logger.LogInformation("Starting balance tracking...");
// Get all active bots
var bots = await _mediator.Send(new GetActiveBotsCommand());
if (bots.Count == 0)
{
_logger.LogWarning("No active bots found. Skipping balance tracking.");
return;
}
_logger.LogInformation($"Found {bots.Count} active bots. Proceeding with balance tracking.");
await TrackBalances(bots);
_logger.LogInformation("Completed balance tracking");
}
private async Task TrackBalances(List<ITradingBot> bots)
{
// Group bots by agent/user
var botsByAgent = bots
.Where(b => b.User != null)
@@ -59,8 +74,25 @@ public class BalanceTrackingWorker : BackgroundService
{
var agentName = agentEntry.Key;
var agentBots = agentEntry.Value;
// Check if we need to update this agent's balance
var lastBalance = (await _agentBalanceRepository.GetAgentBalances(
agentName,
DateTime.UtcNow.AddDays(-1),
DateTime.UtcNow)).OrderByDescending(b => b.Time).FirstOrDefault();
if (lastBalance != null && DateTime.UtcNow.Subtract(lastBalance.Time).TotalHours < 24)
{
_logger.LogInformation(
$"Skipping agent {agentName} - Last balance update was {lastBalance.Time:g} UTC");
continue;
}
decimal totalAgentValue = 0;
decimal totalBotAllocatedBalance = 0;
decimal totalAccountUsdValue = 0;
decimal botsAllocationUsdValue = 0;
decimal totalPnL = 0;
_logger.LogInformation($"Processing agent: {agentName} with {agentBots.Count} bots");
@@ -80,7 +112,7 @@ public class BalanceTrackingWorker : BackgroundService
if (accountBalance.Balances != null)
{
var accountTotalValue = accountBalance.Balances.Sum(b => b.Value);
// If this is the account that holds the bot balances (USDC), subtract the allocated amounts
var usdcBalance = accountBalance.Balances.FirstOrDefault(b => b.TokenName == "USDC");
if (usdcBalance != null)
@@ -92,11 +124,11 @@ public class BalanceTrackingWorker : BackgroundService
$"Account {accountBalance.Name} USDC balance after bot allocation: {usdcBalance.Value} USD");
}
totalAgentValue += accountTotalValue;
totalAccountUsdValue += accountTotalValue;
_logger.LogInformation(
$"Account {accountBalance.Name} total value: {accountTotalValue} USD");
// Log individual token balances for debugging
foreach (var balance in accountBalance.Balances)
{
@@ -106,25 +138,42 @@ public class BalanceTrackingWorker : BackgroundService
}
}
// Add up all bot wallet balances for this agent
// Process all bots in a single iteration
foreach (var bot in agentBots)
{
// Get wallet balance
var latestBotBalance = bot.WalletBalances
.OrderByDescending(x => x.Key)
.FirstOrDefault();
if (latestBotBalance.Key != default)
{
totalAgentValue += latestBotBalance.Value;
botsAllocationUsdValue += latestBotBalance.Value;
_logger.LogInformation(
$"Bot {bot.Name} wallet balance: {latestBotBalance.Value} USD at {latestBotBalance.Key}");
}
// Calculate PnL
totalPnL += bot.GetProfitAndLoss();
}
totalAgentValue = totalAccountUsdValue + botsAllocationUsdValue;
_logger.LogInformation(
$"Agent {agentName} total aggregated value: {totalAgentValue} USD");
// TODO: Save aggregated agent balance to database
$"Agent {agentName} total aggregated value: {totalAgentValue} USD (Account: {totalAccountUsdValue} USD, Bot Wallet: {botsAllocationUsdValue} USD)");
// Create and save the agent balance
var agentBalance = new AgentBalance
{
AgentName = agentName,
TotalValue = totalAgentValue,
TotalAccountUsdValue = totalAccountUsdValue,
BotsAllocationUsdValue = botsAllocationUsdValue,
PnL = totalPnL,
Time = DateTime.UtcNow
};
_agentBalanceRepository.InsertAgentBalance(agentBalance);
}
catch (Exception ex)
{

View File

@@ -0,0 +1,23 @@
using Managing.Application.ManageBot;
using Managing.Application.Workers.Abstractions;
using MediatR;
using Microsoft.Extensions.Logging;
using static Managing.Common.Enums;
namespace Managing.Application.Workers;
public class BotManagerWorker(
ILogger<BotManagerWorker> logger,
IMediator mediadior,
IWorkerService workerService)
: BaseWorker<BotManagerWorker>(WorkerType.BotManager,
logger,
TimeSpan.FromMinutes(5),
workerService)
{
protected override async Task Run(CancellationToken cancellationToken)
{
var loadBackupBotCommand = new LoadBackupBotCommand();
await mediadior.Send(loadBackupBotCommand, cancellationToken);
}
}