From b59db3c690db7821ed4aaa5e50ffae72d0c41a6f Mon Sep 17 00:00:00 2001 From: Stefano Date: Sat, 29 Nov 2025 15:43:20 +0900 Subject: [PATCH 1/4] add more metrics on profit stat --- freqtrade/rpc/rpc.py | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 22e457eef..6bea1fff3 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -19,7 +19,16 @@ from freqtrade import __version__ from freqtrade.configuration.timerange import TimeRange from freqtrade.constants import CANCEL_REASON, DEFAULT_DATAFRAME_COLUMNS, Config from freqtrade.data.history import load_data -from freqtrade.data.metrics import DrawDownResult, calculate_expectancy, calculate_max_drawdown +from freqtrade.data.metrics import ( + DrawDownResult, + calculate_cagr, + calculate_calmar, + calculate_expectancy, + calculate_max_drawdown, + calculate_sharpe, + calculate_sortino, + calculate_sqn, +) from freqtrade.enums import ( CandleType, ExitCheckTuple, @@ -689,6 +698,34 @@ class RPC: last_date = trades[-1].open_date_utc if trades else None num = float(len(durations) or 1) bot_start = KeyValueStore.get_datetime_value("bot_start_time") + + sharpe = calculate_sharpe( + trades=trades_df, + min_date=first_date, + max_date=last_date, + starting_balance=starting_balance, + ) + sortino = calculate_sortino( + trades=trades_df, + min_date=first_date, + max_date=last_date, + starting_balance=starting_balance, + ) + sqn = calculate_sqn(trades=trades_df, starting_balance=starting_balance) + calmar = calculate_calmar( + trades=trades_df, + min_date=first_date, + max_date=last_date, + starting_balance=starting_balance, + ) + current_balance = self._freqtrade.wallets.get_total_stake_amount() + days_passed = max(1, (last_date - first_date).days) + cagr = calculate_cagr( + starting_balance=starting_balance, + final_balance=current_balance, + days_passed=days_passed, + ) + return { "profit_closed_coin": profit_closed_coin_sum, "profit_closed_percent_mean": round(profit_closed_ratio_mean * 100, 2), @@ -725,6 +762,11 @@ class RPC: "winrate": winrate, "expectancy": expectancy, "expectancy_ratio": expectancy_ratio, + "sharpe": sharpe, + "sortino": sortino, + "sqn": sqn, + "calmar": calmar, + "cagr": cagr, "max_drawdown": drawdown.relative_account_drawdown, "max_drawdown_abs": drawdown.drawdown_abs, "max_drawdown_start": format_date(drawdown.high_date), From 645f70e216a12b489cd957727d0010d677788ba5 Mon Sep 17 00:00:00 2001 From: Stefano Date: Sat, 29 Nov 2025 15:53:28 +0900 Subject: [PATCH 2/4] add None --- freqtrade/data/metrics.py | 15 ++++++++++++--- freqtrade/rpc/rpc.py | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/freqtrade/data/metrics.py b/freqtrade/data/metrics.py index a4b6898e2..c13edacc6 100644 --- a/freqtrade/data/metrics.py +++ b/freqtrade/data/metrics.py @@ -333,7 +333,10 @@ def calculate_expectancy(trades: pd.DataFrame) -> tuple[float, float]: def calculate_sortino( - trades: pd.DataFrame, min_date: datetime, max_date: datetime, starting_balance: float + trades: pd.DataFrame, + min_date: datetime | None, + max_date: datetime | None, + starting_balance: float, ) -> float: """ Calculate sortino @@ -361,7 +364,10 @@ def calculate_sortino( def calculate_sharpe( - trades: pd.DataFrame, min_date: datetime, max_date: datetime, starting_balance: float + trades: pd.DataFrame, + min_date: datetime | None, + max_date: datetime | None, + starting_balance: float, ) -> float: """ Calculate sharpe @@ -388,7 +394,10 @@ def calculate_sharpe( def calculate_calmar( - trades: pd.DataFrame, min_date: datetime, max_date: datetime, starting_balance: float + trades: pd.DataFrame, + min_date: datetime | None, + max_date: datetime | None, + starting_balance: float, ) -> float: """ Calculate calmar diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 6bea1fff3..f76b26478 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -719,7 +719,7 @@ class RPC: starting_balance=starting_balance, ) current_balance = self._freqtrade.wallets.get_total_stake_amount() - days_passed = max(1, (last_date - first_date).days) + days_passed = max(1, (last_date - first_date).days) if first_date and last_date else 1 cagr = calculate_cagr( starting_balance=starting_balance, final_balance=current_balance, From 6f2ba13b0c4e46d2e87c39f3f57011ddaf101c48 Mon Sep 17 00:00:00 2001 From: Stefano Date: Wed, 31 Dec 2025 10:05:18 +0900 Subject: [PATCH 3/4] add to api schemas --- freqtrade/rpc/api_server/api_schemas.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 0dcd95edf..1783c9ebf 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -157,6 +157,11 @@ class Profit(BaseModel): winrate: float expectancy: float expectancy_ratio: float + sharpe: float + sortino: float + sqn: float + calmar: float + cagr: float max_drawdown: float max_drawdown_abs: float max_drawdown_start: str From 1e6d832f71e344886b60d099c08628b6712b4c8a Mon Sep 17 00:00:00 2001 From: Stefano Date: Wed, 31 Dec 2025 10:40:09 +0900 Subject: [PATCH 4/4] fix test --- tests/rpc/test_rpc_apiserver.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 768858aac..0a6c1d57d 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1199,6 +1199,11 @@ def test_api_logs(botclient): "winrate": 0.0, "expectancy": -0.0033695635, "expectancy_ratio": -1.0, + "cagr": -0.0024567404889381805, + "calmar": -1910.497317469542, + "sharpe": -58.138247358830355, + "sortino": -58.138247358830355, + "sqn": -1.5215, "trading_volume": 75.945, }, ), @@ -1231,6 +1236,11 @@ def test_api_logs(botclient): "winrate": 1.0, "expectancy": 0.0003695635, "expectancy_ratio": 100, + "cagr": 0.0002698167695580622, + "calmar": -100.0, + "sharpe": 65.81269184917424, + "sortino": -100.0, + "sqn": 1.7224, "trading_volume": 75.945, }, ), @@ -1263,6 +1273,11 @@ def test_api_logs(botclient): "winrate": 0.5, "expectancy": -0.0027145635000000003, "expectancy_ratio": -0.48612137582114445, + "cagr": -0.0019796559404918757, + "calmar": -1857.4671689202785, + "sharpe": -36.14602907243071, + "sortino": -100.0, + "sqn": -0.946, "trading_volume": 75.945, }, ), @@ -1326,6 +1341,11 @@ def test_api_profit(botclient, mocker, ticker, fee, markets, is_short, expected) "winrate": expected["winrate"], "expectancy": expected["expectancy"], "expectancy_ratio": expected["expectancy_ratio"], + "sharpe": expected["sharpe"], + "sortino": expected["sortino"], + "sqn": expected["sqn"], + "calmar": expected["calmar"], + "cagr": expected["cagr"], "max_drawdown": ANY, "max_drawdown_abs": ANY, "max_drawdown_start": ANY,