diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md
index 43ab66cbf01..946686b1cf4 100644
--- a/docs/telegram-usage.md
+++ b/docs/telegram-usage.md
@@ -360,6 +360,8 @@ Return the performance of each crypto-currency the bot has sold.
> 5. `STORJ/BTC 0.0009 BTC (27.24%) (1)`
> ...
+The relative performance is calculated against the total investment in the currency, aggregating all filled entries for the currency.
+
### /balance
Return the balance of all crypto-currency your have on the exchange.
diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py
index 5f64e7c4a0e..0d5e7d20058 100644
--- a/freqtrade/persistence/trade_model.py
+++ b/freqtrade/persistence/trade_model.py
@@ -19,6 +19,7 @@
Select,
String,
UniqueConstraint,
+ case,
desc,
func,
select,
@@ -1934,17 +1935,49 @@ def get_overall_performance(minutes=None) -> list[dict[str, Any]]:
start_date = datetime.now(timezone.utc) - timedelta(minutes=minutes)
filters.append(Trade.close_date >= start_date)
- pair_rates = Trade.session.execute(
+ pair_costs = (
+ select(
+ Trade.pair,
+ func.sum(
+ (
+ func.coalesce(Order.filled, Order.amount)
+ * func.coalesce(Order.average, Order.price, Order.ft_price)
+ )
+ / func.coalesce(Trade.leverage, 1)
+ ).label("cost_per_pair"),
+ )
+ .join(Order, Trade.id == Order.ft_trade_id)
+ .filter(
+ *filters,
+ Order.ft_order_side == case((Trade.is_short.is_(True), "sell"), else_="buy"),
+ )
+ # Order.filled.gt > 0
+ .group_by(Trade.pair)
+ .cte("pair_costs")
+ )
+ trades_grouped = (
select(
Trade.pair,
- func.sum(Trade.close_profit).label("profit_sum"),
func.sum(Trade.close_profit_abs).label("profit_sum_abs"),
func.count(Trade.pair).label("count"),
)
.filter(*filters)
.group_by(Trade.pair)
+ .cte("trades_grouped")
+ )
+ q = (
+ select(
+ trades_grouped.c.pair,
+ (trades_grouped.c.profit_sum_abs / pair_costs.c.cost_per_pair).label(
+ "profit_ratio"
+ ),
+ trades_grouped.c.profit_sum_abs,
+ trades_grouped.c.count,
+ )
+ .join(pair_costs, trades_grouped.c.pair == pair_costs.c.pair)
.order_by(desc("profit_sum_abs"))
- ).all()
+ )
+ pair_rates = Trade.session.execute(q).all()
return [
{
diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py
index 2aab2245313..5de33900cf9 100644
--- a/tests/rpc/test_rpc.py
+++ b/tests/rpc/test_rpc.py
@@ -993,7 +993,7 @@ def test_performance_handle(default_conf_usdt, ticker, fee, mocker) -> None:
assert res[0]["pair"] == "NEO/USDT"
assert res[0]["count"] == 1
assert res[0]["profit_abs"] == 3.9875
- assert res[0]["profit_pct"] == 5.0
+ assert res[0]["profit_pct"] == 1.99
def test_enter_tag_performance_handle(default_conf, ticker, fee, mocker) -> None:
diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py
index 737df389c4a..762dede40d8 100644
--- a/tests/rpc/test_rpc_apiserver.py
+++ b/tests/rpc/test_rpc_apiserver.py
@@ -1166,26 +1166,26 @@ def test_api_performance(botclient, fee):
{
"count": 1,
"pair": "NEO/USDT",
- "profit": 5.0,
- "profit_pct": 5,
- "profit_ratio": 0.05,
+ "profit": 1.99,
+ "profit_pct": 1.99,
+ "profit_ratio": 0.0199375,
"profit_abs": 3.9875,
},
{
"count": 1,
"pair": "XRP/USDT",
- "profit": 10.0,
+ "profit": 9.47,
"profit_abs": 2.8425,
- "profit_pct": 10.0,
- "profit_ratio": 0.1,
+ "profit_pct": 9.47,
+ "profit_ratio": pytest.approx(0.094749999),
},
{
"count": 1,
"pair": "LTC/USDT",
- "profit": -20.0,
+ "profit": -20.45,
"profit_abs": -4.09,
- "profit_pct": -20.0,
- "profit_ratio": -0.2,
+ "profit_pct": -20.45,
+ "profit_ratio": -0.2045,
},
]
diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py
index 26db9c0f251..b743cdd8dfa 100644
--- a/tests/rpc/test_rpc_telegram.py
+++ b/tests/rpc/test_rpc_telegram.py
@@ -1591,7 +1591,7 @@ async def test_telegram_performance_handle(default_conf_usdt, update, ticker, fe
await telegram._performance(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert "Performance" in msg_mock.call_args_list[0][0][0]
- assert "XRP/USDT\t2.842 USDT (10.00%) (1)" in msg_mock.call_args_list[0][0][0]
+ assert "XRP/USDT\t2.842 USDT (9.47%) (1)" in msg_mock.call_args_list[0][0][0]
async def test_telegram_entry_tag_performance_handle(