Add balance tracking on bot start/restart; implement TrackBalanceOnBotStartAsync in IAgentGrain and AgentGrain, and trigger it in LiveTradingBotGrain. Enhance logging for balance tracking operations.
This commit is contained in:
@@ -67,5 +67,12 @@ namespace Managing.Application.Abstractions.Grains
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[OneWay]
|
[OneWay]
|
||||||
Task ForceUpdateSummary();
|
Task ForceUpdateSummary();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggers balance tracking data insertion when a bot starts/restarts.
|
||||||
|
/// This captures the balance change related to botsAllocationUsdValue.
|
||||||
|
/// </summary>
|
||||||
|
[OneWay]
|
||||||
|
Task TrackBalanceOnBotStartAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -665,4 +665,94 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
(int)this.GetPrimaryKeyLong());
|
(int)this.GetPrimaryKeyLong());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggers balance tracking data insertion when a bot starts/restarts.
|
||||||
|
/// This captures the balance change related to botsAllocationUsdValue.
|
||||||
|
/// </summary>
|
||||||
|
[OneWay]
|
||||||
|
public async Task TrackBalanceOnBotStartAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Tracking balance on bot start/restart for user {UserId}", this.GetPrimaryKeyLong());
|
||||||
|
|
||||||
|
// Get all positions for this agent's bots as initiator
|
||||||
|
var positions = (await _tradingService.GetPositionByUserIdAsync((int)this.GetPrimaryKeyLong()))
|
||||||
|
.Where(p => p.IsValidForMetrics()).ToList();
|
||||||
|
|
||||||
|
var metrics = TradingBox.CalculateAgentSummaryMetrics(positions);
|
||||||
|
|
||||||
|
// Calculate total balance (USDC wallet + USDC in open positions value)
|
||||||
|
decimal totalBalance = 0;
|
||||||
|
decimal usdcWalletValue = 0;
|
||||||
|
decimal usdcInPositionsValue = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var userId = (int)this.GetPrimaryKeyLong();
|
||||||
|
var user = await _userService.GetUserByIdAsync(userId);
|
||||||
|
var userAccounts = await _accountService.GetAccountsByUserAsync(user, hideSecrets: true, true);
|
||||||
|
|
||||||
|
foreach (var account in userAccounts)
|
||||||
|
{
|
||||||
|
// Get USDC balance
|
||||||
|
var usdcBalances = await GetOrRefreshBalanceDataAsync(account.Name);
|
||||||
|
var usdcBalance = usdcBalances?.UsdcValue ?? 0;
|
||||||
|
usdcWalletValue += usdcBalance;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var position in positions.Where(p => p.IsOpen()))
|
||||||
|
{
|
||||||
|
var positionUsd = position.Open.Price * position.Open.Quantity;
|
||||||
|
var net = position.ProfitAndLoss?.Net ?? 0;
|
||||||
|
usdcInPositionsValue += positionUsd + net;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalBalance = usdcWalletValue + usdcInPositionsValue;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error calculating total balance for agent {UserId} during bot start tracking",
|
||||||
|
this.GetPrimaryKeyLong());
|
||||||
|
totalBalance = 0; // Set to 0 if calculation fails
|
||||||
|
usdcWalletValue = 0;
|
||||||
|
usdcInPositionsValue = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get active strategies to calculate botsAllocationUsdValue
|
||||||
|
var activeStrategies = await ServiceScopeHelpers.WithScopedService<IBotService, List<Bot>>(_scopeFactory,
|
||||||
|
async (botService) =>
|
||||||
|
{
|
||||||
|
return (await botService.GetBotsByUser((int)this.GetPrimaryKeyLong()))
|
||||||
|
.Where(b => b.Status == BotStatus.Running)
|
||||||
|
.ToList();
|
||||||
|
});
|
||||||
|
|
||||||
|
var botsAllocationUsdValue = 0m;
|
||||||
|
|
||||||
|
if (activeStrategies.Any())
|
||||||
|
{
|
||||||
|
// Calculate bots allocation USD value from bot configurations
|
||||||
|
var botIds = activeStrategies.Select(b => b.Identifier);
|
||||||
|
var botConfigs =
|
||||||
|
await ServiceScopeHelpers.WithScopedService<IBotService, IEnumerable<TradingBotConfig>>(
|
||||||
|
_scopeFactory,
|
||||||
|
async (botService) => { return await botService.GetBotConfigsByIdsAsync(botIds); });
|
||||||
|
botsAllocationUsdValue = botConfigs.Sum(config => config.BotTradingBalance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert balance tracking data
|
||||||
|
InsertBalanceTrackingData(totalBalance, botsAllocationUsdValue, metrics.NetPnL, usdcWalletValue,
|
||||||
|
usdcInPositionsValue);
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Balance tracking completed on bot start/restart for user {UserId}: TotalBalance={TotalBalance}, BotsAllocation={BotsAllocation}, NetPnL={NetPnL}",
|
||||||
|
this.GetPrimaryKeyLong(), totalBalance, botsAllocationUsdValue, metrics.NetPnL);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error tracking balance on bot start/restart for user {UserId}",
|
||||||
|
this.GetPrimaryKeyLong());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -247,6 +247,24 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
|||||||
await SaveBotAsync(BotStatus.Running);
|
await SaveBotAsync(BotStatus.Running);
|
||||||
await UpdateBotRegistryStatus(BotStatus.Running);
|
await UpdateBotRegistryStatus(BotStatus.Running);
|
||||||
|
|
||||||
|
// Trigger balance tracking since we now have a balance change related to botsAllocationUsdValue
|
||||||
|
if (_state.State.User != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var agentGrain = GrainFactory.GetGrain<IAgentGrain>(_state.State.User.Id);
|
||||||
|
await agentGrain.TrackBalanceOnBotStartAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex,
|
||||||
|
"Failed to track balance on bot start for LiveTradingBotGrain {GrainId}, but bot started successfully",
|
||||||
|
this.GetPrimaryKey());
|
||||||
|
SentrySdk.CaptureException(ex);
|
||||||
|
// Don't throw - bot started successfully, balance tracking is non-critical
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_logger.LogInformation("LiveTradingBotGrain {GrainId} resumed successfully", this.GetPrimaryKey());
|
_logger.LogInformation("LiveTradingBotGrain {GrainId} resumed successfully", this.GetPrimaryKey());
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -109,18 +109,11 @@ public abstract class TradingBotBase : ITradingBot
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case BotStatus.Running:
|
case BotStatus.Running:
|
||||||
|
case BotStatus.Stopped:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case BotStatus.Stopped:
|
|
||||||
// If status was Stopped we log a message to inform the user that the bot is restarting
|
|
||||||
await LogInformationAsync($"🔄 Bot Restarted\n" +
|
|
||||||
$"📊 Resuming operations with {Signals.Count} signals and {Positions.Count} positions\n" +
|
|
||||||
$"✅ Ready to continue trading");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Handle any other status if needed
|
return;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
Reference in New Issue
Block a user