Fix allocated amount when no bot
This commit is contained in:
@@ -25,7 +25,7 @@ public interface IBotService
|
|||||||
Task<IEnumerable<TradingBotConfig>> GetBotConfigsByIdsAsync(IEnumerable<Guid> botIds);
|
Task<IEnumerable<TradingBotConfig>> GetBotConfigsByIdsAsync(IEnumerable<Guid> botIds);
|
||||||
Task<bool> UpdateBotStatisticsAsync(Guid identifier);
|
Task<bool> UpdateBotStatisticsAsync(Guid identifier);
|
||||||
Task<bool> SaveBotStatisticsAsync(Bot bot);
|
Task<bool> SaveBotStatisticsAsync(Bot bot);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Computes the remaining available USDC allocation for the provided account,
|
/// Computes the remaining available USDC allocation for the provided account,
|
||||||
/// subtracting the sum of BotTradingBalance from other bots using the same account.
|
/// subtracting the sum of BotTradingBalance from other bots using the same account.
|
||||||
@@ -35,7 +35,7 @@ public interface IBotService
|
|||||||
/// <param name="excludeIdentifier">Bot identifier to exclude from allocation sum.</param>
|
/// <param name="excludeIdentifier">Bot identifier to exclude from allocation sum.</param>
|
||||||
/// <returns>Available USDC amount that can be allocated.</returns>
|
/// <returns>Available USDC amount that can be allocated.</returns>
|
||||||
Task<decimal> GetAvailableAllocationUsdAsync(Account account, Guid excludeIdentifier = default);
|
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>
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ namespace Managing.Application.ManageBot
|
|||||||
var botConfig = await botGrain.GetConfiguration();
|
var botConfig = await botGrain.GetConfiguration();
|
||||||
var account = await ServiceScopeHelpers.WithScopedService<IAccountService, Account>(
|
var account = await ServiceScopeHelpers.WithScopedService<IAccountService, Account>(
|
||||||
_scopeFactory,
|
_scopeFactory,
|
||||||
async accountService => await accountService.GetAccount(botConfig.AccountName, true, false));
|
async accountService => await accountService.GetAccount(botConfig.AccountName, true, true));
|
||||||
|
|
||||||
if (account.Exchange == TradingExchanges.Evm || account.Exchange == TradingExchanges.GmxV2)
|
if (account.Exchange == TradingExchanges.Evm || account.Exchange == TradingExchanges.GmxV2)
|
||||||
{
|
{
|
||||||
@@ -219,7 +219,7 @@ namespace Managing.Application.ManageBot
|
|||||||
public async Task<IEnumerable<TradingBotConfig>> GetBotConfigsByIdsAsync(IEnumerable<Guid> botIds)
|
public async Task<IEnumerable<TradingBotConfig>> GetBotConfigsByIdsAsync(IEnumerable<Guid> botIds)
|
||||||
{
|
{
|
||||||
var configs = new List<TradingBotConfig>();
|
var configs = new List<TradingBotConfig>();
|
||||||
|
|
||||||
foreach (var botId in botIds)
|
foreach (var botId in botIds)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -234,7 +234,7 @@ namespace Managing.Application.ManageBot
|
|||||||
// Continue with other bots even if one fails
|
// Continue with other bots even if one fails
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return configs;
|
return configs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,7 +378,8 @@ namespace Managing.Application.ManageBot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<decimal> GetAvailableAllocationUsdAsync(Account account, Guid excludeIdentifier = default)
|
public async Task<decimal> GetAvailableAllocationUsdAsync(Account account,
|
||||||
|
Guid excludeIdentifier = default)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -387,40 +388,44 @@ namespace Managing.Application.ManageBot
|
|||||||
async repo =>
|
async repo =>
|
||||||
{
|
{
|
||||||
// Get all bots for the account's user
|
// Get all bots for the account's user
|
||||||
var botsForUser = await repo.GetBotsByUserIdAsync(account.User.Id);
|
var botsForUser = (await repo.GetBotsByUserIdAsync(account.User.Id)).ToList();
|
||||||
|
|
||||||
// Sum allocations for bots using this account name, excluding the requested identifier
|
// Sum allocations for bots using this account name, excluding the requested identifier
|
||||||
decimal totalAllocatedForAccount = 0m;
|
var totalAllocatedForAccount = 0m;
|
||||||
foreach (var bot in botsForUser)
|
var usdcBalance = account.Balances.FirstOrDefault(b => b.TokenName == Ticker.USDC.ToString());
|
||||||
|
|
||||||
|
if (botsForUser.Any())
|
||||||
{
|
{
|
||||||
if (excludeIdentifier != default && bot.Identifier == excludeIdentifier)
|
foreach (var bot in botsForUser)
|
||||||
{
|
{
|
||||||
continue;
|
if (excludeIdentifier != default && bot.Identifier == excludeIdentifier)
|
||||||
}
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var grain = _grainFactory.GetGrain<ILiveTradingBotGrain>(bot.Identifier);
|
var grain = _grainFactory.GetGrain<ILiveTradingBotGrain>(bot.Identifier);
|
||||||
TradingBotConfig config;
|
TradingBotConfig config;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
config = await grain.GetConfiguration();
|
config = await grain.GetConfiguration();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(config.AccountName, account.Name, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(config.AccountName, account.Name, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
totalAllocatedForAccount += config.BotTradingBalance;
|
totalAllocatedForAccount += config.BotTradingBalance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
totalAllocatedForAccount = usdcBalance?.Value ?? 0m;
|
||||||
|
}
|
||||||
|
|
||||||
// Current USDC balance for the account
|
var usdcValue = usdcBalance?.Value ?? 0m;
|
||||||
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;
|
var available = usdcValue - totalAllocatedForAccount;
|
||||||
return available < 0m ? 0m : available;
|
return available < 0m ? 0m : available;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Managing.Application.Abstractions.Grains;
|
|||||||
using Managing.Application.Abstractions.Services;
|
using Managing.Application.Abstractions.Services;
|
||||||
using Managing.Application.ManageBot.Commands;
|
using Managing.Application.ManageBot.Commands;
|
||||||
using Managing.Common;
|
using Managing.Common;
|
||||||
|
using Managing.Domain.Accounts;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
|
|
||||||
@@ -42,7 +43,7 @@ namespace Managing.Application.ManageBot
|
|||||||
$"Bot trading balance must be greater than {Constants.GMX.Config.MinimumPositionAmount}");
|
$"Bot trading balance must be greater than {Constants.GMX.Config.MinimumPositionAmount}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var account = await _accountService.GetAccount(request.Config.AccountName, true, false);
|
var account = await _accountService.GetAccount(request.Config.AccountName, true, true);
|
||||||
|
|
||||||
if (account == null)
|
if (account == null)
|
||||||
{
|
{
|
||||||
@@ -59,16 +60,18 @@ namespace Managing.Application.ManageBot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Balance usdcBalance = null;
|
||||||
// For other exchanges, keep the original USDC balance check
|
// For other exchanges, keep the original USDC balance check
|
||||||
if (account.Exchange != TradingExchanges.Evm && account.Exchange != TradingExchanges.GmxV2)
|
if (account.Exchange != TradingExchanges.Evm && account.Exchange != TradingExchanges.GmxV2)
|
||||||
{
|
{
|
||||||
var usdcBalance = account.Balances.FirstOrDefault(b => b.TokenName == Ticker.USDC.ToString());
|
usdcBalance = account.Balances.FirstOrDefault(b => b.TokenName == Ticker.USDC.ToString());
|
||||||
|
|
||||||
if (usdcBalance == null ||
|
if (usdcBalance == null ||
|
||||||
usdcBalance.Value < Constants.GMX.Config.MinimumPositionAmount ||
|
usdcBalance.Value < Constants.GMX.Config.MinimumPositionAmount ||
|
||||||
usdcBalance.Value < request.Config.BotTradingBalance)
|
usdcBalance.Value < request.Config.BotTradingBalance)
|
||||||
{
|
{
|
||||||
throw new Exception($"Account {request.Config.AccountName} has no USDC balance or not enough balance");
|
throw new Exception(
|
||||||
|
$"Account {request.Config.AccountName} has no USDC balance or not enough balance");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,14 +80,15 @@ namespace Managing.Application.ManageBot
|
|||||||
if (request.Config.BotTradingBalance > availableAllocation)
|
if (request.Config.BotTradingBalance > availableAllocation)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
$"Insufficient available allocation on account '{account.Name}'. Requested: {request.Config.BotTradingBalance:F2} USDC, Available: {availableAllocation:F2} USDC.");
|
$"Insufficient available allocation on account '{account.Name}'. Requested: {request.Config.BotTradingBalance:F2} USDC, " +
|
||||||
|
$"Balance : {usdcBalance?.Value:F2 ?? 0} Available: {availableAllocation:F2} USDC.");
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var botGrain = _grainFactory.GetGrain<ILiveTradingBotGrain>(Guid.NewGuid());
|
var botGrain = _grainFactory.GetGrain<ILiveTradingBotGrain>(Guid.NewGuid());
|
||||||
await botGrain.CreateAsync(request.Config, request.User);
|
await botGrain.CreateAsync(request.Config, request.User);
|
||||||
|
|
||||||
// Only start the bot if createOnly is false
|
// Only start the bot if createOnly is false
|
||||||
if (!request.CreateOnly)
|
if (!request.CreateOnly)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ function PlatformSummary({index}: { index: number }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Main Stats Grid */}
|
{/* Main Stats Grid */}
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6 mb-8">
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
||||||
{/* Total Volume Traded */}
|
{/* Total Volume Traded */}
|
||||||
<div className="bg-base-200 rounded-lg p-6">
|
<div className="bg-base-200 rounded-lg p-6">
|
||||||
<h3 className="text-lg font-semibold text-gray-400 mb-2">Total Volume Traded</h3>
|
<h3 className="text-lg font-semibold text-gray-400 mb-2">Total Volume Traded</h3>
|
||||||
@@ -319,7 +319,7 @@ function PlatformSummary({index}: { index: number }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Platform Summary Stats */}
|
{/* Platform Summary Stats */}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-7 gap-6 mb-8">
|
||||||
<div className="bg-base-200 rounded-lg p-6">
|
<div className="bg-base-200 rounded-lg p-6">
|
||||||
<h3 className="text-lg font-semibold text-gray-400 mb-2">Total Agents</h3>
|
<h3 className="text-lg font-semibold text-gray-400 mb-2">Total Agents</h3>
|
||||||
<div className="text-3xl font-bold text-white mb-1">
|
<div className="text-3xl font-bold text-white mb-1">
|
||||||
@@ -367,10 +367,7 @@ function PlatformSummary({index}: { index: number }) {
|
|||||||
{changesToday.openInterestChange >= 0 ? '+' : ''}{formatCurrency(changesToday.openInterestChange)} Today
|
{changesToday.openInterestChange >= 0 ? '+' : ''}{formatCurrency(changesToday.openInterestChange)} Today
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Position Metrics */}
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
|
||||||
<div className="bg-base-200 rounded-lg p-6">
|
<div className="bg-base-200 rounded-lg p-6">
|
||||||
<h3 className="text-lg font-semibold text-gray-400 mb-2">Total Positions</h3>
|
<h3 className="text-lg font-semibold text-gray-400 mb-2">Total Positions</h3>
|
||||||
<div className="text-3xl font-bold text-white mb-1">
|
<div className="text-3xl font-bold text-white mb-1">
|
||||||
@@ -415,6 +412,11 @@ function PlatformSummary({index}: { index: number }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Position Metrics */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Platform Metrics Chart */}
|
{/* Platform Metrics Chart */}
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<PlatformLineChart
|
<PlatformLineChart
|
||||||
|
|||||||
Reference in New Issue
Block a user