Fetch closed position to get last pnl realized

This commit is contained in:
2025-10-05 23:31:17 +07:00
parent 1b060fb145
commit dac0a9641f
14 changed files with 749 additions and 23 deletions

View File

@@ -1196,6 +1196,122 @@ public class TradingBotBase : ITradingBot
: await exchangeService.GetCandle(Account, Config.Ticker, DateTime.UtcNow);
});
// For live trading on GMX, fetch the actual position history to get real PnL data
if (!Config.IsForBacktest)
{
try
{
Logger.LogInformation(
$"🔍 **Fetching Position History from GMX**\nPosition: `{position.Identifier}`\nTicker: `{Config.Ticker}`");
List<Position> positionHistory = null;
await ServiceScopeHelpers.WithScopedService<IExchangeService>(_scopeFactory,
async exchangeService =>
{
// Get position history from the last 24 hours
var fromDate = DateTime.UtcNow.AddHours(-24);
var toDate = DateTime.UtcNow;
positionHistory =
await exchangeService.GetPositionHistory(Account, Config.Ticker, fromDate, toDate);
});
// Find the matching position in history based on the most recent closed position
if (positionHistory != null && positionHistory.Any())
{
// Get the most recent closed position from GMX
var gmxPosition = positionHistory.OrderByDescending(p => p.Open?.Date ?? DateTime.MinValue)
.FirstOrDefault();
if (gmxPosition != null && gmxPosition.ProfitAndLoss != null)
{
Logger.LogInformation(
$"✅ **GMX Position History Found**\n" +
$"Position: `{position.Identifier}`\n" +
$"GMX Realized PnL (after fees): `${gmxPosition.ProfitAndLoss.Realized:F2}`\n" +
$"Bot's UI Fees: `${position.UiFees:F2}`\n" +
$"Bot's Gas Fees: `${position.GasFees:F2}`");
// Use the actual GMX PnL data (this is already net of fees from GMX)
// We use this for reconciliation with the bot's own calculations
var totalBotFees = position.GasFees + position.UiFees;
var gmxNetPnl = gmxPosition.ProfitAndLoss.Realized; // This is already after GMX fees
position.ProfitAndLoss = new ProfitAndLoss
{
// GMX's realized PnL is already after their fees
Realized = gmxNetPnl,
// For net, we keep it the same since GMX PnL is already net of their fees
Net = gmxNetPnl - totalBotFees
};
// Update the closing trade price if available
if (gmxPosition.Open != null)
{
var closingPrice = gmxPosition.Open.Price;
// Determine which trade was the closing trade based on profitability
bool isProfitable = position.ProfitAndLoss.Realized > 0;
if (isProfitable)
{
if (position.TakeProfit1 != null)
{
position.TakeProfit1.SetPrice(closingPrice, 2);
position.TakeProfit1.SetDate(gmxPosition.Open.Date);
position.TakeProfit1.SetStatus(TradeStatus.Filled);
}
// Cancel SL trade when TP is hit
if (position.StopLoss != null)
{
position.StopLoss.SetStatus(TradeStatus.Cancelled);
}
}
else
{
if (position.StopLoss != null)
{
position.StopLoss.SetPrice(closingPrice, 2);
position.StopLoss.SetDate(gmxPosition.Open.Date);
position.StopLoss.SetStatus(TradeStatus.Filled);
}
// Cancel TP trades when SL is hit
if (position.TakeProfit1 != null)
{
position.TakeProfit1.SetStatus(TradeStatus.Cancelled);
}
if (position.TakeProfit2 != null)
{
position.TakeProfit2.SetStatus(TradeStatus.Cancelled);
}
}
Logger.LogInformation(
$"📊 **Position Reconciliation Complete**\n" +
$"Position: `{position.Identifier}`\n" +
$"Closing Price: `${closingPrice:F2}`\n" +
$"Used: `{(isProfitable ? "Take Profit" : "Stop Loss")}`\n" +
$"PnL from GMX: `${position.ProfitAndLoss.Realized:F2}`");
}
// Skip the candle-based PnL calculation since we have actual GMX data
goto SkipCandleBasedCalculation;
}
}
Logger.LogWarning(
$"⚠️ **No GMX Position History Found**\nPosition: `{position.Identifier}`\nFalling back to candle-based calculation");
}
catch (Exception ex)
{
Logger.LogError(ex,
"Error fetching position history from GMX for position {PositionId}. Falling back to candle-based calculation.",
position.Identifier);
}
}
if (currentCandle != null)
{
List<Candle> recentCandles = null;
@@ -1402,6 +1518,7 @@ public class TradingBotBase : ITradingBot
// No need to subtract fees from PnL as they're tracked separately
}
SkipCandleBasedCalculation:
await SetPositionStatus(position.SignalIdentifier, PositionStatus.Finished);
// Update position in database with all trade changes