Fix dailySnapshot for platformsummary
This commit is contained in:
@@ -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.Api.Models.Responses;
|
||||||
using Managing.Application.Abstractions.Grains;
|
using Managing.Application.Abstractions.Grains;
|
||||||
using Managing.Application.Abstractions.Services;
|
using Managing.Application.Abstractions.Services;
|
||||||
@@ -15,6 +14,7 @@ using MediatR;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
|
using DailySnapshot = Managing.Api.Models.Responses.DailySnapshot;
|
||||||
|
|
||||||
namespace Managing.Api.Controllers;
|
namespace Managing.Api.Controllers;
|
||||||
|
|
||||||
@@ -563,10 +563,10 @@ public class DataController : ControllerBase
|
|||||||
var platformSummaryGrain = _grainFactory.GetGrain<IPlatformSummaryGrain>("platform-summary");
|
var platformSummaryGrain = _grainFactory.GetGrain<IPlatformSummaryGrain>("platform-summary");
|
||||||
|
|
||||||
// Get the platform summary from the grain (handles caching and real-time updates)
|
// 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
|
// Map the state to the view model
|
||||||
var summary = abstractionsSummary.ToApiViewModel();
|
var summary = MapPlatformSummaryStateToViewModel(state);
|
||||||
|
|
||||||
return Ok(summary);
|
return Ok(summary);
|
||||||
}
|
}
|
||||||
@@ -778,4 +778,49 @@ public class DataController : ControllerBase
|
|||||||
|
|
||||||
return scenario;
|
return scenario;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps PlatformSummaryGrainState to PlatformSummaryViewModel
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">The platform summary grain state</param>
|
||||||
|
/// <returns>A mapped platform summary view model</returns>
|
||||||
|
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<Ticker, decimal>(),
|
||||||
|
PositionCountByAsset = state.PositionCountByAsset ?? new Dictionary<Ticker, int>(),
|
||||||
|
PositionCountByDirection = state.PositionCountByDirection ?? new Dictionary<TradeDirection, int>()
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
using Managing.Api.Models.Responses;
|
|
||||||
using Managing.Common;
|
|
||||||
using AbstractionsPlatformSummaryViewModel = Managing.Application.Abstractions.Models.PlatformSummaryViewModel;
|
|
||||||
|
|
||||||
namespace Managing.Api.Extensions;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Extension methods for converting between Platform Summary ViewModels
|
|
||||||
/// </summary>
|
|
||||||
public static class PlatformSummaryExtensions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Converts from the Abstractions PlatformSummaryViewModel to the API PlatformSummaryViewModel
|
|
||||||
/// </summary>
|
|
||||||
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<Enums.Ticker, decimal>(),
|
|
||||||
PositionCountByAsset = abstractionsModel.PositionCountByAsset ?? new Dictionary<Enums.Ticker, int>(),
|
|
||||||
PositionCountByDirection = abstractionsModel.PositionCountByDirection?.ToDictionary(
|
|
||||||
kvp => kvp.Key,
|
|
||||||
kvp => kvp.Value) ?? new Dictionary<Enums.TradeDirection, int>(),
|
|
||||||
LastUpdated = abstractionsModel.LastUpdated,
|
|
||||||
Last24HourSnapshot = abstractionsModel.Last24HourSnapshot,
|
|
||||||
VolumeHistory = abstractionsModel.VolumeHistory,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -59,4 +59,8 @@
|
|||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Extensions\"/>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using Managing.Application.Abstractions.Models;
|
|
||||||
using Managing.Common;
|
using Managing.Common;
|
||||||
|
|
||||||
namespace Managing.Api.Models.Responses
|
namespace Managing.Api.Models.Responses
|
||||||
@@ -55,6 +54,22 @@ namespace Managing.Api.Models.Responses
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class PlatformSummaryViewModel
|
public class PlatformSummaryViewModel
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// When the data was last updated
|
||||||
|
/// </summary>
|
||||||
|
public required DateTime LastUpdated { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When the last 24-hour snapshot was taken
|
||||||
|
/// </summary>
|
||||||
|
public required DateTime LastSnapshot { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether there are pending changes to be saved
|
||||||
|
/// </summary>
|
||||||
|
public required bool HasPendingChanges { get; set; }
|
||||||
|
|
||||||
|
// Current metrics
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Total number of agents on the platform
|
/// Total number of agents on the platform
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -75,58 +90,34 @@ namespace Managing.Api.Models.Responses
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public required decimal TotalPlatformVolume { get; set; }
|
public required decimal TotalPlatformVolume { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Total volume traded across all agents in the last 24 hours in USD
|
|
||||||
/// </summary>
|
|
||||||
public required decimal TotalPlatformVolumeLast24h { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Total open interest across all positions in USD
|
/// Total open interest across all positions in USD
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required decimal TotalOpenInterest { get; set; }
|
public required decimal OpenInterest { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Total number of open positions across all strategies
|
/// Total number of open positions across all strategies
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required int TotalPositionCount { get; set; }
|
public required int TotalPositionCount { get; set; }
|
||||||
|
|
||||||
// 24-hour changes
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Change in agent count over the last 24 hours
|
/// Total platform-wide fees paid in USD
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required int AgentsChange24h { get; set; }
|
public required decimal TotalPlatformFees { get; set; }
|
||||||
|
|
||||||
|
// Historical snapshots
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Change in strategy count over the last 24 hours
|
/// Daily snapshots for the last 60 days
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required int StrategiesChange24h { get; set; }
|
public required List<DailySnapshot> DailySnapshots { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
// Volume breakdown by asset
|
||||||
/// Change in PnL over the last 24 hours
|
|
||||||
/// </summary>
|
|
||||||
public required decimal PnLChange24h { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change in volume over the last 24 hours
|
|
||||||
/// </summary>
|
|
||||||
public required decimal VolumeChange24h { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change in open interest over the last 24 hours
|
|
||||||
/// </summary>
|
|
||||||
public required decimal OpenInterestChange24h { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change in position count over the last 24 hours
|
|
||||||
/// </summary>
|
|
||||||
public required int PositionCountChange24h { get; set; }
|
|
||||||
|
|
||||||
// Breakdowns
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Volume breakdown by asset/ticker
|
/// Volume breakdown by asset/ticker
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required Dictionary<Enums.Ticker, decimal> VolumeByAsset { get; set; }
|
public required Dictionary<Enums.Ticker, decimal> VolumeByAsset { get; set; }
|
||||||
|
|
||||||
|
// Position count breakdown
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Position count breakdown by asset/ticker
|
/// Position count breakdown by asset/ticker
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -136,18 +127,47 @@ namespace Managing.Api.Models.Responses
|
|||||||
/// Position count breakdown by direction (Long/Short)
|
/// Position count breakdown by direction (Long/Short)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required Dictionary<Enums.TradeDirection, int> PositionCountByDirection { get; set; }
|
public required Dictionary<Enums.TradeDirection, int> PositionCountByDirection { get; set; }
|
||||||
|
}
|
||||||
// Metadata
|
|
||||||
/// <summary>
|
|
||||||
/// When the data was last updated
|
|
||||||
/// </summary>
|
|
||||||
public required DateTime LastUpdated { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When the last 24-hour snapshot was taken
|
/// Daily snapshot of platform metrics
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required DateTime Last24HourSnapshot { get; set; }
|
public class DailySnapshot
|
||||||
public List<VolumeHistoryPoint> VolumeHistory { get; internal set; }
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Date of the snapshot
|
||||||
|
/// </summary>
|
||||||
|
public required DateTime Date { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total number of agents on this date
|
||||||
|
/// </summary>
|
||||||
|
public required int TotalAgents { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total number of active strategies on this date
|
||||||
|
/// </summary>
|
||||||
|
public required int TotalStrategies { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total volume traded on this date in USD
|
||||||
|
/// </summary>
|
||||||
|
public required decimal TotalVolume { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total PnL on this date in USD
|
||||||
|
/// </summary>
|
||||||
|
public required decimal TotalPnL { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total open interest on this date in USD
|
||||||
|
/// </summary>
|
||||||
|
public required decimal TotalOpenInterest { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total number of positions on this date
|
||||||
|
/// </summary>
|
||||||
|
public required int TotalPositionCount { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using Managing.Application.Abstractions.Models;
|
|
||||||
using Orleans;
|
using Orleans;
|
||||||
using Orleans.Concurrency;
|
using Orleans.Concurrency;
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
@@ -13,7 +12,7 @@ public interface IPlatformSummaryGrain : IGrainWithStringKey
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current platform summary data
|
/// Gets the current platform summary data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Task<PlatformSummaryViewModel> GetPlatformSummaryAsync();
|
Task<PlatformSummaryGrainState> GetPlatformSummaryAsync();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Forces a refresh of all platform data
|
/// Forces a refresh of all platform data
|
||||||
@@ -45,11 +44,6 @@ public interface IPlatformSummaryGrain : IGrainWithStringKey
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Task<decimal> GetTotalFeesAsync();
|
Task<decimal> GetTotalFeesAsync();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the daily volume history for the last 30 days for chart visualization
|
|
||||||
/// </summary>
|
|
||||||
Task<List<VolumeHistoryPoint>> GetVolumeHistoryAsync();
|
|
||||||
|
|
||||||
// Event handlers for immediate updates
|
// Event handlers for immediate updates
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the active strategy count
|
/// Updates the active strategy count
|
||||||
|
|||||||
@@ -28,33 +28,18 @@ public class PlatformSummaryGrainState
|
|||||||
|
|
||||||
[Id(8)] public int TotalPositionCount { get; set; }
|
[Id(8)] public int TotalPositionCount { get; set; }
|
||||||
|
|
||||||
[Id(20)] public decimal TotalPlatformFees { get; set; }
|
[Id(9)] 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; }
|
|
||||||
|
|
||||||
// Historical snapshots
|
// Historical snapshots
|
||||||
[Id(15)] public List<DailySnapshot> DailySnapshots { get; set; } = new();
|
[Id(10)] public List<DailySnapshot> DailySnapshots { get; set; } = new();
|
||||||
|
|
||||||
// Volume breakdown by asset
|
// Volume breakdown by asset
|
||||||
[Id(16)] public Dictionary<Ticker, decimal> VolumeByAsset { get; set; } = new();
|
[Id(11)] public Dictionary<Ticker, decimal> VolumeByAsset { get; set; } = new();
|
||||||
|
|
||||||
// Position count breakdown
|
// Position count breakdown
|
||||||
[Id(17)] public Dictionary<Ticker, int> PositionCountByAsset { get; set; } = new();
|
[Id(12)] public Dictionary<Ticker, int> PositionCountByAsset { get; set; } = new();
|
||||||
|
|
||||||
[Id(18)] public Dictionary<TradeDirection, int> PositionCountByDirection { get; set; } = new();
|
[Id(13)] public Dictionary<TradeDirection, int> PositionCountByDirection { get; set; } = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -76,6 +61,4 @@ public class DailySnapshot
|
|||||||
[Id(5)] public decimal TotalOpenInterest { get; set; }
|
[Id(5)] public decimal TotalOpenInterest { get; set; }
|
||||||
|
|
||||||
[Id(6)] public int TotalPositionCount { get; set; }
|
[Id(6)] public int TotalPositionCount { get; set; }
|
||||||
|
|
||||||
[Id(7)] public decimal TotalFees { get; set; }
|
|
||||||
}
|
}
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
using Orleans;
|
|
||||||
using static Managing.Common.Enums;
|
|
||||||
|
|
||||||
namespace Managing.Application.Abstractions.Models;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Platform-wide statistics without individual agent details
|
|
||||||
/// </summary>
|
|
||||||
[GenerateSerializer]
|
|
||||||
public class PlatformSummaryViewModel
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Total number of agents on the platform
|
|
||||||
/// </summary>
|
|
||||||
[Id(0)]
|
|
||||||
public required int TotalAgents { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Total number of active strategies across all agents
|
|
||||||
/// </summary>
|
|
||||||
[Id(1)]
|
|
||||||
public required int TotalActiveStrategies { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Total platform-wide profit and loss in USD
|
|
||||||
/// </summary>
|
|
||||||
[Id(2)]
|
|
||||||
public required decimal TotalPlatformPnL { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Total volume traded across all agents in USD
|
|
||||||
/// </summary>
|
|
||||||
[Id(3)]
|
|
||||||
public required decimal TotalPlatformVolume { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Total volume traded across all agents in the last 24 hours in USD
|
|
||||||
/// </summary>
|
|
||||||
[Id(4)]
|
|
||||||
public required decimal TotalPlatformVolumeLast24h { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Total open interest across all positions in USD
|
|
||||||
/// </summary>
|
|
||||||
[Id(5)]
|
|
||||||
public required decimal TotalOpenInterest { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Total number of open positions across all strategies
|
|
||||||
/// </summary>
|
|
||||||
[Id(6)]
|
|
||||||
public required int TotalPositionCount { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Total platform-wide fees paid in USD
|
|
||||||
/// </summary>
|
|
||||||
[Id(19)]
|
|
||||||
public required decimal TotalPlatformFees { get; set; }
|
|
||||||
|
|
||||||
// 24-hour changes
|
|
||||||
/// <summary>
|
|
||||||
/// Change in agent count over the last 24 hours
|
|
||||||
/// </summary>
|
|
||||||
[Id(7)]
|
|
||||||
public required int AgentsChange24h { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change in strategy count over the last 24 hours
|
|
||||||
/// </summary>
|
|
||||||
[Id(8)]
|
|
||||||
public required int StrategiesChange24h { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change in PnL over the last 24 hours
|
|
||||||
/// </summary>
|
|
||||||
[Id(9)]
|
|
||||||
public required decimal PnLChange24h { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change in volume over the last 24 hours
|
|
||||||
/// </summary>
|
|
||||||
[Id(10)]
|
|
||||||
public required decimal VolumeChange24h { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change in open interest over the last 24 hours
|
|
||||||
/// </summary>
|
|
||||||
[Id(11)]
|
|
||||||
public required decimal OpenInterestChange24h { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change in position count over the last 24 hours
|
|
||||||
/// </summary>
|
|
||||||
[Id(12)]
|
|
||||||
public required int PositionCountChange24h { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change in fees over the last 24 hours
|
|
||||||
/// </summary>
|
|
||||||
[Id(20)]
|
|
||||||
public required decimal FeesChange24h { get; set; }
|
|
||||||
|
|
||||||
// Breakdowns
|
|
||||||
/// <summary>
|
|
||||||
/// Volume breakdown by asset/ticker
|
|
||||||
/// </summary>
|
|
||||||
[Id(13)]
|
|
||||||
public required Dictionary<Ticker, decimal> VolumeByAsset { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Position count breakdown by asset/ticker
|
|
||||||
/// </summary>
|
|
||||||
[Id(14)]
|
|
||||||
public required Dictionary<Ticker, int> PositionCountByAsset { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Position count breakdown by direction (Long/Short)
|
|
||||||
/// </summary>
|
|
||||||
[Id(15)]
|
|
||||||
public required Dictionary<TradeDirection, int> PositionCountByDirection { get; set; }
|
|
||||||
|
|
||||||
// Metadata
|
|
||||||
/// <summary>
|
|
||||||
/// When the data was last updated
|
|
||||||
/// </summary>
|
|
||||||
[Id(16)]
|
|
||||||
public required DateTime LastUpdated { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// When the last 24-hour snapshot was taken
|
|
||||||
/// </summary>
|
|
||||||
[Id(17)]
|
|
||||||
public required DateTime Last24HourSnapshot { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Daily volume history for the last 30 days for chart visualization
|
|
||||||
/// </summary>
|
|
||||||
[Id(18)]
|
|
||||||
public required List<VolumeHistoryPoint> VolumeHistory { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a volume data point for historical charting
|
|
||||||
/// </summary>
|
|
||||||
[GenerateSerializer]
|
|
||||||
public class VolumeHistoryPoint
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Date of the volume measurement
|
|
||||||
/// </summary>
|
|
||||||
[Id(0)]
|
|
||||||
public required DateTime Date { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Total volume for that date in USD
|
|
||||||
/// </summary>
|
|
||||||
[Id(1)]
|
|
||||||
public required decimal Volume { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using Managing.Application.Abstractions;
|
using Managing.Application.Abstractions;
|
||||||
using Managing.Application.Abstractions.Grains;
|
using Managing.Application.Abstractions.Grains;
|
||||||
using Managing.Application.Abstractions.Models;
|
|
||||||
using Managing.Application.Abstractions.Services;
|
using Managing.Application.Abstractions.Services;
|
||||||
using Managing.Application.Orleans;
|
using Managing.Application.Orleans;
|
||||||
using Managing.Domain.Bots;
|
using Managing.Domain.Bots;
|
||||||
@@ -58,11 +57,32 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
// Initial data load if state is empty
|
// Initial data load if state is empty
|
||||||
if (_state.State.LastUpdated == default)
|
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();
|
await RefreshDataAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PlatformSummaryViewModel> GetPlatformSummaryAsync()
|
public async Task<PlatformSummaryGrainState> GetPlatformSummaryAsync()
|
||||||
{
|
{
|
||||||
// If data is stale or has pending changes, refresh it
|
// If data is stale or has pending changes, refresh it
|
||||||
if (IsDataStale() || _state.State.HasPendingChanges)
|
if (IsDataStale() || _state.State.HasPendingChanges)
|
||||||
@@ -70,7 +90,7 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
await RefreshDataAsync();
|
await RefreshDataAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
return MapToViewModel(_state.State);
|
return _state.State;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RefreshDataAsync()
|
public async Task RefreshDataAsync()
|
||||||
@@ -238,20 +258,6 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
return Task.FromResult(_state.State.TotalPlatformFees);
|
return Task.FromResult(_state.State.TotalPlatformFees);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<List<VolumeHistoryPoint>> 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
|
// Event handlers for immediate updates
|
||||||
public async Task UpdateActiveStrategyCountAsync(int newActiveCount)
|
public async Task UpdateActiveStrategyCountAsync(int newActiveCount)
|
||||||
{
|
{
|
||||||
@@ -395,15 +401,6 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
{
|
{
|
||||||
_logger.LogInformation("Taking daily snapshot");
|
_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
|
// Add daily snapshot
|
||||||
var dailySnapshot = new DailySnapshot
|
var dailySnapshot = new DailySnapshot
|
||||||
{
|
{
|
||||||
@@ -414,13 +411,12 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
TotalPnL = _state.State.TotalPlatformPnL,
|
TotalPnL = _state.State.TotalPlatformPnL,
|
||||||
TotalOpenInterest = _state.State.OpenInterest,
|
TotalOpenInterest = _state.State.OpenInterest,
|
||||||
TotalPositionCount = _state.State.TotalPositionCount,
|
TotalPositionCount = _state.State.TotalPositionCount,
|
||||||
TotalFees = _state.State.TotalPlatformFees
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_state.State.DailySnapshots.Add(dailySnapshot);
|
_state.State.DailySnapshots.Add(dailySnapshot);
|
||||||
|
|
||||||
// Keep only last 30 days
|
// Keep only last 60 days
|
||||||
var cutoff = DateTime.UtcNow.AddDays(-30);
|
var cutoff = DateTime.UtcNow.AddDays(-60);
|
||||||
_state.State.DailySnapshots.RemoveAll(s => s.Date < cutoff);
|
_state.State.DailySnapshots.RemoveAll(s => s.Date < cutoff);
|
||||||
|
|
||||||
_state.State.LastSnapshot = DateTime.UtcNow;
|
_state.State.LastSnapshot = DateTime.UtcNow;
|
||||||
@@ -433,50 +429,4 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
var timeSinceLastUpdate = DateTime.UtcNow - _state.State.LastUpdated;
|
var timeSinceLastUpdate = DateTime.UtcNow - _state.State.LastUpdated;
|
||||||
return timeSinceLastUpdate > TimeSpan.FromMinutes(5);
|
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<Ticker, decimal>(),
|
|
||||||
PositionCountByAsset = state.PositionCountByAsset ?? new Dictionary<Ticker, int>(),
|
|
||||||
PositionCountByDirection = state.PositionCountByDirection ?? new Dictionary<TradeDirection, int>(),
|
|
||||||
|
|
||||||
// Volume history for charting (last 30 days)
|
|
||||||
VolumeHistory = volumeHistory,
|
|
||||||
|
|
||||||
// Metadata
|
|
||||||
LastUpdated = state.LastUpdated,
|
|
||||||
Last24HourSnapshot = state.LastSnapshot
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -4096,6 +4096,7 @@ export interface LightBacktest {
|
|||||||
sharpeRatio?: number | null;
|
sharpeRatio?: number | null;
|
||||||
score?: number;
|
score?: number;
|
||||||
scoreMessage?: string | null;
|
scoreMessage?: string | null;
|
||||||
|
metadata?: any | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RunBacktestRequest {
|
export interface RunBacktestRequest {
|
||||||
@@ -4533,7 +4534,6 @@ export interface UserStrategyDetailsViewModel {
|
|||||||
state?: BotStatus;
|
state?: BotStatus;
|
||||||
pnL?: number;
|
pnL?: number;
|
||||||
roiPercentage?: number;
|
roiPercentage?: number;
|
||||||
roiLast24H?: number;
|
|
||||||
runtime?: Date;
|
runtime?: Date;
|
||||||
winRate?: number;
|
winRate?: number;
|
||||||
totalVolumeTraded?: number;
|
totalVolumeTraded?: number;
|
||||||
@@ -4547,30 +4547,30 @@ export interface UserStrategyDetailsViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface PlatformSummaryViewModel {
|
export interface PlatformSummaryViewModel {
|
||||||
|
lastUpdated?: Date;
|
||||||
|
lastSnapshot?: Date;
|
||||||
|
hasPendingChanges?: boolean;
|
||||||
totalAgents?: number;
|
totalAgents?: number;
|
||||||
totalActiveStrategies?: number;
|
totalActiveStrategies?: number;
|
||||||
totalPlatformPnL?: number;
|
totalPlatformPnL?: number;
|
||||||
totalPlatformVolume?: number;
|
totalPlatformVolume?: number;
|
||||||
totalPlatformVolumeLast24h?: number;
|
openInterest?: number;
|
||||||
totalOpenInterest?: number;
|
|
||||||
totalPositionCount?: number;
|
totalPositionCount?: number;
|
||||||
agentsChange24h?: number;
|
totalPlatformFees?: number;
|
||||||
strategiesChange24h?: number;
|
dailySnapshots?: DailySnapshot[] | null;
|
||||||
pnLChange24h?: number;
|
|
||||||
volumeChange24h?: number;
|
|
||||||
openInterestChange24h?: number;
|
|
||||||
positionCountChange24h?: number;
|
|
||||||
volumeByAsset?: { [key in keyof typeof Ticker]?: number; } | null;
|
volumeByAsset?: { [key in keyof typeof Ticker]?: number; } | null;
|
||||||
positionCountByAsset?: { [key in keyof typeof Ticker]?: number; } | null;
|
positionCountByAsset?: { [key in keyof typeof Ticker]?: number; } | null;
|
||||||
positionCountByDirection?: { [key in keyof typeof TradeDirection]?: 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;
|
date?: Date;
|
||||||
volume?: number;
|
totalAgents?: number;
|
||||||
|
totalStrategies?: number;
|
||||||
|
totalVolume?: number;
|
||||||
|
totalPnL?: number;
|
||||||
|
totalOpenInterest?: number;
|
||||||
|
totalPositionCount?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PaginatedAgentIndexResponse {
|
export interface PaginatedAgentIndexResponse {
|
||||||
|
|||||||
@@ -544,6 +544,7 @@ export interface LightBacktest {
|
|||||||
sharpeRatio?: number | null;
|
sharpeRatio?: number | null;
|
||||||
score?: number;
|
score?: number;
|
||||||
scoreMessage?: string | null;
|
scoreMessage?: string | null;
|
||||||
|
metadata?: any | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RunBacktestRequest {
|
export interface RunBacktestRequest {
|
||||||
@@ -981,7 +982,6 @@ export interface UserStrategyDetailsViewModel {
|
|||||||
state?: BotStatus;
|
state?: BotStatus;
|
||||||
pnL?: number;
|
pnL?: number;
|
||||||
roiPercentage?: number;
|
roiPercentage?: number;
|
||||||
roiLast24H?: number;
|
|
||||||
runtime?: Date;
|
runtime?: Date;
|
||||||
winRate?: number;
|
winRate?: number;
|
||||||
totalVolumeTraded?: number;
|
totalVolumeTraded?: number;
|
||||||
@@ -995,30 +995,30 @@ export interface UserStrategyDetailsViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface PlatformSummaryViewModel {
|
export interface PlatformSummaryViewModel {
|
||||||
|
lastUpdated?: Date;
|
||||||
|
lastSnapshot?: Date;
|
||||||
|
hasPendingChanges?: boolean;
|
||||||
totalAgents?: number;
|
totalAgents?: number;
|
||||||
totalActiveStrategies?: number;
|
totalActiveStrategies?: number;
|
||||||
totalPlatformPnL?: number;
|
totalPlatformPnL?: number;
|
||||||
totalPlatformVolume?: number;
|
totalPlatformVolume?: number;
|
||||||
totalPlatformVolumeLast24h?: number;
|
openInterest?: number;
|
||||||
totalOpenInterest?: number;
|
|
||||||
totalPositionCount?: number;
|
totalPositionCount?: number;
|
||||||
agentsChange24h?: number;
|
totalPlatformFees?: number;
|
||||||
strategiesChange24h?: number;
|
dailySnapshots?: DailySnapshot[] | null;
|
||||||
pnLChange24h?: number;
|
|
||||||
volumeChange24h?: number;
|
|
||||||
openInterestChange24h?: number;
|
|
||||||
positionCountChange24h?: number;
|
|
||||||
volumeByAsset?: { [key in keyof typeof Ticker]?: number; } | null;
|
volumeByAsset?: { [key in keyof typeof Ticker]?: number; } | null;
|
||||||
positionCountByAsset?: { [key in keyof typeof Ticker]?: number; } | null;
|
positionCountByAsset?: { [key in keyof typeof Ticker]?: number; } | null;
|
||||||
positionCountByDirection?: { [key in keyof typeof TradeDirection]?: 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;
|
date?: Date;
|
||||||
volume?: number;
|
totalAgents?: number;
|
||||||
|
totalStrategies?: number;
|
||||||
|
totalVolume?: number;
|
||||||
|
totalPnL?: number;
|
||||||
|
totalOpenInterest?: number;
|
||||||
|
totalPositionCount?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PaginatedAgentIndexResponse {
|
export interface PaginatedAgentIndexResponse {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
import React, {useMemo} from 'react'
|
||||||
import {useQuery, useQueryClient} from '@tanstack/react-query'
|
import {useQuery, useQueryClient} from '@tanstack/react-query'
|
||||||
import useApiUrlStore from '../../app/store/apiStore'
|
import useApiUrlStore from '../../app/store/apiStore'
|
||||||
import {fetchPlatformData} from '../../services/platformService'
|
import {fetchPlatformData} from '../../services/platformService'
|
||||||
@@ -26,6 +26,37 @@ function PlatformSummary({index}: { index: number }) {
|
|||||||
const topStrategiesByRoi = data?.topStrategiesByRoi
|
const topStrategiesByRoi = data?.topStrategiesByRoi
|
||||||
const topAgentsByPnL = data?.topAgentsByPnL
|
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) => {
|
const formatCurrency = (value: number) => {
|
||||||
if (value >= 1000000) {
|
if (value >= 1000000) {
|
||||||
return `$${(value / 1000000).toFixed(2)}M`
|
return `$${(value / 1000000).toFixed(2)}M`
|
||||||
@@ -113,7 +144,7 @@ function PlatformSummary({index}: { index: number }) {
|
|||||||
{formatNumber(platformData?.totalActiveStrategies || 0)} Strategies Deployed
|
{formatNumber(platformData?.totalActiveStrategies || 0)} Strategies Deployed
|
||||||
</h1>
|
</h1>
|
||||||
<div className="text-lg">
|
<div className="text-lg">
|
||||||
{platformData && formatChangeIndicator(platformData.strategiesChange24h || 0)}
|
{platformData && formatChangeIndicator(changes24h.strategiesChange)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -126,15 +157,33 @@ function PlatformSummary({index}: { index: number }) {
|
|||||||
{formatCurrency(platformData?.totalPlatformVolume || 0)}
|
{formatCurrency(platformData?.totalPlatformVolume || 0)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`text-sm ${(platformData?.volumeChange24h || 0) >= 0 ? 'text-green-500' : 'text-red-500'}`}>
|
className={`text-sm ${changes24h.volumeChange >= 0 ? 'text-green-500' : 'text-red-500'}`}>
|
||||||
{(platformData?.volumeChange24h || 0) >= 0 ? '+' : ''}{formatCurrency(platformData?.volumeChange24h || 0)} Today
|
{changes24h.volumeChange >= 0 ? '+' : ''}{formatCurrency(changes24h.volumeChange)} Today
|
||||||
<span className="ml-2 text-gray-400">
|
<span className="ml-2 text-gray-400">
|
||||||
({formatPercentageChange(platformData?.totalPlatformVolume || 0, platformData?.volumeChange24h || 0)})
|
({formatPercentageChange(platformData?.totalPlatformVolume || 0, changes24h.volumeChange)})
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{/* Simple chart placeholder - you can replace with actual chart */}
|
{/* Volume chart using daily snapshots */}
|
||||||
<div className="mt-4 h-16 flex items-end">
|
<div className="mt-4 h-16 flex items-end gap-1">
|
||||||
|
{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 (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="flex-1 bg-green-500 rounded-sm opacity-60 hover:opacity-80 transition-opacity"
|
||||||
|
style={{ height: `${Math.max(height, 4)}%` }}
|
||||||
|
title={`${new Date(snapshot.date || 0).toLocaleDateString()}: ${formatCurrency(snapshot.totalVolume || 0)}`}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
) : (
|
||||||
<div className="w-full h-8 bg-green-500 rounded opacity-20"></div>
|
<div className="w-full h-8 bg-green-500 rounded opacity-20"></div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -261,8 +310,8 @@ function PlatformSummary({index}: { index: number }) {
|
|||||||
{formatNumber(platformData?.totalAgents || 0)}
|
{formatNumber(platformData?.totalAgents || 0)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`text-sm ${(platformData?.agentsChange24h || 0) >= 0 ? 'text-green-500' : 'text-red-500'}`}>
|
className={`text-sm ${changes24h.agentsChange >= 0 ? 'text-green-500' : 'text-red-500'}`}>
|
||||||
{formatChangeIndicator(platformData?.agentsChange24h || 0)}
|
{formatChangeIndicator(changes24h.agentsChange)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -272,8 +321,8 @@ function PlatformSummary({index}: { index: number }) {
|
|||||||
{formatNumber(platformData?.totalActiveStrategies || 0)}
|
{formatNumber(platformData?.totalActiveStrategies || 0)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`text-sm ${(platformData?.strategiesChange24h || 0) >= 0 ? 'text-green-500' : 'text-red-500'}`}>
|
className={`text-sm ${changes24h.strategiesChange >= 0 ? 'text-green-500' : 'text-red-500'}`}>
|
||||||
{formatChangeIndicator(platformData?.strategiesChange24h || 0)}
|
{formatChangeIndicator(changes24h.strategiesChange)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -284,19 +333,19 @@ function PlatformSummary({index}: { index: number }) {
|
|||||||
{(platformData?.totalPlatformPnL || 0) >= 0 ? '+' : ''}{formatCurrency(platformData?.totalPlatformPnL || 0)}
|
{(platformData?.totalPlatformPnL || 0) >= 0 ? '+' : ''}{formatCurrency(platformData?.totalPlatformPnL || 0)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`text-sm ${(platformData?.pnLChange24h || 0) >= 0 ? 'text-green-500' : 'text-red-500'}`}>
|
className={`text-sm ${changes24h.pnLChange >= 0 ? 'text-green-500' : 'text-red-500'}`}>
|
||||||
{(platformData?.pnLChange24h || 0) >= 0 ? '+' : ''}{formatCurrency(platformData?.pnLChange24h || 0)} Today
|
{changes24h.pnLChange >= 0 ? '+' : ''}{formatCurrency(changes24h.pnLChange)} Today
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<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">Open Interest</h3>
|
<h3 className="text-lg font-semibold text-gray-400 mb-2">Open Interest</h3>
|
||||||
<div className="text-3xl font-bold text-white mb-1">
|
<div className="text-3xl font-bold text-white mb-1">
|
||||||
{formatCurrency(platformData?.totalOpenInterest || 0)}
|
{formatCurrency(platformData?.openInterest || 0)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`text-sm ${(platformData?.openInterestChange24h || 0) >= 0 ? 'text-green-500' : 'text-red-500'}`}>
|
className={`text-sm ${changes24h.openInterestChange >= 0 ? 'text-green-500' : 'text-red-500'}`}>
|
||||||
{(platformData?.openInterestChange24h || 0) >= 0 ? '+' : ''}{formatCurrency(platformData?.openInterestChange24h || 0)} Today
|
{changes24h.openInterestChange >= 0 ? '+' : ''}{formatCurrency(changes24h.openInterestChange)} Today
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -309,8 +358,8 @@ function PlatformSummary({index}: { index: number }) {
|
|||||||
{formatNumber(platformData?.totalPositionCount || 0)}
|
{formatNumber(platformData?.totalPositionCount || 0)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`text-sm ${(platformData?.positionCountChange24h || 0) >= 0 ? 'text-green-500' : 'text-red-500'}`}>
|
className={`text-sm ${changes24h.positionCountChange >= 0 ? 'text-green-500' : 'text-red-500'}`}>
|
||||||
{formatChangeIndicator(platformData?.positionCountChange24h || 0)}
|
{formatChangeIndicator(changes24h.positionCountChange)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -445,7 +494,7 @@ function PlatformSummary({index}: { index: number }) {
|
|||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<span>24h snapshot: {platformData?.last24HourSnapshot ? new Date(platformData.last24HourSnapshot).toLocaleString() : 'Unknown'}</span>
|
<span>Last snapshot: {platformData?.lastSnapshot ? new Date(platformData.lastSnapshot).toLocaleString() : 'Unknown'}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user