189 lines
5.5 KiB
C#
189 lines
5.5 KiB
C#
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; }
|
|
|
|
/// <summary>
|
|
/// Identifier of the bot or entity that initiated this position
|
|
/// </summary>
|
|
[Id(17)]
|
|
[Required]
|
|
public Guid InitiatorIdentifier { get; set; }
|
|
|
|
/// <summary>
|
|
/// Indicates whether position recovery has been attempted for this cancelled position
|
|
/// Used to prevent repeated recovery attempts for positions that were never filled
|
|
/// </summary>
|
|
[Id(18)]
|
|
public bool RecoveryAttempted { get; set; }
|
|
|
|
/// <summary>
|
|
/// Return true if position is finished even if the position was canceled or rejected
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public bool IsFinished()
|
|
{
|
|
return Status switch
|
|
{
|
|
PositionStatus.Finished => true,
|
|
PositionStatus.Canceled => true,
|
|
PositionStatus.Rejected => true,
|
|
PositionStatus.Flipped => true,
|
|
_ => false
|
|
};
|
|
}
|
|
|
|
public bool IsInProfit()
|
|
{
|
|
if (ProfitAndLoss?.Net == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return ProfitAndLoss.Net > 0;
|
|
}
|
|
|
|
public bool IsOpen()
|
|
{
|
|
return Status switch
|
|
{
|
|
PositionStatus.Filled => true,
|
|
_ => false
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return true if position is valid for metrics calculation (PnL, WinRate, etc.)
|
|
/// Only positions with status Filled, Finished or Flipped are considered valid
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public bool IsValidForMetrics()
|
|
{
|
|
return Status switch
|
|
{
|
|
PositionStatus.Filled => true,
|
|
PositionStatus.Finished => true,
|
|
PositionStatus.Flipped => true,
|
|
_ => false
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the total fees for this position based on GMX V2 fee structure
|
|
/// </summary>
|
|
/// <returns>The total fees for the position</returns>
|
|
public decimal CalculateTotalFees()
|
|
{
|
|
return UiFees + GasFees;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the net PnL after deducting fees
|
|
/// </summary>
|
|
/// <returns>The net PnL after fees</returns>
|
|
public decimal GetPnLBeforeFees()
|
|
{
|
|
if (ProfitAndLoss?.Realized == null)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return ProfitAndLoss.Realized;
|
|
}
|
|
|
|
public decimal GetNetPnl()
|
|
{
|
|
if (ProfitAndLoss?.Net == null)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return ProfitAndLoss.Realized - UiFees - GasFees;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the UI fees for this position
|
|
/// </summary>
|
|
/// <param name="uiFees">The UI fees to add</param>
|
|
public void AddUiFees(decimal uiFees)
|
|
{
|
|
UiFees += uiFees;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the gas fees for this position
|
|
/// </summary>
|
|
/// <param name="gasFees">The gas fees to add</param>
|
|
public void AddGasFees(decimal gasFees)
|
|
{
|
|
GasFees += gasFees;
|
|
}
|
|
}
|
|
} |