diff --git a/docs/configuration.md b/docs/configuration.md
index 5c6236e58..73b0e9c9a 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 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).
+#### 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/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/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..0048dbf48 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])
@@ -138,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:
@@ -154,10 +158,8 @@ 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:
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',
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)