Update account/position and platform summary

This commit is contained in:
2025-09-26 01:18:59 +07:00
parent b2e38811ed
commit bcfeb693ce
32 changed files with 3301 additions and 151 deletions

View File

@@ -9,27 +9,30 @@ namespace Managing.Domain.Accounts;
public class Account
{
[Id(0)]
[Required] public string Name { get; set; }
public int Id { get; set; }
[Id(1)]
[Required] public TradingExchanges Exchange { get; set; }
[Required] public string Name { get; set; }
[Id(2)]
[Required] public AccountType Type { get; set; }
[Required] public TradingExchanges Exchange { get; set; }
[Id(3)]
public string Key { get; set; }
[Required] public AccountType Type { get; set; }
[Id(4)]
public string Secret { get; set; }
public string Key { get; set; }
[Id(5)]
public User User { get; set; }
public string Secret { get; set; }
[Id(6)]
public List<Balance> Balances { get; set; }
public User User { get; set; }
[Id(7)]
public List<Balance> Balances { get; set; }
[Id(8)]
public bool IsGmxInitialized { get; set; } = false;
public bool IsPrivyWallet => Type == AccountType.Privy;

View File

@@ -1,7 +1,9 @@
using Exilion.TradingAtomics;
using Managing.Common;
using Managing.Domain.Accounts;
using Managing.Domain.Candles;
using Managing.Domain.Statistics;
using Managing.Domain.Trades;
using static Managing.Common.Enums;
namespace Managing.Domain.Shared.Helpers;
@@ -97,4 +99,94 @@ public static class TradingHelpers
return traders;
}
/// <summary>
/// Calculates the total fees for a position based on GMX V2 fee structure
/// </summary>
/// <param name="position">The position to calculate fees for</param>
/// <returns>The total fees for the position</returns>
public static decimal CalculatePositionFees(Position position)
{
var (uiFees, gasFees) = CalculatePositionFeesBreakdown(position);
return uiFees + gasFees;
}
/// <summary>
/// Calculates the UI and Gas fees breakdown for a position based on GMX V2 fee structure
/// </summary>
/// <param name="position">The position to calculate fees for</param>
/// <returns>A tuple containing (uiFees, gasFees)</returns>
public static (decimal uiFees, decimal gasFees) CalculatePositionFeesBreakdown(Position position)
{
decimal uiFees = 0;
decimal gasFees = 0;
if (position?.Open?.Price <= 0 || position?.Open?.Quantity <= 0)
{
return (uiFees, gasFees); // Return 0 if position data is invalid
}
// Calculate position size in USD (leverage is already included in quantity calculation)
var positionSizeUsd = (position.Open.Price * position.Open.Quantity) * position.Open.Leverage;
// UI Fee: 0.1% of position size paid on opening
var uiFeeOpen = positionSizeUsd * Constants.GMX.Config.UiFeeRate; // Fee paid on opening
uiFees += uiFeeOpen;
// UI Fee: 0.1% of position size paid on closing - only if position was actually closed
// Check which closing trade was executed (StopLoss, TakeProfit1, or TakeProfit2)
if (position.StopLoss?.Status == TradeStatus.Filled)
{
var stopLossPositionSizeUsd = (position.StopLoss.Price * position.StopLoss.Quantity) * position.StopLoss.Leverage;
var uiFeeClose = stopLossPositionSizeUsd * Constants.GMX.Config.UiFeeRate; // Fee paid on closing via StopLoss
uiFees += uiFeeClose;
}
else if (position.TakeProfit1?.Status == TradeStatus.Filled)
{
var takeProfit1PositionSizeUsd = (position.TakeProfit1.Price * position.TakeProfit1.Quantity) * position.TakeProfit1.Leverage;
var uiFeeClose = takeProfit1PositionSizeUsd * Constants.GMX.Config.UiFeeRate; // Fee paid on closing via TakeProfit1
uiFees += uiFeeClose;
}
else if (position.TakeProfit2?.Status == TradeStatus.Filled)
{
var takeProfit2PositionSizeUsd = (position.TakeProfit2.Price * position.TakeProfit2.Quantity) * position.TakeProfit2.Leverage;
var uiFeeClose = takeProfit2PositionSizeUsd * Constants.GMX.Config.UiFeeRate; // Fee paid on closing via TakeProfit2
uiFees += uiFeeClose;
}
// Gas Fee: $0.15 for opening position only
// Closing is handled by oracle, so no gas fee for closing
gasFees += Constants.GMX.Config.GasFeePerTransaction;
return (uiFees, gasFees);
}
/// <summary>
/// Calculates UI fees for opening a position
/// </summary>
/// <param name="positionSizeUsd">The position size in USD</param>
/// <returns>The UI fees for opening</returns>
public static decimal CalculateOpeningUiFees(decimal positionSizeUsd)
{
return positionSizeUsd * Constants.GMX.Config.UiFeeRate;
}
/// <summary>
/// Calculates UI fees for closing a position
/// </summary>
/// <param name="positionSizeUsd">The position size in USD</param>
/// <returns>The UI fees for closing</returns>
public static decimal CalculateClosingUiFees(decimal positionSizeUsd)
{
return positionSizeUsd * Constants.GMX.Config.UiFeeRate;
}
/// <summary>
/// Calculates gas fees for opening a position
/// </summary>
/// <returns>The gas fees for opening (fixed at $0.15)</returns>
public static decimal CalculateOpeningGasFees()
{
return Constants.GMX.Config.GasFeePerTransaction;
}
}

