From 93c1dff71bbae773b922794f956013e0d0b9c908 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 2 Sep 2021 20:43:07 +0200 Subject: [PATCH 01/24] Allow adding new additional headers --- freqtrade/exchange/exchange.py | 9 ++++++++- tests/exchange/test_exchange.py | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index ecf3302d8..3dc295563 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -54,6 +54,9 @@ class Exchange: # Parameters to add directly to buy/sell calls (like agreeing to trading agreement) _params: Dict = {} + # Additional headers - added to the ccxt object + _headers: Dict = {} + # Dict to specify which options each exchange implements # This defines defaults, which can be selectively overridden by subclasses using _ft_has # or by specifying them in the configuration. @@ -169,7 +172,7 @@ class Exchange: asyncio.get_event_loop().run_until_complete(self._api_async.close()) def _init_ccxt(self, exchange_config: Dict[str, Any], ccxt_module: CcxtModuleType = ccxt, - ccxt_kwargs: dict = None) -> ccxt.Exchange: + ccxt_kwargs: Dict = {}) -> ccxt.Exchange: """ Initialize ccxt with given config and return valid ccxt instance. @@ -188,6 +191,10 @@ class Exchange: } if ccxt_kwargs: logger.info('Applying additional ccxt config: %s', ccxt_kwargs) + if self._headers: + # Inject static headers after the above output to not confuse users. + ccxt_kwargs = deep_merge_dicts({'headers': self._headers}, ccxt_kwargs) + if ccxt_kwargs: ex_config.update(ccxt_kwargs) try: diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 42da5dddc..144063c07 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -108,6 +108,13 @@ def test_init_ccxt_kwargs(default_conf, mocker, caplog): assert hasattr(ex._api_async, 'TestKWARG') assert log_has("Applying additional ccxt config: {'TestKWARG': 11, 'TestKWARG44': 11}", caplog) assert log_has(asynclogmsg, caplog) + # Test additional headers case + Exchange._headers = {'hello': 'world'} + ex = Exchange(conf) + + assert log_has("Applying additional ccxt config: {'TestKWARG': 11, 'TestKWARG44': 11}", caplog) + assert ex._api.headers == {'hello': 'world'} + Exchange._headers = {} def test_destroy(default_conf, mocker, caplog): From 19ad1654836992365af7536189095662205d768a Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Sep 2021 08:48:53 +0200 Subject: [PATCH 02/24] Add time_in_force for kucoin --- docs/configuration.md | 4 ++-- docs/exchanges.md | 5 +++++ freqtrade/exchange/binance.py | 1 + freqtrade/exchange/exchange.py | 4 +++- freqtrade/exchange/kucoin.py | 2 ++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 09198e019..6ccea4c73 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -444,8 +444,8 @@ The possible values are: `gtc` (default), `fok` or `ioc`. ``` !!! Warning - This is ongoing work. For now, it is supported only for binance. - Please don't change the default value unless you know what you are doing and have researched the impact of using different values. + This is ongoing work. For now, it is supported only for binance and kucoin. + Please don't change the default value unless you know what you are doing and have researched the impact of using different values for your particular exchange. ### Exchange configuration diff --git a/docs/exchanges.md b/docs/exchanges.md index 5f54a524e..81ad670a3 100644 --- a/docs/exchanges.md +++ b/docs/exchanges.md @@ -4,6 +4,9 @@ This page combines common gotchas and informations which are exchange-specific a ## Binance +Binance supports [time_in_force](configuration.md#understand-order_time_in_force). + + !!! Tip "Stoploss on Exchange" Binance supports `stoploss_on_exchange` and uses stop-loss-limit orders. It provides great advantages, so we recommend to benefit from it. @@ -115,6 +118,8 @@ Kucoin requires a passphrase for each api key, you will therefore need to add th "password": "your_exchange_api_key_password", ``` +Kucoin supports [time_in_force](configuration.md#understand-order_time_in_force). + ### Kucoin Blacklists For Kucoin, please add `"KCS/"` to your blacklist to avoid issues. diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 0c470cb24..189f5f481 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -18,6 +18,7 @@ class Binance(Exchange): _ft_has: Dict = { "stoploss_on_exchange": True, "order_time_in_force": ['gtc', 'fok', 'ioc'], + "time_in_force_parameter": "timeInForce", "ohlcv_candle_limit": 1000, "trades_pagination": "id", "trades_pagination_arg": "fromId", diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 3dc295563..80f20b17e 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -63,6 +63,7 @@ class Exchange: _ft_has_default: Dict = { "stoploss_on_exchange": False, "order_time_in_force": ["gtc"], + "time_in_force_parameter": "timeInForce", "ohlcv_params": {}, "ohlcv_candle_limit": 500, "ohlcv_partial_candle": True, @@ -723,7 +724,8 @@ class Exchange: params = self._params.copy() if time_in_force != 'gtc' and ordertype != 'market': - params.update({'timeInForce': time_in_force}) + param = self._ft_has.get('time_in_force_parameter', '') + params.update({param: time_in_force}) try: # Set the precision for amount and price(rate) as accepted by the exchange diff --git a/freqtrade/exchange/kucoin.py b/freqtrade/exchange/kucoin.py index 22886a1d8..5d818f6a2 100644 --- a/freqtrade/exchange/kucoin.py +++ b/freqtrade/exchange/kucoin.py @@ -21,4 +21,6 @@ class Kucoin(Exchange): _ft_has: Dict = { "l2_limit_range": [20, 100], "l2_limit_range_required": False, + "order_time_in_force": ['gtc', 'fok', 'ioc'], + "time_in_force_parameter": "timeInForce", } From e64ccd8fc111e6d5eeeb193509317f0be00f1d80 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Sep 2021 08:54:15 +0200 Subject: [PATCH 03/24] Add new_config section for kucoin --- freqtrade/commands/build_config_commands.py | 8 ++++++++ .../templates/subtemplates/exchange_kucoin.j2 | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 freqtrade/templates/subtemplates/exchange_kucoin.j2 diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index 1fe90e83a..780ad4161 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -105,6 +105,8 @@ def ask_user_config() -> Dict[str, Any]: "bittrex", "kraken", "ftx", + "kucoin", + "gateio", Separator(), "other", ], @@ -128,6 +130,12 @@ def ask_user_config() -> Dict[str, Any]: "message": "Insert Exchange Secret", "when": lambda x: not x['dry_run'] }, + { + "type": "password", + "name": "exchange_key_password", + "message": "Insert Exchange API Key password", + "when": lambda x: not x['dry_run'] and x['exchange_name'] == 'kucoin' + }, { "type": "confirm", "name": "telegram", diff --git a/freqtrade/templates/subtemplates/exchange_kucoin.j2 b/freqtrade/templates/subtemplates/exchange_kucoin.j2 new file mode 100644 index 000000000..f9dfff663 --- /dev/null +++ b/freqtrade/templates/subtemplates/exchange_kucoin.j2 @@ -0,0 +1,18 @@ +"exchange": { + "name": "{{ exchange_name | lower }}", + "key": "{{ exchange_key }}", + "secret": "{{ exchange_secret }}", + "password": "{{ exchange_key_password }}", + "ccxt_config": { + "enableRateLimit": true + "rateLimit": 200 + }, + "ccxt_async_config": { + "enableRateLimit": true, + "rateLimit": 200 + }, + "pair_whitelist": [ + ], + "pair_blacklist": [ + ] +} From 68f13173bcaf4d88c2835abc66f9d0b92bf7ce7e Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Sep 2021 08:59:08 +0200 Subject: [PATCH 04/24] Update new-config templates to use USDT by default --- freqtrade/commands/build_config_commands.py | 4 ++-- .../subtemplates/exchange_binance.j2 | 15 ------------- .../subtemplates/exchange_bittrex.j2 | 10 --------- .../templates/subtemplates/exchange_kraken.j2 | 22 ++----------------- 4 files changed, 4 insertions(+), 47 deletions(-) diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index 780ad4161..faa8a98f4 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -61,13 +61,13 @@ def ask_user_config() -> Dict[str, Any]: "type": "text", "name": "stake_currency", "message": "Please insert your stake currency:", - "default": 'BTC', + "default": 'USDT', }, { "type": "text", "name": "stake_amount", "message": f"Please insert your stake amount (Number or '{UNLIMITED_STAKE_AMOUNT}'):", - "default": "0.01", + "default": "100", "validate": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_float(val), "filter": lambda val: '"' + UNLIMITED_STAKE_AMOUNT + '"' if val == UNLIMITED_STAKE_AMOUNT diff --git a/freqtrade/templates/subtemplates/exchange_binance.j2 b/freqtrade/templates/subtemplates/exchange_binance.j2 index 38ba4fa5c..217002a7c 100644 --- a/freqtrade/templates/subtemplates/exchange_binance.j2 +++ b/freqtrade/templates/subtemplates/exchange_binance.j2 @@ -8,21 +8,6 @@ "rateLimit": 200 }, "pair_whitelist": [ - "ALGO/BTC", - "ATOM/BTC", - "BAT/BTC", - "BCH/BTC", - "BRD/BTC", - "EOS/BTC", - "ETH/BTC", - "IOTA/BTC", - "LINK/BTC", - "LTC/BTC", - "NEO/BTC", - "NXS/BTC", - "XMR/BTC", - "XRP/BTC", - "XTZ/BTC" ], "pair_blacklist": [ "BNB/BTC", diff --git a/freqtrade/templates/subtemplates/exchange_bittrex.j2 b/freqtrade/templates/subtemplates/exchange_bittrex.j2 index 7b27318ca..0394790ce 100644 --- a/freqtrade/templates/subtemplates/exchange_bittrex.j2 +++ b/freqtrade/templates/subtemplates/exchange_bittrex.j2 @@ -15,16 +15,6 @@ "rateLimit": 500 }, "pair_whitelist": [ - "ETH/BTC", - "LTC/BTC", - "ETC/BTC", - "DASH/BTC", - "ZEC/BTC", - "XLM/BTC", - "XRP/BTC", - "TRX/BTC", - "ADA/BTC", - "XMR/BTC" ], "pair_blacklist": [ ] diff --git a/freqtrade/templates/subtemplates/exchange_kraken.j2 b/freqtrade/templates/subtemplates/exchange_kraken.j2 index 7139a0830..4d0e4c1ff 100644 --- a/freqtrade/templates/subtemplates/exchange_kraken.j2 +++ b/freqtrade/templates/subtemplates/exchange_kraken.j2 @@ -7,28 +7,10 @@ "ccxt_async_config": { "enableRateLimit": true, "rateLimit": 1000 + // Enable the below for downoading data. + //"rateLimit": 3100 }, "pair_whitelist": [ - "ADA/EUR", - "ATOM/EUR", - "BAT/EUR", - "BCH/EUR", - "BTC/EUR", - "DAI/EUR", - "DASH/EUR", - "EOS/EUR", - "ETC/EUR", - "ETH/EUR", - "LINK/EUR", - "LTC/EUR", - "QTUM/EUR", - "REP/EUR", - "WAVES/EUR", - "XLM/EUR", - "XMR/EUR", - "XRP/EUR", - "XTZ/EUR", - "ZEC/EUR" ], "pair_blacklist": [ From c489e6825c3cc0affeb46e2a2f1f78d119e933f5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Sep 2021 09:18:15 +0200 Subject: [PATCH 05/24] Simplify binance blacklist --- .../templates/subtemplates/exchange_binance.j2 | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/freqtrade/templates/subtemplates/exchange_binance.j2 b/freqtrade/templates/subtemplates/exchange_binance.j2 index 217002a7c..3022464c7 100644 --- a/freqtrade/templates/subtemplates/exchange_binance.j2 +++ b/freqtrade/templates/subtemplates/exchange_binance.j2 @@ -10,17 +10,6 @@ "pair_whitelist": [ ], "pair_blacklist": [ - "BNB/BTC", - "BNB/BUSD", - "BNB/ETH", - "BNB/EUR", - "BNB/NGN", - "BNB/PAX", - "BNB/RUB", - "BNB/TRY", - "BNB/TUSD", - "BNB/USDC", - "BNB/USDS", - "BNB/USDT" + "BNB/.*", ] } From b4130dfabbdd0a68119080f33c990b34d4116d77 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Sep 2021 09:23:26 +0200 Subject: [PATCH 06/24] Use volumePairlist instead of staticPairlist in generated config --- freqtrade/templates/base_config.json.j2 | 9 ++++++++- freqtrade/templates/subtemplates/exchange_binance.j2 | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/freqtrade/templates/base_config.json.j2 b/freqtrade/templates/base_config.json.j2 index a5782f7cd..68eebdbd4 100644 --- a/freqtrade/templates/base_config.json.j2 +++ b/freqtrade/templates/base_config.json.j2 @@ -1,3 +1,10 @@ +{%set volume_pairlist = '{ + "method": "VolumePairList", + "number_assets": 20, + "sort_key": "quoteVolume", + "min_value": 0, + "refresh_period": 1800 + }' %} { "max_open_trades": {{ max_open_trades }}, "stake_currency": "{{ stake_currency }}", @@ -29,7 +36,7 @@ }, {{ exchange | indent(4) }}, "pairlists": [ - {"method": "StaticPairList"} + {{ '{"method": "StaticPairList"}' if exchange_name == 'bittrex' else volume_pairlist }} ], "edge": { "enabled": false, diff --git a/freqtrade/templates/subtemplates/exchange_binance.j2 b/freqtrade/templates/subtemplates/exchange_binance.j2 index 3022464c7..de58b6f72 100644 --- a/freqtrade/templates/subtemplates/exchange_binance.j2 +++ b/freqtrade/templates/subtemplates/exchange_binance.j2 @@ -10,6 +10,6 @@ "pair_whitelist": [ ], "pair_blacklist": [ - "BNB/.*", + "BNB/.*" ] } From 2f92838c39639e4770b95258ca0357d4e69c7d40 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Sep 2021 16:18:47 +0200 Subject: [PATCH 07/24] Properly close parenteses in exchange doc --- docs/exchanges.md | 5 ++++- mkdocs.yml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/exchanges.md b/docs/exchanges.md index 81ad670a3..42a850acd 100644 --- a/docs/exchanges.md +++ b/docs/exchanges.md @@ -6,7 +6,6 @@ This page combines common gotchas and informations which are exchange-specific a Binance supports [time_in_force](configuration.md#understand-order_time_in_force). - !!! Tip "Stoploss on Exchange" Binance supports `stoploss_on_exchange` and uses stop-loss-limit orders. It provides great advantages, so we recommend to benefit from it. @@ -116,6 +115,8 @@ Kucoin requires a passphrase for each api key, you will therefore need to add th "key": "your_exchange_key", "secret": "your_exchange_secret", "password": "your_exchange_api_key_password", + // ... +} ``` Kucoin supports [time_in_force](configuration.md#understand-order_time_in_force). @@ -163,6 +164,8 @@ For example, to test the order type `FOK` with Kraken, and modify candle limit t "order_time_in_force": ["gtc", "fok"], "ohlcv_candle_limit": 200 } + //... +} ``` !!! Warning diff --git a/mkdocs.yml b/mkdocs.yml index 854939ca0..05156168f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -23,10 +23,10 @@ nav: - Hyperopt: hyperopt.md - Utility Sub-commands: utils.md - Plotting: plotting.md + - Exchange-specific Notes: exchanges.md - Data Analysis: - Jupyter Notebooks: data-analysis.md - Strategy analysis: strategy_analysis_example.md - - Exchange-specific Notes: exchanges.md - Advanced Topics: - Advanced Post-installation Tasks: advanced-setup.md - Edge Positioning: edge.md From 103a8e827ea7e280b93d806d355ca1157ed55692 Mon Sep 17 00:00:00 2001 From: Rikj000 Date: Fri, 3 Sep 2021 16:37:36 +0200 Subject: [PATCH 08/24] =?UTF-8?q?=E2=9A=A1=20`setup.sh`=20-=20Use=20`build?= =?UTF-8?q?=5Fhelpers/install=5Fta-lib.sh`=20for=20TA-Lib=20installation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build_helpers/install_ta-lib.sh | 2 +- setup.sh | 14 +------------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/build_helpers/install_ta-lib.sh b/build_helpers/install_ta-lib.sh index dd87cf105..590b7d961 100755 --- a/build_helpers/install_ta-lib.sh +++ b/build_helpers/install_ta-lib.sh @@ -13,7 +13,7 @@ if [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then && ./configure --prefix=${INSTALL_LOC}/ \ && make -j$(nproc) \ && which sudo && sudo make install || make install \ - && cd .. + && cd .. && rm -rf ./ta-lib/ else echo "TA-lib already installed, skipping installation" fi diff --git a/setup.sh b/setup.sh index e5f81578d..217500569 100755 --- a/setup.sh +++ b/setup.sh @@ -95,19 +95,7 @@ function install_talib() { return fi - cd build_helpers - tar zxvf ta-lib-0.4.0-src.tar.gz - cd ta-lib - sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h - ./configure --prefix=/usr/local - make - sudo make install - if [ -x "$(command -v apt-get)" ]; then - echo "Updating library path using ldconfig" - sudo ldconfig - fi - cd .. && rm -rf ./ta-lib/ - cd .. + cd build_helpers && ./install_ta-lib.sh && cd .. } function install_mac_newer_python_dependencies() { From 493fb3507316296f90f6c6384a1e84d366b82efa Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Sep 2021 22:05:40 +0200 Subject: [PATCH 09/24] Fix uvicorn not working properly on windows --- freqtrade/rpc/api_server/uvicorn_threaded.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server/uvicorn_threaded.py b/freqtrade/rpc/api_server/uvicorn_threaded.py index b63999f51..79af659c7 100644 --- a/freqtrade/rpc/api_server/uvicorn_threaded.py +++ b/freqtrade/rpc/api_server/uvicorn_threaded.py @@ -5,6 +5,20 @@ import time import uvicorn +def asyncio_setup() -> None: # pragma: no cover + # Set eventloop for win32 setups + # Reverts a change done in uvicorn 0.15.0 - which now sets the eventloop + # via policy. + import sys + + if sys.version_info >= (3, 8) and sys.platform == "win32": + import asyncio + import selectors + selector = selectors.SelectSelector() + loop = asyncio.SelectorEventLoop(selector) + asyncio.set_event_loop(loop) + + class UvicornServer(uvicorn.Server): """ Multithreaded server - as found in https://github.com/encode/uvicorn/issues/742 @@ -28,7 +42,7 @@ class UvicornServer(uvicorn.Server): try: import uvloop # noqa except ImportError: # pragma: no cover - from uvicorn.loops.asyncio import asyncio_setup + asyncio_setup() else: asyncio.set_event_loop(uvloop.new_event_loop()) From eb0362c29ef7f125db4fda5590485c4c9f002f7b Mon Sep 17 00:00:00 2001 From: Rik Helsen Date: Fri, 3 Sep 2021 23:52:40 +0200 Subject: [PATCH 10/24] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20=EF=B8=8F`install=5F?= =?UTF-8?q?ta-lib.sh`=20-=20Run=20`ldconfig`=20after=20`make=20install`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build_helpers/install_ta-lib.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/build_helpers/install_ta-lib.sh b/build_helpers/install_ta-lib.sh index 590b7d961..d12b16364 100755 --- a/build_helpers/install_ta-lib.sh +++ b/build_helpers/install_ta-lib.sh @@ -12,9 +12,12 @@ if [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then && curl 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD' -o config.sub \ && ./configure --prefix=${INSTALL_LOC}/ \ && make -j$(nproc) \ - && which sudo && sudo make install || make install \ - && cd .. && rm -rf ./ta-lib/ + && which sudo && sudo make install || make install + if [ -x "$(command -v apt-get)" ]; then + echo "Updating library path using ldconfig" + sudo ldconfig + fi + cd .. && rm -rf ./ta-lib/ else echo "TA-lib already installed, skipping installation" fi -# && sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h \ From 4e049f65f227c7e2bf103db5cd9f97988c7a2250 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 5 Sep 2021 09:14:44 +0200 Subject: [PATCH 11/24] Exclude some parts from coverage that can't really be tested --- freqtrade/__init__.py | 2 +- freqtrade/loggers.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/__init__.py b/freqtrade/__init__.py index e96e7f530..2747efc96 100644 --- a/freqtrade/__init__.py +++ b/freqtrade/__init__.py @@ -22,7 +22,7 @@ if __version__ == 'develop': # subprocess.check_output( # ['git', 'log', '--format="%h"', '-n 1'], # stderr=subprocess.DEVNULL).decode("utf-8").rstrip().strip('"') - except Exception: + except Exception: # pragma: no cover # git not available, ignore try: # Try Fallback to freqtrade_commit file (created by CI while building docker image) diff --git a/freqtrade/loggers.py b/freqtrade/loggers.py index fbb05d879..5c5831695 100644 --- a/freqtrade/loggers.py +++ b/freqtrade/loggers.py @@ -87,7 +87,7 @@ def setup_logging(config: Dict[str, Any]) -> None: # syslog config. The messages should be equal for this. handler_sl.setFormatter(Formatter('%(name)s - %(levelname)s - %(message)s')) logging.root.addHandler(handler_sl) - elif s[0] == 'journald': + elif s[0] == 'journald': # pragma: no cover try: from systemd.journal import JournaldLogHandler except ImportError: From 2173ff0133db834cbda72a2d35fa6a07e5d574b9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 5 Sep 2021 09:16:19 +0200 Subject: [PATCH 12/24] Update PR template to not link to issues in changelog --- .github/PULL_REQUEST_TEMPLATE.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 20ef27f0f..7c0655b20 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -2,14 +2,16 @@ Thank you for sending your pull request. But first, have you included unit tests, and is your code PEP8 conformant? [More details](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md) ## Summary + Explain in one sentence the goal of this PR Solve the issue: #___ ## Quick changelog -- -- +- +- ## What's new? + *Explain in details what this PR solve or improve. You can include visuals.* From a8f28ffb11a48ce1a8bbb26b209bfd9fa34705d0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 5 Sep 2021 15:34:57 +0200 Subject: [PATCH 13/24] Increase test coverage --- tests/strategy/test_interface.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 128599668..250dcf63d 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -735,11 +735,16 @@ def test_auto_hyperopt_interface(default_conf): PairLocks.timeframe = default_conf['timeframe'] strategy = StrategyResolver.load_strategy(default_conf) + with pytest.raises(OperationalException): + next(strategy.enumerate_parameters('deadBeef')) + assert strategy.buy_rsi.value == strategy.buy_params['buy_rsi'] # PlusDI is NOT in the buy-params, so default should be used assert strategy.buy_plusdi.value == 0.5 assert strategy.sell_rsi.value == strategy.sell_params['sell_rsi'] + assert repr(strategy.sell_rsi) == 'IntParameter(74)' + # Parameter is disabled - so value from sell_param dict will NOT be used. assert strategy.sell_minusdi.value == 0.5 all_params = strategy.detect_all_parameters() From c519ecf8df2fae0e8d789c5abacb6662620d73e7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 5 Sep 2021 15:40:21 +0200 Subject: [PATCH 14/24] Exclude more untestable sections from coverage --- freqtrade/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/main.py b/freqtrade/main.py index 2fd3d32bb..6593fbcb6 100755 --- a/freqtrade/main.py +++ b/freqtrade/main.py @@ -9,7 +9,7 @@ from typing import Any, List # check min. python version -if sys.version_info < (3, 7): +if sys.version_info < (3, 7): # pragma: no cover sys.exit("Freqtrade requires Python version >= 3.7") from freqtrade.commands import Arguments @@ -46,7 +46,7 @@ def main(sysargv: List[str] = None) -> None: "`freqtrade --help` or `freqtrade --help`." ) - except SystemExit as e: + except SystemExit as e: # pragma: no cover return_code = e except KeyboardInterrupt: logger.info('SIGINT received, aborting ...') @@ -60,5 +60,5 @@ def main(sysargv: List[str] = None) -> None: sys.exit(return_code) -if __name__ == '__main__': +if __name__ == '__main__': # pragma: no cover main() From 1d24d3d5ee68624f2706e2a45ea939c87fa0b3ab Mon Sep 17 00:00:00 2001 From: lenik terenin Date: Sun, 5 Sep 2021 22:41:58 +0900 Subject: [PATCH 15/24] case insensitive blacklist Allow "btc/usdt" pairs in blacklist to match to "BTC/USDT" pairs that come from the exchange. --- freqtrade/plugins/pairlist/pairlist_helpers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/plugins/pairlist/pairlist_helpers.py b/freqtrade/plugins/pairlist/pairlist_helpers.py index 924bfb293..1de27fcbd 100644 --- a/freqtrade/plugins/pairlist/pairlist_helpers.py +++ b/freqtrade/plugins/pairlist/pairlist_helpers.py @@ -17,7 +17,7 @@ def expand_pairlist(wildcardpl: List[str], available_pairs: List[str], if keep_invalid: for pair_wc in wildcardpl: try: - comp = re.compile(pair_wc) + comp = re.compile(pair_wc, re.IGNORECASE) result_partial = [ pair for pair in available_pairs if re.fullmatch(comp, pair) ] @@ -33,7 +33,7 @@ def expand_pairlist(wildcardpl: List[str], available_pairs: List[str], else: for pair_wc in wildcardpl: try: - comp = re.compile(pair_wc) + comp = re.compile(pair_wc, re.IGNORECASE) result += [ pair for pair in available_pairs if re.fullmatch(comp, pair) ] From 4daa4b9e63960da073e8e2d5f7e00906d4117cf5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 03:01:10 +0000 Subject: [PATCH 16/24] Bump pytest from 6.2.4 to 6.2.5 Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.2.4 to 6.2.5. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/6.2.4...6.2.5) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 67ee0035b..34d5607f3 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -8,7 +8,7 @@ flake8==3.9.2 flake8-type-annotations==0.1.0 flake8-tidy-imports==4.4.1 mypy==0.910 -pytest==6.2.4 +pytest==6.2.5 pytest-asyncio==0.15.1 pytest-cov==2.12.1 pytest-mock==3.6.1 From 771193cbe47b0bd812e87662bdc141b911e316a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 03:01:19 +0000 Subject: [PATCH 17/24] Bump plotly from 5.3.0 to 5.3.1 Bumps [plotly](https://github.com/plotly/plotly.py) from 5.3.0 to 5.3.1. - [Release notes](https://github.com/plotly/plotly.py/releases) - [Changelog](https://github.com/plotly/plotly.py/blob/master/CHANGELOG.md) - [Commits](https://github.com/plotly/plotly.py/compare/v5.3.0...v5.3.1) --- updated-dependencies: - dependency-name: plotly dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-plot.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-plot.txt b/requirements-plot.txt index 62836a729..8e17232b0 100644 --- a/requirements-plot.txt +++ b/requirements-plot.txt @@ -1,5 +1,5 @@ # Include all requirements to run the bot. -r requirements.txt -plotly==5.3.0 +plotly==5.3.1 From 44f8d7abf2ba21c3eb0e1c0f5804d8bafb9d2e31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 03:01:23 +0000 Subject: [PATCH 18/24] Bump ccxt from 1.55.56 to 1.55.83 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.55.56 to 1.55.83. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg) - [Commits](https://github.com/ccxt/ccxt/compare/1.55.56...1.55.83) --- updated-dependencies: - dependency-name: ccxt dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f77edddfe..e2bed0f9e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ numpy==1.21.2 pandas==1.3.2 -ccxt==1.55.56 +ccxt==1.55.83 # Pin cryptography for now due to rust build errors with piwheels cryptography==3.4.8 aiohttp==3.7.4.post0 From 765e72715bf739504e53140cd29eb24ef40dda44 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 03:01:28 +0000 Subject: [PATCH 19/24] Bump mkdocs-material from 7.2.5 to 7.2.6 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 7.2.5 to 7.2.6. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/7.2.5...7.2.6) --- updated-dependencies: - dependency-name: mkdocs-material dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index d820c9412..9927740c2 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,4 +1,4 @@ mkdocs==1.2.2 -mkdocs-material==7.2.5 +mkdocs-material==7.2.6 mdx_truly_sane_lists==1.2 pymdown-extensions==8.2 From a04875eb55beab2f9d86534434daf2465b9f0d78 Mon Sep 17 00:00:00 2001 From: EnzovdWetering <36194995+EnzovdWetering@users.noreply.github.com> Date: Mon, 6 Sep 2021 17:53:44 +0200 Subject: [PATCH 20/24] Update edge.md Typo fix --- docs/edge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/edge.md b/docs/edge.md index 237ff36f6..4402d767f 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -3,7 +3,7 @@ The `Edge Positioning` module uses probability to calculate your win rate and risk reward ratio. It will use these statistics to control your strategy trade entry points, position size and, stoploss. !!! Warning - WHen using `Edge positioning` with a dynamic whitelist (VolumePairList), make sure to also use `AgeFilter` and set it to at least `calculate_since_number_of_days` to avoid problems with missing data. + When using `Edge positioning` with a dynamic whitelist (VolumePairList), make sure to also use `AgeFilter` and set it to at least `calculate_since_number_of_days` to avoid problems with missing data. !!! Note `Edge Positioning` only considers *its own* buy/sell/stoploss signals. It ignores the stoploss, trailing stoploss, and ROI settings in the strategy configuration file. From 6bd495a32a58b6da236f53da2d166f683a21cfff Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 6 Sep 2021 19:53:32 +0200 Subject: [PATCH 21/24] Fix 0Exception error happens when wrong stake-currency is selected and /profit is called --- freqtrade/rpc/rpc.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 95a37452b..ca2e84e48 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -403,8 +403,11 @@ class RPC: # 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_closed_ratio_fromstart = 0 + profit_all_ratio_fromstart = 0 + if 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, From 10d0987f49b8179f840895882bccebb732098192 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 6 Sep 2021 19:54:34 +0200 Subject: [PATCH 22/24] Fix docs for custom hyperopt space --- docs/advanced-hyperopt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/advanced-hyperopt.md b/docs/advanced-hyperopt.md index 8f233438b..4a2bafd2e 100644 --- a/docs/advanced-hyperopt.md +++ b/docs/advanced-hyperopt.md @@ -80,7 +80,7 @@ To override a pre-defined space (`roi_space`, `generate_roi_table`, `stoploss_sp class MyAwesomeStrategy(IStrategy): class HyperOpt: # Define a custom stoploss space. - def stoploss_space(self): + def stoploss_space(): return [SKDecimal(-0.05, -0.01, decimals=3, name='stoploss')] ``` From 880474594e5357eea9b47b8d1c8449a968bce4c3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 7 Sep 2021 06:51:31 +0200 Subject: [PATCH 23/24] have ftuser use `/bin/bash` in dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4c4722452..f7e26efe3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ RUN mkdir /freqtrade \ && apt-get update \ && apt-get -y install sudo libatlas3-base curl sqlite3 libhdf5-serial-dev \ && apt-get clean \ - && useradd -u 1000 -G sudo -U -m ftuser \ + && useradd -u 1000 -G sudo -U -m -s /bin/bash ftuser \ && chown ftuser:ftuser /freqtrade \ # Allow sudoers && echo "ftuser ALL=(ALL) NOPASSWD: /bin/chown" >> /etc/sudoers From 79ca6135a2cb599de9fa4fde397226d63dda2832 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Tue, 7 Sep 2021 21:53:38 -0600 Subject: [PATCH 24/24] added caplog clears to freqtradebot tests --- tests/test_freqtradebot.py | 53 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 75b67e59c..ddd031f77 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -107,6 +107,7 @@ def test_order_dict_dry_run(default_conf, mocker, caplog) -> None: freqtrade = FreqtradeBot(conf) assert not freqtrade.strategy.order_types['stoploss_on_exchange'] assert not log_has_re(".*stoploss_on_exchange .* dry-run", caplog) + caplog.clear() def test_order_dict_live(default_conf, mocker, caplog) -> None: @@ -140,6 +141,7 @@ def test_order_dict_live(default_conf, mocker, caplog) -> None: freqtrade = FreqtradeBot(conf) assert not freqtrade.strategy.order_types['stoploss_on_exchange'] assert not log_has_re(".*stoploss_on_exchange .* dry-run", caplog) + caplog.clear() def test_get_trade_stake_amount(default_conf, ticker, mocker) -> None: @@ -415,6 +417,7 @@ def test_create_trade_too_small_stake_amount(default_conf, ticker, limit_buy_ord assert freqtrade.create_trade('ETH/BTC') assert log_has_re(r"Stake amount for pair .* is too small.*", caplog) + caplog.clear() def test_create_trade_zero_stake_amount(default_conf, ticker, limit_buy_order_open, @@ -478,6 +481,7 @@ def test_enter_positions_no_pairs_left(default_conf, ticker, limit_buy_order_ope n = freqtrade.enter_positions() assert n == 0 assert log_has_re(r"No currency pair in active pair whitelist.*", caplog) + caplog.clear() def test_enter_positions_no_pairs_in_whitelist(default_conf, ticker, limit_buy_order, fee, @@ -518,11 +522,13 @@ def test_enter_positions_global_pairlock(default_conf, ticker, limit_buy_order, # 0 trades, but it's not because of pairlock. assert n == 0 assert not log_has_re(message, caplog) + caplog.clear() PairLocks.lock_pair('*', arrow.utcnow().shift(minutes=20).datetime, 'Just because') n = freqtrade.enter_positions() assert n == 0 assert log_has_re(message, caplog) + caplog.clear() def test_create_trade_no_signal(default_conf, fee, mocker) -> None: @@ -1086,6 +1092,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, assert log_has_re(r'STOP_LOSS_LIMIT is hit for Trade\(id=1, .*\)\.', caplog) assert trade.stoploss_order_id is None assert trade.is_open is False + caplog.clear() mocker.patch( 'freqtrade.exchange.Binance.stoploss', @@ -1115,6 +1122,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss) assert freqtrade.handle_stoploss_on_exchange(trade) is False assert stoploss.call_count == 0 + caplog.clear() def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog, @@ -1154,6 +1162,7 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog, assert log_has_re(r'Stoploss order was cancelled, but unable to recreate one.*', caplog) assert trade.stoploss_order_id is None assert trade.is_open is True + caplog.clear() def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee, @@ -1202,6 +1211,7 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee, assert rpc_mock.call_count == 2 assert rpc_mock.call_args_list[1][0][0]['sell_reason'] == SellType.EMERGENCY_SELL.value assert rpc_mock.call_args_list[1][0][0]['order_type'] == 'market' + caplog.clear() def test_create_stoploss_order_insufficient_funds(mocker, default_conf, caplog, fee, @@ -1428,6 +1438,7 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c freqtrade.handle_trailing_stoploss_on_exchange(trade, stoploss_order_hanging) assert cancel_mock.call_count == 1 assert log_has_re(r"Could not create trailing stoploss order for pair ETH/BTC\..*", caplog) + caplog.clear() @pytest.mark.usefixtures("init_persistence") @@ -1662,6 +1673,7 @@ def test_enter_positions(mocker, default_conf, caplog) -> None: assert log_has('Found no buy signals for whitelisted currencies. Trying again...', caplog) # create_trade should be called once for every pair in the whitelist. assert mock_ct.call_count == len(default_conf['exchange']['pair_whitelist']) + caplog.clear() def test_enter_positions_exception(mocker, default_conf, caplog) -> None: @@ -1701,6 +1713,7 @@ def test_exit_positions(mocker, default_conf, limit_buy_order, caplog) -> None: # test amount modified by fee-logic n = freqtrade.exit_positions(trades) assert n == 0 + caplog.clear() def test_exit_positions_exception(mocker, default_conf, limit_buy_order, caplog) -> None: @@ -1721,6 +1734,7 @@ def test_exit_positions_exception(mocker, default_conf, limit_buy_order, caplog) n = freqtrade.exit_positions(trades) assert n == 0 assert log_has('Unable to sell trade ETH/BTC: ', caplog) + caplog.clear() def test_update_trade_state(mocker, default_conf, limit_buy_order, caplog) -> None: @@ -1743,10 +1757,12 @@ def test_update_trade_state(mocker, default_conf, limit_buy_order, caplog) -> No ) assert not freqtrade.update_trade_state(trade, None) assert log_has_re(r'Orderid for trade .* is empty.', caplog) + caplog.clear() # Add datetime explicitly since sqlalchemy defaults apply only once written to database freqtrade.update_trade_state(trade, '123') # Test amount not modified by fee-logic assert not log_has_re(r'Applying fee to .*', caplog) + caplog.clear() assert trade.open_order_id is None assert trade.amount == limit_buy_order['amount'] @@ -1764,6 +1780,7 @@ def test_update_trade_state(mocker, default_conf, limit_buy_order, caplog) -> No freqtrade.update_trade_state(trade, '123') assert log_has_re('Found open order for.*', caplog) + caplog.clear() def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_buy_order, fee, @@ -1814,6 +1831,7 @@ def test_update_trade_state_withorderdict_rounding_fee(default_conf, trades_for_ assert trade.amount != amount assert trade.amount == limit_buy_order['amount'] assert log_has_re(r'Applying fee on amount for .*', caplog) + caplog.clear() def test_update_trade_state_exception(mocker, default_conf, @@ -1832,6 +1850,7 @@ def test_update_trade_state_exception(mocker, default_conf, ) freqtrade.update_trade_state(trade, trade.open_order_id) assert log_has('Could not update trade amount: ', caplog) + caplog.clear() def test_update_trade_state_orderexception(mocker, default_conf, caplog) -> None: @@ -1848,6 +1867,7 @@ def test_update_trade_state_orderexception(mocker, default_conf, caplog) -> None freqtrade.update_trade_state(trade, trade.open_order_id) assert grm_mock.call_count == 0 assert log_has(f'Unable to fetch order {trade.open_order_id}: ', caplog) + caplog.clear() def test_update_trade_state_sell(default_conf, trades_for_order, limit_sell_order_open, @@ -2016,6 +2036,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order_open, assert freqtrade.handle_trade(trade) assert log_has("ETH/BTC - Required profit reached. sell_type=SellType.ROI", caplog) + caplog.clear() def test_handle_trade_use_sell_signal(default_conf, ticker, limit_buy_order_open, @@ -2048,6 +2069,7 @@ def test_handle_trade_use_sell_signal(default_conf, ticker, limit_buy_order_open assert freqtrade.handle_trade(trade) assert log_has("ETH/BTC - Sell signal received. sell_type=SellType.SELL_SIGNAL", caplog) + caplog.clear() def test_close_trade(default_conf, ticker, limit_buy_order, limit_buy_order_open, limit_sell_order, @@ -2088,6 +2110,7 @@ def test_bot_loop_start_called_once(mocker, default_conf, caplog): assert log_has_re(r'Strategy caused the following exception.*', caplog) assert ftbot.strategy.bot_loop_start.call_count == 1 assert ftbot.strategy.analyze.call_count == 1 + caplog.clear() def test_check_handle_timedout_buy_usercustom(default_conf, ticker, limit_buy_order_old, open_trade, @@ -2202,6 +2225,7 @@ def test_check_handle_cancelled_buy(default_conf, ticker, limit_buy_order_old, o nb_trades = len(trades) assert nb_trades == 0 assert log_has_re("Buy order cancelled on exchange for Trade.*", caplog) + caplog.clear() def test_check_handle_timedout_buy_exception(default_conf, ticker, limit_buy_order_old, open_trade, @@ -2336,6 +2360,7 @@ def test_check_handle_cancelled_sell(default_conf, ticker, limit_sell_order_old, assert rpc_mock.call_count == 1 assert open_trade.is_open is True assert log_has_re("Sell order cancelled on exchange for Trade.*", caplog) + caplog.clear() def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old_partial, @@ -2404,6 +2429,7 @@ def test_check_handle_timedout_partial_fee(default_conf, ticker, open_trade, cap assert trades[0].open_order_id is None assert trades[0].fee_updated('buy') assert pytest.approx(trades[0].fee_open) == 0.001 + caplog.clear() def test_check_handle_timedout_partial_except(default_conf, ticker, open_trade, caplog, fee, @@ -2444,6 +2470,7 @@ def test_check_handle_timedout_partial_except(default_conf, ticker, open_trade, limit_buy_order_old_partial['remaining']) assert trades[0].open_order_id is None assert trades[0].fee_open == fee() + caplog.clear() def test_check_handle_timedout_exception(default_conf, ticker, open_trade, mocker, caplog) -> None: @@ -2472,6 +2499,7 @@ def test_check_handle_timedout_exception(default_conf, ticker, open_trade, mocke f"{open_trade.open_date.strftime('%Y-%m-%d %H:%M:%S')}" r"\) due to Traceback \(most recent call last\):\n*", caplog) + caplog.clear() def test_handle_cancel_buy(mocker, caplog, default_conf, limit_buy_order) -> None: @@ -2515,6 +2543,7 @@ def test_handle_cancel_buy(mocker, caplog, default_conf, limit_buy_order) -> Non mocker.patch('freqtrade.exchange.Exchange.cancel_order_with_result', cancel_order_mock) assert not freqtrade.handle_cancel_buy(trade, limit_buy_order, reason) assert log_has_re(r"Order .* for .* not cancelled.", caplog) + caplog.clear() @pytest.mark.parametrize("limit_buy_order_canceled_empty", ['binance', 'ftx', 'kraken', 'bittrex'], @@ -2536,6 +2565,7 @@ def test_handle_cancel_buy_exchanges(mocker, caplog, default_conf, assert cancel_order_mock.call_count == 0 assert log_has_re(r'Buy order fully cancelled. Removing .* from database\.', caplog) assert nofiy_mock.call_count == 1 + caplog.clear() @pytest.mark.parametrize('cancelorder', [ @@ -2905,6 +2935,7 @@ def test_execute_trade_exit_sloe_cancel_exception( sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS)) assert create_order_mock.call_count == 2 assert log_has('Could not cancel stoploss order abcd', caplog) + caplog.clear() def test_execute_trade_exit_with_stoploss_on_exchange(default_conf, ticker, fee, ticker_sell_up, @@ -3300,6 +3331,7 @@ def test_sell_not_enough_balance(default_conf, limit_buy_order, limit_buy_order_ assert freqtrade.handle_trade(trade) is True assert log_has_re(r'.*Falling back to wallet-amount.', caplog) assert trade.amount != amnt + caplog.clear() def test__safe_sell_amount(default_conf, fee, caplog, mocker): @@ -3330,6 +3362,7 @@ def test__safe_sell_amount(default_conf, fee, caplog, mocker): assert freqtrade._safe_sell_amount(trade.pair, amount_wallet) == amount_wallet assert not log_has_re(r'.*Falling back to wallet-amount.', caplog) assert wallet_update.call_count == 1 + caplog.clear() def test__safe_sell_amount_error(default_conf, fee, caplog, mocker): @@ -3386,6 +3419,7 @@ def test_locked_pairs(default_conf, ticker, fee, ticker_sell_down, mocker, caplo freqtrade.enter_positions() assert log_has_re(f"Pair {trade.pair} is still locked.*", caplog) + caplog.clear() def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_buy_order_open, @@ -3477,6 +3511,7 @@ def test_trailing_stop_loss(default_conf, limit_buy_order_open, limit_buy_order, assert log_has("ETH/BTC - HIT STOP: current price at 0.000012, stoploss is 0.000015, " "initial stoploss was at 0.000010, trade opened at 0.000011", caplog) assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value + caplog.clear() def test_trailing_stop_loss_positive(default_conf, limit_buy_order, limit_buy_order_open, fee, @@ -3524,6 +3559,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, limit_buy_or assert log_has("ETH/BTC - Using positive stoploss: 0.01 offset: 0 profit: 0.2666%", caplog) assert log_has("ETH/BTC - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000138501 + caplog.clear() mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ @@ -3537,6 +3573,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, limit_buy_or f"ETH/BTC - HIT STOP: current price at {buy_price + 0.000002:.6f}, " f"stoploss is {trade.stop_loss:.6f}, " f"initial stoploss was at 0.000010, trade opened at 0.000011", caplog) + caplog.clear() def test_trailing_stop_loss_offset(default_conf, limit_buy_order, limit_buy_order_open, fee, @@ -3584,6 +3621,7 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, limit_buy_orde assert log_has("ETH/BTC - Using positive stoploss: 0.01 offset: 0.011 profit: 0.2666%", caplog) assert log_has("ETH/BTC - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000138501 + caplog.clear() mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ @@ -3598,6 +3636,7 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, limit_buy_orde f"stoploss is {trade.stop_loss:.6f}, " f"initial stoploss was at 0.000010, trade opened at 0.000011", caplog) assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value + caplog.clear() def test_tsl_only_offset_reached(default_conf, limit_buy_order, limit_buy_order_open, fee, @@ -3648,6 +3687,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, limit_buy_order_ assert not log_has("ETH/BTC - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000098910 + caplog.clear() # price rises above the offset (rises 12% when the offset is 5.5%) mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', @@ -3661,6 +3701,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, limit_buy_order_ assert log_has("ETH/BTC - Using positive stoploss: 0.05 offset: 0.055 profit: 0.1218%", caplog) assert log_has("ETH/BTC - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000117705 + caplog.clear() def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_buy_order_open, @@ -3722,6 +3763,7 @@ def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, fe assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, ' 'open_rate=0.24544100, open_since=closed) (from 8.0 to 7.992).', caplog) + caplog.clear() def test_get_real_amount_quote_dust(default_conf, trades_for_order, buy_order_fee, fee, @@ -3747,6 +3789,7 @@ def test_get_real_amount_quote_dust(default_conf, trades_for_order, buy_order_fe assert walletmock.call_count == 1 assert log_has_re(r'Fee amount for Trade.* was in base currency ' '- Eating Fee 0.008 into dust', caplog) + caplog.clear() def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, fee): @@ -3769,6 +3812,7 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, f assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, ' 'open_rate=0.24544100, open_since=closed) failed: myTrade-Dict empty found', caplog) + caplog.clear() def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, fee, mocker): @@ -3862,6 +3906,7 @@ def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, c assert trade.fee_open_currency is not None assert trade.fee_close_cost is None assert trade.fee_close_currency is None + caplog.clear() def test_get_real_amount_multi2(default_conf, trades_for_order3, buy_order_fee, caplog, fee, @@ -3897,6 +3942,7 @@ def test_get_real_amount_multi2(default_conf, trades_for_order3, buy_order_fee, assert trade.fee_open_currency is not None assert trade.fee_close_cost is None assert trade.fee_close_currency is None + caplog.clear() def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee, fee, @@ -3925,6 +3971,7 @@ def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, ' 'open_rate=0.24544100, open_since=closed) (from 8.0 to 7.996).', caplog) + caplog.clear() def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order_fee, fee, mocker): @@ -4168,6 +4215,7 @@ def test_order_book_bid_strategy_exception(mocker, default_conf, caplog) -> None with pytest.raises(PricingError): freqtrade.exchange.get_rate('ETH/BTC', refresh=True, side="buy") assert log_has_re(r'Buy Price at location 1 from orderbook could not be determined.', caplog) + caplog.clear() def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2) -> None: @@ -4238,6 +4286,7 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order_open, limit_buy_o freqtrade.handle_trade(trade) assert log_has_re(r'Sell Price at location 1 from orderbook could not be determined\..*', caplog) + caplog.clear() def test_startup_state(default_conf, mocker): @@ -4296,6 +4345,7 @@ def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order_ assert log_has_re(r"Unable to create trade for XRP/BTC: " r"Available balance \(0.0 BTC\) is lower than stake amount \(0.001 BTC\)", caplog) + caplog.clear() @pytest.mark.usefixtures("init_persistence") @@ -4339,6 +4389,7 @@ def test_update_open_orders(mocker, default_conf, fee, caplog): freqtrade.update_open_orders() assert not log_has_re(r"Error updating Order .*", caplog) + caplog.clear() freqtrade.config['dry_run'] = False freqtrade.update_open_orders() @@ -4454,6 +4505,7 @@ def test_reupdate_buy_order_fees(mocker, default_conf, fee, caplog): assert log_has_re(r"Trying to reupdate buy fees for .*", caplog) assert mock_uts.call_count == 0 assert not log_has_re(r"Updating buy-fee on trade .* for order .*\.", caplog) + caplog.clear() @pytest.mark.usefixtures("init_persistence") @@ -4591,6 +4643,7 @@ def test_refind_lost_order(mocker, default_conf, fee, caplog): freqtrade.refind_lost_order(trades[4]) assert log_has(f"Error updating {order['id']}.", caplog) + caplog.clear() def test_get_valid_price(mocker, default_conf) -> None: