Fix global PNL

This commit is contained in:
2025-09-25 23:23:53 +07:00
parent c297429b18
commit b2e38811ed
5 changed files with 52 additions and 3 deletions

View File

@@ -28,6 +28,7 @@ public interface ITradingRepository
Task<IEnumerable<Position>> GetPositionsByInitiatorIdentifierAsync(Guid initiatorIdentifier); Task<IEnumerable<Position>> GetPositionsByInitiatorIdentifierAsync(Guid initiatorIdentifier);
Task<IEnumerable<Position>> GetPositionsByInitiatorIdentifiersAsync(IEnumerable<Guid> initiatorIdentifiers); Task<IEnumerable<Position>> GetPositionsByInitiatorIdentifiersAsync(IEnumerable<Guid> initiatorIdentifiers);
Task<IEnumerable<Position>> GetAllPositionsAsync(); Task<IEnumerable<Position>> GetAllPositionsAsync();
Task<decimal> GetGlobalPnLFromPositionsAsync();
Task UpdateScenarioAsync(Scenario scenario); Task UpdateScenarioAsync(Scenario scenario);
Task UpdateStrategyAsync(IndicatorBase indicatorBase); Task UpdateStrategyAsync(IndicatorBase indicatorBase);

View File

@@ -39,6 +39,7 @@ public interface ITradingService
Task<IEnumerable<Position>> GetAllDatabasePositionsAsync(); Task<IEnumerable<Position>> GetAllDatabasePositionsAsync();
Task<IEnumerable<Position>> GetPositionsByInitiatorIdentifierAsync(Guid initiatorIdentifier); Task<IEnumerable<Position>> GetPositionsByInitiatorIdentifierAsync(Guid initiatorIdentifier);
Task<IEnumerable<Position>> GetPositionsByInitiatorIdentifiersAsync(IEnumerable<Guid> initiatorIdentifiers); Task<IEnumerable<Position>> GetPositionsByInitiatorIdentifiersAsync(IEnumerable<Guid> initiatorIdentifiers);
Task<decimal> GetGlobalPnLFromPositionsAsync();
Task<PrivyInitAddressResponse> InitPrivyWallet(string publicAddress, TradingExchanges tradingExchange); Task<PrivyInitAddressResponse> InitPrivyWallet(string publicAddress, TradingExchanges tradingExchange);
// Synth API integration methods // Synth API integration methods

View File

@@ -106,9 +106,11 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
var totalAgents = agents.Count(); var totalAgents = agents.Count();
var totalActiveStrategies = strategies.Count(s => s.Status == BotStatus.Running); var totalActiveStrategies = strategies.Count(s => s.Status == BotStatus.Running);
// Calculate volume and PnL from strategies // Calculate volume from strategies
var totalVolume = strategies.Sum(s => s.Volume); var totalVolume = strategies.Sum(s => s.Volume);
var totalPnL = strategies.Sum(s => s.Pnl);
// Calculate PnL directly from database positions (closed positions only)
var totalPnL = await _tradingService.GetGlobalPnLFromPositionsAsync();
// Calculate real open interest and position count from actual positions // Calculate real open interest and position count from actual positions
var (totalOpenInterest, totalPositionCount) = await CalculatePositionMetricsAsync(); var (totalOpenInterest, totalPositionCount) = await CalculatePositionMetricsAsync();
@@ -317,7 +319,11 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
} }
_state.State.TotalPlatformVolume += evt.Volume; _state.State.TotalPlatformVolume += evt.Volume;
_state.State.TotalPlatformPnL += evt.RealizedPnL;
// PnL is now calculated directly from database positions, not from events
// This ensures accuracy and prevents double-counting issues
// Refresh PnL from database to get the latest accurate value
await RefreshPnLFromDatabaseAsync();
// Update volume by asset // Update volume by asset
var asset = evt.Ticker; var asset = evt.Ticker;
@@ -452,6 +458,20 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
await _state.WriteStateAsync(); await _state.WriteStateAsync();
} }
private async Task RefreshPnLFromDatabaseAsync()
{
try
{
var totalPnL = await _tradingService.GetGlobalPnLFromPositionsAsync();
_state.State.TotalPlatformPnL = totalPnL;
_logger.LogDebug("Refreshed PnL from database: {TotalPnL}", totalPnL);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error refreshing PnL from database");
}
}
private bool IsDataStale() private bool IsDataStale()
{ {
var timeSinceLastUpdate = DateTime.UtcNow - _state.State.LastUpdated; var timeSinceLastUpdate = DateTime.UtcNow - _state.State.LastUpdated;

View File

@@ -273,6 +273,11 @@ public class TradingService : ITradingService
return await _tradingRepository.GetPositionsByInitiatorIdentifiersAsync(initiatorIdentifiers); return await _tradingRepository.GetPositionsByInitiatorIdentifiersAsync(initiatorIdentifiers);
} }
public async Task<decimal> GetGlobalPnLFromPositionsAsync()
{
return await _tradingRepository.GetGlobalPnLFromPositionsAsync();
}
private async Task ManageTrader(TraderFollowup a, List<Ticker> tickers) private async Task ManageTrader(TraderFollowup a, List<Ticker> tickers)
{ {
var shortAddress = a.Account.Address.Substring(0, 6); var shortAddress = a.Account.Address.Substring(0, 6);

View File

@@ -505,6 +505,28 @@ public class PostgreSqlTradingRepository : ITradingRepository
return PostgreSqlMappers.Map(positions); return PostgreSqlMappers.Map(positions);
} }
public async Task<decimal> GetGlobalPnLFromPositionsAsync()
{
try
{
await PostgreSqlConnectionHelper.EnsureConnectionOpenAsync(_context);
// Calculate total PnL from all finished positions (closed positions)
// Only include positions that are Finished or Flipped (closed positions)
var totalPnL = await _context.Positions
.AsNoTracking()
.Where(p => p.Status == PositionStatus.Finished || p.Status == PositionStatus.Flipped)
.SumAsync(p => p.ProfitAndLoss)
.ConfigureAwait(false);
return totalPnL;
}
finally
{
await PostgreSqlConnectionHelper.SafeCloseConnectionAsync(_context);
}
}
#endregion #endregion
#region Signal Methods #region Signal Methods