From ee209e3b44dc637f9c9f7dbccd90ee37adf953ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 03:56:56 +0000 Subject: [PATCH 01/25] Bump mkdocs-material from 9.0.11 to 9.0.12 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.0.11 to 9.0.12. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.0.11...9.0.12) --- 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 0e3bf898f..8d99e3e58 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,6 +1,6 @@ markdown==3.3.7 mkdocs==1.4.2 -mkdocs-material==9.0.11 +mkdocs-material==9.0.12 mdx_truly_sane_lists==1.3 pymdown-extensions==9.9.2 jinja2==3.1.2 From b05999f6d52c035b1db84ac3b38cfea71e1617c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 03:57:11 +0000 Subject: [PATCH 02/25] Bump orjson from 3.8.5 to 3.8.6 Bumps [orjson](https://github.com/ijl/orjson) from 3.8.5 to 3.8.6. - [Release notes](https://github.com/ijl/orjson/releases) - [Changelog](https://github.com/ijl/orjson/blob/master/CHANGELOG.md) - [Commits](https://github.com/ijl/orjson/compare/3.8.5...3.8.6) --- updated-dependencies: - dependency-name: orjson 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 e3c71965d..1b9d2b70e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -30,7 +30,7 @@ py_find_1st==1.1.5 # Load ticker files 30% faster python-rapidjson==1.9 # Properly format api responses -orjson==3.8.5 +orjson==3.8.6 # Notify systemd sdnotify==0.3.2 From bbb62c8a4b60b18c4314c8d66c8fa7e87f33aaac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 03:57:16 +0000 Subject: [PATCH 03/25] Bump types-requests from 2.28.11.8 to 2.28.11.12 Bumps [types-requests](https://github.com/python/typeshed) from 2.28.11.8 to 2.28.11.12. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-requests 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 3488fdbfd..ee585947a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -28,6 +28,6 @@ nbconvert==7.2.9 # mypy types types-cachetools==5.3.0.0 types-filelock==3.2.7 -types-requests==2.28.11.8 +types-requests==2.28.11.12 types-tabulate==0.9.0.0 types-python-dateutil==2.8.19.6 From 48c331785c30a1b222b327283ca5ed5394432803 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 03:58:34 +0000 Subject: [PATCH 04/25] Bump mypy from 0.991 to 1.0.0 Bumps [mypy](https://github.com/python/mypy) from 0.991 to 1.0.0. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v0.991...v1.0.0) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:development update-type: version-update:semver-major ... 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 3488fdbfd..d1ebf36ce 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -9,7 +9,7 @@ coveralls==3.3.1 flake8==6.0.0 flake8-tidy-imports==4.8.0 -mypy==0.991 +mypy==1.0.0 pre-commit==3.0.4 pytest==7.2.1 pytest-asyncio==0.20.3 From 9faa926803cc8df051f34585dd7f205c2eb07849 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 03:58:55 +0000 Subject: [PATCH 05/25] Bump fastapi from 0.89.1 to 0.91.0 Bumps [fastapi](https://github.com/tiangolo/fastapi) from 0.89.1 to 0.91.0. - [Release notes](https://github.com/tiangolo/fastapi/releases) - [Commits](https://github.com/tiangolo/fastapi/compare/0.89.1...0.91.0) --- updated-dependencies: - dependency-name: fastapi dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index e3c71965d..2d8791018 100644 --- a/requirements.txt +++ b/requirements.txt @@ -36,7 +36,7 @@ orjson==3.8.5 sdnotify==0.3.2 # API Server -fastapi==0.89.1 +fastapi==0.91.0 pydantic==1.10.4 uvicorn==0.20.0 pyjwt==2.6.0 From d14283b0e73106d7095c8ede83e1564823803313 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 13 Feb 2023 06:22:13 +0100 Subject: [PATCH 06/25] types-requests - precommit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d50506650..529140572 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: additional_dependencies: - types-cachetools==5.3.0.0 - types-filelock==3.2.7 - - types-requests==2.28.11.8 + - types-requests==2.28.11.12 - types-tabulate==0.9.0.0 - types-python-dateutil==2.8.19.6 # stages: [push] From 2a87ad044d102f43b76e1b3035591c62e13a7b7b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 06:11:33 +0000 Subject: [PATCH 07/25] Bump tensorboard from 2.11.2 to 2.12.0 Bumps [tensorboard](https://github.com/tensorflow/tensorboard) from 2.11.2 to 2.12.0. - [Release notes](https://github.com/tensorflow/tensorboard/releases) - [Changelog](https://github.com/tensorflow/tensorboard/blob/master/RELEASE.md) - [Commits](https://github.com/tensorflow/tensorboard/compare/2.11.2...2.12.0) --- updated-dependencies: - dependency-name: tensorboard dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-freqai.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-freqai.txt b/requirements-freqai.txt index 914dbb745..cf5bc4c0b 100644 --- a/requirements-freqai.txt +++ b/requirements-freqai.txt @@ -8,4 +8,4 @@ joblib==1.2.0 catboost==1.1.1; platform_machine != 'aarch64' lightgbm==3.3.5 xgboost==1.7.3 -tensorboard==2.11.2 +tensorboard==2.12.0 From 50a9df9b299780bad05f7f4cba36c30fe6466a47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 06:11:37 +0000 Subject: [PATCH 08/25] Bump aiofiles from 22.1.0 to 23.1.0 Bumps [aiofiles](https://github.com/Tinche/aiofiles) from 22.1.0 to 23.1.0. - [Release notes](https://github.com/Tinche/aiofiles/releases) - [Commits](https://github.com/Tinche/aiofiles/compare/v22.1.0...v23.1.0) --- updated-dependencies: - dependency-name: aiofiles dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index dcdb91837..765cb5082 100644 --- a/requirements.txt +++ b/requirements.txt @@ -40,7 +40,7 @@ fastapi==0.91.0 pydantic==1.10.4 uvicorn==0.20.0 pyjwt==2.6.0 -aiofiles==22.1.0 +aiofiles==23.1.0 psutil==5.9.4 # Support for colorized terminal output From f681ee7942f2f2466c6dc9d0ea58e3fd658aaf70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 06:11:49 +0000 Subject: [PATCH 09/25] Bump aiohttp from 3.8.3 to 3.8.4 Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.8.3 to 3.8.4. - [Release notes](https://github.com/aio-libs/aiohttp/releases) - [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst) - [Commits](https://github.com/aio-libs/aiohttp/compare/v3.8.3...v3.8.4) --- updated-dependencies: - dependency-name: aiohttp 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 dcdb91837..50710a1fd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ ccxt==2.7.80 # Pin cryptography for now due to rust build errors with piwheels cryptography==38.0.1; platform_machine == 'armv7l' cryptography==39.0.1; platform_machine != 'armv7l' -aiohttp==3.8.3 +aiohttp==3.8.4 SQLAlchemy==1.4.46 python-telegram-bot==13.15 arrow==1.2.3 From f16fd0ad23959e529beacf2c52a5f12ad9a3faf9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 12 Feb 2023 20:12:06 +0100 Subject: [PATCH 10/25] Reenable binanceus active test --- tests/exchange/test_ccxt_compat.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index 483a3ae06..f1d240f9f 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -534,8 +534,7 @@ class TestCCXTExchange(): def test_ccxt__async_get_candle_history(self, exchange: EXCHANGE_FIXTURE_TYPE): exc, exchangename = exchange - if exchangename in ('binanceus', 'bittrex'): - # TODO: reenable binanceus test once downtime "ages out" (2023-02-06) + if exchangename in ('bittrex'): # For some weired reason, this test returns random lengths for bittrex. pytest.skip("Exchange doesn't provide stable ohlcv history") From f3a68978700755a2e153b319f457b116c9832edd Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 13 Feb 2023 07:12:28 +0100 Subject: [PATCH 11/25] Bump Docker images to latest minor version --- Dockerfile | 2 +- docker/Dockerfile.armhf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index b3e5d5e88..6a4a168c1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.10.7-slim-bullseye as base +FROM python:3.10.10-slim-bullseye as base # Setup env ENV LANG C.UTF-8 diff --git a/docker/Dockerfile.armhf b/docker/Dockerfile.armhf index 7b663ae6c..4972e7109 100644 --- a/docker/Dockerfile.armhf +++ b/docker/Dockerfile.armhf @@ -1,4 +1,4 @@ -FROM python:3.9.12-slim-bullseye as base +FROM python:3.9.16-slim-bullseye as base # Setup env ENV LANG C.UTF-8 From 9061c04f1da0978928b29a526b044f1d2be54c52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 16:09:57 +0000 Subject: [PATCH 12/25] Bump ccxt from 2.7.80 to 2.7.93 Bumps [ccxt](https://github.com/ccxt/ccxt) from 2.7.80 to 2.7.93. - [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/2.7.80...2.7.93) --- 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 994140b8b..38591b6dd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.24.2 pandas==1.5.3 pandas-ta==0.3.14b -ccxt==2.7.80 +ccxt==2.7.93 # Pin cryptography for now due to rust build errors with piwheels cryptography==38.0.1; platform_machine == 'armv7l' cryptography==39.0.1; platform_machine != 'armv7l' From 69d54594602b074be5023b7ea965139d2b544dd2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 13 Feb 2023 18:25:15 +0100 Subject: [PATCH 13/25] Improve stop behavior in SIGTERM cases (docker). --- freqtrade/commands/trade_commands.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/freqtrade/commands/trade_commands.py b/freqtrade/commands/trade_commands.py index 535844844..0707cc803 100644 --- a/freqtrade/commands/trade_commands.py +++ b/freqtrade/commands/trade_commands.py @@ -1,4 +1,5 @@ import logging +import signal from typing import Any, Dict @@ -12,15 +13,20 @@ def start_trading(args: Dict[str, Any]) -> int: # Import here to avoid loading worker module when it's not used from freqtrade.worker import Worker + def term_handler(signum, frame): + # Raise KeyboardInterrupt - so we can handle it in the same way as Ctrl-C + raise KeyboardInterrupt() + # Create and run worker worker = None try: + signal.signal(signal.SIGTERM, term_handler) worker = Worker(args) worker.run() except Exception as e: logger.error(str(e)) logger.exception("Fatal exception!") - except KeyboardInterrupt: + except (KeyboardInterrupt): logger.info('SIGINT received, aborting ...') finally: if worker: From ce7d24f529ab764f71d854f282a8a06b700d4ce2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 13 Feb 2023 19:53:04 +0100 Subject: [PATCH 14/25] Extract ft_stoploss_adjust to seperate method --- freqtrade/strategy/interface.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 70d656199..65d6f9fc3 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -1153,13 +1153,12 @@ class IStrategy(ABC, HyperStrategyMixin): return exits - def stop_loss_reached(self, current_rate: float, trade: Trade, - current_time: datetime, current_profit: float, - force_stoploss: float, low: Optional[float] = None, - high: Optional[float] = None) -> ExitCheckTuple: + def ft_stoploss_adjust(self, current_rate: float, trade: Trade, + current_time: datetime, current_profit: float, + force_stoploss: float, low: Optional[float] = None, + high: Optional[float] = None) -> None: """ - Based on current profit of the trade and configured (trailing) stoploss, - decides to exit or not + Adjust stop-loss dynamically if configured to do so. :param current_profit: current profit as ratio :param low: Low value of this candle, only set in backtesting :param high: High value of this candle, only set in backtesting @@ -1205,6 +1204,20 @@ class IStrategy(ABC, HyperStrategyMixin): trade.adjust_stop_loss(bound or current_rate, stop_loss_value) + def stop_loss_reached(self, current_rate: float, trade: Trade, + current_time: datetime, current_profit: float, + force_stoploss: float, low: Optional[float] = None, + high: Optional[float] = None) -> ExitCheckTuple: + """ + Based on current profit of the trade and configured (trailing) stoploss, + decides to exit or not + :param current_profit: current profit as ratio + :param low: Low value of this candle, only set in backtesting + :param high: High value of this candle, only set in backtesting + """ + self.ft_stoploss_adjust(current_rate, trade, current_time, current_profit, + force_stoploss, low, high) + sl_higher_long = (trade.stop_loss >= (low or current_rate) and not trade.is_short) sl_lower_short = (trade.stop_loss <= (high or current_rate) and trade.is_short) liq_higher_long = (trade.liquidation_price From cdd324d0a9c2a9b66eafa87e0dfb2f23f83095c2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 13 Feb 2023 20:08:54 +0100 Subject: [PATCH 15/25] Rename stoploss_reached to ft_stoploss_reached --- freqtrade/strategy/interface.py | 16 ++++++++-------- tests/strategy/test_interface.py | 20 ++++++++++---------- tests/test_freqtradebot.py | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 65d6f9fc3..1f687c196 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -1083,10 +1083,10 @@ class IStrategy(ABC, HyperStrategyMixin): trade.adjust_min_max_rates(high or current_rate, low or current_rate) - stoplossflag = self.stop_loss_reached(current_rate=current_rate, trade=trade, - current_time=current_time, - current_profit=current_profit, - force_stoploss=force_stoploss, low=low, high=high) + stoplossflag = self.ft_stoploss_reached(current_rate=current_rate, trade=trade, + current_time=current_time, + current_profit=current_profit, + force_stoploss=force_stoploss, low=low, high=high) # Set current rate to high for backtesting exits current_rate = (low if trade.is_short else high) or rate @@ -1204,10 +1204,10 @@ class IStrategy(ABC, HyperStrategyMixin): trade.adjust_stop_loss(bound or current_rate, stop_loss_value) - def stop_loss_reached(self, current_rate: float, trade: Trade, - current_time: datetime, current_profit: float, - force_stoploss: float, low: Optional[float] = None, - high: Optional[float] = None) -> ExitCheckTuple: + def ft_stoploss_reached(self, current_rate: float, trade: Trade, + current_time: datetime, current_profit: float, + force_stoploss: float, low: Optional[float] = None, + high: Optional[float] = None) -> ExitCheckTuple: """ Based on current profit of the trade and configured (trailing) stoploss, decides to exit or not diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 294021c83..fe562907a 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -452,8 +452,8 @@ def test_min_roi_reached3(default_conf, fee) -> None: (0.05, 0.9, ExitType.NONE, None, False, True, 0.09, 0.9, ExitType.NONE, lambda **kwargs: None), ]) -def test_stop_loss_reached(default_conf, fee, profit, adjusted, expected, liq, trailing, custom, - profit2, adjusted2, expected2, custom_stop) -> None: +def test_ft_stoploss_reached(default_conf, fee, profit, adjusted, expected, liq, trailing, custom, + profit2, adjusted2, expected2, custom_stop) -> None: strategy = StrategyResolver.load_strategy(default_conf) trade = Trade( @@ -477,9 +477,9 @@ def test_stop_loss_reached(default_conf, fee, profit, adjusted, expected, liq, t now = arrow.utcnow().datetime current_rate = trade.open_rate * (1 + profit) - sl_flag = strategy.stop_loss_reached(current_rate=current_rate, trade=trade, - current_time=now, current_profit=profit, - force_stoploss=0, high=None) + sl_flag = strategy.ft_stoploss_reached(current_rate=current_rate, trade=trade, + current_time=now, current_profit=profit, + force_stoploss=0, high=None) assert isinstance(sl_flag, ExitCheckTuple) assert sl_flag.exit_type == expected if expected == ExitType.NONE: @@ -489,9 +489,9 @@ def test_stop_loss_reached(default_conf, fee, profit, adjusted, expected, liq, t assert round(trade.stop_loss, 2) == adjusted current_rate2 = trade.open_rate * (1 + profit2) - sl_flag = strategy.stop_loss_reached(current_rate=current_rate2, trade=trade, - current_time=now, current_profit=profit2, - force_stoploss=0, high=None) + sl_flag = strategy.ft_stoploss_reached(current_rate=current_rate2, trade=trade, + current_time=now, current_profit=profit2, + force_stoploss=0, high=None) assert sl_flag.exit_type == expected2 if expected2 == ExitType.NONE: assert sl_flag.exit_flag is False @@ -579,7 +579,7 @@ def test_should_sell(default_conf, fee) -> None: assert res == [ExitCheckTuple(exit_type=ExitType.ROI)] strategy.min_roi_reached = MagicMock(return_value=True) - strategy.stop_loss_reached = MagicMock( + strategy.ft_stoploss_reached = MagicMock( return_value=ExitCheckTuple(exit_type=ExitType.STOP_LOSS)) res = strategy.should_exit(trade, 1, now, @@ -603,7 +603,7 @@ def test_should_sell(default_conf, fee) -> None: ExitCheckTuple(exit_type=ExitType.ROI), ] - strategy.stop_loss_reached = MagicMock( + strategy.ft_stoploss_reached = MagicMock( return_value=ExitCheckTuple(exit_type=ExitType.TRAILING_STOP_LOSS)) # Regular exit signal res = strategy.should_exit(trade, 1, now, diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 5e580e4fa..9e8353a4b 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3902,7 +3902,7 @@ def test_exit_profit_only( if exit_type == ExitType.EXIT_SIGNAL.value: freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) else: - freqtrade.strategy.stop_loss_reached = MagicMock(return_value=ExitCheckTuple( + freqtrade.strategy.ft_stoploss_reached = MagicMock(return_value=ExitCheckTuple( exit_type=ExitType.NONE)) freqtrade.enter_positions() From bddec476f9e40839b3eec65e23fbe45706293a76 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 13 Feb 2023 20:13:26 +0100 Subject: [PATCH 16/25] Fix missing typehint in hyper.py --- freqtrade/strategy/hyper.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/strategy/hyper.py b/freqtrade/strategy/hyper.py index 2be1d7e86..52ba22951 100644 --- a/freqtrade/strategy/hyper.py +++ b/freqtrade/strategy/hyper.py @@ -163,7 +163,7 @@ class HyperStrategyMixin: else: logger.info(f'Strategy Parameter(default): {attr_name} = {attr.value}') - def get_no_optimize_params(self): + def get_no_optimize_params(self) -> Dict[str, Dict]: """ Returns list of Parameters that are not part of the current optimize job """ @@ -173,7 +173,7 @@ class HyperStrategyMixin: 'protection': {}, } for name, p in self.enumerate_parameters(): - if not p.optimize or not p.in_space: + if p.category and (not p.optimize or not p.in_space): params[p.category][name] = p.value return params From 6e55a873b3de8bdb9b4d3c240d945d98cb205339 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 14 Feb 2023 07:18:11 +0100 Subject: [PATCH 17/25] Rename edge.stoploss to get_stoploss this will make it clear that it's different from --- freqtrade/edge/edge_positioning.py | 4 ++-- freqtrade/freqtradebot.py | 4 ++-- tests/edge/test_edge.py | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/freqtrade/edge/edge_positioning.py b/freqtrade/edge/edge_positioning.py index 4656b7c93..73820ecbe 100644 --- a/freqtrade/edge/edge_positioning.py +++ b/freqtrade/edge/edge_positioning.py @@ -195,7 +195,7 @@ class Edge: def stake_amount(self, pair: str, free_capital: float, total_capital: float, capital_in_trade: float) -> float: - stoploss = self.stoploss(pair) + stoploss = self.get_stoploss(pair) available_capital = (total_capital + capital_in_trade) * self._capital_ratio allowed_capital_at_risk = available_capital * self._allowed_risk max_position_size = abs(allowed_capital_at_risk / stoploss) @@ -214,7 +214,7 @@ class Edge: ) return round(position_size, 15) - def stoploss(self, pair: str) -> float: + def get_stoploss(self, pair: str) -> float: if pair in self._cached_pairs: return self._cached_pairs[pair].stoploss else: diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 0db420758..c15ff42fc 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1078,7 +1078,7 @@ class FreqtradeBot(LoggingMixin): datetime.now(timezone.utc), enter=enter, exit_=exit_, - force_stoploss=self.edge.stoploss(trade.pair) if self.edge else 0 + force_stoploss=self.edge.get_stoploss(trade.pair) if self.edge else 0 ) for should_exit in exits: if should_exit.exit_flag: @@ -1172,7 +1172,7 @@ class FreqtradeBot(LoggingMixin): if not stoploss_order: stop_price = trade.stoploss_or_liquidation if self.edge: - stoploss = self.edge.stoploss(pair=trade.pair) + stoploss = self.edge.get_stoploss(pair=trade.pair) stop_price = ( trade.open_rate * (1 - stoploss) if trade.is_short else trade.open_rate * (1 + stoploss) diff --git a/tests/edge/test_edge.py b/tests/edge/test_edge.py index 1b0191fda..e414d7624 100644 --- a/tests/edge/test_edge.py +++ b/tests/edge/test_edge.py @@ -139,7 +139,7 @@ def test_adjust(mocker, edge_conf): assert (edge.adjust(pairs) == ['E/F', 'C/D']) -def test_stoploss(mocker, edge_conf): +def test_edge_get_stoploss(mocker, edge_conf): freqtrade = get_patched_freqtradebot(mocker, edge_conf) edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock( @@ -150,10 +150,10 @@ def test_stoploss(mocker, edge_conf): } )) - assert edge.stoploss('E/F') == -0.01 + assert edge.get_stoploss('E/F') == -0.01 -def test_nonexisting_stoploss(mocker, edge_conf): +def test_nonexisting_get_stoploss(mocker, edge_conf): freqtrade = get_patched_freqtradebot(mocker, edge_conf) edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock( @@ -162,7 +162,7 @@ def test_nonexisting_stoploss(mocker, edge_conf): } )) - assert edge.stoploss('N/O') == -0.1 + assert edge.get_stoploss('N/O') == -0.1 def test_edge_stake_amount(mocker, edge_conf): From 3397e47ccfe3e7908bf865994987c0f8a2f3200c Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 14 Feb 2023 20:42:08 +0100 Subject: [PATCH 18/25] Rename stoploss() to create_stoploss() --- freqtrade/exchange/exchange.py | 4 ++-- freqtrade/exchange/kraken.py | 4 ++-- freqtrade/freqtradebot.py | 2 +- tests/exchange/test_binance.py | 18 +++++++-------- tests/exchange/test_exchange.py | 4 ++-- tests/exchange/test_huobi.py | 36 ++++++++++++++--------------- tests/exchange/test_kraken.py | 14 ++++++------ tests/exchange/test_kucoin.py | 38 +++++++++++++++---------------- tests/test_freqtradebot.py | 40 ++++++++++++++++----------------- tests/test_integration.py | 2 +- 10 files changed, 81 insertions(+), 81 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 332209246..3a32824fc 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1131,8 +1131,8 @@ class Exchange: return params @retrier(retries=0) - def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict, - side: BuySell, leverage: float) -> Dict: + def create_stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict, + side: BuySell, leverage: float) -> Dict: """ creates a stoploss order. requires `_ft_has['stoploss_order_types']` to be set as a dict mapping limit and market diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index 2b37c45bd..8a4f7f7e0 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -97,8 +97,8 @@ class Kraken(Exchange): )) @retrier(retries=0) - def stoploss(self, pair: str, amount: float, stop_price: float, - order_types: Dict, side: BuySell, leverage: float) -> Dict: + def create_stoploss(self, pair: str, amount: float, stop_price: float, + order_types: Dict, side: BuySell, leverage: float) -> Dict: """ Creates a stoploss market order. Stoploss market orders is the only stoploss type supported by kraken. diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index c15ff42fc..82be6f3b5 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1098,7 +1098,7 @@ class FreqtradeBot(LoggingMixin): :return: True if the order succeeded, and False in case of problems. """ try: - stoploss_order = self.exchange.stoploss( + stoploss_order = self.exchange.create_stoploss( pair=trade.pair, amount=trade.amount, stop_price=stop_price, diff --git a/tests/exchange/test_binance.py b/tests/exchange/test_binance.py index 432747be0..31f2fae29 100644 --- a/tests/exchange/test_binance.py +++ b/tests/exchange/test_binance.py @@ -20,7 +20,7 @@ from tests.exchange.test_exchange import ccxt_exceptionhandlers (0.99, 220 * 1.01, "buy"), (0.98, 220 * 1.02, "buy"), ]) -def test_stoploss_order_binance(default_conf, mocker, limitratio, expected, side, trademode): +def test_create_stoploss_order_binance(default_conf, mocker, limitratio, expected, side, trademode): api_mock = MagicMock() order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6)) order_type = 'stop_loss_limit' if trademode == TradingMode.SPOT else 'stop' @@ -40,7 +40,7 @@ def test_stoploss_order_binance(default_conf, mocker, limitratio, expected, side exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance') with pytest.raises(OperationalException): - order = exchange.stoploss( + order = exchange.create_stoploss( pair='ETH/BTC', amount=1, stop_price=190, @@ -54,7 +54,7 @@ def test_stoploss_order_binance(default_conf, mocker, limitratio, expected, side if limitratio is not None: order_types.update({'stoploss_on_exchange_limit_ratio': limitratio}) - order = exchange.stoploss( + order = exchange.create_stoploss( pair='ETH/BTC', amount=1, stop_price=220, @@ -82,7 +82,7 @@ def test_stoploss_order_binance(default_conf, mocker, limitratio, expected, side with pytest.raises(DependencyException): api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance")) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance') - exchange.stoploss( + exchange.create_stoploss( pair='ETH/BTC', amount=1, stop_price=220, @@ -94,7 +94,7 @@ def test_stoploss_order_binance(default_conf, mocker, limitratio, expected, side api_mock.create_order = MagicMock( side_effect=ccxt.InvalidOrder("binance Order would trigger immediately.")) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance') - exchange.stoploss( + exchange.create_stoploss( pair='ETH/BTC', amount=1, stop_price=220, @@ -104,12 +104,12 @@ def test_stoploss_order_binance(default_conf, mocker, limitratio, expected, side ) ccxt_exceptionhandlers(mocker, default_conf, api_mock, "binance", - "stoploss", "create_order", retries=1, + "create_stoploss", "create_order", retries=1, pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side, leverage=1.0) -def test_stoploss_order_dry_run_binance(default_conf, mocker): +def test_create_stoploss_order_dry_run_binance(default_conf, mocker): api_mock = MagicMock() order_type = 'stop_loss_limit' default_conf['dry_run'] = True @@ -119,7 +119,7 @@ def test_stoploss_order_dry_run_binance(default_conf, mocker): exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance') with pytest.raises(OperationalException): - order = exchange.stoploss( + order = exchange.create_stoploss( pair='ETH/BTC', amount=1, stop_price=190, @@ -130,7 +130,7 @@ def test_stoploss_order_dry_run_binance(default_conf, mocker): api_mock.create_order.reset_mock() - order = exchange.stoploss( + order = exchange.create_stoploss( pair='ETH/BTC', amount=1, stop_price=220, diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 0cd2a528a..dc97bcfde 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -3380,7 +3380,7 @@ def test_get_fee(default_conf, mocker, exchange_name): def test_stoploss_order_unsupported_exchange(default_conf, mocker): exchange = get_patched_exchange(mocker, default_conf, id='bittrex') with pytest.raises(OperationalException, match=r"stoploss is not implemented .*"): - exchange.stoploss( + exchange.create_stoploss( pair='ETH/BTC', amount=1, stop_price=220, @@ -5318,7 +5318,7 @@ def test_stoploss_contract_size(mocker, default_conf, contract_size, order_amoun exchange.get_contract_size = MagicMock(return_value=contract_size) api_mock.create_order.reset_mock() - order = exchange.stoploss( + order = exchange.create_stoploss( pair='ETH/BTC', amount=100, stop_price=220, diff --git a/tests/exchange/test_huobi.py b/tests/exchange/test_huobi.py index 2ce379a47..e5fa986c3 100644 --- a/tests/exchange/test_huobi.py +++ b/tests/exchange/test_huobi.py @@ -14,7 +14,7 @@ from tests.exchange.test_exchange import ccxt_exceptionhandlers (0.99, 220 * 0.99, "sell"), (0.98, 220 * 0.98, "sell"), ]) -def test_stoploss_order_huobi(default_conf, mocker, limitratio, expected, side): +def test_create_stoploss_order_huobi(default_conf, mocker, limitratio, expected, side): api_mock = MagicMock() order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6)) order_type = 'stop-limit' @@ -32,15 +32,15 @@ def test_stoploss_order_huobi(default_conf, mocker, limitratio, expected, side): exchange = get_patched_exchange(mocker, default_conf, api_mock, 'huobi') with pytest.raises(OperationalException): - order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=190, - order_types={'stoploss_on_exchange_limit_ratio': 1.05}, - side=side, - leverage=1.0) + order = exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=190, + order_types={'stoploss_on_exchange_limit_ratio': 1.05}, + side=side, + leverage=1.0) api_mock.create_order.reset_mock() order_types = {} if limitratio is None else {'stoploss_on_exchange_limit_ratio': limitratio} - order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types=order_types, - side=side, leverage=1.0) + order = exchange.create_stoploss( + pair='ETH/BTC', amount=1, stop_price=220, order_types=order_types, side=side, leverage=1.0) assert 'id' in order assert 'info' in order @@ -59,23 +59,23 @@ def test_stoploss_order_huobi(default_conf, mocker, limitratio, expected, side): with pytest.raises(DependencyException): api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance")) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'huobi') - exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, - order_types={}, side=side, leverage=1.0) + exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=220, + order_types={}, side=side, leverage=1.0) with pytest.raises(InvalidOrderException): api_mock.create_order = MagicMock( side_effect=ccxt.InvalidOrder("binance Order would trigger immediately.")) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance') - exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, - order_types={}, side=side, leverage=1.0) + exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=220, + order_types={}, side=side, leverage=1.0) ccxt_exceptionhandlers(mocker, default_conf, api_mock, "huobi", - "stoploss", "create_order", retries=1, + "create_stoploss", "create_order", retries=1, pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side, leverage=1.0) -def test_stoploss_order_dry_run_huobi(default_conf, mocker): +def test_create_stoploss_order_dry_run_huobi(default_conf, mocker): api_mock = MagicMock() order_type = 'stop-limit' default_conf['dry_run'] = True @@ -85,14 +85,14 @@ def test_stoploss_order_dry_run_huobi(default_conf, mocker): exchange = get_patched_exchange(mocker, default_conf, api_mock, 'huobi') with pytest.raises(OperationalException): - order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=190, - order_types={'stoploss_on_exchange_limit_ratio': 1.05}, - side='sell', leverage=1.0) + order = exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=190, + order_types={'stoploss_on_exchange_limit_ratio': 1.05}, + side='sell', leverage=1.0) api_mock.create_order.reset_mock() - order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, - order_types={}, side='sell', leverage=1.0) + order = exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=220, + order_types={}, side='sell', leverage=1.0) assert 'id' in order assert 'info' in order diff --git a/tests/exchange/test_kraken.py b/tests/exchange/test_kraken.py index 66006f2fe..3a183de93 100644 --- a/tests/exchange/test_kraken.py +++ b/tests/exchange/test_kraken.py @@ -179,7 +179,7 @@ def test_get_balances_prod(default_conf, mocker): ("sell", 217.8), ("buy", 222.2), ]) -def test_stoploss_order_kraken(default_conf, mocker, ordertype, side, adjustedprice): +def test_create_stoploss_order_kraken(default_conf, mocker, ordertype, side, adjustedprice): api_mock = MagicMock() order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6)) @@ -196,7 +196,7 @@ def test_stoploss_order_kraken(default_conf, mocker, ordertype, side, adjustedpr exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kraken') - order = exchange.stoploss( + order = exchange.create_stoploss( pair='ETH/BTC', amount=1, stop_price=220, @@ -230,7 +230,7 @@ def test_stoploss_order_kraken(default_conf, mocker, ordertype, side, adjustedpr with pytest.raises(DependencyException): api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance")) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kraken') - exchange.stoploss( + exchange.create_stoploss( pair='ETH/BTC', amount=1, stop_price=220, @@ -243,7 +243,7 @@ def test_stoploss_order_kraken(default_conf, mocker, ordertype, side, adjustedpr api_mock.create_order = MagicMock( side_effect=ccxt.InvalidOrder("kraken Order would trigger immediately.")) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kraken') - exchange.stoploss( + exchange.create_stoploss( pair='ETH/BTC', amount=1, stop_price=220, @@ -253,13 +253,13 @@ def test_stoploss_order_kraken(default_conf, mocker, ordertype, side, adjustedpr ) ccxt_exceptionhandlers(mocker, default_conf, api_mock, "kraken", - "stoploss", "create_order", retries=1, + "create_stoploss", "create_order", retries=1, pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side, leverage=1.0) @pytest.mark.parametrize('side', ['buy', 'sell']) -def test_stoploss_order_dry_run_kraken(default_conf, mocker, side): +def test_create_stoploss_order_dry_run_kraken(default_conf, mocker, side): api_mock = MagicMock() default_conf['dry_run'] = True mocker.patch('freqtrade.exchange.Exchange.amount_to_precision', lambda s, x, y: y) @@ -269,7 +269,7 @@ def test_stoploss_order_dry_run_kraken(default_conf, mocker, side): api_mock.create_order.reset_mock() - order = exchange.stoploss( + order = exchange.create_stoploss( pair='ETH/BTC', amount=1, stop_price=220, diff --git a/tests/exchange/test_kucoin.py b/tests/exchange/test_kucoin.py index ebaf5ae81..65c855b7a 100644 --- a/tests/exchange/test_kucoin.py +++ b/tests/exchange/test_kucoin.py @@ -15,7 +15,7 @@ from tests.exchange.test_exchange import ccxt_exceptionhandlers (0.99, 220 * 0.99, "sell"), (0.98, 220 * 0.98, "sell"), ]) -def test_stoploss_order_kucoin(default_conf, mocker, limitratio, expected, side, order_type): +def test_create_stoploss_order_kucoin(default_conf, mocker, limitratio, expected, side, order_type): api_mock = MagicMock() order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6)) @@ -32,18 +32,18 @@ def test_stoploss_order_kucoin(default_conf, mocker, limitratio, expected, side, exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kucoin') if order_type == 'limit': with pytest.raises(OperationalException): - order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=190, - order_types={ - 'stoploss': order_type, - 'stoploss_on_exchange_limit_ratio': 1.05}, - side=side, leverage=1.0) + order = exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=190, + order_types={ + 'stoploss': order_type, + 'stoploss_on_exchange_limit_ratio': 1.05}, + side=side, leverage=1.0) api_mock.create_order.reset_mock() order_types = {'stoploss': order_type} if limitratio is not None: order_types.update({'stoploss_on_exchange_limit_ratio': limitratio}) - order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, - order_types=order_types, side=side, leverage=1.0) + order = exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=220, + order_types=order_types, side=side, leverage=1.0) assert 'id' in order assert 'info' in order @@ -67,18 +67,18 @@ def test_stoploss_order_kucoin(default_conf, mocker, limitratio, expected, side, with pytest.raises(DependencyException): api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance")) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kucoin') - exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, - order_types={}, side=side, leverage=1.0) + exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=220, + order_types={}, side=side, leverage=1.0) with pytest.raises(InvalidOrderException): api_mock.create_order = MagicMock( side_effect=ccxt.InvalidOrder("kucoin Order would trigger immediately.")) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kucoin') - exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, - order_types={}, side=side, leverage=1.0) + exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=220, + order_types={}, side=side, leverage=1.0) ccxt_exceptionhandlers(mocker, default_conf, api_mock, "kucoin", - "stoploss", "create_order", retries=1, + "create_stoploss", "create_order", retries=1, pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side, leverage=1.0) @@ -93,15 +93,15 @@ def test_stoploss_order_dry_run_kucoin(default_conf, mocker): exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kucoin') with pytest.raises(OperationalException): - order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=190, - order_types={'stoploss': 'limit', - 'stoploss_on_exchange_limit_ratio': 1.05}, - side='sell', leverage=1.0) + order = exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=190, + order_types={'stoploss': 'limit', + 'stoploss_on_exchange_limit_ratio': 1.05}, + side='sell', leverage=1.0) api_mock.create_order.reset_mock() - order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, - order_types={}, side='sell', leverage=1.0) + order = exchange.create_stoploss(pair='ETH/BTC', amount=1, stop_price=220, + order_types={}, side='sell', leverage=1.0) assert 'id' in order assert 'info' in order diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 9e8353a4b..d51a1d49f 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1070,7 +1070,7 @@ def test_add_stoploss_on_exchange(mocker, default_conf_usdt, limit_order, is_sho mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[]) stoploss = MagicMock(return_value={'id': 13434334}) - mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss) + mocker.patch('freqtrade.exchange.Binance.create_stoploss', stoploss) freqtrade = FreqtradeBot(default_conf_usdt) freqtrade.strategy.order_types['stoploss_on_exchange'] = True @@ -1109,7 +1109,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ exit_order, ]), get_fee=fee, - stoploss=stoploss + create_stoploss=stoploss ) freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short) @@ -1191,7 +1191,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ caplog.clear() mocker.patch( - 'freqtrade.exchange.Exchange.stoploss', + 'freqtrade.exchange.Exchange.create_stoploss', side_effect=ExchangeError() ) trade.is_open = True @@ -1205,7 +1205,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ stoploss.reset_mock() mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', side_effect=InvalidOrderException()) - mocker.patch('freqtrade.exchange.Exchange.stoploss', stoploss) + mocker.patch('freqtrade.exchange.Exchange.create_stoploss', stoploss) freqtrade.handle_stoploss_on_exchange(trade) assert stoploss.call_count == 1 @@ -1215,7 +1215,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ trade.is_open = False stoploss.reset_mock() mocker.patch('freqtrade.exchange.Exchange.fetch_order') - mocker.patch('freqtrade.exchange.Exchange.stoploss', stoploss) + mocker.patch('freqtrade.exchange.Exchange.create_stoploss', stoploss) assert freqtrade.handle_stoploss_on_exchange(trade) is False assert stoploss.call_count == 0 @@ -1240,7 +1240,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ mocker.patch('freqtrade.exchange.Exchange.cancel_stoploss_order_with_result', side_effect=InvalidOrderException()) mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', stoploss_order_cancelled) - mocker.patch('freqtrade.exchange.Exchange.stoploss', stoploss) + mocker.patch('freqtrade.exchange.Exchange.create_stoploss', stoploss) assert freqtrade.handle_stoploss_on_exchange(trade) is False assert trade.stoploss_order_id is None assert trade.is_open is False @@ -1271,7 +1271,7 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf_usdt, fee, caplog, mocker.patch.multiple( 'freqtrade.exchange.Binance', fetch_stoploss_order=MagicMock(return_value={'status': 'canceled', 'id': 100}), - stoploss=MagicMock(side_effect=ExchangeError()), + create_stoploss=MagicMock(side_effect=ExchangeError()), ) freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short) @@ -1315,7 +1315,7 @@ def test_create_stoploss_order_invalid_order( mocker.patch.multiple( 'freqtrade.exchange.Binance', fetch_order=MagicMock(return_value={'status': 'canceled'}), - stoploss=MagicMock(side_effect=InvalidOrderException()), + create_stoploss=MagicMock(side_effect=InvalidOrderException()), ) freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short) @@ -1367,7 +1367,7 @@ def test_create_stoploss_order_insufficient_funds( ) mocker.patch.multiple( 'freqtrade.exchange.Binance', - stoploss=MagicMock(side_effect=InsufficientFundsError()), + create_stoploss=MagicMock(side_effect=InsufficientFundsError()), ) patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short) freqtrade.strategy.order_types['stoploss_on_exchange'] = True @@ -1417,7 +1417,7 @@ def test_handle_stoploss_on_exchange_trailing( ) mocker.patch.multiple( 'freqtrade.exchange.Binance', - stoploss=stoploss, + create_stoploss=stoploss, stoploss_adjust=MagicMock(return_value=True), ) @@ -1478,7 +1478,7 @@ def test_handle_stoploss_on_exchange_trailing( cancel_order_mock = MagicMock() stoploss_order_mock = MagicMock(return_value={'id': 'so1'}) mocker.patch('freqtrade.exchange.Binance.cancel_stoploss_order', cancel_order_mock) - mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss_order_mock) + mocker.patch('freqtrade.exchange.Binance.create_stoploss', stoploss_order_mock) # stoploss should not be updated as the interval is 60 seconds assert freqtrade.handle_trade(trade) is False @@ -1542,7 +1542,7 @@ def test_handle_stoploss_on_exchange_trailing_error( ) mocker.patch.multiple( 'freqtrade.exchange.Binance', - stoploss=stoploss, + create_stoploss=stoploss, stoploss_adjust=MagicMock(return_value=True), ) @@ -1593,7 +1593,7 @@ def test_handle_stoploss_on_exchange_trailing_error( trade.stoploss_last_update = arrow.utcnow().shift(minutes=-601).datetime caplog.clear() cancel_mock = mocker.patch("freqtrade.exchange.Binance.cancel_stoploss_order", MagicMock()) - mocker.patch("freqtrade.exchange.Binance.stoploss", side_effect=ExchangeError()) + mocker.patch("freqtrade.exchange.Binance.create_stoploss", side_effect=ExchangeError()) 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/USDT\..*", caplog) @@ -1611,7 +1611,7 @@ def test_stoploss_on_exchange_price_rounding( adjust_mock = MagicMock(return_value=False) mocker.patch.multiple( 'freqtrade.exchange.Binance', - stoploss=stoploss_mock, + create_stoploss=stoploss_mock, stoploss_adjust=adjust_mock, price_to_precision=price_mock, ) @@ -1650,7 +1650,7 @@ def test_handle_stoploss_on_exchange_custom_stop( ) mocker.patch.multiple( 'freqtrade.exchange.Binance', - stoploss=stoploss, + create_stoploss=stoploss, stoploss_adjust=MagicMock(return_value=True), ) @@ -1710,7 +1710,7 @@ def test_handle_stoploss_on_exchange_custom_stop( cancel_order_mock = MagicMock() stoploss_order_mock = MagicMock(return_value={'id': 'so1'}) mocker.patch('freqtrade.exchange.Binance.cancel_stoploss_order', cancel_order_mock) - mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss_order_mock) + mocker.patch('freqtrade.exchange.Binance.create_stoploss', stoploss_order_mock) # stoploss should not be updated as the interval is 60 seconds assert freqtrade.handle_trade(trade) is False @@ -1775,7 +1775,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, limit_orde {'id': exit_order['id']}, ]), get_fee=fee, - stoploss=stoploss, + create_stoploss=stoploss, ) # enabling TSL @@ -1827,7 +1827,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, limit_orde cancel_order_mock = MagicMock() stoploss_order_mock = MagicMock() mocker.patch('freqtrade.exchange.Exchange.cancel_stoploss_order', cancel_order_mock) - mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss_order_mock) + mocker.patch('freqtrade.exchange.Binance.create_stoploss', stoploss_order_mock) # price goes down 5% mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ @@ -3607,7 +3607,7 @@ def test_execute_trade_exit_with_stoploss_on_exchange( get_fee=fee, amount_to_precision=lambda s, x, y: y, price_to_precision=lambda s, x, y: y, - stoploss=stoploss, + create_stoploss=stoploss, cancel_stoploss_order=cancel_order, _is_dry_limit_order_filled=MagicMock(side_effect=[True, False]), ) @@ -3668,7 +3668,7 @@ def test_may_execute_trade_exit_after_stoploss_on_exchange_hit( } }) - mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss) + mocker.patch('freqtrade.exchange.Binance.create_stoploss', stoploss) freqtrade = FreqtradeBot(default_conf_usdt) freqtrade.strategy.order_types['stoploss_on_exchange'] = True diff --git a/tests/test_integration.py b/tests/test_integration.py index 01a2801ad..3680ddf46 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -56,7 +56,7 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee, [ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL)]] ) cancel_order_mock = MagicMock() - mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss) + mocker.patch('freqtrade.exchange.Binance.create_stoploss', stoploss) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, From ecff21ac2184a976e1e9326dc1ad3811223e2149 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Feb 2023 07:01:36 +0100 Subject: [PATCH 19/25] type Orderbook --- freqtrade/constants.py | 1 + freqtrade/data/dataprovider.py | 3 ++- freqtrade/exchange/exchange.py | 13 +++++++------ freqtrade/exchange/types.py | 9 +++++++++ 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 08048c3e7..b2e707d1a 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -681,6 +681,7 @@ EntryExit = Literal['entry', 'exit'] BuySell = Literal['buy', 'sell'] MakerTaker = Literal['maker', 'taker'] BidAsk = Literal['bid', 'ask'] +OBLiteral = Literal['asks', 'bids'] Config = Dict[str, Any] IntOrInf = float diff --git a/freqtrade/data/dataprovider.py b/freqtrade/data/dataprovider.py index 60a058952..78390e3a4 100644 --- a/freqtrade/data/dataprovider.py +++ b/freqtrade/data/dataprovider.py @@ -18,6 +18,7 @@ from freqtrade.data.history import load_pair_history from freqtrade.enums import CandleType, RPCMessageType, RunMode from freqtrade.exceptions import ExchangeError, OperationalException from freqtrade.exchange import Exchange, timeframe_to_seconds +from freqtrade.exchange.types import OrderBook from freqtrade.misc import append_candles_to_dataframe from freqtrade.rpc import RPCManager from freqtrade.util import PeriodicCache @@ -489,7 +490,7 @@ class DataProvider: except ExchangeError: return {} - def orderbook(self, pair: str, maximum: int) -> Dict[str, List]: + def orderbook(self, pair: str, maximum: int) -> OrderBook: """ Fetch latest l2 orderbook data Warning: Does a network request - so use with common sense. diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 3a32824fc..77d4ff4c7 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -21,7 +21,7 @@ from pandas import DataFrame, concat from freqtrade.constants import (DEFAULT_AMOUNT_RESERVE_PERCENT, NON_OPEN_EXCHANGE_STATES, BidAsk, BuySell, Config, EntryExit, ListPairsWithTimeframes, MakerTaker, - PairWithTimeframe) + OBLiteral, PairWithTimeframe) from freqtrade.data.converter import clean_ohlcv_dataframe, ohlcv_to_dataframe, trades_dict_to_list from freqtrade.enums import OPTIMIZE_MODES, CandleType, MarginMode, TradingMode from freqtrade.enums.pricetype import PriceType @@ -37,7 +37,7 @@ from freqtrade.exchange.exchange_utils import (CcxtModuleType, amount_to_contrac price_to_precision, timeframe_to_minutes, timeframe_to_msecs, timeframe_to_next_date, timeframe_to_prev_date, timeframe_to_seconds) -from freqtrade.exchange.types import OHLCVResponse, Ticker, Tickers +from freqtrade.exchange.types import OHLCVResponse, OrderBook, Ticker, Tickers from freqtrade.misc import (chunks, deep_merge_dicts, file_dump_json, file_load_json, safe_value_fallback2) from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist @@ -901,7 +901,7 @@ class Exchange: """ if self.exchange_has('fetchL2OrderBook'): ob = self.fetch_l2_order_book(pair, 20) - ob_type = 'asks' if side == 'buy' else 'bids' + ob_type: OBLiteral = 'asks' if side == 'buy' else 'bids' slippage = 0.05 max_slippage_val = rate * ((1 + slippage) if side == 'buy' else (1 - slippage)) @@ -1511,7 +1511,7 @@ class Exchange: return result @retrier - def fetch_l2_order_book(self, pair: str, limit: int = 100) -> dict: + def fetch_l2_order_book(self, pair: str, limit: int = 100) -> OrderBook: """ Get L2 order book from exchange. Can be limited to a certain amount (if supported). @@ -1554,7 +1554,7 @@ class Exchange: def get_rate(self, pair: str, refresh: bool, side: EntryExit, is_short: bool, - order_book: Optional[dict] = None, ticker: Optional[Ticker] = None) -> float: + order_book: Optional[OrderBook] = None, ticker: Optional[Ticker] = None) -> float: """ Calculates bid/ask target bid rate - between current ask price and last price @@ -1592,7 +1592,8 @@ class Exchange: logger.debug('order_book %s', order_book) # top 1 = index 0 try: - rate = order_book[f"{price_side}s"][order_book_top - 1][0] + obside: OBLiteral = 'bids' if price_side == 'bid' else 'asks' + rate = order_book[obside][order_book_top - 1][0] except (IndexError, KeyError) as e: logger.warning( f"{pair} - {name} Price at location {order_book_top} from orderbook " diff --git a/freqtrade/exchange/types.py b/freqtrade/exchange/types.py index 813b09297..1b71c9708 100644 --- a/freqtrade/exchange/types.py +++ b/freqtrade/exchange/types.py @@ -15,6 +15,15 @@ class Ticker(TypedDict): # Several more - only listing required. +class OrderBook(TypedDict): + symbol: str + bids: List[Tuple[float, float]] + asks: List[Tuple[float, float]] + timestamp: int + datetime: str + nonce: int + + Tickers = Dict[str, Ticker] # pair, timeframe, candleType, OHLCV, drop last?, From 020c9a5cececbf1a349afa4197c36d9fc001246c Mon Sep 17 00:00:00 2001 From: Robert Caulk Date: Wed, 15 Feb 2023 21:54:45 +0100 Subject: [PATCH 20/25] Update freqai.md --- docs/freqai.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/freqai.md b/docs/freqai.md index d13d43f66..85a8ddc7c 100644 --- a/docs/freqai.md +++ b/docs/freqai.md @@ -4,7 +4,7 @@ ## Introduction -FreqAI is a software designed to automate a variety of tasks associated with training a predictive machine learning model to generate market forecasts given a set of input signals. In general, the FreqAI aims to be a sand-box for easily deploying robust machine-learning libraries on real-time data ([details])(#freqai-position-in-open-source-machine-learning-landscape). +FreqAI is a software designed to automate a variety of tasks associated with training a predictive machine learning model to generate market forecasts given a set of input signals. In general, FreqAI aims to be a sand-box for easily deploying robust machine-learning libraries on real-time data ([details](#freqai-position-in-open-source-machine-learning-landscape)). Features include: From 7c10921564bd71e19b44da099f246eef0d7bd34e Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Feb 2023 07:15:54 +0100 Subject: [PATCH 21/25] Improve Orderbook typing to align for diff. exchanges --- freqtrade/exchange/types.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/exchange/types.py b/freqtrade/exchange/types.py index 1b71c9708..5568e4336 100644 --- a/freqtrade/exchange/types.py +++ b/freqtrade/exchange/types.py @@ -19,9 +19,9 @@ class OrderBook(TypedDict): symbol: str bids: List[Tuple[float, float]] asks: List[Tuple[float, float]] - timestamp: int - datetime: str - nonce: int + timestamp: Optional[int] + datetime: Optional[str] + nonce: Optional[int] Tickers = Dict[str, Ticker] From de7d274fcfa36676d4ec554c9ea93663bd1d8562 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Feb 2023 07:19:47 +0100 Subject: [PATCH 22/25] Pass orderbook to dry-run fill logic --- freqtrade/exchange/exchange.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 77d4ff4c7..e9cb35383 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -860,10 +860,13 @@ class Exchange: dry_order["stopPrice"] = dry_order["price"] # Workaround to avoid filling stoploss orders immediately dry_order["ft_order_type"] = "stoploss" + orderbook: Optional[OrderBook] = None + if self.exchange_has('fetchL2OrderBook'): + orderbook = self.fetch_l2_order_book(pair, 20) if dry_order["type"] == "market" and not dry_order.get("ft_order_type"): # Update market order pricing - average = self.get_dry_market_fill_price(pair, side, amount, rate) + average = self.get_dry_market_fill_price(pair, side, amount, rate, orderbook) dry_order.update({ 'average': average, 'filled': _amount, @@ -873,7 +876,7 @@ class Exchange: # market orders will always incurr taker fees dry_order = self.add_dry_order_fee(pair, dry_order, 'taker') - dry_order = self.check_dry_limit_order_filled(dry_order, immediate=True) + dry_order = self.check_dry_limit_order_filled(dry_order, immediate=True, ob=orderbook) self._dry_run_open_orders[dry_order["id"]] = dry_order # Copy order and close it - so the returned order is open unless it's a market order @@ -895,12 +898,15 @@ class Exchange: }) return dry_order - def get_dry_market_fill_price(self, pair: str, side: str, amount: float, rate: float) -> float: + def get_dry_market_fill_price( + self, pair: str, side: str, amount: float, rate: float, + ob: Optional[OrderBook]) -> float: """ Get the market order fill price based on orderbook interpolation """ if self.exchange_has('fetchL2OrderBook'): - ob = self.fetch_l2_order_book(pair, 20) + if not ob: + ob = self.fetch_l2_order_book(pair, 20) ob_type: OBLiteral = 'asks' if side == 'buy' else 'bids' slippage = 0.05 max_slippage_val = rate * ((1 + slippage) if side == 'buy' else (1 - slippage)) @@ -936,10 +942,12 @@ class Exchange: return rate - def _is_dry_limit_order_filled(self, pair: str, side: str, limit: float) -> bool: + def _is_dry_limit_order_filled( + self, pair: str, side: str, limit: float, ob: Optional[OrderBook] = None) -> bool: if not self.exchange_has('fetchL2OrderBook'): return True - ob = self.fetch_l2_order_book(pair, 1) + if not ob: + ob = self.fetch_l2_order_book(pair, 1) try: if side == 'buy': price = ob['asks'][0][0] @@ -957,7 +965,8 @@ class Exchange: return False def check_dry_limit_order_filled( - self, order: Dict[str, Any], immediate: bool = False) -> Dict[str, Any]: + self, order: Dict[str, Any], immediate: bool = False, + ob: Optional[OrderBook] = None) -> Dict[str, Any]: """ Check dry-run limit order fill and update fee (if it filled). """ @@ -965,7 +974,7 @@ class Exchange: and order['type'] in ["limit"] and not order.get('ft_order_type')): pair = order['symbol'] - if self._is_dry_limit_order_filled(pair, order['side'], order['price']): + if self._is_dry_limit_order_filled(pair, order['side'], order['price'], ob): order.update({ 'status': 'closed', 'filled': order['amount'], From 8ef110cc5f849e03243e67da5761d9ef02e38923 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Feb 2023 07:21:18 +0100 Subject: [PATCH 23/25] Rename ob variable to orderbook --- freqtrade/exchange/exchange.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index e9cb35383..22cce626e 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -876,7 +876,8 @@ class Exchange: # market orders will always incurr taker fees dry_order = self.add_dry_order_fee(pair, dry_order, 'taker') - dry_order = self.check_dry_limit_order_filled(dry_order, immediate=True, ob=orderbook) + dry_order = self.check_dry_limit_order_filled( + dry_order, immediate=True, orderbook=orderbook) self._dry_run_open_orders[dry_order["id"]] = dry_order # Copy order and close it - so the returned order is open unless it's a market order @@ -898,15 +899,14 @@ class Exchange: }) return dry_order - def get_dry_market_fill_price( - self, pair: str, side: str, amount: float, rate: float, - ob: Optional[OrderBook]) -> float: + def get_dry_market_fill_price(self, pair: str, side: str, amount: float, rate: float, + orderbook: Optional[OrderBook]) -> float: """ Get the market order fill price based on orderbook interpolation """ if self.exchange_has('fetchL2OrderBook'): - if not ob: - ob = self.fetch_l2_order_book(pair, 20) + if not orderbook: + orderbook = self.fetch_l2_order_book(pair, 20) ob_type: OBLiteral = 'asks' if side == 'buy' else 'bids' slippage = 0.05 max_slippage_val = rate * ((1 + slippage) if side == 'buy' else (1 - slippage)) @@ -914,7 +914,7 @@ class Exchange: remaining_amount = amount filled_amount = 0.0 book_entry_price = 0.0 - for book_entry in ob[ob_type]: + for book_entry in orderbook[ob_type]: book_entry_price = book_entry[0] book_entry_coin_volume = book_entry[1] if remaining_amount > 0: @@ -942,20 +942,20 @@ class Exchange: return rate - def _is_dry_limit_order_filled( - self, pair: str, side: str, limit: float, ob: Optional[OrderBook] = None) -> bool: + def _is_dry_limit_order_filled(self, pair: str, side: str, limit: float, + orderbook: Optional[OrderBook] = None) -> bool: if not self.exchange_has('fetchL2OrderBook'): return True - if not ob: - ob = self.fetch_l2_order_book(pair, 1) + if not orderbook: + orderbook = self.fetch_l2_order_book(pair, 1) try: if side == 'buy': - price = ob['asks'][0][0] + price = orderbook['asks'][0][0] logger.debug(f"{pair} checking dry buy-order: price={price}, limit={limit}") if limit >= price: return True else: - price = ob['bids'][0][0] + price = orderbook['bids'][0][0] logger.debug(f"{pair} checking dry sell-order: price={price}, limit={limit}") if limit <= price: return True @@ -966,7 +966,7 @@ class Exchange: def check_dry_limit_order_filled( self, order: Dict[str, Any], immediate: bool = False, - ob: Optional[OrderBook] = None) -> Dict[str, Any]: + orderbook: Optional[OrderBook] = None) -> Dict[str, Any]: """ Check dry-run limit order fill and update fee (if it filled). """ @@ -974,7 +974,7 @@ class Exchange: and order['type'] in ["limit"] and not order.get('ft_order_type')): pair = order['symbol'] - if self._is_dry_limit_order_filled(pair, order['side'], order['price'], ob): + if self._is_dry_limit_order_filled(pair, order['side'], order['price'], orderbook): order.update({ 'status': 'closed', 'filled': order['amount'], From a2e1389943cb4aaddcc298ec3155f8686f394a7e Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 16 Feb 2023 18:06:34 +0100 Subject: [PATCH 24/25] Update Binance leverage code --- docs/developer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developer.md b/docs/developer.md index ea2e36ce1..0546c20e9 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -363,7 +363,7 @@ from pathlib import Path exchange = ccxt.binance({ 'apiKey': '', 'secret': '' - 'options': {'defaultType': 'future'} + 'options': {'defaultType': 'swap'} }) _ = exchange.load_markets() From 36d65e00f93f4961db248ff6780d4918de00debd Mon Sep 17 00:00:00 2001 From: robcaulk Date: Thu, 16 Feb 2023 18:33:40 +0100 Subject: [PATCH 25/25] generalize model_exists() for RL and Keras --- freqtrade/freqai/freqai_interface.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 00342cc6b..c265e42f9 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -563,7 +563,13 @@ class IFreqaiModel(ABC): :return: :boolean: whether the model file exists or not. """ - path_to_modelfile = Path(dk.data_path / f"{dk.model_filename}_model.joblib") + if self.dd.model_type == 'joblib': + file_type = ".joblib" + elif self.dd.model_type == 'keras': + file_type = ".h5" + elif 'stable_baselines' in self.dd.model_type or 'sb3_contrib' == self.dd.model_type: + file_type = ".zip" + path_to_modelfile = Path(dk.data_path / f"{dk.model_filename}_model.{file_type}") file_exists = path_to_modelfile.is_file() if file_exists: logger.info("Found model at %s", dk.data_path / dk.model_filename)