Add agent fees

This commit is contained in:
2025-09-28 20:57:42 +07:00
parent fd2387932e
commit 16a56bd26c
20 changed files with 108 additions and 166 deletions

View File

@@ -56,10 +56,10 @@ public class AgentGrain : Grain, IAgentGrain
_scopeFactory = scopeFactory;
}
public override Task OnActivateAsync(CancellationToken cancellationToken)
public override async Task OnActivateAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("AgentGrain activated for user {UserId}", this.GetPrimaryKeyLong());
return base.OnActivateAsync(cancellationToken);
await base.OnActivateAsync(cancellationToken);
}
public async Task InitializeAsync(int userId, string agentName)
@@ -86,6 +86,14 @@ public class AgentGrain : Grain, IAgentGrain
await _agentService.SaveOrUpdateAgentSummary(emptySummary);
_logger.LogInformation("Agent {UserId} initialized with name {AgentName} and empty summary", userId, agentName);
// Notify platform summary about new agent activation
await ServiceScopeHelpers.WithScopedService<IGrainFactory>(_scopeFactory, async grainFactory =>
{
var platformGrain = grainFactory.GetGrain<IPlatformSummaryGrain>("platform-summary");
await platformGrain.IncrementAgentCountAsync();
_logger.LogDebug("Notified platform summary about new agent activation for user {UserId}", userId);
});
}
public async Task UpdateAgentNameAsync(string agentName)
@@ -162,14 +170,19 @@ public class AgentGrain : Grain, IAgentGrain
var totalVolume = positions.Sum(p => p.Open.Price * p.Open.Quantity * p.Open.Leverage);
var collateral = positions.Sum(p => p.Open.Price * p.Open.Quantity);
var totalFees = positions.Sum(p => p.CalculateTotalFees());
// Store total fees in grain state for caching
_state.State.TotalFees = totalFees;
// Calculate wins/losses from position PnL
var totalWins = positions.Count(p => (p.ProfitAndLoss?.Realized ?? 0) > 0);
var totalLosses = positions.Count(p => (p.ProfitAndLoss?.Realized ?? 0) <= 0);
// Calculate ROI based on PnL minus fees
var netPnL = totalPnL - totalFees;
var totalROI = collateral switch
{
> 0 => (totalPnL / collateral) * 100,
> 0 => (netPnL / collateral) * 100,
>= 0 => 0,
_ => 0
};
@@ -223,7 +236,7 @@ public class AgentGrain : Grain, IAgentGrain
{
UserId = (int)this.GetPrimaryKeyLong(),
AgentName = _state.State.AgentName,
TotalPnL = totalPnL,
TotalPnL = totalPnL, // Use net PnL without fees
Wins = totalWins,
Losses = totalLosses,
TotalROI = totalROI,
@@ -231,13 +244,14 @@ public class AgentGrain : Grain, IAgentGrain
ActiveStrategiesCount = activeStrategiesCount,
TotalVolume = totalVolume,
TotalBalance = totalBalance,
TotalFees = totalFees,
};
// Save summary to database
await _agentService.SaveOrUpdateAgentSummary(summary);
_logger.LogDebug("Updated agent summary from position data for user {UserId}: PnL={PnL}, Volume={Volume}, Wins={Wins}, Losses={Losses}",
this.GetPrimaryKeyLong(), totalPnL, totalVolume, totalWins, totalLosses);
_logger.LogDebug("Updated agent summary from position data for user {UserId}: NetPnL={NetPnL}, TotalPnL={TotalPnL}, Fees={Fees}, Volume={Volume}, Wins={Wins}, Losses={Losses}",
this.GetPrimaryKeyLong(), netPnL, totalPnL, totalFees, totalVolume, totalWins, totalLosses);
}
catch (Exception ex)
{

View File

@@ -24,6 +24,12 @@ namespace Managing.Application.Bots.Models
/// </summary>
[Id(4)]
public CachedBalanceData? CachedBalanceData { get; set; } = null;
/// <summary>
/// Total fees paid by this agent across all positions
/// </summary>
[Id(5)]
public decimal TotalFees { get; set; } = 0;
}
/// <summary>

View File

@@ -406,10 +406,13 @@ public class TradingBotBase : ITradingBot
await UpdatePositionDatabase(internalPosition);
if (previousPositionStatus != PositionStatus.Filled && internalPosition.Status == PositionStatus.Filled)
if (previousPositionStatus != PositionStatus.Filled &&
internalPosition.Status == PositionStatus.Filled)
{
await NotifyAgentAndPlatformGrainAsync(NotificationEventType.PositionOpened, internalPosition);
}else{
}
else
{
await NotifyAgentAndPlatformGrainAsync(NotificationEventType.PositionUpdated, internalPosition);
}
}
@@ -750,8 +753,6 @@ public class TradingBotBase : ITradingBot
currentPrice, true);
}
}
}
catch (Exception ex)
{
@@ -763,10 +764,8 @@ public class TradingBotBase : ITradingBot
private async Task UpdatePositionDatabase(Position position)
{
await ServiceScopeHelpers.WithScopedService<ITradingService>(_scopeFactory, async tradingService =>
{
await tradingService.UpdatePositionAsync(position);
});
await ServiceScopeHelpers.WithScopedService<ITradingService>(_scopeFactory,
async tradingService => { await tradingService.UpdatePositionAsync(position); });
}
private async Task<Position> OpenPosition(LightSignal signal)
@@ -1347,6 +1346,7 @@ public class TradingBotBase : ITradingBot
// Update position in database with all trade changes
if (!Config.IsForBacktest)
{
position.Status = PositionStatus.Finished;
await UpdatePositionDatabase(position);
await NotifyAgentAndPlatformGrainAsync(NotificationEventType.PositionClosed, position);
}
@@ -1468,10 +1468,13 @@ public class TradingBotBase : ITradingBot
{
if (Positions[identifier].ProfitAndLoss == null)
{
Positions[identifier].ProfitAndLoss = new ProfitAndLoss(){
Positions[identifier].ProfitAndLoss = new ProfitAndLoss()
{
Realized = realized
};
}else{
}
else
{
Positions[identifier].ProfitAndLoss.Realized = realized;
}
}