Use usdc balance instead usdc value for ensuring balance check

This commit is contained in:
2025-10-05 01:36:25 +07:00
parent 63683d6bdf
commit de0d042254
7 changed files with 72 additions and 96 deletions

View File

@@ -19,7 +19,7 @@ public interface IEvmManager
string VerifySignature(string signature, string message); string VerifySignature(string signature, string message);
Task<List<EvmBalance>> GetBalances(Chain chain, int page, int pageSize, string publicAddress); Task<List<EvmBalance>> GetBalances(Chain chain, int page, int pageSize, string publicAddress);
Task<List<EvmBalance>> GetAllBalances(Chain chain, string publicAddress); Task<List<EvmBalance>> GetAllBalances(Chain chain, string publicAddress);
Task<List<EvmBalance>> GetAllBalancesOnAllChain(string publicAddress); Task<List<Balance>> GetAllBalancesOnAllChain(string publicAddress);
Task<List<Candle>> GetCandles(Ticker ticker, DateTime startDate, Task<List<Candle>> GetCandles(Ticker ticker, DateTime startDate,
Timeframe interval, bool isFirstCall = false); Timeframe interval, bool isFirstCall = false);
@@ -68,7 +68,7 @@ public interface IEvmManager
Task<string> SignMessageAsync(string embeddedWalletId, string address, string message); Task<string> SignMessageAsync(string embeddedWalletId, string address, string message);
Task<List<Position>> GetPositions(Account account); Task<List<Position>> GetPositions(Account account);
/// <summary> /// <summary>
/// Clears the cached balances for a specific chain and address /// Clears the cached balances for a specific chain and address
/// </summary> /// </summary>

View File

@@ -590,7 +590,7 @@ public class AgentGrain : Grain, IAgentGrain
return null; return null;
} }
var userAccounts = await _accountService.GetAccountsByUserAsync(user, hideSecrets: true, true); var userAccounts = await _accountService.GetAccountsByUserAsync(user, hideSecrets: true, false);
var account = userAccounts.FirstOrDefault(a => a.Name == accountName); var account = userAccounts.FirstOrDefault(a => a.Name == accountName);
if (account == null) if (account == null)
{ {
@@ -604,7 +604,7 @@ public class AgentGrain : Grain, IAgentGrain
var usdcBalance = balances.FirstOrDefault(b => b.TokenName?.ToUpper() == "USDC"); var usdcBalance = balances.FirstOrDefault(b => b.TokenName?.ToUpper() == "USDC");
var ethValueInUsd = ethBalance?.Amount * ethBalance?.Price ?? 0; var ethValueInUsd = ethBalance?.Amount * ethBalance?.Price ?? 0;
var usdcValue = usdcBalance?.Value ?? 0; var usdc = usdcBalance?.Amount ?? 0;
// Cache the balance data // Cache the balance data
var balanceData = new CachedBalanceData var balanceData = new CachedBalanceData
@@ -612,7 +612,7 @@ public class AgentGrain : Grain, IAgentGrain
LastFetched = DateTime.UtcNow, LastFetched = DateTime.UtcNow,
AccountName = accountName, AccountName = accountName,
EthValueInUsd = ethValueInUsd, EthValueInUsd = ethValueInUsd,
UsdcValue = usdcValue UsdcValue = usdc
}; };
_state.State.CachedBalanceData = balanceData; _state.State.CachedBalanceData = balanceData;

View File

@@ -67,7 +67,7 @@ namespace Managing.Application.Bots.Models
/// <summary> /// <summary>
/// Whether the cached data is still valid (less than 1 minute old) /// Whether the cached data is still valid (less than 1 minute old)
/// </summary> /// </summary>
public bool IsValid => DateTime.UtcNow - LastFetched < TimeSpan.FromMinutes(1.5); public bool IsValid => DateTime.UtcNow - LastFetched < TimeSpan.FromMinutes(1);
} }
/// <summary> /// <summary>

View File