View File

@@ -9,11 +9,11 @@ namespace Managing.Domain.Trades
[GenerateSerializer]
public class Position
{
public Position(Guid identifier, string accountName, TradeDirection originDirection, Ticker ticker,
public Position(Guid identifier, int accountId, TradeDirection originDirection, Ticker ticker,
LightMoneyManagement moneyManagement, PositionInitiator initiator, DateTime date, User user)
{
Identifier = identifier;
AccountName = accountName;
AccountId = accountId;
OriginDirection = originDirection;
Ticker = ticker;
MoneyManagement = moneyManagement;
@@ -23,9 +23,9 @@ namespace Managing.Domain.Trades
User = user;
}
[Id(0)] [Required] public string AccountName { get; set; }
[Id(0)] [Required] public DateTime Date { get; set; }
[Id(1)] [Required] public DateTime Date { get; set; }
[Id(1)] [Required] public int AccountId { get; set; }
[Id(2)] [Required] public TradeDirection OriginDirection { get; set; }
@@ -56,20 +56,24 @@ namespace Managing.Domain.Trades
[JsonPropertyName("ProfitAndLoss")]
public ProfitAndLoss ProfitAndLoss { get; set; }
[Id(10)] [Required] public PositionStatus Status { get; set; }
[Id(10)] public decimal UiFees { get; set; }
[Id(11)] public string SignalIdentifier { get; set; }
[Id(11)] public decimal GasFees { get; set; }
[Id(12)] [Required] public Guid Identifier { get; set; }
[Id(12)] [Required] public PositionStatus Status { get; set; }
[Id(13)] [Required] public PositionInitiator Initiator { get; set; }
[Id(13)] public string SignalIdentifier { get; set; }
[Id(14)] [Required] public User User { 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(15)] [Required] public Guid InitiatorIdentifier { get; set; }
[Id(17)] [Required] public Guid InitiatorIdentifier { get; set; }
public bool IsFinished()
{
@@ -80,5 +84,46 @@ namespace Managing.Domain.Trades
_ => 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 GetNetPnL()
{
if (ProfitAndLoss?.Realized == null)
{
return 0;
}
return ProfitAndLoss.Realized - CalculateTotalFees();
}
/// <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;
}
}
}