diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 1882e3bdf..41b8475ec 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,11 +1,20 @@
{
"name": "freqtrade Develop",
-
- "dockerComposeFile": [
- "docker-compose.yml"
+ "build": {
+ "dockerfile": "Dockerfile",
+ "context": ".."
+ },
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [
+ 8080
],
+ "mounts": [
+ "source=freqtrade-bashhistory,target=/home/ftuser/commandhistory,type=volume"
+ ],
+ // Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root.
+ "remoteUser": "ftuser",
- "service": "ft_vscode",
+ "postCreateCommand": "freqtrade create-userdir --userdir user_data/",
"workspaceFolder": "/freqtrade/",
@@ -25,20 +34,6 @@
"ms-python.vscode-pylance",
"davidanson.vscode-markdownlint",
"ms-azuretools.vscode-docker",
+ "vscode-icons-team.vscode-icons",
],
-
- // Use 'forwardPorts' to make a list of ports inside the container available locally.
- // "forwardPorts": [],
-
- // Uncomment the next line if you want start specific services in your Docker Compose config.
- // "runServices": [],
-
- // Uncomment the next line if you want to keep your containers running after VS Code shuts down.
- // "shutdownAction": "none",
-
- // Uncomment the next line to run commands after the container is created - for example installing curl.
- // "postCreateCommand": "sudo apt-get update && apt-get install -y git",
-
- // Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root.
- "remoteUser": "ftuser"
}
diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml
deleted file mode 100644
index 20ec247d1..000000000
--- a/.devcontainer/docker-compose.yml
+++ /dev/null
@@ -1,24 +0,0 @@
----
-version: '3'
-services:
- ft_vscode:
- build:
- context: ..
- dockerfile: ".devcontainer/Dockerfile"
- volumes:
- # Allow git usage within container
- - "${HOME}/.ssh:/home/ftuser/.ssh:ro"
- - "${HOME}/.gitconfig:/home/ftuser/.gitconfig:ro"
- - ..:/freqtrade:cached
- # Persist bash-history
- - freqtrade-vscode-server:/home/ftuser/.vscode-server
- - freqtrade-bashhistory:/home/ftuser/commandhistory
- # Expose API port
- ports:
- - "127.0.0.1:8080:8080"
- command: /bin/sh -c "while sleep 1000; do :; done"
-
-
-volumes:
- freqtrade-vscode-server:
- freqtrade-bashhistory:
diff --git a/docs/configuration.md b/docs/configuration.md
index c84a0ac34..e1c7e77d5 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.
@@ -164,7 +165,7 @@ Values set in the configuration file always overwrite values set in the strategy
### Configuring amount per trade
-There are several methods to configure how much of the stake currency the bot will use to enter a trade. All methods respect the [available balance configuration](#available-balance) as explained below.
+There are several methods to configure how much of the stake currency the bot will use to enter a trade. All methods respect the [available balance configuration](#tradable-balance) as explained below.
#### Minimum trade stake
@@ -183,7 +184,7 @@ To limit this calculation in case of large stoploss values, the calculated minim
!!! Warning
Since the limits on exchanges are usually stable and are not updated often, some pairs can show pretty high minimum limits, simply because the price increased a lot since the last limit adjustment by the exchange.
-#### Available balance
+#### Tradable balance
By default, the bot assumes that the `complete amount - 1%` is at it's disposal, and when using [dynamic stake amount](#dynamic-stake-amount), it will split the complete balance into `max_open_trades` buckets per trade.
Freqtrade will reserve 1% for eventual fees when entering a trade and will therefore not touch that by default.
@@ -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/setup.sh b/setup.sh
index 631c31df2..3bcbfc48d 100755
--- a/setup.sh
+++ b/setup.sh
@@ -17,35 +17,20 @@ function check_installed_python() {
exit 2
fi
- which python3.8
- if [ $? -eq 0 ]; then
- echo "using Python 3.8"
- PYTHON=python3.8
- check_installed_pip
- return
- fi
+ for v in 8 9 7
+ do
+ PYTHON="python3.${v}"
+ which $PYTHON
+ if [ $? -eq 0 ]; then
+ echo "using ${PYTHON}"
- which python3.9
- if [ $? -eq 0 ]; then
- echo "using Python 3.9"
- PYTHON=python3.9
- check_installed_pip
- return
- fi
+ check_installed_pip
+ return
+ fi
+ done
- which python3.7
- if [ $? -eq 0 ]; then
- echo "using Python 3.7"
- PYTHON=python3.7
- check_installed_pip
- return
- fi
-
-
- if [ -z ${PYTHON} ]; then
- echo "No usable python found. Please make sure to have python3.7 or newer installed"
- exit 1
- fi
+ echo "No usable python found. Please make sure to have python3.7 or newer installed"
+ exit 1
}
function updateenv() {
@@ -122,6 +107,25 @@ function install_talib() {
cd ..
}
+function install_mac_newer_python_dependencies() {
+
+ if [ ! $(brew --prefix --installed hdf5 2>/dev/null) ]
+ then
+ echo "-------------------------"
+ echo "Installing hdf5"
+ echo "-------------------------"
+ brew install hdf5
+ fi
+
+ if [ ! $(brew --prefix --installed c-blosc 2>/dev/null) ]
+ then
+ echo "-------------------------"
+ echo "Installing c-blosc"
+ echo "-------------------------"
+ brew install c-blosc
+ fi
+}
+
# Install bot MacOS
function install_macos() {
if [ ! -x "$(command -v brew)" ]
@@ -131,8 +135,13 @@ function install_macos() {
echo "-------------------------"
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
fi
+ #Gets number after decimal in python version
+ version=$(egrep -o 3.\[0-9\]+ <<< $PYTHON | sed 's/3.//g' )
+
+ if [[ $version -ge 9 ]]; then #Checks if python version >= 3.9
+ install_mac_newer_python_dependencies
+ fi
install_talib
- test_and_fix_python_on_mac
}
# Install bot Debian_ubuntu
@@ -189,19 +198,6 @@ function reset() {
updateenv
}
-function test_and_fix_python_on_mac() {
-
- if ! [ -x "$(command -v python3.6)" ]
- then
- echo "-------------------------"
- echo "Fixing Python"
- echo "-------------------------"
- echo "Python 3.6 is not linked in your system. Fixing it..."
- brew link --overwrite python
- echo
- fi
-}
-
function config() {
echo "-------------------------"
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)