From d2a4bd4426f6b873d413d1bab5bbd57290de8bf6 Mon Sep 17 00:00:00 2001 From: cryptooda Date: Wed, 24 Sep 2025 12:21:56 +0700 Subject: [PATCH] Fix dailySnapshot for platformsummary --- .../Controllers/DataController.cs | 55 +++++- .../Extensions/PlatformSummaryExtensions.cs | 42 ----- src/Managing.Api/Managing.Api.csproj | 4 + .../Models/Responses/AgentSummaryViewModel.cs | 98 ++++++----- .../Grains/IPlatformSummaryGrain.cs | 8 +- .../Grains/PlatformSummaryGrainState.cs | 27 +-- .../Models/PlatformSummaryViewModel.cs | 159 ------------------ .../Grains/PlatformSummaryGrain.cs | 100 +++-------- .../src/generated/ManagingApi.ts | 28 +-- .../src/generated/ManagingApiTypes.ts | 28 +-- .../pages/dashboardPage/platformSummary.tsx | 89 +++++++--- 11 files changed, 241 insertions(+), 397 deletions(-) delete mode 100644 src/Managing.Api/Extensions/PlatformSummaryExtensions.cs delete mode 100644 src/Managing.Application.Abstractions/Models/PlatformSummaryViewModel.cs diff --git a/src/Managing.Api/Controllers/DataController.cs b/src/Managing.Api/Controllers/DataController.cs index b51454be..61e222f0 100644 --- a/src/Managing.Api/Controllers/DataController.cs +++ b/src/Managing.Api/Controllers/DataController.cs @@ -1,5 +1,4 @@ -using Managing.Api.Extensions; -using Managing.Api.Models.Requests; +using Managing.Api.Models.Requests; using Managing.Api.Models.Responses; using Managing.Application.Abstractions.Grains; using Managing.Application.Abstractions.Services; @@ -15,6 +14,7 @@ using MediatR; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using static Managing.Common.Enums; +using DailySnapshot = Managing.Api.Models.Responses.DailySnapshot; namespace Managing.Api.Controllers; @@ -563,10 +563,10 @@ public class DataController : ControllerBase var platformSummaryGrain = _grainFactory.GetGrain("platform-summary"); // Get the platform summary from the grain (handles caching and real-time updates) - var abstractionsSummary = await platformSummaryGrain.GetPlatformSummaryAsync(); + var state = await platformSummaryGrain.GetPlatformSummaryAsync(); - // Convert to API ViewModel - var summary = abstractionsSummary.ToApiViewModel(); + // Map the state to the view model + var summary = MapPlatformSummaryStateToViewModel(state); return Ok(summary); } @@ -778,4 +778,49 @@ public class DataController : ControllerBase return scenario; } + + /// + /// Maps PlatformSummaryGrainState to PlatformSummaryViewModel + /// + /// The platform summary grain state + /// A mapped platform summary view model + private PlatformSummaryViewModel MapPlatformSummaryStateToViewModel(PlatformSummaryGrainState state) + { + return new PlatformSummaryViewModel + { + // Metadata + LastUpdated = state.LastUpdated, + LastSnapshot = state.LastSnapshot, + HasPendingChanges = state.HasPendingChanges, + + // Current metrics + TotalAgents = state.TotalAgents, + TotalActiveStrategies = state.TotalActiveStrategies, + TotalPlatformPnL = state.TotalPlatformPnL, + TotalPlatformVolume = state.TotalPlatformVolume, + OpenInterest = state.OpenInterest, + TotalPositionCount = state.TotalPositionCount, + TotalPlatformFees = state.TotalPlatformFees, + + // Historical snapshots + DailySnapshots = state.DailySnapshots + .OrderBy(s => s.Date) + .Select(s => new DailySnapshot + { + Date = s.Date, + TotalAgents = s.TotalAgents, + TotalStrategies = s.TotalStrategies, + TotalVolume = s.TotalVolume, + TotalPnL = s.TotalPnL, + TotalOpenInterest = s.TotalOpenInterest, + TotalPositionCount = s.TotalPositionCount + }) + .ToList(), + + // Breakdowns + VolumeByAsset = state.VolumeByAsset ?? new Dictionary(), + PositionCountByAsset = state.PositionCountByAsset ?? new Dictionary(), + PositionCountByDirection = state.PositionCountByDirection ?? new Dictionary() + }; + } } \ No newline at end of file diff --git a/src/Managing.Api/Extensions/PlatformSummaryExtensions.cs b/src/Managing.Api/Extensions/PlatformSummaryExtensions.cs deleted file mode 100644 index 2bb719e9..00000000 --- a/src/Managing.Api/Extensions/PlatformSummaryExtensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Managing.Api.Models.Responses; -using Managing.Common; -using AbstractionsPlatformSummaryViewModel = Managing.Application.Abstractions.Models.PlatformSummaryViewModel; - -namespace Managing.Api.Extensions; - -/// -/// Extension methods for converting between Platform Summary ViewModels -/// -public static class PlatformSummaryExtensions -{ - /// - /// Converts from the Abstractions PlatformSummaryViewModel to the API PlatformSummaryViewModel - /// - public static PlatformSummaryViewModel ToApiViewModel(this AbstractionsPlatformSummaryViewModel abstractionsModel) - { - return new PlatformSummaryViewModel - { - TotalAgents = abstractionsModel.TotalAgents, - TotalActiveStrategies = abstractionsModel.TotalActiveStrategies, - TotalPlatformPnL = abstractionsModel.TotalPlatformPnL, - TotalPlatformVolume = abstractionsModel.TotalPlatformVolume, - TotalPlatformVolumeLast24h = abstractionsModel.TotalPlatformVolumeLast24h, - TotalOpenInterest = abstractionsModel.TotalOpenInterest, - TotalPositionCount = abstractionsModel.TotalPositionCount, - AgentsChange24h = abstractionsModel.AgentsChange24h, - StrategiesChange24h = abstractionsModel.StrategiesChange24h, - PnLChange24h = abstractionsModel.PnLChange24h, - VolumeChange24h = abstractionsModel.VolumeChange24h, - OpenInterestChange24h = abstractionsModel.OpenInterestChange24h, - PositionCountChange24h = abstractionsModel.PositionCountChange24h, - VolumeByAsset = abstractionsModel.VolumeByAsset ?? new Dictionary(), - PositionCountByAsset = abstractionsModel.PositionCountByAsset ?? new Dictionary(), - PositionCountByDirection = abstractionsModel.PositionCountByDirection?.ToDictionary( - kvp => kvp.Key, - kvp => kvp.Value) ?? new Dictionary(), - LastUpdated = abstractionsModel.LastUpdated, - Last24HourSnapshot = abstractionsModel.Last24HourSnapshot, - VolumeHistory = abstractionsModel.VolumeHistory, - }; - } -} \ No newline at end of file diff --git a/src/Managing.Api/Managing.Api.csproj b/src/Managing.Api/Managing.Api.csproj index da7879b6..2685c37d 100644 --- a/src/Managing.Api/Managing.Api.csproj +++ b/src/Managing.Api/Managing.Api.csproj @@ -59,4 +59,8 @@ Always + + + + diff --git a/src/Managing.Api/Models/Responses/AgentSummaryViewModel.cs b/src/Managing.Api/Models/Responses/AgentSummaryViewModel.cs index b8d4ee36..b5c69553 100644 --- a/src/Managing.Api/Models/Responses/AgentSummaryViewModel.cs +++ b/src/Managing.Api/Models/Responses/AgentSummaryViewModel.cs @@ -1,4 +1,3 @@ -using Managing.Application.Abstractions.Models; using Managing.Common; namespace Managing.Api.Models.Responses @@ -55,6 +54,22 @@ namespace Managing.Api.Models.Responses /// public class PlatformSummaryViewModel { + /// + /// When the data was last updated + /// + public required DateTime LastUpdated { get; set; } + + /// + /// When the last 24-hour snapshot was taken + /// + public required DateTime LastSnapshot { get; set; } + + /// + /// Whether there are pending changes to be saved + /// + public required bool HasPendingChanges { get; set; } + + // Current metrics /// /// Total number of agents on the platform /// @@ -75,58 +90,34 @@ namespace Managing.Api.Models.Responses /// public required decimal TotalPlatformVolume { get; set; } - /// - /// Total volume traded across all agents in the last 24 hours in USD - /// - public required decimal TotalPlatformVolumeLast24h { get; set; } - /// /// Total open interest across all positions in USD /// - public required decimal TotalOpenInterest { get; set; } + public required decimal OpenInterest { get; set; } /// /// Total number of open positions across all strategies /// public required int TotalPositionCount { get; set; } - // 24-hour changes /// - /// Change in agent count over the last 24 hours + /// Total platform-wide fees paid in USD /// - public required int AgentsChange24h { get; set; } + public required decimal TotalPlatformFees { get; set; } + // Historical snapshots /// - /// Change in strategy count over the last 24 hours + /// Daily snapshots for the last 60 days /// - public required int StrategiesChange24h { get; set; } + public required List DailySnapshots { get; set; } - /// - /// Change in PnL over the last 24 hours - /// - public required decimal PnLChange24h { get; set; } - - /// - /// Change in volume over the last 24 hours - /// - public required decimal VolumeChange24h { get; set; } - - /// - /// Change in open interest over the last 24 hours - /// - public required decimal OpenInterestChange24h { get; set; } - - /// - /// Change in position count over the last 24 hours - /// - public required int PositionCountChange24h { get; set; } - - // Breakdowns + // Volume breakdown by asset /// /// Volume breakdown by asset/ticker /// public required Dictionary VolumeByAsset { get; set; } + // Position count breakdown /// /// Position count breakdown by asset/ticker /// @@ -136,18 +127,47 @@ namespace Managing.Api.Models.Responses /// Position count breakdown by direction (Long/Short) /// public required Dictionary PositionCountByDirection { get; set; } + } - // Metadata + /// + /// Daily snapshot of platform metrics + /// + public class DailySnapshot + { /// - /// When the data was last updated + /// Date of the snapshot /// - public required DateTime LastUpdated { get; set; } + public required DateTime Date { get; set; } /// - /// When the last 24-hour snapshot was taken + /// Total number of agents on this date /// - public required DateTime Last24HourSnapshot { get; set; } - public List VolumeHistory { get; internal set; } + public required int TotalAgents { get; set; } + + /// + /// Total number of active strategies on this date + /// + public required int TotalStrategies { get; set; } + + /// + /// Total volume traded on this date in USD + /// + public required decimal TotalVolume { get; set; } + + /// + /// Total PnL on this date in USD + /// + public required decimal TotalPnL { get; set; } + + /// + /// Total open interest on this date in USD + /// + public required decimal TotalOpenInterest { get; set; } + + /// + /// Total number of positions on this date + /// + public required int TotalPositionCount { get; set; } } /// diff --git a/src/Managing.Application.Abstractions/Grains/IPlatformSummaryGrain.cs b/src/Managing.Application.Abstractions/Grains/IPlatformSummaryGrain.cs index 6c90d00b..f724b459 100644 --- a/src/Managing.Application.Abstractions/Grains/IPlatformSummaryGrain.cs +++ b/src/Managing.Application.Abstractions/Grains/IPlatformSummaryGrain.cs @@ -1,4 +1,3 @@ -using Managing.Application.Abstractions.Models; using Orleans; using Orleans.Concurrency; using static Managing.Common.Enums; @@ -13,7 +12,7 @@ public interface IPlatformSummaryGrain : IGrainWithStringKey /// /// Gets the current platform summary data /// - Task GetPlatformSummaryAsync(); + Task GetPlatformSummaryAsync(); /// /// Forces a refresh of all platform data @@ -45,11 +44,6 @@ public interface IPlatformSummaryGrain : IGrainWithStringKey /// Task GetTotalFeesAsync(); - /// - /// Gets the daily volume history for the last 30 days for chart visualization - /// - Task> GetVolumeHistoryAsync(); - // Event handlers for immediate updates /// /// Updates the active strategy count diff --git a/src/Managing.Application.Abstractions/Grains/PlatformSummaryGrainState.cs b/src/Managing.Application.Abstractions/Grains/PlatformSummaryGrainState.cs index b291a083..9539eea3 100644 --- a/src/Managing.Application.Abstractions/Grains/PlatformSummaryGrainState.cs +++ b/src/Managing.Application.Abstractions/Grains/PlatformSummaryGrainState.cs @@ -28,33 +28,18 @@ public class PlatformSummaryGrainState [Id(8)] public int TotalPositionCount { get; set; } - [Id(20)] public decimal TotalPlatformFees { get; set; } - - // 24-hour ago values (for comparison) - [Id(9)] public int TotalAgents24hAgo { get; set; } - - [Id(10)] public int TotalActiveStrategies24hAgo { get; set; } - - [Id(11)] public decimal TotalPlatformPnL24hAgo { get; set; } - - [Id(12)] public decimal TotalPlatformVolume24hAgo { get; set; } - - [Id(13)] public decimal TotalOpenInterest24hAgo { get; set; } - - [Id(14)] public int TotalPositionCount24hAgo { get; set; } - - [Id(21)] public decimal TotalPlatformFees24hAgo { get; set; } + [Id(9)] public decimal TotalPlatformFees { get; set; } // Historical snapshots - [Id(15)] public List DailySnapshots { get; set; } = new(); + [Id(10)] public List DailySnapshots { get; set; } = new(); // Volume breakdown by asset - [Id(16)] public Dictionary VolumeByAsset { get; set; } = new(); + [Id(11)] public Dictionary VolumeByAsset { get; set; } = new(); // Position count breakdown - [Id(17)] public Dictionary PositionCountByAsset { get; set; } = new(); + [Id(12)] public Dictionary PositionCountByAsset { get; set; } = new(); - [Id(18)] public Dictionary PositionCountByDirection { get; set; } = new(); + [Id(13)] public Dictionary PositionCountByDirection { get; set; } = new(); } /// @@ -76,6 +61,4 @@ public class DailySnapshot [Id(5)] public decimal TotalOpenInterest { get; set; } [Id(6)] public int TotalPositionCount { get; set; } - - [Id(7)] public decimal TotalFees { get; set; } } \ No newline at end of file diff --git a/src/Managing.Application.Abstractions/Models/PlatformSummaryViewModel.cs b/src/Managing.Application.Abstractions/Models/PlatformSummaryViewModel.cs deleted file mode 100644 index 31befa05..00000000 --- a/src/Managing.Application.Abstractions/Models/PlatformSummaryViewModel.cs +++ /dev/null @@ -1,159 +0,0 @@ -using Orleans; -using static Managing.Common.Enums; - -namespace Managing.Application.Abstractions.Models; - -/// -/// Platform-wide statistics without individual agent details -/// -[GenerateSerializer] -public class PlatformSummaryViewModel -{ - /// - /// Total number of agents on the platform - /// - [Id(0)] - public required int TotalAgents { get; set; } - - /// - /// Total number of active strategies across all agents - /// - [Id(1)] - public required int TotalActiveStrategies { get; set; } - - /// - /// Total platform-wide profit and loss in USD - /// - [Id(2)] - public required decimal TotalPlatformPnL { get; set; } - - /// - /// Total volume traded across all agents in USD - /// - [Id(3)] - public required decimal TotalPlatformVolume { get; set; } - - /// - /// Total volume traded across all agents in the last 24 hours in USD - /// - [Id(4)] - public required decimal TotalPlatformVolumeLast24h { get; set; } - - /// - /// Total open interest across all positions in USD - /// - [Id(5)] - public required decimal TotalOpenInterest { get; set; } - - /// - /// Total number of open positions across all strategies - /// - [Id(6)] - public required int TotalPositionCount { get; set; } - - /// - /// Total platform-wide fees paid in USD - /// - [Id(19)] - public required decimal TotalPlatformFees { get; set; } - - // 24-hour changes - /// - /// Change in agent count over the last 24 hours - /// - [Id(7)] - public required int AgentsChange24h { get; set; } - - /// - /// Change in strategy count over the last 24 hours - /// - [Id(8)] - public required int StrategiesChange24h { get; set; } - - /// - /// Change in PnL over the last 24 hours - /// - [Id(9)] - public required decimal PnLChange24h { get; set; } - - /// - /// Change in volume over the last 24 hours - /// - [Id(10)] - public required decimal VolumeChange24h { get; set; } - - /// - /// Change in open interest over the last 24 hours - /// - [Id(11)] - public required decimal OpenInterestChange24h { get; set; } - - /// - /// Change in position count over the last 24 hours - /// - [Id(12)] - public required int PositionCountChange24h { get; set; } - - /// - /// Change in fees over the last 24 hours - /// - [Id(20)] - public required decimal FeesChange24h { get; set; } - - // Breakdowns - /// - /// Volume breakdown by asset/ticker - /// - [Id(13)] - public required Dictionary VolumeByAsset { get; set; } - - /// - /// Position count breakdown by asset/ticker - /// - [Id(14)] - public required Dictionary PositionCountByAsset { get; set; } - - /// - /// Position count breakdown by direction (Long/Short) - /// - [Id(15)] - public required Dictionary PositionCountByDirection { get; set; } - - // Metadata - /// - /// When the data was last updated - /// - [Id(16)] - public required DateTime LastUpdated { get; set; } - - /// - /// When the last 24-hour snapshot was taken - /// - [Id(17)] - public required DateTime Last24HourSnapshot { get; set; } - - /// - /// Daily volume history for the last 30 days for chart visualization - /// - [Id(18)] - public required List VolumeHistory { get; set; } -} - -/// -/// Represents a volume data point for historical charting -/// -[GenerateSerializer] -public class VolumeHistoryPoint -{ - /// - /// Date of the volume measurement - /// - [Id(0)] - public required DateTime Date { get; set; } - - /// - /// Total volume for that date in USD - /// - [Id(1)] - public required decimal Volume { get; set; } -} diff --git a/src/Managing.Application/Grains/PlatformSummaryGrain.cs b/src/Managing.Application/Grains/PlatformSummaryGrain.cs index 6d8c5714..cb4254e2 100644 --- a/src/Managing.Application/Grains/PlatformSummaryGrain.cs +++ b/src/Managing.Application/Grains/PlatformSummaryGrain.cs @@ -1,6 +1,5 @@ using Managing.Application.Abstractions; using Managing.Application.Abstractions.Grains; -using Managing.Application.Abstractions.Models; using Managing.Application.Abstractions.Services; using Managing.Application.Orleans; using Managing.Domain.Bots; @@ -58,11 +57,32 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable // Initial data load if state is empty if (_state.State.LastUpdated == default) { + // Create initial empty daily snapshot if none exist + if (!_state.State.DailySnapshots.Any()) + { + var today = DateTime.UtcNow.Date.AddSeconds(1); // Today at 00:00:01 UTC + var initialSnapshot = new DailySnapshot + { + Date = today, + TotalAgents = 0, + TotalStrategies = 0, + TotalVolume = 0, + TotalPnL = 0, + TotalOpenInterest = 0, + TotalPositionCount = 0, + }; + + _state.State.DailySnapshots.Add(initialSnapshot); + _state.State.LastSnapshot = today; + _state.State.LastUpdated = today; + _logger.LogInformation("Created initial empty daily snapshot for {Date}", today); + } + await RefreshDataAsync(); } } - public async Task GetPlatformSummaryAsync() + public async Task GetPlatformSummaryAsync() { // If data is stale or has pending changes, refresh it if (IsDataStale() || _state.State.HasPendingChanges) @@ -70,7 +90,7 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable await RefreshDataAsync(); } - return MapToViewModel(_state.State); + return _state.State; } public async Task RefreshDataAsync() @@ -238,20 +258,6 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable return Task.FromResult(_state.State.TotalPlatformFees); } - public Task> GetVolumeHistoryAsync() - { - var historyPoints = _state.State.DailySnapshots - .OrderBy(s => s.Date) - .Select(s => new VolumeHistoryPoint - { - Date = s.Date, - Volume = s.TotalVolume - }) - .ToList(); - - return Task.FromResult(historyPoints); - } - // Event handlers for immediate updates public async Task UpdateActiveStrategyCountAsync(int newActiveCount) { @@ -395,15 +401,6 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable { _logger.LogInformation("Taking daily snapshot"); - // Store 24-hour ago values for comparison - _state.State.TotalAgents24hAgo = _state.State.TotalAgents; - _state.State.TotalActiveStrategies24hAgo = _state.State.TotalActiveStrategies; - _state.State.TotalPlatformPnL24hAgo = _state.State.TotalPlatformPnL; - _state.State.TotalPlatformVolume24hAgo = _state.State.TotalPlatformVolume; - _state.State.TotalOpenInterest24hAgo = _state.State.OpenInterest; - _state.State.TotalPositionCount24hAgo = _state.State.TotalPositionCount; - _state.State.TotalPlatformFees24hAgo = _state.State.TotalPlatformFees; - // Add daily snapshot var dailySnapshot = new DailySnapshot { @@ -414,13 +411,12 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable TotalPnL = _state.State.TotalPlatformPnL, TotalOpenInterest = _state.State.OpenInterest, TotalPositionCount = _state.State.TotalPositionCount, - TotalFees = _state.State.TotalPlatformFees }; _state.State.DailySnapshots.Add(dailySnapshot); - // Keep only last 30 days - var cutoff = DateTime.UtcNow.AddDays(-30); + // Keep only last 60 days + var cutoff = DateTime.UtcNow.AddDays(-60); _state.State.DailySnapshots.RemoveAll(s => s.Date < cutoff); _state.State.LastSnapshot = DateTime.UtcNow; @@ -433,50 +429,4 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable var timeSinceLastUpdate = DateTime.UtcNow - _state.State.LastUpdated; return timeSinceLastUpdate > TimeSpan.FromMinutes(5); } - - private PlatformSummaryViewModel MapToViewModel(PlatformSummaryGrainState state) - { - // Generate volume history from daily snapshots - var volumeHistory = state.DailySnapshots - .OrderBy(s => s.Date) - .Select(s => new VolumeHistoryPoint - { - Date = s.Date, - Volume = s.TotalVolume - }) - .ToList(); - - return new PlatformSummaryViewModel - { - TotalAgents = state.TotalAgents, - TotalActiveStrategies = state.TotalActiveStrategies, - TotalPlatformPnL = state.TotalPlatformPnL, - TotalPlatformVolume = state.TotalPlatformVolume, - TotalPlatformVolumeLast24h = state.TotalPlatformVolume - state.TotalPlatformVolume24hAgo, - TotalOpenInterest = state.OpenInterest, - TotalPositionCount = state.TotalPositionCount, - TotalPlatformFees = state.TotalPlatformFees, - - // 24-hour changes - AgentsChange24h = state.TotalAgents - state.TotalAgents24hAgo, - StrategiesChange24h = state.TotalActiveStrategies - state.TotalActiveStrategies24hAgo, - PnLChange24h = state.TotalPlatformPnL - state.TotalPlatformPnL24hAgo, - VolumeChange24h = state.TotalPlatformVolume - state.TotalPlatformVolume24hAgo, - OpenInterestChange24h = state.OpenInterest - state.TotalOpenInterest24hAgo, - PositionCountChange24h = state.TotalPositionCount - state.TotalPositionCount24hAgo, - FeesChange24h = state.TotalPlatformFees - state.TotalPlatformFees24hAgo, - - // Breakdowns - VolumeByAsset = state.VolumeByAsset ?? new Dictionary(), - PositionCountByAsset = state.PositionCountByAsset ?? new Dictionary(), - PositionCountByDirection = state.PositionCountByDirection ?? new Dictionary(), - - // Volume history for charting (last 30 days) - VolumeHistory = volumeHistory, - - // Metadata - LastUpdated = state.LastUpdated, - Last24HourSnapshot = state.LastSnapshot - }; - } } \ No newline at end of file diff --git a/src/Managing.WebApp/src/generated/ManagingApi.ts b/src/Managing.WebApp/src/generated/ManagingApi.ts index 7b298aec..d9384274 100644 --- a/src/Managing.WebApp/src/generated/ManagingApi.ts +++ b/src/Managing.WebApp/src/generated/ManagingApi.ts @@ -4096,6 +4096,7 @@ export interface LightBacktest { sharpeRatio?: number | null; score?: number; scoreMessage?: string | null; + metadata?: any | null; } export interface RunBacktestRequest { @@ -4533,7 +4534,6 @@ export interface UserStrategyDetailsViewModel { state?: BotStatus; pnL?: number; roiPercentage?: number; - roiLast24H?: number; runtime?: Date; winRate?: number; totalVolumeTraded?: number; @@ -4547,30 +4547,30 @@ export interface UserStrategyDetailsViewModel { } export interface PlatformSummaryViewModel { + lastUpdated?: Date; + lastSnapshot?: Date; + hasPendingChanges?: boolean; totalAgents?: number; totalActiveStrategies?: number; totalPlatformPnL?: number; totalPlatformVolume?: number; - totalPlatformVolumeLast24h?: number; - totalOpenInterest?: number; + openInterest?: number; totalPositionCount?: number; - agentsChange24h?: number; - strategiesChange24h?: number; - pnLChange24h?: number; - volumeChange24h?: number; - openInterestChange24h?: number; - positionCountChange24h?: number; + totalPlatformFees?: number; + dailySnapshots?: DailySnapshot[] | null; volumeByAsset?: { [key in keyof typeof Ticker]?: number; } | null; positionCountByAsset?: { [key in keyof typeof Ticker]?: number; } | null; positionCountByDirection?: { [key in keyof typeof TradeDirection]?: number; } | null; - lastUpdated?: Date; - last24HourSnapshot?: Date; - volumeHistory?: VolumeHistoryPoint[] | null; } -export interface VolumeHistoryPoint { +export interface DailySnapshot { date?: Date; - volume?: number; + totalAgents?: number; + totalStrategies?: number; + totalVolume?: number; + totalPnL?: number; + totalOpenInterest?: number; + totalPositionCount?: number; } export interface PaginatedAgentIndexResponse { diff --git a/src/Managing.WebApp/src/generated/ManagingApiTypes.ts b/src/Managing.WebApp/src/generated/ManagingApiTypes.ts index 01961df5..93ef3a14 100644 --- a/src/Managing.WebApp/src/generated/ManagingApiTypes.ts +++ b/src/Managing.WebApp/src/generated/ManagingApiTypes.ts @@ -544,6 +544,7 @@ export interface LightBacktest { sharpeRatio?: number | null; score?: number; scoreMessage?: string | null; + metadata?: any | null; } export interface RunBacktestRequest { @@ -981,7 +982,6 @@ export interface UserStrategyDetailsViewModel { state?: BotStatus; pnL?: number; roiPercentage?: number; - roiLast24H?: number; runtime?: Date; winRate?: number; totalVolumeTraded?: number; @@ -995,30 +995,30 @@ export interface UserStrategyDetailsViewModel { } export interface PlatformSummaryViewModel { + lastUpdated?: Date; + lastSnapshot?: Date; + hasPendingChanges?: boolean; totalAgents?: number; totalActiveStrategies?: number; totalPlatformPnL?: number; totalPlatformVolume?: number; - totalPlatformVolumeLast24h?: number; - totalOpenInterest?: number; + openInterest?: number; totalPositionCount?: number; - agentsChange24h?: number; - strategiesChange24h?: number; - pnLChange24h?: number; - volumeChange24h?: number; - openInterestChange24h?: number; - positionCountChange24h?: number; + totalPlatformFees?: number; + dailySnapshots?: DailySnapshot[] | null; volumeByAsset?: { [key in keyof typeof Ticker]?: number; } | null; positionCountByAsset?: { [key in keyof typeof Ticker]?: number; } | null; positionCountByDirection?: { [key in keyof typeof TradeDirection]?: number; } | null; - lastUpdated?: Date; - last24HourSnapshot?: Date; - volumeHistory?: VolumeHistoryPoint[] | null; } -export interface VolumeHistoryPoint { +export interface DailySnapshot { date?: Date; - volume?: number; + totalAgents?: number; + totalStrategies?: number; + totalVolume?: number; + totalPnL?: number; + totalOpenInterest?: number; + totalPositionCount?: number; } export interface PaginatedAgentIndexResponse { diff --git a/src/Managing.WebApp/src/pages/dashboardPage/platformSummary.tsx b/src/Managing.WebApp/src/pages/dashboardPage/platformSummary.tsx index 8d82d137..9f073eff 100644 --- a/src/Managing.WebApp/src/pages/dashboardPage/platformSummary.tsx +++ b/src/Managing.WebApp/src/pages/dashboardPage/platformSummary.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, {useMemo} from 'react' import {useQuery, useQueryClient} from '@tanstack/react-query' import useApiUrlStore from '../../app/store/apiStore' import {fetchPlatformData} from '../../services/platformService' @@ -26,6 +26,37 @@ function PlatformSummary({index}: { index: number }) { const topStrategiesByRoi = data?.topStrategiesByRoi const topAgentsByPnL = data?.topAgentsByPnL + // Calculate 24-hour changes from daily snapshots + const changes24h = useMemo(() => { + if (!platformData?.dailySnapshots || platformData.dailySnapshots.length < 2) { + return { + agentsChange: 0, + strategiesChange: 0, + volumeChange: 0, + pnLChange: 0, + openInterestChange: 0, + positionCountChange: 0 + } + } + + // Sort snapshots by date (most recent first) + const sortedSnapshots = [...platformData.dailySnapshots].sort((a, b) => + new Date(b.date || 0).getTime() - new Date(a.date || 0).getTime() + ) + + const latest = sortedSnapshots[0] + const previous = sortedSnapshots[1] + + return { + agentsChange: (latest.totalAgents || 0) - (previous.totalAgents || 0), + strategiesChange: (latest.totalStrategies || 0) - (previous.totalStrategies || 0), + volumeChange: (latest.totalVolume || 0) - (previous.totalVolume || 0), + pnLChange: (latest.totalPnL || 0) - (previous.totalPnL || 0), + openInterestChange: (latest.totalOpenInterest || 0) - (previous.totalOpenInterest || 0), + positionCountChange: (latest.totalPositionCount || 0) - (previous.totalPositionCount || 0) + } + }, [platformData?.dailySnapshots]) + const formatCurrency = (value: number) => { if (value >= 1000000) { return `$${(value / 1000000).toFixed(2)}M` @@ -113,7 +144,7 @@ function PlatformSummary({index}: { index: number }) { {formatNumber(platformData?.totalActiveStrategies || 0)} Strategies Deployed
- {platformData && formatChangeIndicator(platformData.strategiesChange24h || 0)} + {platformData && formatChangeIndicator(changes24h.strategiesChange)}
@@ -126,15 +157,33 @@ function PlatformSummary({index}: { index: number }) { {formatCurrency(platformData?.totalPlatformVolume || 0)}
= 0 ? 'text-green-500' : 'text-red-500'}`}> - {(platformData?.volumeChange24h || 0) >= 0 ? '+' : ''}{formatCurrency(platformData?.volumeChange24h || 0)} Today + className={`text-sm ${changes24h.volumeChange >= 0 ? 'text-green-500' : 'text-red-500'}`}> + {changes24h.volumeChange >= 0 ? '+' : ''}{formatCurrency(changes24h.volumeChange)} Today - ({formatPercentageChange(platformData?.totalPlatformVolume || 0, platformData?.volumeChange24h || 0)}) + ({formatPercentageChange(platformData?.totalPlatformVolume || 0, changes24h.volumeChange)})
- {/* Simple chart placeholder - you can replace with actual chart */} -
-
+ {/* Volume chart using daily snapshots */} +
+ {platformData?.dailySnapshots && platformData.dailySnapshots.length > 0 ? ( + [...platformData.dailySnapshots] + .sort((a, b) => new Date(a.date || 0).getTime() - new Date(b.date || 0).getTime()) + .slice(-7) // Last 7 days + .map((snapshot, index) => { + const maxVolume = Math.max(...platformData.dailySnapshots?.map(s => s.totalVolume || 0) || [0]) + const height = maxVolume > 0 ? ((snapshot.totalVolume || 0) / maxVolume) * 100 : 0 + return ( +
+ ) + }) + ) : ( +
+ )}
@@ -261,8 +310,8 @@ function PlatformSummary({index}: { index: number }) { {formatNumber(platformData?.totalAgents || 0)}
= 0 ? 'text-green-500' : 'text-red-500'}`}> - {formatChangeIndicator(platformData?.agentsChange24h || 0)} + className={`text-sm ${changes24h.agentsChange >= 0 ? 'text-green-500' : 'text-red-500'}`}> + {formatChangeIndicator(changes24h.agentsChange)}
@@ -272,8 +321,8 @@ function PlatformSummary({index}: { index: number }) { {formatNumber(platformData?.totalActiveStrategies || 0)}
= 0 ? 'text-green-500' : 'text-red-500'}`}> - {formatChangeIndicator(platformData?.strategiesChange24h || 0)} + className={`text-sm ${changes24h.strategiesChange >= 0 ? 'text-green-500' : 'text-red-500'}`}> + {formatChangeIndicator(changes24h.strategiesChange)}
@@ -284,19 +333,19 @@ function PlatformSummary({index}: { index: number }) { {(platformData?.totalPlatformPnL || 0) >= 0 ? '+' : ''}{formatCurrency(platformData?.totalPlatformPnL || 0)}
= 0 ? 'text-green-500' : 'text-red-500'}`}> - {(platformData?.pnLChange24h || 0) >= 0 ? '+' : ''}{formatCurrency(platformData?.pnLChange24h || 0)} Today + className={`text-sm ${changes24h.pnLChange >= 0 ? 'text-green-500' : 'text-red-500'}`}> + {changes24h.pnLChange >= 0 ? '+' : ''}{formatCurrency(changes24h.pnLChange)} Today

