From b41c2344405c438eb3f81e60eb8eeb3cef1510ad Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 10 Jul 2021 12:18:55 +0200 Subject: [PATCH 1/5] Extract Closed profit calculation to trade object --- freqtrade/persistence/models.py | 13 +++++++++++++ freqtrade/wallets.py | 4 +--- tests/test_persistence.py | 16 ++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index b4c299120..8dcfc6c94 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -801,6 +801,19 @@ class Trade(_DECL_BASE, LocalTrade): Trade.is_open.is_(False), ]).all() + @staticmethod + def get_total_closed_profit() -> float: + """ + Retrieves total realized profit + """ + if Trade.use_db: + total_profit = Trade.query.with_entities( + func.sum(Trade.close_profit_abs)).filter(Trade.is_open.is_(False)).scalar() + else: + total_profit = sum( + t.close_profit_abs for t in LocalTrade.get_trades_proxy(is_open=False)) + return total_profit or 0 + @staticmethod def total_open_trades_stakes() -> float: """ diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index ece496c90..3d80cc892 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -70,9 +70,7 @@ class Wallets: # If not backtesting... # TODO: potentially remove the ._log workaround to determine backtest mode. if self._log: - closed_trades = Trade.get_trades_proxy(is_open=False) - tot_profit = sum( - [trade.close_profit_abs for trade in closed_trades if trade.close_profit_abs]) + tot_profit = Trade.get_total_closed_profit() else: tot_profit = LocalTrade.total_profit tot_in_trades = sum([trade.stake_amount for trade in open_trades]) diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 1576aaa5a..89d07ca74 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -1124,6 +1124,21 @@ def test_total_open_trades_stakes(fee, use_db): Trade.use_db = True +@pytest.mark.usefixtures("init_persistence") +@pytest.mark.parametrize('use_db', [True, False]) +def test_get_total_closed_profit(fee, use_db): + + Trade.use_db = use_db + Trade.reset_trades() + res = Trade.get_total_closed_profit() + assert res == 0 + create_mock_trades(fee, use_db) + res = Trade.get_total_closed_profit() + assert res == 0.000739127 + + Trade.use_db = True + + @pytest.mark.usefixtures("init_persistence") @pytest.mark.parametrize('use_db', [True, False]) def test_get_trades_proxy(fee, use_db): @@ -1298,6 +1313,7 @@ def test_Trade_object_idem(): 'open_date', 'get_best_pair', 'get_overall_performance', + 'get_total_closed_profit', 'total_open_trades_stakes', 'get_sold_trades_without_assigned_fees', 'get_open_trades_without_assigned_fees', From 786374690406d00cad290a583c87972c436dc527 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 10 Jul 2021 12:30:00 +0200 Subject: [PATCH 2/5] Add available_capital parameter --- freqtrade/constants.py | 4 ++++ freqtrade/wallets.py | 23 ++++++++++++++--------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index acd143708..2f93ace1c 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -113,6 +113,10 @@ CONF_SCHEMA = { 'maximum': 1, 'default': 0.99 }, + 'available_capital': { + 'type': 'number', + 'minimum': 0, + }, 'amend_last_stake_amount': {'type': 'boolean', 'default': False}, 'last_stake_amount_min_ratio': { 'type': 'number', 'minimum': 0.0, 'maximum': 1.0, 'default': 0.5 diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 3d80cc892..0ece65b2b 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -136,12 +136,18 @@ class Wallets: Calculated as ( + free amount) * tradable_balance_ratio """ - # Ensure % is used from the overall balance - # Otherwise we'd risk lowering stakes with each open trade. - # (tied up + current free) * ratio) - tied up val_tied_up = Trade.total_open_trades_stakes() - available_amount = ((val_tied_up + self.get_free(self._config['stake_currency'])) * - self._config['tradable_balance_ratio']) + if "available_capital" in self._config: + starting_balance = self._config['available_capital'] + tot_profit = Trade.get_total_closed_profit() + available_amount = starting_balance + tot_profit + + else: + # Ensure % is used from the overall balance + # Otherwise we'd risk lowering stakes with each open trade. + # (tied up + current free) * ratio) - tied up + available_amount = ((val_tied_up + self.get_free(self._config['stake_currency'])) * + self._config['tradable_balance_ratio']) return available_amount def get_available_stake_amount(self) -> float: @@ -152,10 +158,9 @@ class Wallets: ( + free amount) * tradable_balance_ratio - """ - # Ensure % is used from the overall balance - # Otherwise we'd risk lowering stakes with each open trade. - # (tied up + current free) * ratio) - tied up - return self.get_total_stake_amount() - Trade.total_open_trades_stakes() + + free = self.get_free(self._config['stake_currency']) + return min(self.get_total_stake_amount() - Trade.total_open_trades_stakes(), free) def _calculate_unlimited_stake_amount(self, available_amount: float, val_tied_up: float) -> float: From 6a8e8875a2a7893e9ad28eebce7e6cddd912e833 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 10 Jul 2021 12:39:02 +0200 Subject: [PATCH 3/5] Test new behaviour --- tests/test_wallets.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tests/test_wallets.py b/tests/test_wallets.py index d083a63f6..a44ca243b 100644 --- a/tests/test_wallets.py +++ b/tests/test_wallets.py @@ -121,13 +121,19 @@ def test_get_trade_stake_amount_no_stake_amount(default_conf, mocker) -> None: freqtrade.wallets.get_trade_stake_amount('ETH/BTC') -@pytest.mark.parametrize("balance_ratio,result1,result2", [ - (1, 50, 66.66666), - (0.99, 49.5, 66.0), - (0.50, 25, 33.3333), +@pytest.mark.parametrize("balance_ratio,capital,result1,result2", [ + (1, None, 50, 66.66666), + (0.99, None, 49.5, 66.0), + (0.50, None, 25, 33.3333), + # Tests with capital ignore balance_ratio + (1, 100, 50, 0.0), + (0.99, 200, 50, 66.66666), + (0.99, 150, 50, 50), + (0.50, 50, 25, 0.0), + (0.50, 10, 5, 0.0), ]) -def test_get_trade_stake_amount_unlimited_amount(default_conf, ticker, balance_ratio, result1, - result2, limit_buy_order_open, +def test_get_trade_stake_amount_unlimited_amount(default_conf, ticker, balance_ratio, capital, + result1, result2, limit_buy_order_open, fee, mocker) -> None: mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -141,6 +147,8 @@ def test_get_trade_stake_amount_unlimited_amount(default_conf, ticker, balance_r conf['dry_run_wallet'] = 100 conf['max_open_trades'] = 2 conf['tradable_balance_ratio'] = balance_ratio + if capital is not None: + conf['available_capital'] = capital freqtrade = get_patched_freqtradebot(mocker, conf) From 40db424363556d95cfbfd5cd71faa9a50ca86af6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 11 Jul 2021 10:44:36 +0200 Subject: [PATCH 4/5] Add documentation for available capital setting --- docs/configuration.md | 17 +++++++++++++++++ freqtrade/wallets.py | 1 - 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 5c6236e58..ad7436cb2 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -52,6 +52,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `stake_currency` | **Required.** Crypto-currency used for trading.
**Datatype:** String | `stake_amount` | **Required.** Amount of crypto-currency your bot will use for each trade. Set it to `"unlimited"` to allow the bot to use all available balance. [More information below](#configuring-amount-per-trade).
**Datatype:** Positive float or `"unlimited"`. | `tradable_balance_ratio` | Ratio of the total account balance the bot is allowed to trade. [More information below](#configuring-amount-per-trade).
*Defaults to `0.99` 99%).*
**Datatype:** Positive float between `0.1` and `1.0`. +| `available_capital` | Available starting capital for the bot. Useful when running multiple bots on the same exchange account.[More information below](#configuring-amount-per-trade).
**Datatype:** Positive float. | `amend_last_stake_amount` | Use reduced last stake amount if necessary. [More information below](#configuring-amount-per-trade).
*Defaults to `false`.*
**Datatype:** Boolean | `last_stake_amount_min_ratio` | Defines minimum stake amount that has to be left and executed. Applies only to the last stake amount when it's amended to a reduced value (i.e. if `amend_last_stake_amount` is set to `true`). [More information below](#configuring-amount-per-trade).
*Defaults to `0.5`.*
**Datatype:** Float (as ratio) | `amount_reserve_percent` | Reserve some amount in min pair stake amount. The bot will reserve `amount_reserve_percent` + stoploss value when calculating min pair stake amount in order to avoid possible trade refusals.
*Defaults to `0.05` (5%).*
**Datatype:** Positive Float as ratio. @@ -192,9 +193,25 @@ You can configure the "untouched" amount by using the `tradable_balance_ratio` s For example, if you have 10 ETH available in your wallet on the exchange and `tradable_balance_ratio=0.5` (which is 50%), then the bot will use a maximum amount of 5 ETH for trading and considers this as available balance. The rest of the wallet is untouched by the trades. +!!! Danger + This setting should **not** be used when running multiple bots on the same exchange. Please look at [Available Capital to the bot](#assign-available-capital) instead. + !!! Warning The `tradable_balance_ratio` setting applies to the current balance (free balance + tied up in trades). Therefore, assuming the starting balance of 1000, a configuration with `tradable_balance_ratio=0.99` will not guarantee that 10 currency units will always remain available on the exchange. For example, the free amount may reduce to 5 units if the total balance is reduced to 500 (either by a losing streak, or by withdrawing balance). +#### Assign available Capital + +To fully utilize compounding profits when using multiple bots on the same exchange account, you'll want to limit each bot to a certain starting balance. +This can be accomplished by setting `available_capital` to the desired starting balance. + +Assuming your account has 10.000 USDT and you want to run 2 different strategies on this exchange. +You'd set `available_capital=5000` - granting each bot an initial capital of 5000 USDT. +The bot will then split this starting balance equally into `max_open_trades` buckets. +Profitable trades will result in increased stake-sizes for this bot - without affecting stake-sizes of the other bot. + +!!! Warning "Incompatible with `tradable_balance_ratio`" + Setting this option will replace any configuration of `tradable_balance_ratio`. + #### Amend last stake amount Assuming we have the tradable balance of 1000 USDT, `stake_amount=400`, and `max_open_trades=3`. diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 0ece65b2b..0048dbf48 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -158,7 +158,6 @@ class Wallets: ( + free amount) * tradable_balance_ratio - """ - free = self.get_free(self._config['stake_currency']) return min(self.get_total_stake_amount() - Trade.total_open_trades_stakes(), free) From 29e2b858ca1fff6e23e276b0086e545356694431 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 13 Jul 2021 20:40:06 +0200 Subject: [PATCH 5/5] Improve wording in docs --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index ad7436cb2..73b0e9c9a 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -194,7 +194,7 @@ You can configure the "untouched" amount by using the `tradable_balance_ratio` s For example, if you have 10 ETH available in your wallet on the exchange and `tradable_balance_ratio=0.5` (which is 50%), then the bot will use a maximum amount of 5 ETH for trading and considers this as available balance. The rest of the wallet is untouched by the trades. !!! Danger - This setting should **not** be used when running multiple bots on the same exchange. Please look at [Available Capital to the bot](#assign-available-capital) instead. + This setting should **not** be used when running multiple bots on the same account. Please look at [Available Capital to the bot](#assign-available-capital) instead. !!! Warning The `tradable_balance_ratio` setting applies to the current balance (free balance + tied up in trades). Therefore, assuming the starting balance of 1000, a configuration with `tradable_balance_ratio=0.99` will not guarantee that 10 currency units will always remain available on the exchange. For example, the free amount may reduce to 5 units if the total balance is reduced to 500 (either by a losing streak, or by withdrawing balance).