using System.ComponentModel.DataAnnotations; using System.Text.Json.Serialization; using Managing.Domain.Users; using Orleans; using static Managing.Common.Enums; namespace Managing.Domain.Trades { [GenerateSerializer] public class Position { public Position(Guid identifier, int accountId, TradeDirection originDirection, Ticker ticker, LightMoneyManagement moneyManagement, PositionInitiator initiator, DateTime date, User user) { Identifier = identifier; AccountId = accountId; OriginDirection = originDirection; Ticker = ticker; MoneyManagement = moneyManagement; Initiator = initiator; Date = date; Status = Initiator == PositionInitiator.PaperTrading ? PositionStatus.Filled : PositionStatus.New; User = user; } [Id(0)] [Required] public DateTime Date { get; set; } [Id(1)] [Required] public int AccountId { get; set; } [Id(2)] [Required] public TradeDirection OriginDirection { get; set; } [Id(3)] [Required] public Ticker Ticker { get; set; } [Id(4)] [Required] public LightMoneyManagement MoneyManagement { get; set; } [Id(5)] [Required] [JsonPropertyName("Open")] public Trade Open { get; set; } [Id(6)] [Required] [JsonPropertyName("StopLoss")] public Trade StopLoss { get; set; } [Id(7)] [Required] [JsonPropertyName("TakeProfit1")] public Trade TakeProfit1 { get; set; } [Id(8)] [JsonPropertyName("TakeProfit2")] public Trade TakeProfit2 { get; set; } [Id(9)] [JsonPropertyName("ProfitAndLoss")] public ProfitAndLoss ProfitAndLoss { get; set; } [Id(10)] public decimal UiFees { get; set; } [Id(11)] public decimal GasFees { get; set; } [Id(12)] [Required] public PositionStatus Status { get; set; } [Id(13)] public string SignalIdentifier { get; set; } [Id(14)] [Required] public Guid Identifier { get; set; } [Id(15)] [Required] public PositionInitiator Initiator { get; set; } [Id(16)] [Required] public User User { get; set; } /// /// Identifier of the bot or entity that initiated this position /// [Id(17)] [Required] public Guid InitiatorIdentifier { get; set; } public bool IsFinished() { return Status switch { PositionStatus.Finished => true, PositionStatus.Flipped => true, _ => false }; } public bool IsValidForMetrics() { return Status switch { PositionStatus.Filled => true, PositionStatus.Finished => true, PositionStatus.Flipped => true, PositionStatus.Updating => true, _ => false }; } /// /// Calculates the total fees for this position based on GMX V2 fee structure /// /// The total fees for the position public decimal CalculateTotalFees() { return UiFees + GasFees; } /// /// Gets the net PnL after deducting fees /// /// The net PnL after fees public decimal GetNetPnL() { if (ProfitAndLoss?.Realized == null) { return 0; } return ProfitAndLoss.Realized; } /// /// Updates the UI fees for this position /// /// The UI fees to add public void AddUiFees(decimal uiFees) { UiFees += uiFees; } /// /// Updates the gas fees for this position /// /// The gas fees to add public void AddGasFees(decimal gasFees) { GasFees += gasFees; } } }