From f5c47767cb509836ab7fcd1fd87d629172d21bbb Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 14 Jul 2021 20:51:42 +0200 Subject: [PATCH 1/5] Provide available capital to api --- freqtrade/rpc/api_server/api_schemas.py | 1 + freqtrade/rpc/rpc.py | 1 + 2 files changed, 2 insertions(+) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index a0f1c05a6..40101e609 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -115,6 +115,7 @@ class ShowConfig(BaseModel): dry_run: bool stake_currency: str stake_amount: Union[float, str] + available_capital: Optional[float] stake_currency_decimals: int max_open_trades: int minimal_roi: Dict[str, Any] diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index e0aaefe50..e173673be 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -106,6 +106,7 @@ class RPC: 'stake_currency': config['stake_currency'], 'stake_currency_decimals': decimals_per_coin(config['stake_currency']), 'stake_amount': config['stake_amount'], + 'available_capital': config.get('available_capital'), 'max_open_trades': (config['max_open_trades'] if config['max_open_trades'] != float('inf') else -1), 'minimal_roi': config['minimal_roi'].copy() if 'minimal_roi' in config else {}, From c9c7f84e8c2726b2d423f70ca1e569b21487a084 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 14 Jul 2021 20:55:11 +0200 Subject: [PATCH 2/5] Calculate relative profit based on assumed starting balance --- freqtrade/rpc/api_server/api_schemas.py | 4 ++++ freqtrade/rpc/rpc.py | 17 +++++++++++++---- freqtrade/rpc/telegram.py | 8 ++++---- freqtrade/wallets.py | 13 +++++++++++++ 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 40101e609..d3eec9be6 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -67,12 +67,16 @@ class Profit(BaseModel): profit_closed_ratio_mean: float profit_closed_percent_sum: float profit_closed_ratio_sum: float + profit_closed_percent: float + profit_closed_ratio: float profit_closed_fiat: float profit_all_coin: float profit_all_percent_mean: float profit_all_ratio_mean: float profit_all_percent_sum: float profit_all_ratio_sum: float + profit_all_percent: float + profit_all_ratio: float profit_all_fiat: float trade_count: int closed_trade_count: int diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index e173673be..d6eaf7ca6 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -397,7 +397,12 @@ class RPC: profit_all_coin_sum = round(sum(profit_all_coin), 8) profit_all_ratio_mean = float(mean(profit_all_ratio) if profit_all_ratio else 0.0) + # Doing the sum is not right - overall profit needs to be based on initial capital profit_all_ratio_sum = sum(profit_all_ratio) if profit_all_ratio else 0.0 + starting_balance = self._freqtrade.wallets.get_starting_balance() + profit_closed_ratio_fromstart = profit_closed_coin_sum / starting_balance + profit_all_ratio_fromstart = profit_all_coin_sum / starting_balance + profit_all_fiat = self._fiat_converter.convert_amount( profit_all_coin_sum, stake_currency, @@ -411,14 +416,18 @@ class RPC: 'profit_closed_coin': profit_closed_coin_sum, 'profit_closed_percent_mean': round(profit_closed_ratio_mean * 100, 2), 'profit_closed_ratio_mean': profit_closed_ratio_mean, - 'profit_closed_percent_sum': round(profit_closed_ratio_sum * 100, 2), - 'profit_closed_ratio_sum': profit_closed_ratio_sum, + 'profit_closed_percent_sum': round(profit_closed_ratio_sum * 100, 2), # Deprecated + 'profit_closed_ratio_sum': profit_closed_ratio_sum, # Deprecated + 'profit_closed_ratio': profit_closed_ratio_fromstart, + 'profit_closed_percent': round(profit_closed_ratio_fromstart * 100, 2), 'profit_closed_fiat': profit_closed_fiat, 'profit_all_coin': profit_all_coin_sum, 'profit_all_percent_mean': round(profit_all_ratio_mean * 100, 2), 'profit_all_ratio_mean': profit_all_ratio_mean, - 'profit_all_percent_sum': round(profit_all_ratio_sum * 100, 2), - 'profit_all_ratio_sum': profit_all_ratio_sum, + 'profit_all_percent_sum': round(profit_all_ratio_sum * 100, 2), # Deprecated + 'profit_all_ratio_sum': profit_all_ratio_sum, # Deprecated + 'profit_all_ratio': profit_all_ratio_fromstart, + 'profit_all_percent': round(profit_all_ratio_fromstart * 100, 2), 'profit_all_fiat': profit_all_fiat, 'trade_count': len(trades), 'closed_trade_count': len([t for t in trades if not t.is_open]), diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 319a6c9c0..263a3fc6d 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -494,11 +494,11 @@ class Telegram(RPCHandler): start_date) profit_closed_coin = stats['profit_closed_coin'] profit_closed_percent_mean = stats['profit_closed_percent_mean'] - profit_closed_percent_sum = stats['profit_closed_percent_sum'] + profit_closed_percent = stats['profit_closed_percent'] profit_closed_fiat = stats['profit_closed_fiat'] profit_all_coin = stats['profit_all_coin'] profit_all_percent_mean = stats['profit_all_percent_mean'] - profit_all_percent_sum = stats['profit_all_percent_sum'] + profit_all_percent = stats['profit_all_percent'] profit_all_fiat = stats['profit_all_fiat'] trade_count = stats['trade_count'] first_trade_date = stats['first_trade_date'] @@ -514,7 +514,7 @@ class Telegram(RPCHandler): markdown_msg = ("*ROI:* Closed trades\n" f"∙ `{round_coin_value(profit_closed_coin, stake_cur)} " f"({profit_closed_percent_mean:.2f}%) " - f"({profit_closed_percent_sum} \N{GREEK CAPITAL LETTER SIGMA}%)`\n" + f"({profit_closed_percent} \N{GREEK CAPITAL LETTER SIGMA}%)`\n" f"∙ `{round_coin_value(profit_closed_fiat, fiat_disp_cur)}`\n") else: markdown_msg = "`No closed trade` \n" @@ -523,7 +523,7 @@ class Telegram(RPCHandler): f"*ROI:* All trades\n" f"∙ `{round_coin_value(profit_all_coin, stake_cur)} " f"({profit_all_percent_mean:.2f}%) " - f"({profit_all_percent_sum} \N{GREEK CAPITAL LETTER SIGMA}%)`\n" + f"({profit_all_percent} \N{GREEK CAPITAL LETTER SIGMA}%)`\n" f"∙ `{round_coin_value(profit_all_fiat, fiat_disp_cur)}`\n" f"*Total Trade Count:* `{trade_count}`\n" f"*{'First Trade opened' if not timescale else 'Showing Profit since'}:* " diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 0048dbf48..e51a01afc 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -129,6 +129,19 @@ class Wallets: def get_all_balances(self) -> Dict[str, Any]: return self._wallets + def get_starting_balance(self) -> float: + """ + Retrieves starting balance - based on either available capital, + or by using current balance subtracting + """ + if "available_capital" in self._config: + return self._config['available_capital'] + else: + tot_profit = Trade.get_total_closed_profit() + open_stakes = Trade.total_open_trades_stakes() + available_balance = self.get_free(self._config['stake_currency']) + return available_balance - tot_profit + open_stakes + def get_total_stake_amount(self): """ Return the total currently available balance in stake currency, including tied up stake and From 02d716a8be1963d7741a20d0c435a307793ba006 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 14 Jul 2021 20:59:47 +0200 Subject: [PATCH 3/5] Fix api test --- tests/rpc/test_rpc_apiserver.py | 4 ++++ tests/rpc/test_rpc_telegram.py | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 89da68da7..4dea2bbfa 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -677,12 +677,16 @@ def test_api_profit(botclient, mocker, ticker, fee, markets): 'profit_all_ratio_mean': -0.6641100666666667, 'profit_all_percent_sum': -398.47, 'profit_all_ratio_sum': -3.9846604, + 'profit_all_percent': -4.41, + 'profit_all_ratio': -0.044063014216106644, 'profit_closed_coin': 0.00073913, 'profit_closed_fiat': 9.124559849999999, 'profit_closed_ratio_mean': 0.0075, 'profit_closed_percent_mean': 0.75, 'profit_closed_ratio_sum': 0.015, 'profit_closed_percent_sum': 1.5, + 'profit_closed_ratio': 7.391275897987988e-07, + 'profit_closed_percent': 0.0, 'trade_count': 6, 'closed_trade_count': 2, 'winning_trades': 2, diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 4784f1172..cccc78117 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -452,7 +452,8 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee, assert msg_mock.call_count == 1 assert 'No closed trade' in msg_mock.call_args_list[-1][0][0] assert '*ROI:* All trades' in msg_mock.call_args_list[-1][0][0] - assert ('∙ `-0.00000500 BTC (-0.50%) (-0.5 \N{GREEK CAPITAL LETTER SIGMA}%)`' + mocker.patch('freqtrade.wallets.Wallets.get_starting_balance', return_value=0.01) + assert ('∙ `-0.00000500 BTC (-0.50%) (-0.0 \N{GREEK CAPITAL LETTER SIGMA}%)`' in msg_mock.call_args_list[-1][0][0]) msg_mock.reset_mock() @@ -466,11 +467,11 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee, telegram._profit(update=update, context=MagicMock()) assert msg_mock.call_count == 1 assert '*ROI:* Closed trades' in msg_mock.call_args_list[-1][0][0] - assert ('∙ `0.00006217 BTC (6.20%) (6.2 \N{GREEK CAPITAL LETTER SIGMA}%)`' + assert ('∙ `0.00006217 BTC (6.20%) (0.62 \N{GREEK CAPITAL LETTER SIGMA}%)`' in msg_mock.call_args_list[-1][0][0]) assert '∙ `0.933 USD`' in msg_mock.call_args_list[-1][0][0] assert '*ROI:* All trades' in msg_mock.call_args_list[-1][0][0] - assert ('∙ `0.00006217 BTC (6.20%) (6.2 \N{GREEK CAPITAL LETTER SIGMA}%)`' + assert ('∙ `0.00006217 BTC (6.20%) (0.62 \N{GREEK CAPITAL LETTER SIGMA}%)`' in msg_mock.call_args_list[-1][0][0]) assert '∙ `0.933 USD`' in msg_mock.call_args_list[-1][0][0] From 697bf92f6f10d6419982e8e45a1c83039be6a4cd Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 14 Jul 2021 21:10:25 +0200 Subject: [PATCH 4/5] Add test for get_starting_balance method --- tests/test_wallets.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/test_wallets.py b/tests/test_wallets.py index a44ca243b..25f2ad89f 100644 --- a/tests/test_wallets.py +++ b/tests/test_wallets.py @@ -197,3 +197,28 @@ def test__validate_stake_amount(mocker, default_conf, return_value=max_stake_amount) res = freqtrade.wallets._validate_stake_amount('XRP/USDT', stake_amount, min_stake_amount) assert res == expected + + +@pytest.mark.parametrize('available_capital,closed_profit,open_stakes,free,expected', [ + (None, 10, 100, 910, 1000), + (None, 0, 0, 2500, 2500), + (None, 500, 0, 2500, 2000), + (None, 500, 0, 2500, 2000), + # Only available balance matters when it's set. + (100, 0, 0, 0, 100), + (1000, 0, 2, 5, 1000), + (1235, 2250, 2, 5, 1235), +]) +def test_get_starting_balance(mocker, default_conf, available_capital, closed_profit, + open_stakes, free, expected): + if available_capital: + default_conf['available_capital'] = available_capital + mocker.patch("freqtrade.persistence.models.Trade.get_total_closed_profit", + return_value=closed_profit) + mocker.patch("freqtrade.persistence.models.Trade.total_open_trades_stakes", + return_value=open_stakes) + mocker.patch("freqtrade.wallets.Wallets.get_free", return_value=free) + + freqtrade = get_patched_freqtradebot(mocker, default_conf) + + assert freqtrade.wallets.get_starting_balance() == expected From 2e95df4d8dde6ff7ff4be9ed41af9da742ba3b18 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 15 Jul 2021 07:11:44 +0200 Subject: [PATCH 5/5] Update docs for /profit output --- docs/telegram-usage.md | 8 ++++++-- freqtrade/rpc/rpc.py | 8 ++++---- tests/test_wallets.py | 2 ++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index f5d9744b4..b020b00db 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -245,10 +245,10 @@ current max Return a summary of your profit/loss and performance. > **ROI:** Close trades -> ∙ `0.00485701 BTC (258.45%)` +> ∙ `0.00485701 BTC (2.2%) (15.2 Σ%)` > ∙ `62.968 USD` > **ROI:** All trades -> ∙ `0.00255280 BTC (143.43%)` +> ∙ `0.00255280 BTC (1.5%) (6.43 Σ%)` > ∙ `33.095 EUR` > > **Total Trade Count:** `138` @@ -257,6 +257,10 @@ Return a summary of your profit/loss and performance. > **Avg. Duration:** `2:33:45` > **Best Performing:** `PAY/BTC: 50.23%` +The relative profit of `1.2%` is the average profit per trade. +The relative profit of `15.2 Σ%` is be based on the starting capital - so in this case, the starting capital was `0.00485701 * 1.152 = 0.00738 BTC`. +Starting capital is either taken from the `available_capital` setting, or calculated by using current wallet size - profits. + ### /forcesell > **BITTREX:** Selling BTC/LTC with limit `0.01650000 (profit: ~-4.07%, -0.00008168)` diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index d6eaf7ca6..db89443bf 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -416,16 +416,16 @@ class RPC: 'profit_closed_coin': profit_closed_coin_sum, 'profit_closed_percent_mean': round(profit_closed_ratio_mean * 100, 2), 'profit_closed_ratio_mean': profit_closed_ratio_mean, - 'profit_closed_percent_sum': round(profit_closed_ratio_sum * 100, 2), # Deprecated - 'profit_closed_ratio_sum': profit_closed_ratio_sum, # Deprecated + 'profit_closed_percent_sum': round(profit_closed_ratio_sum * 100, 2), + 'profit_closed_ratio_sum': profit_closed_ratio_sum, 'profit_closed_ratio': profit_closed_ratio_fromstart, 'profit_closed_percent': round(profit_closed_ratio_fromstart * 100, 2), 'profit_closed_fiat': profit_closed_fiat, 'profit_all_coin': profit_all_coin_sum, 'profit_all_percent_mean': round(profit_all_ratio_mean * 100, 2), 'profit_all_ratio_mean': profit_all_ratio_mean, - 'profit_all_percent_sum': round(profit_all_ratio_sum * 100, 2), # Deprecated - 'profit_all_ratio_sum': profit_all_ratio_sum, # Deprecated + 'profit_all_percent_sum': round(profit_all_ratio_sum * 100, 2), + 'profit_all_ratio_sum': profit_all_ratio_sum, 'profit_all_ratio': profit_all_ratio_fromstart, 'profit_all_percent': round(profit_all_ratio_fromstart * 100, 2), 'profit_all_fiat': profit_all_fiat, diff --git a/tests/test_wallets.py b/tests/test_wallets.py index 25f2ad89f..64db3b9cd 100644 --- a/tests/test_wallets.py +++ b/tests/test_wallets.py @@ -204,10 +204,12 @@ def test__validate_stake_amount(mocker, default_conf, (None, 0, 0, 2500, 2500), (None, 500, 0, 2500, 2000), (None, 500, 0, 2500, 2000), + (None, -70, 0, 1930, 2000), # Only available balance matters when it's set. (100, 0, 0, 0, 100), (1000, 0, 2, 5, 1000), (1235, 2250, 2, 5, 1235), + (1235, -2250, 2, 5, 1235), ]) def test_get_starting_balance(mocker, default_conf, available_capital, closed_profit, open_stakes, free, expected):