@@ -394,35 +394,28 @@ namespace Managing.Application.ManageBot
var totalAllocatedForAccount = 0m; var totalAllocatedForAccount = 0m;
var usdcBalance = account.Balances.FirstOrDefault(b => b.TokenName == Ticker.USDC.ToString()); var usdcBalance = account.Balances.FirstOrDefault(b => b.TokenName == Ticker.USDC.ToString());
if (botsForUser.Any()) foreach (var bot in botsForUser)
{ {
foreach (var bot in botsForUser) if (excludeIdentifier != default && bot.Identifier == excludeIdentifier)
{ {
if (excludeIdentifier != default && bot.Identifier == excludeIdentifier) continue;
{ }
continue;
} var grain = _grainFactory.GetGrain<ILiveTradingBotGrain>(bot.Identifier);
TradingBotConfig config;
var grain = _grainFactory.GetGrain<ILiveTradingBotGrain>(bot.Identifier); try
TradingBotConfig config; {
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;
} }
var usdcValue = usdcBalance?.Value ?? 0m; var usdcValue = usdcBalance?.Value ?? 0m;

View File

@@ -2,7 +2,6 @@
using Managing.Common; using Managing.Common;
using Managing.Domain.Accounts; using Managing.Domain.Accounts;
using Managing.Domain.Candles; using Managing.Domain.Candles;
using Managing.Domain.Evm;
using Managing.Domain.Statistics; using Managing.Domain.Statistics;
using Managing.Domain.Trades; using Managing.Domain.Trades;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@@ -45,21 +44,7 @@ public class EvmProcessor : BaseProcessor
public override async Task<List<Balance>> GetBalances(Account account, bool isForPaperTrading = false) public override async Task<List<Balance>> GetBalances(Account account, bool isForPaperTrading = false)
{ {
var balances = await _evmManager.GetAllBalancesOnAllChain(account.Key); return await _evmManager.GetAllBalancesOnAllChain(account.Key);
return Map(balances);
}
private List<Balance> Map(List<EvmBalance> balances)
{
return balances.ConvertAll(balance => new Balance
{
TokenName = balance.TokenName,
Price = balance.Price,
Value = balance.Value,
Amount = balance.Balance,
TokenAdress = balance.TokenAddress,
Chain = balance.Chain
});
} }
public override async Task<Candle> GetCandle(Account account, Ticker ticker, DateTime date) public override async Task<Candle> GetCandle(Account account, Ticker ticker, DateTime date)
@@ -73,7 +58,8 @@ public class EvmProcessor : BaseProcessor
return await _evmManager.GetCandles(ticker, startDate, interval); return await _evmManager.GetCandles(ticker, startDate, interval);
} }
public async Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate, Timeframe interval, bool isFirstCall) public async Task<List<Candle>> GetCandles(Account account, Ticker ticker, DateTime startDate, Timeframe interval,
bool isFirstCall)
{ {
return await _evmManager.GetCandles(ticker, startDate, interval, isFirstCall); return await _evmManager.GetCandles(ticker, startDate, interval, isFirstCall);
} }
@@ -86,11 +72,13 @@ public class EvmProcessor : BaseProcessor
public override async Task<decimal> GetPrice(Account account, Ticker ticker, DateTime date) public override async Task<decimal> GetPrice(Account account, Ticker ticker, DateTime date)
{ {
var candles = await GetCandles(account, ticker, date, Timeframe.OneMinute, true); var candles = await GetCandles(account, ticker, date, Timeframe.OneMinute, true);
if (candles == null || !candles.Any()) if (candles == null || !candles.Any())
{ {
_logger.LogError($"No candles available for ticker {ticker} at date {date:yyyy-MM-dd HH:mm:ss}. This could indicate a data source issue or invalid ticker."); _logger.LogError(
throw new InvalidOperationException($"Cannot get price for {ticker} - no candle data available for the requested date {date:yyyy-MM-dd HH:mm:ss}. Please check if the ticker is valid and data source is accessible."); $"No candles available for ticker {ticker} at date {date:yyyy-MM-dd HH:mm:ss}. This could indicate a data source issue or invalid ticker.");
throw new InvalidOperationException(
$"Cannot get price for {ticker} - no candle data available for the requested date {date:yyyy-MM-dd HH:mm:ss}. Please check if the ticker is valid and data source is accessible.");
} }
return candles.Last().Close; return candles.Last().Close;
@@ -110,7 +98,7 @@ public class EvmProcessor : BaseProcessor
// Try to get the most recent candle data (last 5 minutes) // Try to get the most recent candle data (last 5 minutes)
var recentDate = DateTime.UtcNow.AddMinutes(-5); var recentDate = DateTime.UtcNow.AddMinutes(-5);
var candles = await GetCandles(account, ticker, recentDate, Timeframe.OneMinute, true); var candles = await GetCandles(account, ticker, recentDate, Timeframe.OneMinute, true);
if (candles != null && candles.Any()) if (candles != null && candles.Any())
{ {
var latestCandle = candles.OrderByDescending(c => c.Date).First(); var latestCandle = candles.OrderByDescending(c => c.Date).First();
@@ -121,17 +109,19 @@ public class EvmProcessor : BaseProcessor
// Fallback: Try to get price from a broader time range // Fallback: Try to get price from a broader time range
var fallbackDate = DateTime.UtcNow.AddHours(-1); var fallbackDate = DateTime.UtcNow.AddHours(-1);
var fallbackCandles = await GetCandles(account, ticker, fallbackDate, Timeframe.OneMinute, true); var fallbackCandles = await GetCandles(account, ticker, fallbackDate, Timeframe.OneMinute, true);
if (fallbackCandles != null && fallbackCandles.Any()) if (fallbackCandles != null && fallbackCandles.Any())
{ {
var latestFallbackCandle = fallbackCandles.OrderByDescending(c => c.Date).First(); var latestFallbackCandle = fallbackCandles.OrderByDescending(c => c.Date).First();
_logger.LogWarning($"Using fallback price {latestFallbackCandle.Close} for {ticker} from 1-hour old data"); _logger.LogWarning(
$"Using fallback price {latestFallbackCandle.Close} for {ticker} from 1-hour old data");
return latestFallbackCandle.Close; return latestFallbackCandle.Close;
} }
// If all else fails, throw a descriptive error // If all else fails, throw a descriptive error
_logger.LogError($"No price data available for {ticker} from any source"); _logger.LogError($"No price data available for {ticker} from any source");
throw new InvalidOperationException($"Cannot get current price for {ticker} - no price data available from broker. Please check if the ticker is valid and the broker is accessible."); throw new InvalidOperationException(
$"Cannot get current price for {ticker} - no price data available from broker. Please check if the ticker is valid and the broker is accessible.");
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -162,7 +152,7 @@ public class EvmProcessor : BaseProcessor
public override async Task<IEnumerable<Position>> GetPositions(Account account) public override async Task<IEnumerable<Position>> GetPositions(Account account)
{ {
return await _evmManager.GetPositions(account); return await _evmManager.GetPositions(account);
} }
public override decimal GetVolume(Account account, Ticker ticker) public override decimal GetVolume(Account account, Ticker ticker)

View File

@@ -343,7 +343,7 @@ public class EvmManager : IEvmManager
"https://api.coingecko.com/api/v3/simple/price?ids=" + idsCombined + "&vs_currencies=usd"); "https://api.coingecko.com/api/v3/simple/price?ids=" + idsCombined + "&vs_currencies=usd");
} }
public async Task<List<EvmBalance>> GetAllBalancesOnAllChain(string publicAddress) public async Task<List<Balance>> GetAllBalancesOnAllChain(string publicAddress)
{ {
try try
{ {
@@ -352,44 +352,17 @@ public class EvmManager : IEvmManager
var chains = new[] { "arbitrum" }; var chains = new[] { "arbitrum" };
// Get balances from Web3Proxy service // Get balances from Web3Proxy service
var balances = await _web3ProxyService.GetWalletBalanceAsync(publicAddress, assets, chains); return await _web3ProxyService.GetWalletBalanceAsync(publicAddress, assets, chains);
// Convert Balance objects to EvmBalance objects // TODO : Update here to get all different chains
var evmBalances = new List<EvmBalance>(); // var othersChains = ChainService.GetChains();
//
foreach (var balance in balances) // foreach (var chain in othersChains)
{ // {
if (balance.Amount > 0) // evmBalances.AddRange(await GetAllBalances(chain, publicAddress));
{ // }
var evmBalance = new EvmBalance //
{ // return evmBalances;
Balance = balance.Amount,
TokenName = balance.TokenName ?? "Unknown",
TokenAddress = balance.TokenAdress ?? "",
TokenImage = balance.TokenImage ?? "",
Price = balance.Price,
Value = balance.Value,
Chain = new Chain
{
Id = balance.Chain?.Id ?? "",
Name = balance.Chain?.Name ?? "Unknown",
ChainId = balance.Chain?.ChainId ?? 0,
RpcUrl = balance.Chain?.RpcUrl ?? ""
}
};
evmBalances.Add(evmBalance);
}
}
var othersChains = ChainService.GetChains();
foreach (var chain in othersChains)
{
evmBalances.AddRange(await GetAllBalances(chain, publicAddress));
}
return evmBalances;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -404,7 +377,7 @@ public class EvmManager : IEvmManager
chainBalances.AddRange(await GetAllBalances(chain, publicAddress)); chainBalances.AddRange(await GetAllBalances(chain, publicAddress));
} }
return chainBalances; return EvmMappers.Map(chainBalances);
} }
} }

View File

@@ -0,0 +1,20 @@
using Managing.Domain.Accounts;
using Managing.Domain.Evm;
namespace Managing.Infrastructure.Evm;
public static class EvmMappers
{
public static List<Balance> Map(List<EvmBalance> balances)
{
return balances.ConvertAll(balance => new Balance
{
TokenName = balance.TokenName,
Price = balance.Price,
Value = balance.Value,
Amount = balance.Balance,
TokenAdress = balance.TokenAddress,
Chain = balance.Chain
});
}
}