using InfluxDB.Client.Api.Domain; using Managing.Application.Abstractions.Repositories; using Managing.Domain.Statistics; using Managing.Infrastructure.Databases.InfluxDb.Abstractions; using Managing.Infrastructure.Databases.InfluxDb.Models; using Microsoft.Extensions.Logging; namespace Managing.Infrastructure.Databases.InfluxDb; public class AgentBalanceRepository : IAgentBalanceRepository { private readonly string _balanceBucket = "agent-balances-bucket"; private readonly IInfluxDbRepository _influxDbRepository; private readonly ILogger _logger; public AgentBalanceRepository(IInfluxDbRepository influxDbRepository, ILogger logger) { _influxDbRepository = influxDbRepository; _logger = logger; } public void InsertAgentBalance(AgentBalance balance) { _influxDbRepository.Write(write => { var balanceDto = new AgentBalanceDto { UserId = balance.UserId, TotalBalanceValue = balance.TotalBalanceValue, UsdcWalletValue = balance.UsdcWalletValue, UsdcInPositionsValue = balance.UsdcInPositionsValue, BotsAllocationUsdValue = balance.BotsAllocationUsdValue, PnL = balance.PnL, Time = balance.Time }; write.WriteMeasurement( balanceDto, WritePrecision.Ns, _balanceBucket, _influxDbRepository.Organization); }); } public async Task> GetAgentBalancesByUserId(int userId, DateTime start, DateTime? end = null) { var results = await _influxDbRepository.QueryAsync(async query => { var effectiveEnd = end ?? DateTime.UtcNow; var timeRange = effectiveEnd - start; // Determine sampling interval based on time range to limit data points string samplingInterval; if (timeRange.TotalDays <= 1) { // Less than 1 day: 5-minute intervals (max ~288 points) samplingInterval = "5m"; } else if (timeRange.TotalDays <= 7) { // 1-7 days: 30-minute intervals (max ~336 points) samplingInterval = "30m"; } else if (timeRange.TotalDays <= 30) { // 1-30 days: 2-hour intervals (max ~360 points) samplingInterval = "2h"; } else if (timeRange.TotalDays <= 90) { // 1-3 months: 6-hour intervals (max ~360 points) samplingInterval = "6h"; } else if (timeRange.TotalDays <= 365) { // 3-12 months: 1-day intervals (max ~365 points) samplingInterval = "1d"; } else { // More than 1 year: 7-day intervals (max ~52 points) samplingInterval = "7d"; } var flux = $"from(bucket:\"{_balanceBucket}\") " + $"|> range(start: {start:s}Z" + (end.HasValue ? $", stop: {end.Value:s}Z" : "") + $") " + $"|> filter(fn: (r) => r[\"user_id\"] == \"{userId}\") " + $"|> aggregateWindow(every: {samplingInterval}, fn: last, createEmpty: false) " + $"|> pivot(rowKey: [\"_time\"], columnKey: [\"_field\"], valueColumn: \"_value\")"; var result = await query.QueryAsync(flux, _influxDbRepository.Organization); return result.Select(balance => new AgentBalance { UserId = balance.UserId, TotalBalanceValue = balance.TotalBalanceValue, UsdcWalletValue = balance.UsdcWalletValue, UsdcInPositionsValue = balance.UsdcInPositionsValue, BotsAllocationUsdValue = balance.BotsAllocationUsdValue, PnL = balance.PnL, Time = balance.Time }).ToList(); }); return results; } }