diff --git a/src/Managing.Application/Backtesting/Backtester.cs b/src/Managing.Application/Backtesting/Backtester.cs
index e2d9ff1..dc6053c 100644
--- a/src/Managing.Application/Backtesting/Backtester.cs
+++ b/src/Managing.Application/Backtesting/Backtester.cs
@@ -205,6 +205,7 @@ namespace Managing.Application.Backtesting
var growthPercentage = TradingHelpers.GetGrowthFromInitalBalance(config.BotTradingBalance, finalPnl);
var hodlPercentage = TradingHelpers.GetHodlPercentage(candles[0], candles.Last());
+ var fees = bot.GetTotalFees();
var scoringParams = new BacktestScoringParams(
sharpeRatio: (double)stats.SharpeRatio,
maxDrawdownPc: (double)stats.MaxDrawdownPc,
@@ -212,7 +213,7 @@ namespace Managing.Application.Backtesting
hodlPercentage: (double)hodlPercentage,
winRate: winRate,
totalPnL: (double)finalPnl,
- fees: (double)bot.GetTotalFees(),
+ fees: (double)fees,
tradeCount: bot.Positions.Count,
maxDrawdownRecoveryTime: stats.MaxDrawdownRecoveryTime
);
@@ -225,7 +226,7 @@ namespace Managing.Application.Backtesting
WinRate = winRate,
GrowthPercentage = growthPercentage,
HodlPercentage = hodlPercentage,
- Fees = bot.GetTotalFees(),
+ Fees = fees,
WalletBalances = bot.WalletBalances.ToList(),
Statistics = stats,
OptimizedMoneyManagement = optimizedMoneyManagement,
diff --git a/src/Managing.Application/Bots/TradingBot.cs b/src/Managing.Application/Bots/TradingBot.cs
index 5d91d22..d856e43 100644
--- a/src/Managing.Application/Bots/TradingBot.cs
+++ b/src/Managing.Application/Bots/TradingBot.cs
@@ -1030,10 +1030,7 @@ public class TradingBot : Bot, ITradingBot
{
// Add PnL (could be positive or negative)
Config.BotTradingBalance += position.ProfitAndLoss.Realized;
-
- // Subtract fees
- Config.BotTradingBalance -= GetPositionFees(position);
-
+
Logger.LogInformation(
$"💰 **Balance Updated**\nNew bot trading balance: `${Config.BotTradingBalance:F2}`");
}
@@ -1146,51 +1143,50 @@ public class TradingBot : Bot, ITradingBot
///
/// Calculates the total fees paid by the trading bot for each position.
+ /// Includes UI fees (0.1% of position size) and network fees ($0.50 for opening).
+ /// Closing fees are handled by oracle, so no network fee for closing.
///
/// Returns the total fees paid as a decimal value.
public decimal GetTotalFees()
{
- decimal fees = 0;
- foreach (var position in Positions.Where(p => p.Open.Fee > 0))
+ decimal totalFees = 0;
+
+ foreach (var position in Positions.Where(p => p.Open.Price > 0 && p.Open.Quantity > 0))
{
- fees += position.Open.Fee;
- fees += position.StopLoss.Status == TradeStatus.Filled ? position.StopLoss.Fee : 0;
- fees += position.TakeProfit1.Status == TradeStatus.Filled ? position.TakeProfit1.Fee : 0;
-
- if (position.IsFinished() &&
- position.StopLoss.Status != TradeStatus.Filled && position.TakeProfit1.Status != TradeStatus.Filled)
- fees += position.Open.Fee;
-
- if (position.TakeProfit2 != null)
- fees += position.TakeProfit2.Fee;
+ totalFees += CalculatePositionFees(position);
}
- return fees;
+ return totalFees;
}
///
- /// Calculates the total fees for a specific position
+ /// Calculates the total fees for a specific position based on GMX V2 fee structure
///
/// The position to calculate fees for
/// The total fees for the position
- private decimal GetPositionFees(Position position)
+ private decimal CalculatePositionFees(Position position)
{
decimal fees = 0;
-
- fees += position.Open.Fee;
- fees += position.StopLoss.Status == TradeStatus.Filled ? position.StopLoss.Fee : 0;
- fees += position.TakeProfit1.Status == TradeStatus.Filled ? position.TakeProfit1.Fee : 0;
-
- if (position.IsFinished() &&
- position.StopLoss.Status != TradeStatus.Filled && position.TakeProfit1.Status != TradeStatus.Filled)
- fees += position.Open.Fee;
-
- if (position.TakeProfit2 != null)
- fees += position.TakeProfit2.Status == TradeStatus.Filled ? position.TakeProfit2.Fee : 0;
-
+
+ // Calculate position size in USD (leverage is already included in quantity calculation)
+ var positionSizeUsd = position.Open.Price * position.Open.Quantity;
+
+ // UI Fee: 0.1% of position size paid BOTH on opening AND closing
+ var uiFeeRate = 0.001m; // 0.1%
+ var uiFeeOpen = positionSizeUsd * uiFeeRate; // Fee paid on opening
+ var uiFeeClose = positionSizeUsd * uiFeeRate; // Fee paid on closing
+ var totalUiFees = uiFeeOpen + uiFeeClose; // Total: 0.2% of position size
+ fees += totalUiFees;
+
+ // Network Fee: $0.50 for opening position only
+ // Closing is handled by oracle, so no network fee for closing
+ var networkFeeForOpening = 0.50m;
+ fees += networkFeeForOpening;
+
return fees;
}
+
public async Task ToggleIsForWatchOnly()
{
Config.IsForWatchingOnly = !Config.IsForWatchingOnly;
diff --git a/src/Managing.WebApp/src/components/organism/Backtest/backtestRowDetails.tsx b/src/Managing.WebApp/src/components/organism/Backtest/backtestRowDetails.tsx
index a61a7ef..07bf275 100644
--- a/src/Managing.WebApp/src/components/organism/Backtest/backtestRowDetails.tsx
+++ b/src/Managing.WebApp/src/components/organism/Backtest/backtestRowDetails.tsx
@@ -332,6 +332,13 @@ const BacktestRowDetails: React.FC = ({
maximumFractionDigits: 2
})}
>
+