Block user to create strategy with over allocation
This commit is contained in:
@@ -26,6 +26,16 @@ public interface IBotService
|
|||||||
Task<bool> UpdateBotStatisticsAsync(Guid identifier);
|
Task<bool> UpdateBotStatisticsAsync(Guid identifier);
|
||||||
Task<bool> SaveBotStatisticsAsync(Bot bot);
|
Task<bool> SaveBotStatisticsAsync(Bot bot);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the remaining available USDC allocation for the provided account,
|
||||||
|
/// subtracting the sum of BotTradingBalance from other bots using the same account.
|
||||||
|
/// Optionally exclude a specific bot identifier from the allocation sum (useful for restarts/updates).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="account">Target account.</param>
|
||||||
|
/// <param name="excludeIdentifier">Bot identifier to exclude from allocation sum.</param>
|
||||||
|
/// <returns>Available USDC amount that can be allocated.</returns>
|
||||||
|
Task<decimal> GetAvailableAllocationUsdAsync(Account account, Guid excludeIdentifier = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets paginated bots with filtering and sorting
|
/// Gets paginated bots with filtering and sorting
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -115,6 +115,14 @@ namespace Managing.Application.ManageBot
|
|||||||
|
|
||||||
if (account.Exchange == TradingExchanges.Evm || account.Exchange == TradingExchanges.GmxV2)
|
if (account.Exchange == TradingExchanges.Evm || account.Exchange == TradingExchanges.GmxV2)
|
||||||
{
|
{
|
||||||
|
// Allocation guard: ensure this bot's configured balance fits in remaining allocation
|
||||||
|
var availableAllocation = await GetAvailableAllocationUsdAsync(account, identifier);
|
||||||
|
if (botConfig.BotTradingBalance > availableAllocation)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Insufficient available allocation on account '{account.Name}'. Requested: {botConfig.BotTradingBalance:F2} USDC, Available: {availableAllocation:F2} USDC.");
|
||||||
|
}
|
||||||
|
|
||||||
var balanceCheckResult = await CheckAccountBalancesAsync(account);
|
var balanceCheckResult = await CheckAccountBalancesAsync(account);
|
||||||
if (!balanceCheckResult.IsSuccessful)
|
if (!balanceCheckResult.IsSuccessful)
|
||||||
{
|
{
|
||||||
@@ -370,6 +378,60 @@ namespace Managing.Application.ManageBot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<decimal> GetAvailableAllocationUsdAsync(Account account, Guid excludeIdentifier = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await ServiceScopeHelpers.WithScopedService<IBotRepository, decimal>(
|
||||||
|
_scopeFactory,
|
||||||
|
async repo =>
|
||||||
|
{
|
||||||
|
// Get all bots for the account's user
|
||||||
|
var botsForUser = await repo.GetBotsByUserIdAsync(account.User.Id);
|
||||||
|
|
||||||
|
// Sum allocations for bots using this account name, excluding the requested identifier
|
||||||
|
decimal totalAllocatedForAccount = 0m;
|
||||||
|
foreach (var bot in botsForUser)
|
||||||
|
{
|
||||||
|
if (excludeIdentifier != default && bot.Identifier == excludeIdentifier)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var grain = _grainFactory.GetGrain<ILiveTradingBotGrain>(bot.Identifier);
|
||||||
|
TradingBotConfig config;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
config = await grain.GetConfiguration();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(config.AccountName, account.Name, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
totalAllocatedForAccount += config.BotTradingBalance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current USDC balance for the account
|
||||||
|
var balances = await ServiceScopeHelpers.WithScopedService<IExchangeService, IEnumerable<Balance>>(
|
||||||
|
_scopeFactory, async exchangeService => await exchangeService.GetBalances(account));
|
||||||
|
var usdc = balances.FirstOrDefault(b => b.TokenName?.ToUpper() == "USDC");
|
||||||
|
var usdcValue = usdc?.Value ?? 0m;
|
||||||
|
|
||||||
|
var available = usdcValue - totalAllocatedForAccount;
|
||||||
|
return available < 0m ? 0m : available;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// On failure, be safe and return 0 to block over-allocation
|
||||||
|
return 0m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<(IEnumerable<Bot> Bots, int TotalCount)> GetBotsPaginatedAsync(
|
public async Task<(IEnumerable<Bot> Bots, int TotalCount)> GetBotsPaginatedAsync(
|
||||||
int pageNumber,
|
int pageNumber,
|
||||||
int pageSize,
|
int pageSize,
|
||||||
|
|||||||
@@ -72,6 +72,14 @@ namespace Managing.Application.ManageBot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enforce allocation limit across all bots using the same account
|
||||||
|
var availableAllocation = await _botService.GetAvailableAllocationUsdAsync(account, default);
|
||||||
|
if (request.Config.BotTradingBalance > availableAllocation)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Insufficient available allocation on account '{account.Name}'. Requested: {request.Config.BotTradingBalance:F2} USDC, Available: {availableAllocation:F2} USDC.");
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var botGrain = _grainFactory.GetGrain<ILiveTradingBotGrain>(Guid.NewGuid());
|
var botGrain = _grainFactory.GetGrain<ILiveTradingBotGrain>(Guid.NewGuid());
|
||||||
|
|||||||
Reference in New Issue
Block a user