Clean and update event
This commit is contained in:
@@ -19,31 +19,6 @@ public interface IPlatformSummaryGrain : IGrainWithStringKey
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Task RefreshDataAsync();
|
Task RefreshDataAsync();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the total volume traded across all strategies
|
|
||||||
/// </summary>
|
|
||||||
Task<decimal> GetTotalVolumeAsync();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the total PnL across all strategies
|
|
||||||
/// </summary>
|
|
||||||
Task<decimal> GetTotalPnLAsync();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the total open interest across all positions
|
|
||||||
/// </summary>
|
|
||||||
Task<decimal> GetTotalOpenInterest();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the total number of open positions
|
|
||||||
/// </summary>
|
|
||||||
Task<int> GetTotalPositionCountAsync();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the total platform fees
|
|
||||||
/// </summary>
|
|
||||||
Task<decimal> GetTotalFeesAsync();
|
|
||||||
|
|
||||||
// Event handlers for immediate updates
|
// Event handlers for immediate updates
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the active strategy count
|
/// Updates the active strategy count
|
||||||
@@ -97,3 +72,9 @@ public class PositionOpenEvent : PlatformMetricsEvent
|
|||||||
[Id(4)] public TradeDirection Direction { get; set; }
|
[Id(4)] public TradeDirection Direction { get; set; }
|
||||||
[Id(5)] public Guid PositionIdentifier { get; set; }
|
[Id(5)] public Guid PositionIdentifier { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[GenerateSerializer]
|
||||||
|
public class PositionUpdatedEvent : PlatformMetricsEvent
|
||||||
|
{
|
||||||
|
[Id(1)] public Guid PositionIdentifier { get; set; }
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ public class AgentSummaryUpdateEvent
|
|||||||
{
|
{
|
||||||
[Id(0)] public Guid BotId { get; set; }
|
[Id(0)] public Guid BotId { get; set; }
|
||||||
|
|
||||||
[Id(1)] public AgentSummaryEventType EventType { get; set; }
|
[Id(1)] public NotificationEventType EventType { get; set; }
|
||||||
|
|
||||||
[Id(2)] public DateTime Timestamp { get; set; } = DateTime.UtcNow;
|
[Id(2)] public DateTime Timestamp { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ public interface ITradingService
|
|||||||
Task<Scenario> GetScenarioByNameAsync(string scenario);
|
Task<Scenario> GetScenarioByNameAsync(string scenario);
|
||||||
Task InsertPositionAsync(Position position);
|
Task InsertPositionAsync(Position position);
|
||||||
Task UpdatePositionAsync(Position position);
|
Task UpdatePositionAsync(Position position);
|
||||||
Task UpdateTradeAsync(Trade trade);
|
|
||||||
Task<IndicatorBase> GetIndicatorByNameAsync(string strategy);
|
Task<IndicatorBase> GetIndicatorByNameAsync(string strategy);
|
||||||
Task InsertScenarioAsync(Scenario scenario);
|
Task InsertScenarioAsync(Scenario scenario);
|
||||||
Task InsertIndicatorAsync(IndicatorBase indicatorBase);
|
Task InsertIndicatorAsync(IndicatorBase indicatorBase);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class AgentGrainTests
|
|||||||
var updateEvent = new AgentSummaryUpdateEvent
|
var updateEvent = new AgentSummaryUpdateEvent
|
||||||
{
|
{
|
||||||
BotId = botId,
|
BotId = botId,
|
||||||
EventType = AgentSummaryEventType.PositionOpened,
|
EventType = NotificationEventType.PositionOpened,
|
||||||
Timestamp = DateTime.UtcNow
|
Timestamp = DateTime.UtcNow
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ public class AgentGrainTests
|
|||||||
var updateEvent = new AgentSummaryUpdateEvent
|
var updateEvent = new AgentSummaryUpdateEvent
|
||||||
{
|
{
|
||||||
BotId = Guid.NewGuid(), // Different bot ID
|
BotId = Guid.NewGuid(), // Different bot ID
|
||||||
EventType = AgentSummaryEventType.PositionOpened,
|
EventType = NotificationEventType.PositionOpened,
|
||||||
Timestamp = DateTime.UtcNow
|
Timestamp = DateTime.UtcNow
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using Managing.Application.Abstractions.Models;
|
|
||||||
using Managing.Application.Bots.Models;
|
using Managing.Application.Bots.Models;
|
||||||
using Orleans.Concurrency;
|
using Orleans.Concurrency;
|
||||||
|
|
||||||
@@ -20,28 +19,38 @@ namespace Managing.Application.Abstractions.Grains
|
|||||||
[OneWay]
|
[OneWay]
|
||||||
Task UpdateAgentNameAsync(string agentName);
|
Task UpdateAgentNameAsync(string agentName);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates a summary of the agent's stats for the AgentRegistryGrain.
|
|
||||||
/// </summary>
|
|
||||||
[OneWay]
|
|
||||||
Task UpdateSummary();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a new bot with this agent.
|
/// Registers a new bot with this agent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[OneWay]
|
||||||
Task RegisterBotAsync(Guid botId);
|
Task RegisterBotAsync(Guid botId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unregisters a bot from this agent.
|
/// Unregisters a bot from this agent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[OneWay]
|
||||||
Task UnregisterBotAsync(Guid botId);
|
Task UnregisterBotAsync(Guid botId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles stream notifications for agent summary updates.
|
/// Handles position opened events for real-time agent summary updates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="updateEvent">The update event from the stream</param>]
|
/// <param name="evt">The position opened event</param>
|
||||||
[OneWay]
|
[OneWay]
|
||||||
Task OnAgentSummaryUpdateAsync(AgentSummaryUpdateEvent updateEvent);
|
Task OnPositionOpenedAsync(PositionOpenEvent evt);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles position closed events for real-time agent summary updates.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="evt">The position closed event</param>
|
||||||
|
[OneWay]
|
||||||
|
Task OnPositionClosedAsync(PositionClosedEvent evt);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles position update events for real-time PnL and status updates.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="evt">The position update event</param>
|
||||||
|
[OneWay]
|
||||||
|
Task OnPositionUpdatedAsync(PositionUpdatedEvent evt);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Coordinates ETH balance checking and swapping for all bots under this agent.
|
/// Coordinates ETH balance checking and swapping for all bots under this agent.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
#nullable enable
|
||||||
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.Bots.Models;
|
using Managing.Application.Bots.Models;
|
||||||
using Managing.Application.Orleans;
|
using Managing.Application.Orleans;
|
||||||
@@ -91,40 +91,107 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
_logger.LogInformation("Agent {UserId} updated with name {AgentName}", this.GetPrimaryKeyLong(), agentName);
|
_logger.LogInformation("Agent {UserId} updated with name {AgentName}", this.GetPrimaryKeyLong(), agentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task OnAgentSummaryUpdateAsync(AgentSummaryUpdateEvent updateEvent)
|
public async Task OnPositionOpenedAsync(PositionOpenEvent evt)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Received agent summary update event for user {UserId}, event type: {EventType}",
|
_logger.LogInformation("Position opened event received for user {UserId}, position: {PositionId}",
|
||||||
this.GetPrimaryKeyLong(), updateEvent.EventType);
|
this.GetPrimaryKeyLong(), evt.PositionIdentifier);
|
||||||
|
|
||||||
// Only update summary if the event is for this agent's bots
|
// Update event-driven metrics
|
||||||
if (_state.State.BotIds.Contains(updateEvent.BotId))
|
_state.State.TotalVolume += evt.Volume;
|
||||||
{
|
_state.State.TotalFees += evt.Fee;
|
||||||
await UpdateSummary();
|
_state.State.LastSummaryUpdate = DateTime.UtcNow;
|
||||||
}
|
|
||||||
|
await _state.WriteStateAsync();
|
||||||
|
|
||||||
|
// Update the agent summary with the new data
|
||||||
|
await UpdateSummary();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Error processing agent summary update event for user {UserId}",
|
_logger.LogError(ex, "Error processing position opened event for user {UserId}",
|
||||||
this.GetPrimaryKeyLong());
|
this.GetPrimaryKeyLong());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateSummary()
|
public async Task OnPositionClosedAsync(PositionClosedEvent evt)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Get all bots for this agent
|
_logger.LogInformation("Position closed event received for user {UserId}, position: {PositionId}, PnL: {PnL}",
|
||||||
var bots = await _botService.GetBotsByIdsAsync(_state.State.BotIds);
|
this.GetPrimaryKeyLong(), evt.PositionIdentifier, evt.RealizedPnL);
|
||||||
|
|
||||||
// Calculate aggregated statistics from bot data
|
// Update event-driven metrics
|
||||||
var totalPnL = bots.Sum(b => b.Pnl);
|
_state.State.TotalPnL += evt.RealizedPnL;
|
||||||
var totalWins = bots.Sum(b => b.TradeWins);
|
_state.State.TotalVolume += evt.Volume;
|
||||||
var totalLosses = bots.Sum(b => b.TradeLosses);
|
|
||||||
|
// Update wins/losses count
|
||||||
|
if (evt.RealizedPnL > 0)
|
||||||
|
{
|
||||||
|
_state.State.Wins++;
|
||||||
|
}
|
||||||
|
else if (evt.RealizedPnL < 0)
|
||||||
|
{
|
||||||
|
_state.State.Losses++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_state.State.LastSummaryUpdate = DateTime.UtcNow;
|
||||||
|
|
||||||
|
await _state.WriteStateAsync();
|
||||||
|
|
||||||
|
// Update the agent summary with the new data
|
||||||
|
await UpdateSummary();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error processing position closed event for user {UserId}",
|
||||||
|
this.GetPrimaryKeyLong());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task OnPositionUpdatedAsync(PositionUpdatedEvent evt)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Position updated event received for user {UserId}, position: {PositionId}",
|
||||||
|
this.GetPrimaryKeyLong(), evt.PositionIdentifier);
|
||||||
|
|
||||||
|
// Update event-driven metrics for PnL changes
|
||||||
|
// Note: This is for real-time PnL updates, not cumulative like closed positions
|
||||||
|
_state.State.LastSummaryUpdate = DateTime.UtcNow;
|
||||||
|
|
||||||
|
await _state.WriteStateAsync();
|
||||||
|
|
||||||
|
// Update the agent summary with the new data
|
||||||
|
await UpdateSummary();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error processing position updated event for user {UserId}",
|
||||||
|
this.GetPrimaryKeyLong());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the agent summary by recalculating from position data (used for initialization or manual refresh)
|
||||||
|
/// </summary>
|
||||||
|
private async Task UpdateSummary()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get all positions for this agent's bots as initiator
|
||||||
|
var positions = await _tradingService.GetPositionsByInitiatorIdentifiersAsync(_state.State.BotIds);
|
||||||
|
|
||||||
|
// Calculate aggregated statistics from position data
|
||||||
|
var totalPnL = positions.Sum(p => p.ProfitAndLoss?.Realized ?? 0);
|
||||||
|
var totalVolume = positions.Sum(p => p.Open.Price * p.Open.Quantity);
|
||||||
|
var totalFees = positions.Sum(p => p.CalculateTotalFees());
|
||||||
|
|
||||||
|
// 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 total volume traded with proper division by zero handling
|
|
||||||
var totalVolume = bots.Sum(b => b.Volume);
|
|
||||||
decimal totalROI;
|
decimal totalROI;
|
||||||
|
|
||||||
if (totalVolume > 0)
|
if (totalVolume > 0)
|
||||||
@@ -148,11 +215,11 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
totalROI = 0;
|
totalROI = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate Runtime based on the farthest date from bot startup times
|
// Calculate Runtime based on the earliest position date
|
||||||
DateTime? runtime = null;
|
DateTime? runtime = null;
|
||||||
if (bots.Any())
|
if (positions.Any())
|
||||||
{
|
{
|
||||||
runtime = bots.Max(b => b.StartupTime);
|
runtime = positions.Min(p => p.Date);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate total balance (USDC + open positions value)
|
// Calculate total balance (USDC + open positions value)
|
||||||
@@ -192,6 +259,10 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
totalBalance = 0; // Set to 0 if calculation fails
|
totalBalance = 0; // Set to 0 if calculation fails
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get active strategies count from bot data (this is still needed for running bots)
|
||||||
|
var bots = await _botService.GetBotsByIdsAsync(_state.State.BotIds);
|
||||||
|
var activeStrategiesCount = bots.Count(b => b.Status == BotStatus.Running);
|
||||||
|
|
||||||
var summary = new AgentSummary
|
var summary = new AgentSummary
|
||||||
{
|
{
|
||||||
UserId = (int)this.GetPrimaryKeyLong(),
|
UserId = (int)this.GetPrimaryKeyLong(),
|
||||||
@@ -201,13 +272,16 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
Losses = totalLosses,
|
Losses = totalLosses,
|
||||||
TotalROI = totalROI,
|
TotalROI = totalROI,
|
||||||
Runtime = runtime,
|
Runtime = runtime,
|
||||||
ActiveStrategiesCount = bots.Count(b => b.Status == BotStatus.Running),
|
ActiveStrategiesCount = activeStrategiesCount,
|
||||||
TotalVolume = totalVolume,
|
TotalVolume = totalVolume,
|
||||||
TotalBalance = totalBalance,
|
TotalBalance = totalBalance,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Save summary to database
|
// Save summary to database
|
||||||
await _agentService.SaveOrUpdateAgentSummary(summary);
|
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);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -219,6 +293,10 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
{
|
{
|
||||||
if (_state.State.BotIds.Add(botId))
|
if (_state.State.BotIds.Add(botId))
|
||||||
{
|
{
|
||||||
|
// Update active strategies count
|
||||||
|
_state.State.ActiveStrategiesCount = _state.State.BotIds.Count;
|
||||||
|
_state.State.LastSummaryUpdate = DateTime.UtcNow;
|
||||||
|
|
||||||
await _state.WriteStateAsync();
|
await _state.WriteStateAsync();
|
||||||
_logger.LogInformation("Bot {BotId} registered to Agent {UserId}", botId, this.GetPrimaryKeyLong());
|
_logger.LogInformation("Bot {BotId} registered to Agent {UserId}", botId, this.GetPrimaryKeyLong());
|
||||||
|
|
||||||
@@ -231,6 +309,10 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
{
|
{
|
||||||
if (_state.State.BotIds.Remove(botId))
|
if (_state.State.BotIds.Remove(botId))
|
||||||
{
|
{
|
||||||
|
// Update active strategies count
|
||||||
|
_state.State.ActiveStrategiesCount = _state.State.BotIds.Count;
|
||||||
|
_state.State.LastSummaryUpdate = DateTime.UtcNow;
|
||||||
|
|
||||||
await _state.WriteStateAsync();
|
await _state.WriteStateAsync();
|
||||||
_logger.LogInformation("Bot {BotId} unregistered from Agent {UserId}", botId, this.GetPrimaryKeyLong());
|
_logger.LogInformation("Bot {BotId} unregistered from Agent {UserId}", botId, this.GetPrimaryKeyLong());
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using Managing.Application.Abstractions;
|
|
||||||
using Managing.Application.Abstractions.Grains;
|
using Managing.Application.Abstractions.Grains;
|
||||||
using Managing.Application.Orleans;
|
using Managing.Application.Orleans;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@@ -17,17 +16,14 @@ public class LiveBotRegistryGrain : Grain, ILiveBotRegistryGrain
|
|||||||
{
|
{
|
||||||
private readonly IPersistentState<BotRegistryState> _state;
|
private readonly IPersistentState<BotRegistryState> _state;
|
||||||
private readonly ILogger<LiveBotRegistryGrain> _logger;
|
private readonly ILogger<LiveBotRegistryGrain> _logger;
|
||||||
private readonly IBotService _botService;
|
|
||||||
|
|
||||||
public LiveBotRegistryGrain(
|
public LiveBotRegistryGrain(
|
||||||
[PersistentState("bot-registry", "registry-store")]
|
[PersistentState("bot-registry", "registry-store")]
|
||||||
IPersistentState<BotRegistryState> state,
|
IPersistentState<BotRegistryState> state,
|
||||||
ILogger<LiveBotRegistryGrain> logger,
|
ILogger<LiveBotRegistryGrain> logger)
|
||||||
IBotService botService)
|
|
||||||
{
|
{
|
||||||
_state = state;
|
_state = state;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_botService = botService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task OnActivateAsync(CancellationToken cancellationToken)
|
public override async Task OnActivateAsync(CancellationToken cancellationToken)
|
||||||
|
|||||||
@@ -24,6 +24,49 @@ namespace Managing.Application.Bots.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Id(4)]
|
[Id(4)]
|
||||||
public CachedBalanceData? CachedBalanceData { get; set; } = null;
|
public CachedBalanceData? CachedBalanceData { get; set; } = null;
|
||||||
|
|
||||||
|
// Event-driven metrics for real-time updates
|
||||||
|
/// <summary>
|
||||||
|
/// Total PnL calculated from position events
|
||||||
|
/// </summary>
|
||||||
|
[Id(5)]
|
||||||
|
public decimal TotalPnL { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total volume calculated from position events
|
||||||
|
/// </summary>
|
||||||
|
[Id(6)]
|
||||||
|
public decimal TotalVolume { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total wins count from closed positions
|
||||||
|
/// </summary>
|
||||||
|
[Id(7)]
|
||||||
|
public int Wins { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total losses count from closed positions
|
||||||
|
/// </summary>
|
||||||
|
[Id(8)]
|
||||||
|
public int Losses { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total fees paid from position events
|
||||||
|
/// </summary>
|
||||||
|
[Id(9)]
|
||||||
|
public decimal TotalFees { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Active strategies count (updated by bot registration/unregistration)
|
||||||
|
/// </summary>
|
||||||
|
[Id(10)]
|
||||||
|
public int ActiveStrategiesCount { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Last time the summary was updated
|
||||||
|
/// </summary>
|
||||||
|
[Id(11)]
|
||||||
|
public DateTime LastSummaryUpdate { get; set; } = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -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.Trading.Commands;
|
using Managing.Application.Trading.Commands;
|
||||||
using Managing.Application.Trading.Handlers;
|
using Managing.Application.Trading.Handlers;
|
||||||
@@ -95,10 +94,6 @@ public class TradingBotBase : ITradingBot
|
|||||||
$"📢 I'll notify you when signals are triggered.";
|
$"📢 I'll notify you when signals are triggered.";
|
||||||
|
|
||||||
await LogInformation(startupMessage);
|
await LogInformation(startupMessage);
|
||||||
|
|
||||||
// Notify AgentGrain about bot startup
|
|
||||||
await NotifyAgentAndPlatformGrainAsync(AgentSummaryEventType.BotStarted,
|
|
||||||
$"Bot: {Config.Name}, Ticker: {Config.Ticker}");
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BotStatus.Running:
|
case BotStatus.Running:
|
||||||
@@ -393,36 +388,29 @@ public class TradingBotBase : ITradingBot
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
NotificationEventType eventType = NotificationEventType.PositionUpdated;
|
||||||
if (!Config.IsForBacktest)
|
if (!Config.IsForBacktest)
|
||||||
{
|
{
|
||||||
var brokerPosition = brokerPositions.FirstOrDefault(p => p.Ticker == Config.Ticker);
|
var brokerPosition = brokerPositions.FirstOrDefault(p => p.Ticker == Config.Ticker);
|
||||||
if (brokerPosition != null)
|
if (brokerPosition != null)
|
||||||
{
|
{
|
||||||
// Calculate net PnL after fees for broker position
|
var previousPositionStatus = internalPosition.Status;
|
||||||
|
// Position found on the broker, means the position is filled
|
||||||
var brokerNetPnL = brokerPosition.GetNetPnL();
|
var brokerNetPnL = brokerPosition.GetNetPnL();
|
||||||
UpdatePositionPnl(positionForSignal.Identifier, brokerNetPnL);
|
UpdatePositionPnl(positionForSignal.Identifier, brokerNetPnL);
|
||||||
internalPosition.ProfitAndLoss = new ProfitAndLoss { Realized = brokerNetPnL };
|
internalPosition.ProfitAndLoss = new ProfitAndLoss { Realized = brokerNetPnL };
|
||||||
internalPosition.Status = PositionStatus.Filled;
|
internalPosition.Status = PositionStatus.Filled;
|
||||||
|
await SetPositionStatus(internalPosition.SignalIdentifier, PositionStatus.Filled);
|
||||||
|
|
||||||
// Update Open trade status when position is found on broker
|
internalPosition.Open.SetStatus(TradeStatus.Filled);
|
||||||
if (internalPosition.Open != null)
|
positionForSignal.Open.SetStatus(TradeStatus.Filled);
|
||||||
|
eventType = NotificationEventType.PositionOpened;
|
||||||
|
|
||||||
|
await UpdatePositionDatabase(internalPosition);
|
||||||
|
|
||||||
|
if (previousPositionStatus != PositionStatus.Filled && internalPosition.Status == PositionStatus.Filled)
|
||||||
{
|
{
|
||||||
internalPosition.Open.SetStatus(TradeStatus.Filled);
|
await NotifyAgentAndPlatformGrainAsync(NotificationEventType.PositionUpdated, internalPosition);
|
||||||
}
|
|
||||||
|
|
||||||
// Also update the position in the bot's positions dictionary
|
|
||||||
if (positionForSignal.Open != null)
|
|
||||||
{
|
|
||||||
positionForSignal.Open.SetStatus(TradeStatus.Filled);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (internalPosition.Status.Equals(PositionStatus.New))
|
|
||||||
{
|
|
||||||
await SetPositionStatus(internalPosition.SignalIdentifier, PositionStatus.Filled);
|
|
||||||
|
|
||||||
// Notify platform summary about the executed trade
|
|
||||||
await NotifyAgentAndPlatformGrainAsync(AgentSummaryEventType.PositionOpened,
|
|
||||||
$"Position found on broker: {internalPosition.Identifier}", internalPosition);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -431,18 +419,6 @@ public class TradingBotBase : ITradingBot
|
|||||||
if (internalPosition.Status.Equals(PositionStatus.Filled))
|
if (internalPosition.Status.Equals(PositionStatus.Filled))
|
||||||
{
|
{
|
||||||
internalPosition.Status = PositionStatus.Finished;
|
internalPosition.Status = PositionStatus.Finished;
|
||||||
|
|
||||||
// Update Open trade status when position becomes Finished
|
|
||||||
if (internalPosition.Open != null)
|
|
||||||
{
|
|
||||||
internalPosition.Open.SetStatus(TradeStatus.Filled);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also update the position in the bot's positions dictionary
|
|
||||||
if (positionForSignal.Open != null)
|
|
||||||
{
|
|
||||||
positionForSignal.Open.SetStatus(TradeStatus.Filled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -496,6 +472,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
}
|
}
|
||||||
else if (ordersCount == 2)
|
else if (ordersCount == 2)
|
||||||
{
|
{
|
||||||
|
// TODO: This should never happen, but just in case
|
||||||
// Check if position is already open on broker with 2 orders
|
// Check if position is already open on broker with 2 orders
|
||||||
await LogInformation(
|
await LogInformation(
|
||||||
$"🔍 **Checking Broker Position**\nPosition has exactly `{orders.Count()}` open orders\nChecking if position is already open on broker...");
|
$"🔍 **Checking Broker Position**\nPosition has exactly `{orders.Count()}` open orders\nChecking if position is already open on broker...");
|
||||||
@@ -532,8 +509,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
await SetPositionStatus(signal.Identifier, PositionStatus.Filled);
|
await SetPositionStatus(signal.Identifier, PositionStatus.Filled);
|
||||||
|
|
||||||
// Notify platform summary about the executed trade
|
// Notify platform summary about the executed trade
|
||||||
await NotifyAgentAndPlatformGrainAsync(AgentSummaryEventType.PositionOpened,
|
await NotifyAgentAndPlatformGrainAsync(NotificationEventType.PositionOpened,
|
||||||
$"Position found on broker with 2 orders: {internalPosition.Identifier}",
|
|
||||||
internalPosition);
|
internalPosition);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -560,8 +536,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
{
|
{
|
||||||
await HandleClosedPosition(positionForSignal);
|
await HandleClosedPosition(positionForSignal);
|
||||||
}
|
}
|
||||||
else if (internalPosition.Status == PositionStatus.Filled ||
|
else if (internalPosition.Status == PositionStatus.Filled)
|
||||||
internalPosition.Status == PositionStatus.PartiallyFilled)
|
|
||||||
{
|
{
|
||||||
Candle lastCandle = null;
|
Candle lastCandle = null;
|
||||||
await ServiceScopeHelpers.WithScopedService<IExchangeService>(_scopeFactory, async exchangeService =>
|
await ServiceScopeHelpers.WithScopedService<IExchangeService>(_scopeFactory, async exchangeService =>
|
||||||
@@ -600,6 +575,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For backtest and to make sure position is closed based on SL and TP
|
||||||
if (positionForSignal.OriginDirection == TradeDirection.Long)
|
if (positionForSignal.OriginDirection == TradeDirection.Long)
|
||||||
{
|
{
|
||||||
if (positionForSignal.StopLoss.Price >= lastCandle.Low)
|
if (positionForSignal.StopLoss.Price >= lastCandle.Low)
|
||||||
@@ -779,36 +755,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Config.IsForBacktest)
|
|
||||||
{
|
|
||||||
// Update position in database with broker data
|
|
||||||
await ServiceScopeHelpers.WithScopedService<ITradingService>(_scopeFactory, async tradingService =>
|
|
||||||
{
|
|
||||||
// Update the internal position with broker data
|
|
||||||
internalPosition.Status = PositionStatus.Filled;
|
|
||||||
// Apply fees to the internal position PnL before saving
|
|
||||||
if (internalPosition.ProfitAndLoss != null)
|
|
||||||
{
|
|
||||||
var totalFees = internalPosition.CalculateTotalFees();
|
|
||||||
internalPosition.ProfitAndLoss.Realized = internalPosition.ProfitAndLoss.Realized - totalFees;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update Open trade status when position is updated to Filled
|
|
||||||
if (internalPosition.Open != null)
|
|
||||||
{
|
|
||||||
internalPosition.Open.SetStatus(TradeStatus.Filled);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also update the position in the bot's positions dictionary
|
|
||||||
if (positionForSignal.Open != null)
|
|
||||||
{
|
|
||||||
positionForSignal.Open.SetStatus(TradeStatus.Filled);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save updated position to database
|
|
||||||
await tradingService.UpdatePositionAsync(internalPosition);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -818,6 +765,14 @@ public class TradingBotBase : ITradingBot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task UpdatePositionDatabase(Position position)
|
||||||
|
{
|
||||||
|
await ServiceScopeHelpers.WithScopedService<ITradingService>(_scopeFactory, async tradingService =>
|
||||||
|
{
|
||||||
|
await tradingService.UpdatePositionAsync(position);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<Position> OpenPosition(LightSignal signal)
|
private async Task<Position> OpenPosition(LightSignal signal)
|
||||||
{
|
{
|
||||||
Logger.LogInformation($"Opening position for {signal.Identifier}");
|
Logger.LogInformation($"Opening position for {signal.Identifier}");
|
||||||
@@ -936,8 +891,8 @@ public class TradingBotBase : ITradingBot
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Notify AgentGrain about position opening
|
// Notify AgentGrain about position opening
|
||||||
await NotifyAgentAndPlatformGrainAsync(AgentSummaryEventType.PositionOpened,
|
await NotifyAgentAndPlatformGrainAsync(NotificationEventType.PositionOpened,
|
||||||
$"Signal: {signal.Identifier}", position);
|
position);
|
||||||
|
|
||||||
Logger.LogInformation($"Position requested");
|
Logger.LogInformation($"Position requested");
|
||||||
return position; // Return the created position without adding to list
|
return position; // Return the created position without adding to list
|
||||||
@@ -1418,13 +1373,6 @@ public class TradingBotBase : ITradingBot
|
|||||||
string.Format("💰 **Balance Updated**\nNew bot trading balance: `${0:F2}`",
|
string.Format("💰 **Balance Updated**\nNew bot trading balance: `${0:F2}`",
|
||||||
Config.BotTradingBalance));
|
Config.BotTradingBalance));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify AgentGrain about position closing
|
|
||||||
var pnlInfo = position.ProfitAndLoss?.Realized != null
|
|
||||||
? string.Format("PnL: {0:F2}", position.ProfitAndLoss.Realized)
|
|
||||||
: "PnL: Unknown";
|
|
||||||
await NotifyAgentAndPlatformGrainAsync(AgentSummaryEventType.PositionClosed,
|
|
||||||
string.Format("Signal: {0}, {1}", position.SignalIdentifier, pnlInfo), position);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1555,7 +1503,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
public decimal GetProfitAndLoss()
|
public decimal GetProfitAndLoss()
|
||||||
{
|
{
|
||||||
// Calculate net PnL after deducting fees for each position
|
// Calculate net PnL after deducting fees for each position
|
||||||
var netPnl = Positions.Values.Where(p => p.ProfitAndLoss != null && p.IsFinished())
|
var netPnl = Positions.Values.Where(p => p.ProfitAndLoss != null)
|
||||||
.Sum(p => p.GetNetPnL());
|
.Sum(p => p.GetNetPnL());
|
||||||
return netPnl;
|
return netPnl;
|
||||||
}
|
}
|
||||||
@@ -2120,13 +2068,12 @@ public class TradingBotBase : ITradingBot
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Notifies both AgentGrain and PlatformSummaryGrain about bot events
|
/// Notifies both AgentGrain and PlatformSummaryGrain about bot events using unified event data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="eventType">The type of event (e.g., PositionOpened, PositionClosed)</param>
|
/// <param name="eventType">The type of event (e.g., PositionOpened, PositionClosed, PositionUpdated)</param>
|
||||||
/// <param name="additionalData">Optional additional context data</param>
|
|
||||||
/// <param name="position">Optional position data for platform summary events</param>
|
/// <param name="position">Optional position data for platform summary events</param>
|
||||||
private async Task NotifyAgentAndPlatformGrainAsync(AgentSummaryEventType eventType, string additionalData = null,
|
private async Task NotifyAgentAndPlatformGrainAsync(NotificationEventType eventType,
|
||||||
Position position = null)
|
Position position)
|
||||||
{
|
{
|
||||||
if (Config.IsForBacktest)
|
if (Config.IsForBacktest)
|
||||||
{
|
{
|
||||||
@@ -2137,33 +2084,13 @@ public class TradingBotBase : ITradingBot
|
|||||||
{
|
{
|
||||||
await ServiceScopeHelpers.WithScopedService<IGrainFactory>(_scopeFactory, async grainFactory =>
|
await ServiceScopeHelpers.WithScopedService<IGrainFactory>(_scopeFactory, async grainFactory =>
|
||||||
{
|
{
|
||||||
// Notify AgentGrain (user-specific metrics)
|
var agentGrain = grainFactory.GetGrain<IAgentGrain>(Account.User.Id);
|
||||||
if (Account?.User != null)
|
|
||||||
{
|
|
||||||
var agentGrain = grainFactory.GetGrain<IAgentGrain>(Account.User.Id);
|
|
||||||
|
|
||||||
var updateEvent = new AgentSummaryUpdateEvent
|
|
||||||
{
|
|
||||||
BotId = Identifier,
|
|
||||||
EventType = eventType,
|
|
||||||
Timestamp = DateTime.UtcNow,
|
|
||||||
AdditionalData = additionalData
|
|
||||||
};
|
|
||||||
|
|
||||||
await agentGrain.OnAgentSummaryUpdateAsync(updateEvent);
|
|
||||||
Logger.LogDebug("Sent agent notification: {EventType} for bot {BotId}", eventType, Identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify PlatformSummaryGrain (platform-wide metrics)
|
|
||||||
var platformGrain = grainFactory.GetGrain<IPlatformSummaryGrain>("platform-summary");
|
var platformGrain = grainFactory.GetGrain<IPlatformSummaryGrain>("platform-summary");
|
||||||
|
|
||||||
|
// Create unified event objects based on event type
|
||||||
switch (eventType)
|
switch (eventType)
|
||||||
{
|
{
|
||||||
case AgentSummaryEventType.PositionOpened when position != null:
|
case NotificationEventType.PositionOpened:
|
||||||
// Position opening is now handled by TradeExecutedEvent in PublishTradeExecutedEventAsync
|
|
||||||
Logger.LogDebug(
|
|
||||||
"Position opened notification sent via TradeExecutedEvent for position {PositionId}",
|
|
||||||
position.Identifier);
|
|
||||||
var positionOpenEvent = new PositionOpenEvent
|
var positionOpenEvent = new PositionOpenEvent
|
||||||
{
|
{
|
||||||
PositionIdentifier = position.Identifier,
|
PositionIdentifier = position.Identifier,
|
||||||
@@ -2172,10 +2099,15 @@ public class TradingBotBase : ITradingBot
|
|||||||
Fee = position.GasFees + position.UiFees,
|
Fee = position.GasFees + position.UiFees,
|
||||||
Direction = position.OriginDirection
|
Direction = position.OriginDirection
|
||||||
};
|
};
|
||||||
|
|
||||||
|
await agentGrain.OnPositionOpenedAsync(positionOpenEvent);
|
||||||
await platformGrain.OnPositionOpenAsync(positionOpenEvent);
|
await platformGrain.OnPositionOpenAsync(positionOpenEvent);
|
||||||
|
|
||||||
|
Logger.LogDebug("Sent position opened event to both grains for position {PositionId}",
|
||||||
|
position.Identifier);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AgentSummaryEventType.PositionClosed when position != null:
|
case NotificationEventType.PositionClosed:
|
||||||
var positionClosedEvent = new PositionClosedEvent
|
var positionClosedEvent = new PositionClosedEvent
|
||||||
{
|
{
|
||||||
PositionIdentifier = position.Identifier,
|
PositionIdentifier = position.Identifier,
|
||||||
@@ -2183,8 +2115,23 @@ public class TradingBotBase : ITradingBot
|
|||||||
RealizedPnL = position.ProfitAndLoss?.Realized ?? 0,
|
RealizedPnL = position.ProfitAndLoss?.Realized ?? 0,
|
||||||
Volume = position.Open.Price * position.Open.Quantity * position.Open.Leverage,
|
Volume = position.Open.Price * position.Open.Quantity * position.Open.Leverage,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
await agentGrain.OnPositionClosedAsync(positionClosedEvent);
|
||||||
await platformGrain.OnPositionClosedAsync(positionClosedEvent);
|
await platformGrain.OnPositionClosedAsync(positionClosedEvent);
|
||||||
Logger.LogDebug("Sent platform position closed notification for position {PositionId}",
|
|
||||||
|
Logger.LogDebug("Sent position closed event to both grains for position {PositionId}",
|
||||||
|
position.Identifier);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotificationEventType.PositionUpdated:
|
||||||
|
var positionUpdatedEvent = new PositionUpdatedEvent
|
||||||
|
{
|
||||||
|
PositionIdentifier = position.Identifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
await agentGrain.OnPositionUpdatedAsync(positionUpdatedEvent);
|
||||||
|
|
||||||
|
Logger.LogDebug("Sent position updated event to both grains for position {PositionId}",
|
||||||
position.Identifier);
|
position.Identifier);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -254,31 +254,6 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<decimal> GetTotalVolumeAsync()
|
|
||||||
{
|
|
||||||
return Task.FromResult(_state.State.TotalPlatformVolume);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<decimal> GetTotalPnLAsync()
|
|
||||||
{
|
|
||||||
return Task.FromResult(_state.State.TotalPlatformPnL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<decimal> GetTotalOpenInterest()
|
|
||||||
{
|
|
||||||
return Task.FromResult(_state.State.OpenInterest);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<int> GetTotalPositionCountAsync()
|
|
||||||
{
|
|
||||||
return Task.FromResult(_state.State.TotalPositionCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<decimal> GetTotalFeesAsync()
|
|
||||||
{
|
|
||||||
return Task.FromResult(_state.State.TotalPlatformFees);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Event handlers for immediate updates
|
// Event handlers for immediate updates
|
||||||
public async Task UpdateActiveStrategyCountAsync(int newActiveCount)
|
public async Task UpdateActiveStrategyCountAsync(int newActiveCount)
|
||||||
{
|
{
|
||||||
@@ -303,7 +278,6 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task OnPositionClosedAsync(PositionClosedEvent evt)
|
public async Task OnPositionClosedAsync(PositionClosedEvent evt)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -427,7 +401,6 @@ public class PlatformSummaryGrain : Grain, IPlatformSummaryGrain, IRemindable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task TakeDailySnapshotAsync()
|
private async Task TakeDailySnapshotAsync()
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Taking daily snapshot");
|
_logger.LogInformation("Taking daily snapshot");
|
||||||
|
|||||||
@@ -178,27 +178,11 @@ public class TradingService : ITradingService
|
|||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task UpdatePositionAsync(Position position)
|
public async Task UpdatePositionAsync(Position position)
|
||||||
{
|
{
|
||||||
await _tradingRepository.UpdatePositionAsync(position);
|
await _tradingRepository.UpdatePositionAsync(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateTradeAsync(Trade trade)
|
|
||||||
{
|
|
||||||
await _tradingRepository.UpdateTradeAsync(trade);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IEnumerable<Position>> GetPositionsAsync()
|
|
||||||
{
|
|
||||||
var positions = new List<Position>();
|
|
||||||
positions.AddRange(await GetPositionsByStatusAsync(PositionStatus.New));
|
|
||||||
positions.AddRange(await GetPositionsByStatusAsync(PositionStatus.Filled));
|
|
||||||
positions.AddRange(await GetPositionsByStatusAsync(PositionStatus.PartiallyFilled));
|
|
||||||
return positions;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public async Task WatchTrader()
|
public async Task WatchTrader()
|
||||||
{
|
{
|
||||||
var availableTickers = new List<Ticker> { Ticker.BTC, Ticker.ETH, Ticker.UNI, Ticker.LINK };
|
var availableTickers = new List<Ticker> { Ticker.BTC, Ticker.ETH, Ticker.UNI, Ticker.LINK };
|
||||||
@@ -268,7 +252,8 @@ public class TradingService : ITradingService
|
|||||||
return await _tradingRepository.GetPositionsByInitiatorIdentifierAsync(initiatorIdentifier);
|
return await _tradingRepository.GetPositionsByInitiatorIdentifierAsync(initiatorIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<Position>> GetPositionsByInitiatorIdentifiersAsync(IEnumerable<Guid> initiatorIdentifiers)
|
public async Task<IEnumerable<Position>> GetPositionsByInitiatorIdentifiersAsync(
|
||||||
|
IEnumerable<Guid> initiatorIdentifiers)
|
||||||
{
|
{
|
||||||
return await _tradingRepository.GetPositionsByInitiatorIdentifiersAsync(initiatorIdentifiers);
|
return await _tradingRepository.GetPositionsByInitiatorIdentifiersAsync(initiatorIdentifiers);
|
||||||
}
|
}
|
||||||
@@ -385,7 +370,8 @@ public class TradingService : ITradingService
|
|||||||
var account = await _accountRepository.GetAccountByKeyAsync(publicAddress);
|
var account = await _accountRepository.GetAccountByKeyAsync(publicAddress);
|
||||||
if (account != null && account.IsGmxInitialized)
|
if (account != null && account.IsGmxInitialized)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Account with address {PublicAddress} is already initialized for GMX", publicAddress);
|
_logger.LogInformation("Account with address {PublicAddress} is already initialized for GMX",
|
||||||
|
publicAddress);
|
||||||
return new PrivyInitAddressResponse
|
return new PrivyInitAddressResponse
|
||||||
{
|
{
|
||||||
Success = true,
|
Success = true,
|
||||||
|
|||||||
@@ -205,10 +205,9 @@ public static class Enums
|
|||||||
Canceled = 1,
|
Canceled = 1,
|
||||||
Rejected = 2,
|
Rejected = 2,
|
||||||
Updating = 3,
|
Updating = 3,
|
||||||
PartiallyFilled = 4,
|
Filled = 4,
|
||||||
Filled = 5,
|
Flipped = 5,
|
||||||
Flipped = 6,
|
Finished = 6
|
||||||
Finished = 7
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PositionInitiator
|
public enum PositionInitiator
|
||||||
@@ -492,10 +491,11 @@ public static class Enums
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event types for agent summary updates
|
/// Event types for agent summary updates
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum AgentSummaryEventType
|
public enum NotificationEventType
|
||||||
{
|
{
|
||||||
BotStarted,
|
BotStarted,
|
||||||
PositionOpened,
|
PositionOpened,
|
||||||
PositionClosed,
|
PositionClosed,
|
||||||
|
PositionUpdated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,7 +105,7 @@ namespace Managing.Domain.Trades
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ProfitAndLoss.Realized - CalculateTotalFees();
|
return ProfitAndLoss.Realized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user