Fix status IsFinished/IsOpen/IsForMetrics + use redis for markets on gmx.tsx instead of inmemory cache

This commit is contained in:
2025-10-08 12:13:04 +07:00
parent 67065469a6
commit 86dd6849ea
9 changed files with 209 additions and 86 deletions

View File

@@ -564,7 +564,7 @@ public static class TradingBox
foreach (var position in positions.Values)
{
// Only count positions that were opened or closed within the last 24 hours
if (position.IsFinished() &&
if (position.IsValidForMetrics() &&
(position.Open.Date >= cutoff ||
(position.StopLoss.Status == TradeStatus.Filled && position.StopLoss.Date >= cutoff) ||
(position.TakeProfit1.Status == TradeStatus.Filled && position.TakeProfit1.Date >= cutoff) ||
@@ -595,7 +595,7 @@ public static class TradingBox
if (timeFilter == "Total")
{
return positions
.Where(p => p.IsFinished() && p.ProfitAndLoss != null)
.Where(p => p.IsValidForMetrics() && p.ProfitAndLoss != null)
.Sum(p => p.ProfitAndLoss.Realized);
}
@@ -623,7 +623,7 @@ public static class TradingBox
// Include positions that were closed within the time range
return positions
.Where(p => p.IsFinished() && p.ProfitAndLoss != null &&
.Where(p => p.IsValidForMetrics() && p.ProfitAndLoss != null &&
(p.Date >= cutoffDate ||
(p.StopLoss.Status == TradeStatus.Filled && p.StopLoss.Date >= cutoffDate) ||
(p.TakeProfit1.Status == TradeStatus.Filled && p.TakeProfit1.Date >= cutoffDate) ||
@@ -673,8 +673,8 @@ public static class TradingBox
// Filter positions in the time range
var filteredPositions = timeFilter == "Total"
? positions.Where(p => p.IsFinished() && p.ProfitAndLoss != null)
: positions.Where(p => p.IsFinished() && p.ProfitAndLoss != null &&
? positions.Where(p => p.IsValidForMetrics() && p.ProfitAndLoss != null)
: positions.Where(p => p.IsValidForMetrics() && p.ProfitAndLoss != null &&
(p.Date >= cutoffDate ||
(p.StopLoss.Status == TradeStatus.Filled && p.StopLoss.Date >= cutoffDate) ||
(p.TakeProfit1.Status == TradeStatus.Filled && p.TakeProfit1.Date >= cutoffDate) ||
@@ -729,8 +729,8 @@ public static class TradingBox
// Filter positions in the time range
var filteredPositions = timeFilter == "Total"
? positions.Where(p => p.IsFinished())
: positions.Where(p => p.IsFinished() &&
? positions.Where(p => p.IsValidForMetrics())
: positions.Where(p => p.IsValidForMetrics() &&
(p.Date >= cutoffDate ||
(p.StopLoss.Status == TradeStatus.Filled && p.StopLoss.Date >= cutoffDate) ||
(p.TakeProfit1.Status == TradeStatus.Filled && p.TakeProfit1.Date >= cutoffDate) ||

View File

@@ -137,20 +137,26 @@ public static class TradingHelpers
// 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
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
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
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;
}
@@ -190,7 +196,7 @@ public static class TradingHelpers
return Constants.GMX.Config.GasFeePerTransaction;
}
/// <summary>
/// <summary>
/// Calculates the total volume for a position based on its status and filled trades
/// </summary>
/// <param name="position">The position to calculate volume for</param>
@@ -201,7 +207,7 @@ public static class TradingHelpers
var totalVolume = position.Open.Price * position.Open.Quantity * position.Open.Leverage;
// For closed positions, add volume from filled closing trades
if (position.IsFinished())
if (position.IsValidForMetrics())
{
// Add Stop Loss volume if filled
if (position.StopLoss?.Status == TradeStatus.Filled)
@@ -212,13 +218,15 @@ public static class TradingHelpers
// Add Take Profit 1 volume if filled
if (position.TakeProfit1?.Status == TradeStatus.Filled)
{
totalVolume += position.TakeProfit1.Price * position.TakeProfit1.Quantity * position.TakeProfit1.Leverage;
totalVolume += position.TakeProfit1.Price * position.TakeProfit1.Quantity *
position.TakeProfit1.Leverage;
}
// Add Take Profit 2 volume if filled
if (position.TakeProfit2?.Status == TradeStatus.Filled)
{
totalVolume += position.TakeProfit2.Price * position.TakeProfit2.Quantity * position.TakeProfit2.Leverage;
totalVolume += position.TakeProfit2.Price * position.TakeProfit2.Quantity *
position.TakeProfit2.Leverage;
}
}

View File

@@ -77,16 +77,46 @@ namespace Managing.Domain.Trades
[Required]
public Guid InitiatorIdentifier { 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
@@ -94,7 +124,6 @@ namespace Managing.Domain.Trades
PositionStatus.Filled => true,
PositionStatus.Finished => true,
PositionStatus.Flipped => true,
PositionStatus.Updating => true,
_ => false
};
}