Open Interest

- {formatCurrency(platformData?.totalOpenInterest || 0)} + {formatCurrency(platformData?.openInterest || 0)}
= 0 ? 'text-green-500' : 'text-red-500'}`}> - {(platformData?.openInterestChange24h || 0) >= 0 ? '+' : ''}{formatCurrency(platformData?.openInterestChange24h || 0)} Today + className={`text-sm ${changes24h.openInterestChange >= 0 ? 'text-green-500' : 'text-red-500'}`}> + {changes24h.openInterestChange >= 0 ? '+' : ''}{formatCurrency(changes24h.openInterestChange)} Today
@@ -309,8 +358,8 @@ function PlatformSummary({index}: { index: number }) { {formatNumber(platformData?.totalPositionCount || 0)}
= 0 ? 'text-green-500' : 'text-red-500'}`}> - {formatChangeIndicator(platformData?.positionCountChange24h || 0)} + className={`text-sm ${changes24h.positionCountChange >= 0 ? 'text-green-500' : 'text-red-500'}`}> + {formatChangeIndicator(changes24h.positionCountChange)}
@@ -445,7 +494,7 @@ function PlatformSummary({index}: { index: number }) { )} - 24h snapshot: {platformData?.last24HourSnapshot ? new Date(platformData.last24HourSnapshot).toLocaleString() : 'Unknown'} + Last snapshot: {platformData?.lastSnapshot ? new Date(platformData.lastSnapshot).toLocaleString() : 'Unknown'}