diff --git a/src/Managing.Application.Abstractions/Grains/PlatformSummaryGrainState.cs b/src/Managing.Application.Abstractions/Grains/PlatformSummaryGrainState.cs index af35d2d0..a53bfc03 100644 --- a/src/Managing.Application.Abstractions/Grains/PlatformSummaryGrainState.cs +++ b/src/Managing.Application.Abstractions/Grains/PlatformSummaryGrainState.cs @@ -45,29 +45,6 @@ public class PlatformSummaryGrainState // Flag to track if volume has been updated by events (not from bot strategies) [Id(15)] public bool VolumeUpdatedByEvents { get; set; } - - // Historical strategy activation/deactivation events - [Id(16)] public List StrategyEvents { get; set; } = new(); -} - -/// -/// Strategy activation/deactivation event -/// -[GenerateSerializer] -public class StrategyEvent -{ - [Id(0)] public DateTime Timestamp { get; set; } - [Id(1)] public StrategyEventType EventType { get; set; } - [Id(2)] public int NetChange { get; set; } // +1 for activation, -1 for deactivation -} - -/// -/// Type of strategy event -/// -public enum StrategyEventType -{ - Activation, - Deactivation } /// diff --git a/src/Managing.Application/Grains/PlatformSummaryGrain.cs b/src/Managing.Application/Grains/PlatformSummaryGrain.cs index 93199dec..9a2a35dc 100644 --- a/src/Managing.Application/Grains/PlatformSummaryGrain.cs +++ b/src/Managing.Application/Grains/PlatformSummaryGrain.cs @@ -1,5 +1,6 @@ using Managing.Application.Abstractions; using Managing.Application.Abstractions.Grains; +using Managing.Application.Abstractions.Repositories; using Managing.Application.Abstractions.Services; using Managing.Application.Orleans; using Managing.Domain.Candles; @@ -19,6 +20,7 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable { private readonly IPersistentState _state; private readonly IBotService _botService; + private readonly IBotRepository _botRepository; private readonly IAgentService _agentService; private readonly ITradingService _tradingService; private readonly ILogger _logger; @@ -29,12 +31,14 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable [PersistentState("platform-summary-state", "platform-summary-store")] IPersistentState state, IBotService botService, + IBotRepository botRepository, IAgentService agentService, ITradingService tradingService, ILogger logger) { _state = state; _botService = botService; + _botRepository = botRepository; _agentService = agentService; _tradingService = tradingService; _logger = logger; @@ -195,32 +199,6 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable newActiveCount = 0; } - var previousCount = _state.State.TotalActiveStrategies; - var change = newActiveCount - previousCount; - - // Record the strategy event if there was a change - if (change != 0) - { - var eventType = change > 0 ? StrategyEventType.Activation : StrategyEventType.Deactivation; - var strategyEvent = new StrategyEvent - { - Timestamp = DateTime.UtcNow, - EventType = eventType, - NetChange = change - }; - - _state.State.StrategyEvents.Add(strategyEvent); - - // Keep only last 1000 events to prevent unbounded growth - if (_state.State.StrategyEvents.Count > 1000) - { - _state.State.StrategyEvents.RemoveRange(0, _state.State.StrategyEvents.Count - 1000); - } - - _logger.LogInformation("Recorded strategy {EventType} event: {Change} strategies at {Timestamp}", - eventType, change, strategyEvent.Timestamp); - } - _state.State.TotalActiveStrategies = newActiveCount; await _state.WriteStateAsync(); } @@ -306,7 +284,7 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable { Date = today, TotalAgents = _state.State.TotalAgents, - TotalStrategies = CalculateActiveStrategiesForDate(today), + TotalStrategies = await CalculateActiveStrategiesForDateAsync(today), // Use bot entity data TotalVolume = _state.State.TotalPlatformVolume, TotalPnL = _state.State.TotalPlatformPnL, NetPnL = _state.State.NetPnL, @@ -348,38 +326,50 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable } /// - /// Calculates the number of active strategies on a specific date by replaying historical events + /// Calculates the number of active strategies on a specific date by querying bot entities + /// Uses LastStartTime, LastStopTime, and Status to determine activity /// /// The date to calculate active strategies for /// The number of active strategies on the target date - private int CalculateActiveStrategiesForDate(DateTime targetDate) + private async Task CalculateActiveStrategiesForDateAsync(DateTime targetDate) { try { - // Start with 0 active strategies + var today = DateTime.UtcNow.Date; + var bots = await _botRepository.GetBotsAsync(); var activeCount = 0; - // Replay all strategy events up to and including the target date - var relevantEvents = _state.State.StrategyEvents - .Where(e => e.Timestamp.Date <= targetDate.Date) - .OrderBy(e => e.Timestamp) - .ToList(); - - foreach (var strategyEvent in relevantEvents) + foreach (var bot in bots) { - activeCount += strategyEvent.NetChange; + var wasActive = false; - // Ensure we don't go below 0 (defensive programming) - if (activeCount < 0) + // If target date is today, check current status + if (targetDate.Date == today) { - _logger.LogWarning("Active strategy count went negative ({Count}) after event {EventType} at {Timestamp}, resetting to 0", - activeCount, strategyEvent.EventType, strategyEvent.Timestamp); - activeCount = 0; + wasActive = bot.Status == BotStatus.Running; + } + else + { + // For historical dates, use start/stop times + // Bot was active if it was started on or before the target date + // and either never stopped or stopped after the target date + if (bot.LastStartTime.HasValue) + { + var wasStarted = bot.LastStartTime.Value.Date <= targetDate.Date; + var wasNotStopped = !bot.LastStopTime.HasValue || bot.LastStopTime.Value.Date > targetDate.Date; + + wasActive = wasStarted && wasNotStopped; + } + } + + if (wasActive) + { + activeCount++; } } - _logger.LogDebug("Calculated {ActiveCount} active strategies for date {TargetDate} based on {EventCount} historical events", - activeCount, targetDate.Date, relevantEvents.Count); + _logger.LogDebug("Calculated {ActiveCount} active strategies for date {TargetDate} from {TotalBots} total bots", + activeCount, targetDate.Date, bots.Count()); return activeCount; } @@ -588,9 +578,9 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable // Use TradingBox to calculate metrics for filtered positions var metrics = TradingBox.CalculatePlatformSummaryMetrics(filteredPositions); - // Get historical agent and strategy counts for the target date + // Get agent count and calculate active strategies for the target date using bot entity data var totalAgents = await _agentService.GetTotalAgentCount(); - var totalStrategies = CalculateActiveStrategiesForDate(targetDate); + var totalStrategies = await CalculateActiveStrategiesForDateAsync(targetDate); _logger.LogInformation( "Calculated CUMULATIVE snapshot for {TargetDate}: Volume={TotalVolume}, OpenInterest={OpenInterest}, PositionCount={TotalPositionCount}, Fees={Fees}, PnL={PnL}",