From c17595b314fb1e6dcfff38695c51e5c07f2b38fe Mon Sep 17 00:00:00 2001 From: LoveIsGrief Date: Sat, 28 Aug 2021 19:39:50 +0200 Subject: [PATCH 01/76] Docs: Mention Performance Warning for strategies Related to #5408 --- docs/strategy-customization.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index cfea60d22..194517b2b 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -781,6 +781,8 @@ Printing more than a few rows is also possible (simply use `print(dataframe)` i ## Common mistakes when developing strategies +### Peeking into the future while backtesting + Backtesting analyzes the whole time-range at once for performance reasons. Because of this, strategy authors need to make sure that strategies do not look-ahead into the future. This is a common pain-point, which can cause huge differences between backtesting and dry/live run methods, since they all use data which is not available during dry/live runs, so these strategies will perform well during backtesting, but will fail / perform badly in real conditions. @@ -791,6 +793,33 @@ The following lists some common patterns which should be avoided to prevent frus - don't use `dataframe['volume'].mean()`. This uses the full DataFrame for backtesting, including data from the future. Use `dataframe['volume'].rolling().mean()` instead - don't use `.resample('1h')`. This uses the left border of the interval, so moves data from an hour to the start of the hour. Use `.resample('1h', label='right')` instead. +### Performance warning + +When executing a strategy, one can sometimes be greeted by the following in the logs + +> PerformanceWarning: DataFrame is highly fragmented. + +This is a warning from [`pandas`](https://github.com/pandas-dev/pandas) and as the warning continues to say: + use `pd.concat(axis=1)`. For example + +```python +for i in range(100): + dataframe[i] = ta.indicator(dataframe, param=i) +``` + +should be rewritten to + +```python +frames = [dataframe] +for i in range(100): + frames.append({ + str(i): ta.indicator(dataframe, param=i) + }) + +# Append columns to existing dataframe +merged_frame = pd.concat(frames, axis=1) +``` + ## Further strategy ideas To get additional Ideas for strategies, head over to our [strategy repository](https://github.com/freqtrade/freqtrade-strategies). Feel free to use them as they are - but results will depend on the current market situation, pairs used etc. - therefore please backtest the strategy for your exchange/desired pairs first, evaluate carefully, use at your own risk. From 879bf47b32ff692e35f2509665b1ef9899eb3621 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 19 Sep 2021 19:25:36 +0200 Subject: [PATCH 02/76] Refactor telegram.py to simplify send_msg --- freqtrade/rpc/telegram.py | 51 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 19c58b63d..898446ea0 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -260,29 +260,7 @@ class Telegram(RPCHandler): return message - def send_msg(self, msg: Dict[str, Any]) -> None: - """ Send a message to telegram channel """ - - default_noti = 'on' - - msg_type = msg['type'] - noti = '' - if msg_type == RPCMessageType.SELL: - sell_noti = self._config['telegram'] \ - .get('notification_settings', {}).get(str(msg_type), {}) - # For backward compatibility sell still can be string - if isinstance(sell_noti, str): - noti = sell_noti - else: - noti = sell_noti.get(str(msg['sell_reason']), default_noti) - else: - noti = self._config['telegram'] \ - .get('notification_settings', {}).get(str(msg_type), default_noti) - - if noti == 'off': - logger.info(f"Notification '{msg_type}' not sent.") - # Notification disabled - return + def compose_message(self, msg: Dict[str, Any], msg_type: RPCMessageType) -> str: if msg_type == RPCMessageType.BUY: message = self._format_buy_msg(msg) @@ -315,6 +293,33 @@ class Telegram(RPCHandler): else: raise NotImplementedError('Unknown message type: {}'.format(msg_type)) + return message + + def send_msg(self, msg: Dict[str, Any]) -> None: + """ Send a message to telegram channel """ + + default_noti = 'on' + + msg_type = msg['type'] + noti = '' + if msg_type == RPCMessageType.SELL: + sell_noti = self._config['telegram'] \ + .get('notification_settings', {}).get(str(msg_type), {}) + # For backward compatibility sell still can be string + if isinstance(sell_noti, str): + noti = sell_noti + else: + noti = sell_noti.get(str(msg['sell_reason']), default_noti) + else: + noti = self._config['telegram'] \ + .get('notification_settings', {}).get(str(msg_type), default_noti) + + if noti == 'off': + logger.info(f"Notification '{msg_type}' not sent.") + # Notification disabled + return + + message = self.compose_message(msg, msg_type) self._send_msg(message, disable_notification=(noti == 'silent')) From 1da091dea3006b67e2400cf1390981354626f4fb Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 19 Sep 2021 19:41:19 +0200 Subject: [PATCH 03/76] ProtectionManager should return the lock just created --- freqtrade/persistence/pairlock_middleware.py | 4 +++- freqtrade/plugins/protectionmanager.py | 23 ++++++++++---------- tests/plugins/test_protections.py | 4 ++-- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/freqtrade/persistence/pairlock_middleware.py b/freqtrade/persistence/pairlock_middleware.py index af904f693..8662fc36d 100644 --- a/freqtrade/persistence/pairlock_middleware.py +++ b/freqtrade/persistence/pairlock_middleware.py @@ -30,7 +30,8 @@ class PairLocks(): PairLocks.locks = [] @staticmethod - def lock_pair(pair: str, until: datetime, reason: str = None, *, now: datetime = None) -> None: + def lock_pair(pair: str, until: datetime, reason: str = None, *, + now: datetime = None) -> PairLock: """ Create PairLock from now to "until". Uses database by default, unless PairLocks.use_db is set to False, @@ -52,6 +53,7 @@ class PairLocks(): PairLock.query.session.commit() else: PairLocks.locks.append(lock) + return lock @staticmethod def get_pair_locks(pair: Optional[str], now: Optional[datetime] = None) -> List[PairLock]: diff --git a/freqtrade/plugins/protectionmanager.py b/freqtrade/plugins/protectionmanager.py index f33e5b4bc..2510d6fee 100644 --- a/freqtrade/plugins/protectionmanager.py +++ b/freqtrade/plugins/protectionmanager.py @@ -6,6 +6,7 @@ from datetime import datetime, timezone from typing import Dict, List, Optional from freqtrade.persistence import PairLocks +from freqtrade.persistence.models import PairLock from freqtrade.plugins.protections import IProtection from freqtrade.resolvers import ProtectionResolver @@ -43,30 +44,28 @@ class ProtectionManager(): """ return [{p.name: p.short_desc()} for p in self._protection_handlers] - def global_stop(self, now: Optional[datetime] = None) -> bool: + def global_stop(self, now: Optional[datetime] = None) -> Optional[PairLock]: if not now: now = datetime.now(timezone.utc) - result = False + result = None for protection_handler in self._protection_handlers: if protection_handler.has_global_stop: - result, until, reason = protection_handler.global_stop(now) + lock, until, reason = protection_handler.global_stop(now) # Early stopping - first positive result blocks further trades - if result and until: + if lock and until: if not PairLocks.is_global_lock(until): - PairLocks.lock_pair('*', until, reason, now=now) - result = True + result = PairLocks.lock_pair('*', until, reason, now=now) return result - def stop_per_pair(self, pair, now: Optional[datetime] = None) -> bool: + def stop_per_pair(self, pair, now: Optional[datetime] = None) -> Optional[PairLock]: if not now: now = datetime.now(timezone.utc) - result = False + result = None for protection_handler in self._protection_handlers: if protection_handler.has_local_stop: - result, until, reason = protection_handler.stop_per_pair(pair, now) - if result and until: + lock, until, reason = protection_handler.stop_per_pair(pair, now) + if lock and until: if not PairLocks.is_pair_locked(pair, until): - PairLocks.lock_pair(pair, until, reason, now=now) - result = True + result = PairLocks.lock_pair(pair, until, reason, now=now) return result diff --git a/tests/plugins/test_protections.py b/tests/plugins/test_protections.py index c0a9ae72a..a3cb29c9d 100644 --- a/tests/plugins/test_protections.py +++ b/tests/plugins/test_protections.py @@ -125,7 +125,7 @@ def test_stoploss_guard(mocker, default_conf, fee, caplog): # Test 5m after lock-period - this should try and relock the pair, but end-time # should be the previous end-time end_time = PairLocks.get_pair_longest_lock('*').lock_end_time + timedelta(minutes=5) - assert freqtrade.protections.global_stop(end_time) + freqtrade.protections.global_stop(end_time) assert not PairLocks.is_global_lock(end_time) @@ -182,7 +182,7 @@ def test_stoploss_guard_perpair(mocker, default_conf, fee, caplog, only_per_pair min_ago_open=180, min_ago_close=30, profit_rate=0.9, )) - assert freqtrade.protections.stop_per_pair(pair) + freqtrade.protections.stop_per_pair(pair) assert freqtrade.protections.global_stop() != only_per_pair assert PairLocks.is_pair_locked(pair) assert PairLocks.is_global_lock() != only_per_pair From c91a9a92f2ccecc5aac46f25a999c0b4a97b20a7 Mon Sep 17 00:00:00 2001 From: Bernhard Millauer Date: Mon, 20 Sep 2021 14:22:24 +0200 Subject: [PATCH 04/76] Add troubleshooting information The time in wsl docker container shifts over time. Added information how to fix this issue. --- docs/docker_quickstart.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/docker_quickstart.md b/docs/docker_quickstart.md index 1fa229225..f4f8c366d 100644 --- a/docs/docker_quickstart.md +++ b/docs/docker_quickstart.md @@ -149,6 +149,20 @@ You'll then also need to modify the `docker-compose.yml` file and uncomment the You can then run `docker-compose build` to build the docker image, and run it using the commands described above. +### Troubleshooting + +### Docker on Windows + +* Error: `"Timestamp for this request is outside of the recvWindow."` + * The market api requests require a synchronized clock but the time in the docker container shifts a bit over time into the past. + To fix this issue temporarily you need to run `wsl --shutdown` and restart docker again (a popup on windows 10 will ask you to do so). + A permanent solution is either to host the docker container on a linux host or restart the wsl from time to time with the scheduler. + ``` + taskkill /IM "Docker Desktop.exe" /F + wsl --shutdown + start "" "C:\Program Files\Docker\Docker\Docker Desktop.exe" + ``` + ## Plotting with docker-compose Commands `freqtrade plot-profit` and `freqtrade plot-dataframe` ([Documentation](plotting.md)) are available by changing the image to `*_plot` in your docker-compose.yml file. From a0fb43c6caca7d0b0f06cf9814d43f69341339b6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 20 Sep 2021 19:12:59 +0200 Subject: [PATCH 05/76] Add pairlock-notification --- freqtrade/enums/rpcmessagetype.py | 1 + freqtrade/freqtradebot.py | 16 ++++++++++++++-- freqtrade/rpc/telegram.py | 5 +++++ tests/rpc/test_rpc_telegram.py | 14 ++++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/freqtrade/enums/rpcmessagetype.py b/freqtrade/enums/rpcmessagetype.py index 9c59f6108..889d67cf4 100644 --- a/freqtrade/enums/rpcmessagetype.py +++ b/freqtrade/enums/rpcmessagetype.py @@ -11,6 +11,7 @@ class RPCMessageType(Enum): SELL = 'sell' SELL_FILL = 'sell_fill' SELL_CANCEL = 'sell_cancel' + PROTECTION_TRIGGER = 'protection_trigger' def __repr__(self): return self.value diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 1cb8988ff..451b5764a 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1292,8 +1292,7 @@ class FreqtradeBot(LoggingMixin): if not trade.is_open: if not stoploss_order and not trade.open_order_id: self._notify_exit(trade, '', True) - self.protections.stop_per_pair(trade.pair) - self.protections.global_stop() + self.handle_protections(trade.pair) self.wallets.update() elif not trade.open_order_id: # Buy fill @@ -1301,6 +1300,19 @@ class FreqtradeBot(LoggingMixin): return False + def handle_protections(self, pair: str) -> None: + prot_trig = self.protections.stop_per_pair(pair) + if prot_trig: + msg = {'type': RPCMessageType.PROTECTION_TRIGGER, } + msg.update(prot_trig.to_json()) + self.rpc.send_msg(msg) + + prot_trig_glb = self.protections.global_stop() + if prot_trig_glb: + msg = {'type': RPCMessageType.PROTECTION_TRIGGER, } + msg.update(prot_trig_glb.to_json()) + self.rpc.send_msg(msg) + def apply_fee_conditional(self, trade: Trade, trade_base_currency: str, amount: float, fee_abs: float) -> float: """ diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 898446ea0..934a5182a 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -281,6 +281,11 @@ class Telegram(RPCHandler): "for {close_rate}.".format(**msg)) elif msg_type == RPCMessageType.SELL: message = self._format_sell_msg(msg) + elif msg_type == RPCMessageType.PROTECTION_TRIGGER: + message = ( + "*Protection* triggered due to {reason}. " + "{pair} will be locked until {lock_end_time}." + ).format(**msg) elif msg_type == RPCMessageType.STATUS: message = '*Status:* `{status}`'.format(**msg) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 21f1cd000..0675e4d5f 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1313,6 +1313,20 @@ def test_send_msg_buy_cancel_notification(default_conf, mocker) -> None: 'Reason: cancelled due to timeout.') +def test_send_msg_protection_notification(default_conf, mocker, time_machine) -> None: + + telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf) + time_machine.move_to("2021-09-01 05:00:00 +00:00") + lock = PairLocks.lock_pair('ETH/BTC', arrow.utcnow().shift(minutes=6).datetime, 'randreason') + msg = { + 'type': RPCMessageType.PROTECTION_TRIGGER, + } + msg.update(lock.to_json()) + telegram.send_msg(msg) + assert (msg_mock.call_args[0][0] == "*Protection* triggered due to randreason. " + "ETH/BTC will be locked until 2021-09-01 05:10:00.") + + def test_send_msg_buy_fill_notification(default_conf, mocker) -> None: default_conf['telegram']['notification_settings']['buy_fill'] = 'on' From dd0db7ee5db04fb98b542e9541d46768b9bb2c05 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 20 Sep 2021 19:23:40 +0200 Subject: [PATCH 06/76] Split protection-notification into global and per-pair --- config_examples/config_full.example.json | 4 +++- docs/telegram-usage.md | 4 +++- freqtrade/enums/rpcmessagetype.py | 1 + freqtrade/freqtradebot.py | 2 +- freqtrade/rpc/telegram.py | 6 +++++- tests/rpc/test_rpc_telegram.py | 13 +++++++++++++ 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/config_examples/config_full.example.json b/config_examples/config_full.example.json index d0f3f0df6..c415d70b0 100644 --- a/config_examples/config_full.example.json +++ b/config_examples/config_full.example.json @@ -149,7 +149,9 @@ }, "sell_fill": "on", "buy_cancel": "on", - "sell_cancel": "on" + "sell_cancel": "on", + "protection_trigger": "off", + "protection_trigger_global": "on" }, "reload": true, "balance_dust_level": 0.01 diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index b020b00db..1e6fa9dae 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -93,7 +93,9 @@ Example configuration showing the different settings: "buy_cancel": "silent", "sell_cancel": "on", "buy_fill": "off", - "sell_fill": "off" + "sell_fill": "off", + "protection_trigger": "off", + "protection_trigger_global": "on" }, "reload": true, "balance_dust_level": 0.01 diff --git a/freqtrade/enums/rpcmessagetype.py b/freqtrade/enums/rpcmessagetype.py index 889d67cf4..4e3f693e5 100644 --- a/freqtrade/enums/rpcmessagetype.py +++ b/freqtrade/enums/rpcmessagetype.py @@ -12,6 +12,7 @@ class RPCMessageType(Enum): SELL_FILL = 'sell_fill' SELL_CANCEL = 'sell_cancel' PROTECTION_TRIGGER = 'protection_trigger' + PROTECTION_TRIGGER_GLOBAL = 'protection_trigger_global' def __repr__(self): return self.value diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 451b5764a..37be3173a 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1309,7 +1309,7 @@ class FreqtradeBot(LoggingMixin): prot_trig_glb = self.protections.global_stop() if prot_trig_glb: - msg = {'type': RPCMessageType.PROTECTION_TRIGGER, } + msg = {'type': RPCMessageType.PROTECTION_TRIGGER_GLOBAL, } msg.update(prot_trig_glb.to_json()) self.rpc.send_msg(msg) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 934a5182a..0687f95a2 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -286,7 +286,11 @@ class Telegram(RPCHandler): "*Protection* triggered due to {reason}. " "{pair} will be locked until {lock_end_time}." ).format(**msg) - + elif msg_type == RPCMessageType.PROTECTION_TRIGGER_GLOBAL: + message = ( + "*Protection* triggered due to {reason}. " + "All pairs will be locked until {lock_end_time}." + ).format(**msg) elif msg_type == RPCMessageType.STATUS: message = '*Status:* `{status}`'.format(**msg) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 0675e4d5f..d37a74187 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1326,6 +1326,19 @@ def test_send_msg_protection_notification(default_conf, mocker, time_machine) -> assert (msg_mock.call_args[0][0] == "*Protection* triggered due to randreason. " "ETH/BTC will be locked until 2021-09-01 05:10:00.") + msg_mock.reset_mock() + # Test global protection + + msg = { + 'type': RPCMessageType.PROTECTION_TRIGGER_GLOBAL, + } + lock = PairLocks.lock_pair('*', arrow.utcnow().shift(minutes=100).datetime, 'randreason') + msg.update(lock.to_json()) + telegram.send_msg(msg) + assert (msg_mock.call_args[0][0] == "*Protection* triggered due to randreason. " + "All pairs will be locked until 2021-09-01 06:45:00.") + + def test_send_msg_buy_fill_notification(default_conf, mocker) -> None: From fd23ab3d647db7444d12129755ddf001e014dbcd Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 20 Sep 2021 19:49:18 +0200 Subject: [PATCH 07/76] improve formatting, add tests --- freqtrade/rpc/telegram.py | 4 ++-- tests/rpc/test_rpc_telegram.py | 5 ++--- tests/test_freqtradebot.py | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 0687f95a2..059ba9c41 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -284,12 +284,12 @@ class Telegram(RPCHandler): elif msg_type == RPCMessageType.PROTECTION_TRIGGER: message = ( "*Protection* triggered due to {reason}. " - "{pair} will be locked until {lock_end_time}." + "`{pair}` will be locked until `{lock_end_time}`." ).format(**msg) elif msg_type == RPCMessageType.PROTECTION_TRIGGER_GLOBAL: message = ( "*Protection* triggered due to {reason}. " - "All pairs will be locked until {lock_end_time}." + "*All pairs* will be locked until `{lock_end_time}`." ).format(**msg) elif msg_type == RPCMessageType.STATUS: message = '*Status:* `{status}`'.format(**msg) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index d37a74187..8c285a76e 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1324,7 +1324,7 @@ def test_send_msg_protection_notification(default_conf, mocker, time_machine) -> msg.update(lock.to_json()) telegram.send_msg(msg) assert (msg_mock.call_args[0][0] == "*Protection* triggered due to randreason. " - "ETH/BTC will be locked until 2021-09-01 05:10:00.") + "`ETH/BTC` will be locked until `2021-09-01 05:10:00`.") msg_mock.reset_mock() # Test global protection @@ -1336,8 +1336,7 @@ def test_send_msg_protection_notification(default_conf, mocker, time_machine) -> msg.update(lock.to_json()) telegram.send_msg(msg) assert (msg_mock.call_args[0][0] == "*Protection* triggered due to randreason. " - "All pairs will be locked until 2021-09-01 06:45:00.") - + "*All pairs* will be locked until `2021-09-01 06:45:00`.") def test_send_msg_buy_fill_notification(default_conf, mocker) -> None: diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index eb3c77cc7..e1df6dad9 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -526,6 +526,29 @@ def test_enter_positions_global_pairlock(default_conf, ticker, limit_buy_order, assert log_has_re(message, caplog) +def test_handle_protections(mocker, default_conf, fee): + default_conf['protections'] = [ + {"method": "CooldownPeriod", "stop_duration": 60}, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": 4, + "only_per_pair": False + } + ] + + freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade.protections._protection_handlers[1].global_stop = MagicMock( + return_value=(True, arrow.utcnow().shift(hours=1).datetime, "asdf")) + create_mock_trades(fee) + freqtrade.handle_protections('ETC/BTC') + send_msg_mock = freqtrade.rpc.send_msg + assert send_msg_mock.call_count == 2 + assert send_msg_mock.call_args_list[0][0][0]['type'] == RPCMessageType.PROTECTION_TRIGGER + assert send_msg_mock.call_args_list[1][0][0]['type'] == RPCMessageType.PROTECTION_TRIGGER_GLOBAL + + def test_create_trade_no_signal(default_conf, fee, mocker) -> None: default_conf['dry_run'] = True From 3ce05c0d548119fd5618ba2700313a69ec10f3c5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 20 Sep 2021 20:08:48 +0200 Subject: [PATCH 08/76] Add "sane" defaults to protection triggers --- docs/telegram-usage.md | 1 + freqtrade/constants.py | 9 +++++++++ tests/rpc/test_rpc_telegram.py | 2 ++ 3 files changed, 12 insertions(+) diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index 1e6fa9dae..b9d01a236 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -105,6 +105,7 @@ Example configuration showing the different settings: `buy` notifications are sent when the order is placed, while `buy_fill` notifications are sent when the order is filled on the exchange. `sell` notifications are sent when the order is placed, while `sell_fill` notifications are sent when the order is filled on the exchange. `*_fill` notifications are off by default and must be explicitly enabled. +`protection_trigger` notifications are sent when a protection triggers and `protection_trigger_global` notifications trigger when global protections are triggered. `balance_dust_level` will define what the `/balance` command takes as "dust" - Currencies with a balance below this will be shown. diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 9ca43d459..4997108bc 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -284,6 +284,15 @@ CONF_SCHEMA = { 'enum': TELEGRAM_SETTING_OPTIONS, 'default': 'off' }, + 'protection_trigger': { + 'type': 'string', + 'enum': TELEGRAM_SETTING_OPTIONS, + 'default': 'off' + }, + 'protection_trigger_global': { + 'type': 'string', + 'enum': TELEGRAM_SETTING_OPTIONS, + }, } }, 'reload': {'type': 'boolean'}, diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 8c285a76e..7dde7b803 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1315,6 +1315,8 @@ def test_send_msg_buy_cancel_notification(default_conf, mocker) -> None: def test_send_msg_protection_notification(default_conf, mocker, time_machine) -> None: + default_conf['telegram']['notification_settings']['protection_trigger'] = 'on' + telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf) time_machine.move_to("2021-09-01 05:00:00 +00:00") lock = PairLocks.lock_pair('ETH/BTC', arrow.utcnow().shift(minutes=6).datetime, 'randreason') From abddb0db66b431abf5902a8fa74dbf5f2cf16e56 Mon Sep 17 00:00:00 2001 From: Bernhard Millauer Date: Tue, 21 Sep 2021 10:13:19 +0200 Subject: [PATCH 09/76] Fix header indention Co-authored-by: Matthias --- docs/docker_quickstart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docker_quickstart.md b/docs/docker_quickstart.md index f4f8c366d..33b1c7ea1 100644 --- a/docs/docker_quickstart.md +++ b/docs/docker_quickstart.md @@ -151,7 +151,7 @@ You can then run `docker-compose build` to build the docker image, and run it us ### Troubleshooting -### Docker on Windows +#### Docker on Windows * Error: `"Timestamp for this request is outside of the recvWindow."` * The market api requests require a synchronized clock but the time in the docker container shifts a bit over time into the past. From 6fc770d97dd8d4380be3fb94e8f3dcedfa981cd7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 21 Sep 2021 15:12:35 +0200 Subject: [PATCH 10/76] Add warning about running with docker on windows --- docs/docker_quickstart.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/docker_quickstart.md b/docs/docker_quickstart.md index 33b1c7ea1..2f350d207 100644 --- a/docs/docker_quickstart.md +++ b/docs/docker_quickstart.md @@ -163,6 +163,10 @@ You can then run `docker-compose build` to build the docker image, and run it us start "" "C:\Program Files\Docker\Docker\Docker Desktop.exe" ``` +!!! Warning + Due to the above, we do not recommend the usage of docker on windows for production setups, but only for experimentation, datadownload and backtesting. + Best use a linux-VPS for running freqtrade reliably. + ## Plotting with docker-compose Commands `freqtrade plot-profit` and `freqtrade plot-dataframe` ([Documentation](plotting.md)) are available by changing the image to `*_plot` in your docker-compose.yml file. From 277828bf0ebac1c370b02b4dfb6ca15628d63b1e Mon Sep 17 00:00:00 2001 From: matt ferrante Date: Tue, 21 Sep 2021 07:56:16 -0600 Subject: [PATCH 11/76] parameterize some tests --- tests/test_freqtradebot.py | 219 ++++++++++++++----------------------- 1 file changed, 84 insertions(+), 135 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 72d1f6150..d96ef71d6 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3545,8 +3545,34 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, f caplog) -def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, fee, mocker): - trades_for_order[0]['fee']['currency'] = 'ETH' +@pytest.mark.parametrize( + 'fee_cost, fee_currency, fee_reduction_amount, use_ticker_rate, expected_log', + [ + (None, 'ETH', 0, True, None), + (0.004, None, 0, True, None), + (0.00094518, "BNB", 0, True, None), + ( + 0.004, + "LTC", + 0.004, + False, + ( + '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).' + ) + ), + (0.008, None, 0, True, None), + ] +) +def test_get_real_amount( + default_conf, trades_for_order, buy_order_fee, fee, mocker, caplog, + fee_cost, fee_currency, fee_reduction_amount, use_ticker_rate, expected_log +): + + buy_order = deepcopy(buy_order_fee) + buy_order['fee'] = {'cost': fee_cost, 'currency': fee_currency} + trades_for_order[0]['fee']['cost'] = fee_cost + trades_for_order[0]['fee']['currency'] = fee_currency mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) amount = sum(x['amount'] for x in trades_for_order) @@ -3561,19 +3587,58 @@ def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, fe ) freqtrade = get_patched_freqtradebot(mocker, default_conf) + if not use_ticker_rate: + mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', side_effect=ExchangeError) + # Amount does not change - assert freqtrade.get_real_amount(trade, buy_order_fee) == amount + assert freqtrade.get_real_amount(trade, buy_order) == amount - fee_reduction_amount + + if expected_log: + assert log_has(expected_log, caplog) -def test_get_real_amount_no_currency_in_fee(default_conf, trades_for_order, buy_order_fee, - fee, mocker): +@pytest.mark.parametrize( + 'stake_currency, fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log', + [ + ( + "BTC", + None, + None, + 0.001, + 0.001, + ( + '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).' + ) + ), + ( + "ETH", + 0.02, + 'BNB', + 0.0005, + 0.001518575, + ( + '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).' + ) + ), + ] +) +def test_get_real_amount_multi( + default_conf, trades_for_order2, buy_order_fee, caplog, fee, mocker, markets, + stake_currency, fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log, +): - limit_buy_order = deepcopy(buy_order_fee) - limit_buy_order['fee'] = {'cost': 0.004, 'currency': None} - trades_for_order[0]['fee']['currency'] = None + trades_for_order = deepcopy(trades_for_order2) + if fee_cost: + trades_for_order[0]['fee']['cost'] = fee_cost + if fee_currency: + trades_for_order[0]['fee']['currency'] = fee_currency mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) - amount = sum(x['amount'] for x in trades_for_order) + amount = float(sum(x['amount'] for x in trades_for_order)) + default_conf['stake_currency'] = stake_currency + trade = Trade( pair='LTC/ETH', amount=amount, @@ -3583,124 +3648,29 @@ def test_get_real_amount_no_currency_in_fee(default_conf, trades_for_order, buy_ open_rate=0.245441, open_order_id="123456" ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) - # Amount does not change - assert freqtrade.get_real_amount(trade, limit_buy_order) == amount - - -def test_get_real_amount_BNB(default_conf, trades_for_order, buy_order_fee, fee, mocker): - trades_for_order[0]['fee']['currency'] = 'BNB' - trades_for_order[0]['fee']['cost'] = 0.00094518 - - mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) - amount = sum(x['amount'] for x in trades_for_order) - trade = Trade( - pair='LTC/ETH', - amount=amount, - exchange='binance', - fee_open=fee.return_value, - fee_close=fee.return_value, - open_rate=0.245441, - open_order_id="123456" - ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) - - # Amount does not change - assert freqtrade.get_real_amount(trade, buy_order_fee) == amount - - -def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, caplog, fee, mocker): - mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order2) - amount = float(sum(x['amount'] for x in trades_for_order2)) - trade = Trade( - pair='LTC/ETH', - amount=amount, - exchange='binance', - fee_open=fee.return_value, - fee_close=fee.return_value, - open_rate=0.245441, - open_order_id="123456" - ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) - - # Amount is reduced by "fee" - assert freqtrade.get_real_amount(trade, buy_order_fee) == amount - (amount * 0.001) - 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) - - assert trade.fee_open == 0.001 - assert trade.fee_close == 0.001 - assert trade.fee_open_cost is not None - assert trade.fee_open_currency is not None - assert trade.fee_close_cost is None - assert trade.fee_close_currency is None - - -def test_get_real_amount_multi2(default_conf, trades_for_order3, buy_order_fee, caplog, fee, - mocker, markets): - # Different fee currency on both trades - mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order3) - amount = float(sum(x['amount'] for x in trades_for_order3)) - default_conf['stake_currency'] = 'ETH' - trade = Trade( - pair='LTC/ETH', - amount=amount, - exchange='binance', - fee_open=fee.return_value, - fee_close=fee.return_value, - open_rate=0.245441, - open_order_id="123456" - ) # Fake markets entry to enable fee parsing markets['BNB/ETH'] = markets['ETH/BTC'] freqtrade = get_patched_freqtradebot(mocker, default_conf) mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets)) - mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', - return_value={'ask': 0.19, 'last': 0.2}) + mocker.patch( + 'freqtrade.exchange.Exchange.fetch_ticker', + return_value={'ask': 0.19, 'last': 0.2} + ) # Amount is reduced by "fee" - assert freqtrade.get_real_amount(trade, buy_order_fee) == amount - (amount * 0.0005) - 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) - # Overall fee is average of both trade's fee - assert trade.fee_open == 0.001518575 + expected_amount = amount - (amount * fee_reduction_amount) + assert freqtrade.get_real_amount(trade, buy_order_fee) == expected_amount + assert log_has(expected_log, caplog) + + assert trade.fee_open == expected_fee + assert trade.fee_close == expected_fee assert trade.fee_open_cost is not None assert trade.fee_open_currency is not None assert trade.fee_close_cost is None assert trade.fee_close_currency is None -def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee, fee, - caplog, mocker): - limit_buy_order = deepcopy(buy_order_fee) - limit_buy_order['fee'] = {'cost': 0.004, 'currency': 'LTC'} - - mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', - return_value=[trades_for_order]) - amount = float(sum(x['amount'] for x in trades_for_order)) - trade = Trade( - pair='LTC/ETH', - amount=amount, - exchange='binance', - fee_open=fee.return_value, - fee_close=fee.return_value, - open_rate=0.245441, - open_order_id="123456" - ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) - # Ticker rate cannot be found for this to work. - mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', side_effect=ExchangeError) - - # Amount is reduced by "fee" - assert freqtrade.get_real_amount(trade, limit_buy_order) == amount - 0.004 - 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) - - def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order_fee, fee, mocker): limit_buy_order = deepcopy(buy_order_fee) limit_buy_order['fee'] = {'cost': 0.004} @@ -3768,27 +3738,6 @@ def test_get_real_amount_wrong_amount_rounding(default_conf, trades_for_order, b abs_tol=MATH_CLOSE_PREC,) -def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee, fee, mocker): - # Remove "Currency" from fee dict - trades_for_order[0]['fee'] = {'cost': 0.008} - - mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) - amount = sum(x['amount'] for x in trades_for_order) - trade = Trade( - pair='LTC/ETH', - amount=amount, - exchange='binance', - open_rate=0.245441, - fee_open=fee.return_value, - fee_close=fee.return_value, - - open_order_id="123456" - ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) - # Amount does not change - assert freqtrade.get_real_amount(trade, buy_order_fee) == amount - - def test_get_real_amount_open_trade(default_conf, fee, mocker): amount = 12345 trade = Trade( From 707d0ef795868961fe652046f12a190047809de3 Mon Sep 17 00:00:00 2001 From: matt ferrante Date: Tue, 21 Sep 2021 12:16:10 -0600 Subject: [PATCH 12/76] remove trades_for_order3 --- tests/conftest.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 5e08e7097..7354c0b2c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1685,14 +1685,6 @@ def trades_for_order2(): 'fee': {'cost': 0.004, 'currency': 'LTC'}}] -@pytest.fixture(scope="function") -def trades_for_order3(trades_for_order2): - # Different fee currencies for each trade - trades_for_order = deepcopy(trades_for_order2) - trades_for_order[0]['fee'] = {'cost': 0.02, 'currency': 'BNB'} - return trades_for_order - - @pytest.fixture def buy_order_fee(): return { From b0de4d333e86bfe23f065ab365e2ab18bb7ca41d Mon Sep 17 00:00:00 2001 From: Peter Willemsen Date: Tue, 21 Sep 2021 23:20:40 +0200 Subject: [PATCH 13/76] fixed webhook error --- freqtrade/freqtradebot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 1cb8988ff..95f2280ac 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1217,7 +1217,7 @@ class FreqtradeBot(LoggingMixin): 'exchange': trade.exchange.capitalize(), 'pair': trade.pair, 'gain': gain, - 'limit': profit_rate, + 'limit': profit_rate or 0, 'order_type': order_type, 'amount': trade.amount, 'open_rate': trade.open_rate, @@ -1226,7 +1226,7 @@ class FreqtradeBot(LoggingMixin): 'profit_ratio': profit_ratio, 'sell_reason': trade.sell_reason, 'open_date': trade.open_date, - 'close_date': trade.close_date, + 'close_date': trade.close_date or datetime.utcnow(), 'stake_currency': self.config['stake_currency'], 'fiat_currency': self.config.get('fiat_display_currency', None), 'reason': reason, From 553c868d7f2a8d4e7edafaccdf814cc7249e0ac9 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Tue, 21 Sep 2021 16:40:24 -0600 Subject: [PATCH 14/76] combined test_order_book_depth_of_market and test_order_book_depth_of_market_high_delta --- tests/test_freqtradebot.py | 122 +++++++++++++------------------------ 1 file changed, 42 insertions(+), 80 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index d96ef71d6..0a2f73263 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3546,24 +3546,19 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, f @pytest.mark.parametrize( - 'fee_cost, fee_currency, fee_reduction_amount, use_ticker_rate, expected_log', - [ + 'fee_cost, fee_currency, fee_reduction_amount, use_ticker_rate, expected_log', [ (None, 'ETH', 0, True, None), (0.004, None, 0, True, None), - (0.00094518, "BNB", 0, True, None), - ( - 0.004, - "LTC", - 0.004, - False, - ( - '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).' - ) - ), + (0.00094518, "BNB", 0, True, ( + 'Fee for Trade Trade(id=None, pair=LTC/ETH, amount=8.00000000, open_rate=0.24544100,' + ' open_since=closed) [buy]: 0.00094518 BNB - rate: None' + )), + (0.004, "LTC", 0.004, False, ( + '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).' + )), (0.008, None, 0, True, None), - ] -) + ]) def test_get_real_amount( default_conf, trades_for_order, buy_order_fee, fee, mocker, caplog, fee_cost, fee_currency, fee_reduction_amount, use_ticker_rate, expected_log @@ -3590,6 +3585,7 @@ def test_get_real_amount( if not use_ticker_rate: mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', side_effect=ExchangeError) + caplog.clear() # Amount does not change assert freqtrade.get_real_amount(trade, buy_order) == amount - fee_reduction_amount @@ -3598,32 +3594,16 @@ def test_get_real_amount( @pytest.mark.parametrize( - 'stake_currency, fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log', - [ - ( - "BTC", - None, - None, - 0.001, - 0.001, - ( - '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).' - ) - ), - ( - "ETH", - 0.02, - 'BNB', - 0.0005, - 0.001518575, - ( - '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).' - ) - ), - ] -) + 'stake_currency, fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log', [ + ("BTC", None, None, 0.001, 0.001, ( + '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).' + )), + ("ETH", 0.02, 'BNB', 0.0005, 0.001518575, ( + '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).' + )), + ]) def test_get_real_amount_multi( default_conf, trades_for_order2, buy_order_fee, caplog, fee, mocker, markets, stake_currency, fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log, @@ -3653,10 +3633,8 @@ def test_get_real_amount_multi( markets['BNB/ETH'] = markets['ETH/BTC'] freqtrade = get_patched_freqtradebot(mocker, default_conf) mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets)) - mocker.patch( - 'freqtrade.exchange.Exchange.fetch_ticker', - return_value={'ask': 0.19, 'last': 0.2} - ) + mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', + return_value={'ask': 0.19, 'last': 0.2}) # Amount is reduced by "fee" expected_amount = amount - (amount * fee_reduction_amount) @@ -3788,10 +3766,14 @@ def test_apply_fee_conditional(default_conf, fee, caplog, mocker, assert walletmock.call_count == 1 +@pytest.mark.parametrize("delta, is_high_delta", [ + (0.1, False), + (100, True), +]) def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order_open, limit_buy_order, - fee, mocker, order_book_l2): + fee, mocker, order_book_l2, delta, is_high_delta): default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True - default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 0.1 + default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = delta patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2) @@ -3809,42 +3791,22 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order_open, freqtrade.enter_positions() trade = Trade.query.first() - assert trade is not None - assert trade.stake_amount == 0.001 - assert trade.is_open - assert trade.open_date is not None - assert trade.exchange == 'binance' + if is_high_delta: + assert trade is None + else: + assert trade is not None + assert trade.stake_amount == 0.001 + assert trade.is_open + assert trade.open_date is not None + assert trade.exchange == 'binance' - assert len(Trade.query.all()) == 1 + assert len(Trade.query.all()) == 1 - # Simulate fulfilled LIMIT_BUY order for trade - trade.update(limit_buy_order) + # Simulate fulfilled LIMIT_BUY order for trade + trade.update(limit_buy_order) - assert trade.open_rate == 0.00001099 - assert whitelist == default_conf['exchange']['pair_whitelist'] - - -def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_order, - fee, mocker, order_book_l2): - default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True - # delta is 100 which is impossible to reach. hence check_depth_of_market will return false - default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 100 - patch_RPCManager(mocker) - patch_exchange(mocker) - mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2) - mocker.patch.multiple( - 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, - create_order=MagicMock(return_value={'id': limit_buy_order['id']}), - get_fee=fee, - ) - # Save state of current whitelist - freqtrade = FreqtradeBot(default_conf) - patch_get_signal(freqtrade) - freqtrade.enter_positions() - - trade = Trade.query.first() - assert trade is None + assert trade.open_rate == 0.00001099 + assert whitelist == default_conf['exchange']['pair_whitelist'] @pytest.mark.parametrize('exception_thrown,ask,last,order_book_top,order_book', [ From f768bdea503780b6c220afe36691fbbd09752689 Mon Sep 17 00:00:00 2001 From: matt ferrante Date: Wed, 22 Sep 2021 10:32:30 -0600 Subject: [PATCH 15/76] cleanup based on feedback --- tests/test_freqtradebot.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 0a2f73263..eaaadbcb1 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3594,19 +3594,13 @@ def test_get_real_amount( @pytest.mark.parametrize( - 'stake_currency, fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log', [ - ("BTC", None, None, 0.001, 0.001, ( - '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).' - )), - ("ETH", 0.02, 'BNB', 0.0005, 0.001518575, ( - '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).' - )), + 'stake_currency, fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log_amount', [ + (None, None, None, 0.001, 0.001, 7.992), + ("ETH", 0.02, 'BNB', 0.0005, 0.001518575, 7.996), ]) def test_get_real_amount_multi( default_conf, trades_for_order2, buy_order_fee, caplog, fee, mocker, markets, - stake_currency, fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log, + stake_currency, fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log_amount, ): trades_for_order = deepcopy(trades_for_order2) @@ -3617,7 +3611,8 @@ def test_get_real_amount_multi( mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) amount = float(sum(x['amount'] for x in trades_for_order)) - default_conf['stake_currency'] = stake_currency + if stake_currency: + default_conf['stake_currency'] = stake_currency trade = Trade( pair='LTC/ETH', @@ -3639,7 +3634,13 @@ def test_get_real_amount_multi( # Amount is reduced by "fee" expected_amount = amount - (amount * fee_reduction_amount) assert freqtrade.get_real_amount(trade, buy_order_fee) == expected_amount - assert log_has(expected_log, caplog) + assert log_has( + ( + 'Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, ' + f'open_rate=0.24544100, open_since=closed) (from 8.0 to {expected_log_amount}).' + ), + caplog + ) assert trade.fee_open == expected_fee assert trade.fee_close == expected_fee From 8cfb6ddd518bc4edf910c9f07afdc1ee85d103aa Mon Sep 17 00:00:00 2001 From: matt ferrante Date: Wed, 22 Sep 2021 10:48:13 -0600 Subject: [PATCH 16/76] fix long line --- tests/test_freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index eaaadbcb1..b987d54d8 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3594,7 +3594,7 @@ def test_get_real_amount( @pytest.mark.parametrize( - 'stake_currency, fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log_amount', [ + 'stake_currency,fee_cost,fee_currency,fee_reduction_amount,expected_fee,expected_log_amount', [ (None, None, None, 0.001, 0.001, 7.992), ("ETH", 0.02, 'BNB', 0.0005, 0.001518575, 7.996), ]) From 30cc69c880cf736225f6246331527ab202398588 Mon Sep 17 00:00:00 2001 From: matt ferrante Date: Wed, 22 Sep 2021 11:28:42 -0600 Subject: [PATCH 17/76] set all to eth for multi test --- tests/test_freqtradebot.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index b987d54d8..8e036e80a 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3594,13 +3594,13 @@ def test_get_real_amount( @pytest.mark.parametrize( - 'stake_currency,fee_cost,fee_currency,fee_reduction_amount,expected_fee,expected_log_amount', [ - (None, None, None, 0.001, 0.001, 7.992), - ("ETH", 0.02, 'BNB', 0.0005, 0.001518575, 7.996), + 'fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log_amount', [ + (None, None, 0.001, 0.001, 7.992), + (0.02, 'BNB', 0.0005, 0.001518575, 7.996), ]) def test_get_real_amount_multi( default_conf, trades_for_order2, buy_order_fee, caplog, fee, mocker, markets, - stake_currency, fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log_amount, + fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log_amount, ): trades_for_order = deepcopy(trades_for_order2) @@ -3611,8 +3611,7 @@ def test_get_real_amount_multi( mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) amount = float(sum(x['amount'] for x in trades_for_order)) - if stake_currency: - default_conf['stake_currency'] = stake_currency + default_conf['stake_currency'] = "ETH" trade = Trade( pair='LTC/ETH', From 2bf49445b7db8a15681f8fb690d3db6162f0e8c1 Mon Sep 17 00:00:00 2001 From: matt ferrante Date: Wed, 22 Sep 2021 16:11:27 -0600 Subject: [PATCH 18/76] add parameterized names --- tests/test_freqtradebot.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 8e036e80a..9c9271810 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3547,16 +3547,21 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, f @pytest.mark.parametrize( 'fee_cost, fee_currency, fee_reduction_amount, use_ticker_rate, expected_log', [ + # basic, amount does not change (None, 'ETH', 0, True, None), + # no currency in fee (0.004, None, 0, True, None), + # BNB no rate (0.00094518, "BNB", 0, True, ( 'Fee for Trade Trade(id=None, pair=LTC/ETH, amount=8.00000000, open_rate=0.24544100,' ' open_since=closed) [buy]: 0.00094518 BNB - rate: None' )), + # from order (0.004, "LTC", 0.004, False, ( '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).' )), + # invalid, no currency in from fee dict (0.008, None, 0, True, None), ]) def test_get_real_amount( @@ -3586,7 +3591,6 @@ def test_get_real_amount( mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', side_effect=ExchangeError) caplog.clear() - # Amount does not change assert freqtrade.get_real_amount(trade, buy_order) == amount - fee_reduction_amount if expected_log: @@ -3595,7 +3599,9 @@ def test_get_real_amount( @pytest.mark.parametrize( 'fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log_amount', [ + # basic, amount is reduced by fee (None, None, 0.001, 0.001, 7.992), + # different fee currency on both trades, fee is average of both trade's fee (0.02, 'BNB', 0.0005, 0.001518575, 7.996), ]) def test_get_real_amount_multi( From d7903f012f7af5f3c19df527780456bab0ca986f Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 23 Sep 2021 07:25:11 +0200 Subject: [PATCH 19/76] Move PerformanceWarning to advanced section rewrite to use strategy parameters instead of plain range --- docs/strategy-advanced.md | 30 ++++++++++++++++++++++++++++++ docs/strategy-customization.md | 27 --------------------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/docs/strategy-advanced.md b/docs/strategy-advanced.md index 4409af6ea..d7d0dd04a 100644 --- a/docs/strategy-advanced.md +++ b/docs/strategy-advanced.md @@ -695,3 +695,33 @@ The variable 'content', will contain the strategy file in a BASE64 encoded form. ``` Please ensure that 'NameOfStrategy' is identical to the strategy name! + +## Performance warning + +When executing a strategy, one can sometimes be greeted by the following in the logs + +> PerformanceWarning: DataFrame is highly fragmented. + +This is a warning from [`pandas`](https://github.com/pandas-dev/pandas) and as the warning continues to say: +use `pd.concat(axis=1)`. +This can have slight performance implications, which are usually only visible during hyperopt (when optimizing an indicator). + +For example: + +```python +for val in self.buy_ema_short.range: + dataframe[f'ema_short_{val}'] = ta.EMA(dataframe, timeperiod=val) +``` + +should be rewritten to + +```python +frames = [dataframe] +for val in self.buy_ema_short.range: + frames.append({ + f'ema_short_{val}': ta.EMA(dataframe, timeperiod=val) + }) + +# Append columns to existing dataframe +merged_frame = pd.concat(frames, axis=1) +``` diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index 194517b2b..6d6eff2aa 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -793,33 +793,6 @@ The following lists some common patterns which should be avoided to prevent frus - don't use `dataframe['volume'].mean()`. This uses the full DataFrame for backtesting, including data from the future. Use `dataframe['volume'].rolling().mean()` instead - don't use `.resample('1h')`. This uses the left border of the interval, so moves data from an hour to the start of the hour. Use `.resample('1h', label='right')` instead. -### Performance warning - -When executing a strategy, one can sometimes be greeted by the following in the logs - -> PerformanceWarning: DataFrame is highly fragmented. - -This is a warning from [`pandas`](https://github.com/pandas-dev/pandas) and as the warning continues to say: - use `pd.concat(axis=1)`. For example - -```python -for i in range(100): - dataframe[i] = ta.indicator(dataframe, param=i) -``` - -should be rewritten to - -```python -frames = [dataframe] -for i in range(100): - frames.append({ - str(i): ta.indicator(dataframe, param=i) - }) - -# Append columns to existing dataframe -merged_frame = pd.concat(frames, axis=1) -``` - ## Further strategy ideas To get additional Ideas for strategies, head over to our [strategy repository](https://github.com/freqtrade/freqtrade-strategies). Feel free to use them as they are - but results will depend on the current market situation, pairs used etc. - therefore please backtest the strategy for your exchange/desired pairs first, evaluate carefully, use at your own risk. From 692e91a26dfa2ec1c746923d481421cc87a15b8c Mon Sep 17 00:00:00 2001 From: Peter Willemsen Date: Thu, 23 Sep 2021 10:28:15 +0200 Subject: [PATCH 20/76] changed close date from datetime.utcnow() to datetime.now(timezone.utc) --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 95f2280ac..9cfd219a8 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1226,7 +1226,7 @@ class FreqtradeBot(LoggingMixin): 'profit_ratio': profit_ratio, 'sell_reason': trade.sell_reason, 'open_date': trade.open_date, - 'close_date': trade.close_date or datetime.utcnow(), + 'close_date': trade.close_date or datetime.now(timezone.utc), 'stake_currency': self.config['stake_currency'], 'fiat_currency': self.config.get('fiat_display_currency', None), 'reason': reason, From 422d5601890f9749ab7f69a903d2de3f68ea9257 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Sep 2021 05:05:55 +0000 Subject: [PATCH 21/76] Bump types-requests from 2.25.6 to 2.25.8 Bumps [types-requests](https://github.com/python/typeshed) from 2.25.6 to 2.25.8. - [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 4859e1cc6..d8d8ce916 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -23,5 +23,5 @@ nbconvert==6.1.0 # mypy types types-cachetools==4.2.0 types-filelock==0.1.5 -types-requests==2.25.6 +types-requests==2.25.8 types-tabulate==0.8.2 From e85dc6326302e83da897b06941ca725f6d5f242c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Sep 2021 05:06:01 +0000 Subject: [PATCH 22/76] Bump mkdocs-material from 7.2.6 to 7.3.0 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 7.2.6 to 7.3.0. - [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.6...7.3.0) --- updated-dependencies: - dependency-name: mkdocs-material dependency-type: direct:production update-type: version-update:semver-minor ... 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 9927740c2..9b7c12a43 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,4 +1,4 @@ mkdocs==1.2.2 -mkdocs-material==7.2.6 +mkdocs-material==7.3.0 mdx_truly_sane_lists==1.2 pymdown-extensions==8.2 From 766ef90b56cf190b8beeba1a249d9b53792fbba2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Sep 2021 05:06:16 +0000 Subject: [PATCH 23/76] Bump sqlalchemy from 1.4.23 to 1.4.25 Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 1.4.23 to 1.4.25. - [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases) - [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/master/CHANGES) - [Commits](https://github.com/sqlalchemy/sqlalchemy/commits) --- updated-dependencies: - dependency-name: sqlalchemy 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 aa729dd9f..74ce391ed 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ ccxt==1.56.30 # Pin cryptography for now due to rust build errors with piwheels cryptography==3.4.8 aiohttp==3.7.4.post0 -SQLAlchemy==1.4.23 +SQLAlchemy==1.4.25 python-telegram-bot==13.7 arrow==1.1.1 cachetools==4.2.2 From 90d5af9a35211a51756603cfb3ffcb3cf67edc17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Sep 2021 05:06:20 +0000 Subject: [PATCH 24/76] Bump urllib3 from 1.26.6 to 1.26.7 Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.6 to 1.26.7. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/1.26.7/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.26.6...1.26.7) --- updated-dependencies: - dependency-name: urllib3 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 aa729dd9f..2f6a4a104 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ python-telegram-bot==13.7 arrow==1.1.1 cachetools==4.2.2 requests==2.26.0 -urllib3==1.26.6 +urllib3==1.26.7 wrapt==1.12.1 jsonschema==3.2.0 TA-Lib==0.4.21 From 0353f070f9714655e1ccb06448ffa03dbe3f5fb0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Sep 2021 05:06:24 +0000 Subject: [PATCH 25/76] Bump progressbar2 from 3.53.2 to 3.53.3 Bumps [progressbar2](https://github.com/WoLpH/python-progressbar) from 3.53.2 to 3.53.3. - [Release notes](https://github.com/WoLpH/python-progressbar/releases) - [Changelog](https://github.com/WoLpH/python-progressbar/blob/develop/CHANGES.rst) - [Commits](https://github.com/WoLpH/python-progressbar/compare/v3.53.2...v3.53.3) --- updated-dependencies: - dependency-name: progressbar2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-hyperopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index 7dc55a9fc..9feec80f1 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -8,4 +8,4 @@ scikit-optimize==0.8.1 filelock==3.0.12 joblib==1.0.1 psutil==5.8.0 -progressbar2==3.53.2 +progressbar2==3.53.3 From 954c468191b3c130c62d7bedfde1ff138f427908 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Sep 2021 07:12:38 +0200 Subject: [PATCH 26/76] Add pandas-ta to requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index aa729dd9f..f0da0cdb9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ numpy==1.21.2 pandas==1.3.3 +pandas-ta==0.3.14b ccxt==1.56.30 # Pin cryptography for now due to rust build errors with piwheels From 72a1e27fc6cc0454dfb3035f4957820dd6c6423d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Sep 2021 07:31:20 +0000 Subject: [PATCH 27/76] Bump ccxt from 1.56.30 to 1.56.86 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.56.30 to 1.56.86. - [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.56.30...1.56.86) --- 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 3b004dfaa..ede0c74e3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.21.2 pandas==1.3.3 pandas-ta==0.3.14b -ccxt==1.56.30 +ccxt==1.56.86 # Pin cryptography for now due to rust build errors with piwheels cryptography==3.4.8 aiohttp==3.7.4.post0 From b59906b117f300aefd828fa02c8b5c5658388df1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Sep 2021 19:24:33 +0200 Subject: [PATCH 28/76] Update minimum for tradable_balance_ratio to 0.0 --- freqtrade/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 4997108bc..fca319a0f 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -110,7 +110,7 @@ CONF_SCHEMA = { }, 'tradable_balance_ratio': { 'type': 'number', - 'minimum': 0.1, + 'minimum': 0.0, 'maximum': 1, 'default': 0.99 }, From 4c268847d42043d53fc59751ffd1717125d9e0bd Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Sep 2021 19:32:22 +0200 Subject: [PATCH 29/76] Add pandas-ta to setup.py --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 727c40c7c..cf381bdd3 100644 --- a/setup.py +++ b/setup.py @@ -54,6 +54,7 @@ setup( 'wrapt', 'jsonschema', 'TA-Lib', + 'pandas-ta', 'technical', 'tabulate', 'pycoingecko', From f4f204d849eb65eed74a1ac09e1ad52e5a641ee9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Sep 2021 20:09:24 +0200 Subject: [PATCH 30/76] Update test to use cost dict --- tests/test_freqtradebot.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 9c9271810..b233a6267 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3546,33 +3546,32 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, f @pytest.mark.parametrize( - 'fee_cost, fee_currency, fee_reduction_amount, use_ticker_rate, expected_log', [ + 'fee_par,fee_reduction_amount,use_ticker_rate,expected_log', [ # basic, amount does not change - (None, 'ETH', 0, True, None), + ({'cost': 0.008, 'currency': 'ETH'}, 0, False, None), # no currency in fee - (0.004, None, 0, True, None), + ({'cost': 0.004, 'currency': None}, 0, True, None), # BNB no rate - (0.00094518, "BNB", 0, True, ( + ({'cost': 0.00094518, 'currency': 'BNB'}, 0, True, ( 'Fee for Trade Trade(id=None, pair=LTC/ETH, amount=8.00000000, open_rate=0.24544100,' ' open_since=closed) [buy]: 0.00094518 BNB - rate: None' )), # from order - (0.004, "LTC", 0.004, False, ( + ({'cost': 0.004, 'currency': 'LTC'}, 0.004, False, ( '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).' )), # invalid, no currency in from fee dict - (0.008, None, 0, True, None), + ({'cost': 0.008, 'currency': None}, 0, True, None), ]) def test_get_real_amount( default_conf, trades_for_order, buy_order_fee, fee, mocker, caplog, - fee_cost, fee_currency, fee_reduction_amount, use_ticker_rate, expected_log + fee_par, fee_reduction_amount, use_ticker_rate, expected_log ): buy_order = deepcopy(buy_order_fee) - buy_order['fee'] = {'cost': fee_cost, 'currency': fee_currency} - trades_for_order[0]['fee']['cost'] = fee_cost - trades_for_order[0]['fee']['currency'] = fee_currency + buy_order['fee'] = fee_par + trades_for_order[0]['fee'] = fee_par mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) amount = sum(x['amount'] for x in trades_for_order) From 6319c104fe1c51e0343c08def9f4511cc537b377 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Sep 2021 15:07:48 +0200 Subject: [PATCH 31/76] Fix unreliable backtest-result when using webserver mode --- freqtrade/data/dataprovider.py | 2 + freqtrade/optimize/backtesting.py | 50 ++++++++++++------------ freqtrade/rpc/api_server/api_backtest.py | 21 +++++----- 3 files changed, 39 insertions(+), 34 deletions(-) diff --git a/freqtrade/data/dataprovider.py b/freqtrade/data/dataprovider.py index cdee0f078..b197c159f 100644 --- a/freqtrade/data/dataprovider.py +++ b/freqtrade/data/dataprovider.py @@ -149,6 +149,8 @@ class DataProvider: Clear pair dataframe cache. """ self.__cached_pairs = {} + self.__cached_pairs_backtesting = {} + self.__slice_index = 0 # Exchange functions diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 79c861ee8..f406f89d7 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -85,18 +85,7 @@ class Backtesting: "configuration or as cli argument `--timeframe 5m`") self.timeframe = str(self.config.get('timeframe')) self.timeframe_min = timeframe_to_minutes(self.timeframe) - # Load detail timeframe if specified - self.timeframe_detail = str(self.config.get('timeframe_detail', '')) - if self.timeframe_detail: - self.timeframe_detail_min = timeframe_to_minutes(self.timeframe_detail) - if self.timeframe_min <= self.timeframe_detail_min: - raise OperationalException( - "Detail timeframe must be smaller than strategy timeframe.") - - else: - self.timeframe_detail_min = 0 - self.detail_data: Dict[str, DataFrame] = {} - + self.init_backtest_detail() self.pairlists = PairListManager(self.exchange, self.config) if 'VolumePairList' in self.pairlists.name_list: raise OperationalException("VolumePairList not allowed for backtesting.") @@ -119,14 +108,6 @@ class Backtesting: else: self.fee = self.exchange.get_fee(symbol=self.pairlists.whitelist[0]) - Trade.use_db = False - Trade.reset_trades() - PairLocks.timeframe = self.config['timeframe'] - PairLocks.use_db = False - PairLocks.reset_locks() - - self.wallets = Wallets(self.config, self.exchange, log=False) - self.timerange = TimeRange.parse_timerange( None if self.config.get('timerange') is None else str(self.config.get('timerange'))) @@ -135,9 +116,7 @@ class Backtesting: # Add maximum startup candle count to configuration for informative pairs support self.config['startup_candle_count'] = self.required_startup self.exchange.validate_required_startup_candles(self.required_startup, self.timeframe) - - self.progress = BTProgress() - self.abort = False + self.init_backtest() def __del__(self): self.cleanup() @@ -147,6 +126,28 @@ class Backtesting: PairLocks.use_db = True Trade.use_db = True + def init_backtest_detail(self): + # Load detail timeframe if specified + self.timeframe_detail = str(self.config.get('timeframe_detail', '')) + if self.timeframe_detail: + self.timeframe_detail_min = timeframe_to_minutes(self.timeframe_detail) + if self.timeframe_min <= self.timeframe_detail_min: + raise OperationalException( + "Detail timeframe must be smaller than strategy timeframe.") + + else: + self.timeframe_detail_min = 0 + self.detail_data: Dict[str, DataFrame] = {} + + def init_backtest(self): + + self.prepare_backtest(False) + + self.wallets = Wallets(self.config, self.exchange, log=False) + + self.progress = BTProgress() + self.abort = False + def _set_strategy(self, strategy: IStrategy): """ Load strategy into backtesting @@ -226,7 +227,8 @@ class Backtesting: Trade.reset_trades() self.rejected_trades = 0 self.dataprovider.clear_cache() - self._load_protections(self.strategy) + if enable_protections: + self._load_protections(self.strategy) def check_abort(self): """ diff --git a/freqtrade/rpc/api_server/api_backtest.py b/freqtrade/rpc/api_server/api_backtest.py index 4623c187e..32278686c 100644 --- a/freqtrade/rpc/api_server/api_backtest.py +++ b/freqtrade/rpc/api_server/api_backtest.py @@ -47,33 +47,34 @@ async def api_start_backtest(bt_settings: BacktestRequest, background_tasks: Bac not ApiServer._bt or lastconfig.get('timeframe') != strat.timeframe or lastconfig.get('timeframe_detail') != btconfig.get('timeframe_detail') - or lastconfig.get('dry_run_wallet') != btconfig.get('dry_run_wallet', 0) or lastconfig.get('timerange') != btconfig['timerange'] ): from freqtrade.optimize.backtesting import Backtesting ApiServer._bt = Backtesting(btconfig) if ApiServer._bt.timeframe_detail: ApiServer._bt.load_bt_data_detail() - + else: + ApiServer._bt.config = btconfig + ApiServer._bt.init_backtest() # Only reload data if timeframe changed. if ( not ApiServer._bt_data or not ApiServer._bt_timerange - or lastconfig.get('stake_amount') != btconfig.get('stake_amount') - or lastconfig.get('enable_protections') != btconfig.get('enable_protections') - or lastconfig.get('protections') != btconfig.get('protections', []) or lastconfig.get('timeframe') != strat.timeframe ): - lastconfig['timerange'] = btconfig['timerange'] - lastconfig['protections'] = btconfig.get('protections', []) - lastconfig['enable_protections'] = btconfig.get('enable_protections') - lastconfig['dry_run_wallet'] = btconfig.get('dry_run_wallet') - lastconfig['timeframe'] = strat.timeframe ApiServer._bt_data, ApiServer._bt_timerange = ApiServer._bt.load_bt_data() + lastconfig['timerange'] = btconfig['timerange'] + lastconfig['timeframe'] = strat.timeframe + + lastconfig['protections'] = btconfig.get('protections', []) + lastconfig['enable_protections'] = btconfig.get('enable_protections') + lastconfig['dry_run_wallet'] = btconfig.get('dry_run_wallet') + ApiServer._bt.abort = False min_date, max_date = ApiServer._bt.backtest_one_strategy( strat, ApiServer._bt_data, ApiServer._bt_timerange) + ApiServer._bt.results = generate_backtest_stats( ApiServer._bt_data, ApiServer._bt.all_results, min_date=min_date, max_date=max_date) From 08b1f04ed5f9b7ce69827fb44acfc4c154aecc2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Sep 2021 03:01:18 +0000 Subject: [PATCH 32/76] Bump types-requests from 2.25.8 to 2.25.9 Bumps [types-requests](https://github.com/python/typeshed) from 2.25.8 to 2.25.9. - [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 d8d8ce916..1d61369eb 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -23,5 +23,5 @@ nbconvert==6.1.0 # mypy types types-cachetools==4.2.0 types-filelock==0.1.5 -types-requests==2.25.8 +types-requests==2.25.9 types-tabulate==0.8.2 From 905950230329688b81606c9fb78c3e5a631d8cbd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Sep 2021 03:01:27 +0000 Subject: [PATCH 33/76] Bump ccxt from 1.56.86 to 1.57.3 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.56.86 to 1.57.3. - [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.56.86...1.57.3) --- updated-dependencies: - dependency-name: ccxt 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 d1d10dd1d..feeb4d942 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.21.2 pandas==1.3.3 pandas-ta==0.3.14b -ccxt==1.56.86 +ccxt==1.57.3 # Pin cryptography for now due to rust build errors with piwheels cryptography==3.4.8 aiohttp==3.7.4.post0 From 78096c9eff08cc2aea47d44e7ae20751c0b3420a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Sep 2021 04:32:26 +0000 Subject: [PATCH 34/76] Bump nbconvert from 6.1.0 to 6.2.0 Bumps [nbconvert](https://github.com/jupyter/nbconvert) from 6.1.0 to 6.2.0. - [Release notes](https://github.com/jupyter/nbconvert/releases) - [Commits](https://github.com/jupyter/nbconvert/compare/6.1.0...6.2.0) --- updated-dependencies: - dependency-name: nbconvert dependency-type: direct:development update-type: version-update:semver-minor ... 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 1d61369eb..2f03255a0 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -18,7 +18,7 @@ isort==5.9.3 time-machine==2.4.0 # Convert jupyter notebooks to markdown documents -nbconvert==6.1.0 +nbconvert==6.2.0 # mypy types types-cachetools==4.2.0 From 5b7a1f864257c62924760be45f2dc9c651c665a0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 27 Sep 2021 07:12:40 +0200 Subject: [PATCH 35/76] Validate config also in webserver mode --- freqtrade/rpc/api_server/api_backtest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/freqtrade/rpc/api_server/api_backtest.py b/freqtrade/rpc/api_server/api_backtest.py index 32278686c..7ce9f487f 100644 --- a/freqtrade/rpc/api_server/api_backtest.py +++ b/freqtrade/rpc/api_server/api_backtest.py @@ -4,6 +4,7 @@ from copy import deepcopy from fastapi import APIRouter, BackgroundTasks, Depends +from freqtrade.configuration.config_validation import validate_config_consistency from freqtrade.enums import BacktestState from freqtrade.exceptions import DependencyException from freqtrade.rpc.api_server.api_schemas import BacktestRequest, BacktestResponse @@ -42,6 +43,7 @@ async def api_start_backtest(bt_settings: BacktestRequest, background_tasks: Bac # Reload strategy lastconfig = ApiServer._bt_last_config strat = StrategyResolver.load_strategy(btconfig) + validate_config_consistency(btconfig) if ( not ApiServer._bt From 3fbf716f85b96a8d53f99523cd50ab703c034256 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 27 Sep 2021 17:51:01 +0200 Subject: [PATCH 36/76] Fix "sticking" timerange in webserver mode --- freqtrade/rpc/api_server/api_backtest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/rpc/api_server/api_backtest.py b/freqtrade/rpc/api_server/api_backtest.py index 7ce9f487f..edbc39772 100644 --- a/freqtrade/rpc/api_server/api_backtest.py +++ b/freqtrade/rpc/api_server/api_backtest.py @@ -63,12 +63,12 @@ async def api_start_backtest(bt_settings: BacktestRequest, background_tasks: Bac not ApiServer._bt_data or not ApiServer._bt_timerange or lastconfig.get('timeframe') != strat.timeframe + or lastconfig.get('timerange') != btconfig['timerange'] ): ApiServer._bt_data, ApiServer._bt_timerange = ApiServer._bt.load_bt_data() - lastconfig['timerange'] = btconfig['timerange'] - lastconfig['timeframe'] = strat.timeframe - + lastconfig['timerange'] = btconfig['timerange'] + lastconfig['timeframe'] = strat.timeframe lastconfig['protections'] = btconfig.get('protections', []) lastconfig['enable_protections'] = btconfig.get('enable_protections') lastconfig['dry_run_wallet'] = btconfig.get('dry_run_wallet') From 5726886b0620874be0d1c6c8f8b4737912e42786 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 27 Sep 2021 20:52:19 +0200 Subject: [PATCH 37/76] Reduce backtest-noise from "pandas slice" warning --- freqtrade/optimize/backtesting.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index f406f89d7..8328d61d3 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -385,12 +385,12 @@ class Backtesting: detail_data = detail_data.loc[ (detail_data['date'] >= sell_candle_time) & (detail_data['date'] < sell_candle_end) - ] + ].copy() if len(detail_data) == 0: # Fall back to "regular" data if no detail data was found for this candle return self._get_sell_trade_entry_for_candle(trade, sell_row) - detail_data['buy'] = sell_row[BUY_IDX] - detail_data['sell'] = sell_row[SELL_IDX] + detail_data.loc[:, 'buy'] = sell_row[BUY_IDX] + detail_data.loc[:, 'sell'] = sell_row[SELL_IDX] headers = ['date', 'buy', 'open', 'close', 'sell', 'low', 'high'] for det_row in detail_data[headers].values.tolist(): res = self._get_sell_trade_entry_for_candle(trade, det_row) From e025576d8cac9cb0227734efc18d4c978d01cc6f Mon Sep 17 00:00:00 2001 From: Rokas Kupstys Date: Wed, 29 Sep 2021 10:15:05 +0300 Subject: [PATCH 38/76] Introduce markets_static fixture serving an immutable list of markets. Adapt pairlist/markets tests to use this new fixture. This allows freely modifying markets in get_markets() without a need of updating pairlist/markets tests. --- tests/commands/test_commands.py | 9 ++++----- tests/conftest.py | 21 ++++++++++++++++++--- tests/exchange/test_exchange.py | 4 ++-- tests/plugins/test_pairlist.py | 4 ++-- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 135510b38..b236f6a10 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -208,11 +208,10 @@ def test_list_timeframes(mocker, capsys): assert re.search(r"^1d$", captured.out, re.MULTILINE) -def test_list_markets(mocker, markets, capsys): +def test_list_markets(mocker, markets_static, capsys): api_mock = MagicMock() - api_mock.markets = markets - patch_exchange(mocker, api_mock=api_mock, id='bittrex') + patch_exchange(mocker, api_mock=api_mock, id='bittrex', mock_markets=markets_static) # Test with no --config args = [ @@ -237,7 +236,7 @@ def test_list_markets(mocker, markets, capsys): "TKN/BTC, XLTCUSDT, XRP/BTC.\n" in captured.out) - patch_exchange(mocker, api_mock=api_mock, id="binance") + patch_exchange(mocker, api_mock=api_mock, id="binance", mock_markets=markets_static) # Test with --exchange args = [ "list-markets", @@ -250,7 +249,7 @@ def test_list_markets(mocker, markets, capsys): assert re.match("\nExchange Binance has 10 active markets:\n", captured.out) - patch_exchange(mocker, api_mock=api_mock, id="bittrex") + patch_exchange(mocker, api_mock=api_mock, id="bittrex", mock_markets=markets_static) # Test with --all: all markets args = [ "list-markets", "--all", diff --git a/tests/conftest.py b/tests/conftest.py index 7354c0b2c..c908c0cb0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -90,8 +90,10 @@ def patch_exchange(mocker, api_mock=None, id='binance', mock_markets=True) -> No mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value=id.title())) mocker.patch('freqtrade.exchange.Exchange.precisionMode', PropertyMock(return_value=2)) if mock_markets: + if isinstance(mock_markets, bool): + mock_markets = get_markets() mocker.patch('freqtrade.exchange.Exchange.markets', - PropertyMock(return_value=get_markets())) + PropertyMock(return_value=mock_markets)) if api_mock: mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) @@ -376,6 +378,8 @@ def markets(): def get_markets(): + # See get_markets_static() for immutable markets and do not modify them unless absolutely + # necessary! return { 'ETH/BTC': { 'id': 'ethbtc', @@ -675,11 +679,22 @@ def get_markets(): @pytest.fixture -def shitcoinmarkets(markets): +def markets_static(): + # These markets are used in some tests that would need adaptation should anything change in + # market list. Do not modify this list without a good reason! Do not modify market parameters + # of listed pairs in get_markets() without a good reason either! + static_markets = ['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD', + 'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XLTCUSDT', 'XRP/BTC'] + all_markets = get_markets() + return {m: all_markets[m] for m in static_markets} + + +@pytest.fixture +def shitcoinmarkets(markets_static): """ Fixture with shitcoin markets - used to test filters in pairlists """ - shitmarkets = deepcopy(markets) + shitmarkets = deepcopy(markets_static) shitmarkets.update({ 'HOT/BTC': { 'id': 'HOTBTC', diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 97bc33429..79b4a3ff5 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2735,7 +2735,7 @@ def test_get_valid_pair_combination(default_conf, mocker, markets): (['LTC'], ['NONEXISTENT'], False, False, []), ]) -def test_get_markets(default_conf, mocker, markets, +def test_get_markets(default_conf, mocker, markets_static, base_currencies, quote_currencies, pairs_only, active_only, expected_keys): mocker.patch.multiple('freqtrade.exchange.Exchange', @@ -2743,7 +2743,7 @@ def test_get_markets(default_conf, mocker, markets, _load_async_markets=MagicMock(), validate_pairs=MagicMock(), validate_timeframes=MagicMock(), - markets=PropertyMock(return_value=markets)) + markets=PropertyMock(return_value=markets_static)) ex = Exchange(default_conf) pairs = ex.get_markets(base_currencies, quote_currencies, pairs_only, active_only) assert sorted(pairs.keys()) == sorted(expected_keys) diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py index 1ce8d172c..cf918e2a0 100644 --- a/tests/plugins/test_pairlist.py +++ b/tests/plugins/test_pairlist.py @@ -131,9 +131,9 @@ def test_load_pairlist_noexist(mocker, markets, default_conf): default_conf, {}, 1) -def test_load_pairlist_verify_multi(mocker, markets, default_conf): +def test_load_pairlist_verify_multi(mocker, markets_static, default_conf): freqtrade = get_patched_freqtradebot(mocker, default_conf) - mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets)) + mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets_static)) plm = PairListManager(freqtrade.exchange, default_conf) # Call different versions one after the other, should always consider what was passed in # and have no side-effects (therefore the same check multiple times) From 656526c007dfa8fd80036966d601e8b873d1ccd5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Sep 2021 16:50:05 +0200 Subject: [PATCH 39/76] Add trades-to-ohlcv command to simplify adding new timeframes --- freqtrade/commands/__init__.py | 4 +-- freqtrade/commands/arguments.py | 14 +++++++++- freqtrade/commands/data_commands.py | 41 +++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/freqtrade/commands/__init__.py b/freqtrade/commands/__init__.py index a6f14cff7..858c99acd 100644 --- a/freqtrade/commands/__init__.py +++ b/freqtrade/commands/__init__.py @@ -8,8 +8,8 @@ Note: Be careful with file-scoped imports in these subfiles. """ from freqtrade.commands.arguments import Arguments from freqtrade.commands.build_config_commands import start_new_config -from freqtrade.commands.data_commands import (start_convert_data, start_download_data, - start_list_data) +from freqtrade.commands.data_commands import (start_convert_data, start_convert_trades, + start_download_data, start_list_data) from freqtrade.commands.deploy_commands import (start_create_userdir, start_install_ui, start_new_strategy) from freqtrade.commands.hyperopt_commands import start_hyperopt_list, start_hyperopt_show diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index d424f3ce7..48dc48cf1 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -58,6 +58,8 @@ ARGS_BUILD_STRATEGY = ["user_data_dir", "strategy", "template"] ARGS_CONVERT_DATA = ["pairs", "format_from", "format_to", "erase"] ARGS_CONVERT_DATA_OHLCV = ARGS_CONVERT_DATA + ["timeframes"] +ARGS_CONVERT_TRADES = ["pairs", "timeframes", "dataformat_ohlcv", "dataformat_trades"] + ARGS_LIST_DATA = ["exchange", "dataformat_ohlcv", "pairs"] ARGS_DOWNLOAD_DATA = ["pairs", "pairs_file", "days", "new_pairs_days", "timerange", @@ -169,7 +171,8 @@ class Arguments: self.parser = argparse.ArgumentParser(description='Free, open source crypto trading bot') self._build_args(optionlist=['version'], parser=self.parser) - from freqtrade.commands import (start_backtesting, start_convert_data, start_create_userdir, + from freqtrade.commands import (start_backtesting, start_convert_data, start_convert_trades, + start_create_userdir, start_download_data, start_edge, start_hyperopt, start_hyperopt_list, start_hyperopt_show, start_install_ui, start_list_data, start_list_exchanges, start_list_markets, @@ -236,6 +239,15 @@ class Arguments: convert_trade_data_cmd.set_defaults(func=partial(start_convert_data, ohlcv=False)) self._build_args(optionlist=ARGS_CONVERT_DATA, parser=convert_trade_data_cmd) + # Add trades-to-ohlcv subcommand + convert_trade_data_cmd = subparsers.add_parser( + 'trades-to-ohlcv', + help='Convert trade data to OHLCV data.', + parents=[_common_parser], + ) + convert_trade_data_cmd.set_defaults(func=start_convert_trades) + self._build_args(optionlist=ARGS_CONVERT_TRADES, parser=convert_trade_data_cmd) + # Add list-data subcommand list_data_cmd = subparsers.add_parser( 'list-data', diff --git a/freqtrade/commands/data_commands.py b/freqtrade/commands/data_commands.py index 141e85f14..7ef1ae5c7 100644 --- a/freqtrade/commands/data_commands.py +++ b/freqtrade/commands/data_commands.py @@ -89,6 +89,47 @@ def start_download_data(args: Dict[str, Any]) -> None: f"on exchange {exchange.name}.") +def start_convert_trades(args: Dict[str, Any]) -> None: + + config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE) + + timerange = TimeRange() + if 'days' in config: + time_since = (datetime.now() - timedelta(days=config['days'])).strftime("%Y%m%d") + timerange = TimeRange.parse_timerange(f'{time_since}-') + + if 'timerange' in config: + timerange = timerange.parse_timerange(config['timerange']) + + # Remove stake-currency to skip checks which are not relevant for datadownload + config['stake_currency'] = '' + + if 'pairs' not in config: + raise OperationalException( + "Downloading data requires a list of pairs. " + "Please check the documentation on how to configure this.") + + # Init exchange + exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False) + # Manual validations of relevant settings + if not config['exchange'].get('skip_pair_validation', False): + exchange.validate_pairs(config['pairs']) + expanded_pairs = expand_pairlist(config['pairs'], list(exchange.markets)) + + logger.info(f"About to Convert pairs: {expanded_pairs}, " + f"intervals: {config['timeframes']} to {config['datadir']}") + + for timeframe in config['timeframes']: + exchange.validate_timeframes(timeframe) + # Convert downloaded trade data to different timeframes + convert_trades_to_ohlcv( + pairs=expanded_pairs, timeframes=config['timeframes'], + datadir=config['datadir'], timerange=timerange, erase=bool(config.get('erase')), + data_format_ohlcv=config['dataformat_ohlcv'], + data_format_trades=config['dataformat_trades'], + ) + + def start_convert_data(args: Dict[str, Any], ohlcv: bool = True) -> None: """ Convert data from one format to another From fc511aac4486dc99568e88edd01635453d0c1a59 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Sep 2021 19:21:54 +0200 Subject: [PATCH 40/76] don't use %default when no default is defined --- freqtrade/commands/cli_options.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index e3c7fe464..d350a9426 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -381,12 +381,12 @@ AVAILABLE_CLI_OPTIONS = { ), "dataformat_ohlcv": Arg( '--data-format-ohlcv', - help='Storage format for downloaded candle (OHLCV) data. (default: `%(default)s`).', + help='Storage format for downloaded candle (OHLCV) data. (default: `json`).', choices=constants.AVAILABLE_DATAHANDLERS, ), "dataformat_trades": Arg( '--data-format-trades', - help='Storage format for downloaded trades data. (default: `%(default)s`).', + help='Storage format for downloaded trades data. (default: `jsongz`).', choices=constants.AVAILABLE_DATAHANDLERS, ), "exchange": Arg( From 248c61bb26399d3049f7ac2f116d6cf0e49d8665 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Sep 2021 19:39:29 +0200 Subject: [PATCH 41/76] Add test for trades-to-ohlcv --- freqtrade/commands/arguments.py | 4 ++-- freqtrade/commands/data_commands.py | 6 ------ tests/commands/test_commands.py | 28 ++++++++++++++++++++++------ 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 48dc48cf1..2fadf047e 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -58,7 +58,7 @@ ARGS_BUILD_STRATEGY = ["user_data_dir", "strategy", "template"] ARGS_CONVERT_DATA = ["pairs", "format_from", "format_to", "erase"] ARGS_CONVERT_DATA_OHLCV = ARGS_CONVERT_DATA + ["timeframes"] -ARGS_CONVERT_TRADES = ["pairs", "timeframes", "dataformat_ohlcv", "dataformat_trades"] +ARGS_CONVERT_TRADES = ["pairs", "timeframes", "exchange", "dataformat_ohlcv", "dataformat_trades"] ARGS_LIST_DATA = ["exchange", "dataformat_ohlcv", "pairs"] @@ -93,7 +93,7 @@ ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperop NO_CONF_REQURIED = ["convert-data", "convert-trade-data", "download-data", "list-timeframes", "list-markets", "list-pairs", "list-strategies", "list-data", "hyperopt-list", "hyperopt-show", - "plot-dataframe", "plot-profit", "show-trades"] + "plot-dataframe", "plot-profit", "show-trades", "trades-to-ohlcv"] NO_CONF_ALLOWED = ["create-userdir", "list-exchanges", "new-strategy"] diff --git a/freqtrade/commands/data_commands.py b/freqtrade/commands/data_commands.py index 7ef1ae5c7..ee05e6c69 100644 --- a/freqtrade/commands/data_commands.py +++ b/freqtrade/commands/data_commands.py @@ -94,12 +94,6 @@ def start_convert_trades(args: Dict[str, Any]) -> None: config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE) timerange = TimeRange() - if 'days' in config: - time_since = (datetime.now() - timedelta(days=config['days'])).strftime("%Y%m%d") - timerange = TimeRange.parse_timerange(f'{time_since}-') - - if 'timerange' in config: - timerange = timerange.parse_timerange(config['timerange']) # Remove stake-currency to skip checks which are not relevant for datadownload config['stake_currency'] = '' diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index b236f6a10..8889617ba 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -8,12 +8,12 @@ from zipfile import ZipFile import arrow import pytest -from freqtrade.commands import (start_convert_data, start_create_userdir, start_download_data, - start_hyperopt_list, start_hyperopt_show, start_install_ui, - start_list_data, start_list_exchanges, start_list_markets, - start_list_strategies, start_list_timeframes, start_new_strategy, - start_show_trades, start_test_pairlist, start_trading, - start_webserver) +from freqtrade.commands import (start_convert_data, start_convert_trades, start_create_userdir, + start_download_data, start_hyperopt_list, start_hyperopt_show, + start_install_ui, start_list_data, start_list_exchanges, + start_list_markets, start_list_strategies, start_list_timeframes, + start_new_strategy, start_show_trades, start_test_pairlist, + start_trading, start_webserver) from freqtrade.commands.deploy_commands import (clean_ui_subdir, download_and_install_ui, get_ui_download_url, read_ui_version) from freqtrade.configuration import setup_utils_configuration @@ -759,6 +759,22 @@ def test_download_data_trades(mocker, caplog): assert convert_mock.call_count == 1 +def test_start_convert_trades(mocker, caplog): + convert_mock = mocker.patch('freqtrade.commands.data_commands.convert_trades_to_ohlcv', + MagicMock(return_value=[])) + patch_exchange(mocker) + mocker.patch( + 'freqtrade.exchange.Exchange.markets', PropertyMock(return_value={}) + ) + args = [ + "trades-to-ohlcv", + "--exchange", "kraken", + "--pairs", "ETH/BTC", "XRP/BTC", + ] + start_convert_trades(get_args(args)) + assert convert_mock.call_count == 1 + + def test_start_list_strategies(mocker, caplog, capsys): args = [ From 178db516bf79dbaa37ca2ef9b779d77ed8850f75 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Sep 2021 19:48:56 +0200 Subject: [PATCH 42/76] Add documentation for trade-to-ohlcv --- docs/data-download.md | 55 +++++++++++++++++++++++++++++++++ freqtrade/commands/arguments.py | 15 +++++---- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/docs/data-download.md b/docs/data-download.md index 0ca86b0d3..5f605c404 100644 --- a/docs/data-download.md +++ b/docs/data-download.md @@ -204,6 +204,61 @@ It'll also remove original jsongz data files (`--erase` parameter). freqtrade convert-trade-data --format-from jsongz --format-to json --datadir ~/.freqtrade/data/kraken --erase ``` +### Sub-command trades to ohlcv + +When you need to use `--dl-trades` (kraken only) to download data, conversion of trades data to ohlcv data is the last step. +This command will allow you to repeat this last step for additional timeframes without re-downloading the data. + +``` +usage: freqtrade trades-to-ohlcv [-h] [-v] [--logfile FILE] [-V] [-c PATH] + [-d PATH] [--userdir PATH] + [-p PAIRS [PAIRS ...]] + [-t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...]] + [--exchange EXCHANGE] + [--data-format-ohlcv {json,jsongz,hdf5}] + [--data-format-trades {json,jsongz,hdf5}] + +optional arguments: + -h, --help show this help message and exit + -p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...] + Limit command to these pairs. Pairs are space- + separated. + -t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...], --timeframes {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...] + Specify which tickers to download. Space-separated + list. Default: `1m 5m`. + --exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no + config is provided. + --data-format-ohlcv {json,jsongz,hdf5} + Storage format for downloaded candle (OHLCV) data. + (default: `json`). + --data-format-trades {json,jsongz,hdf5} + Storage format for downloaded trades data. (default: + `jsongz`). + +Common arguments: + -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). + --logfile FILE Log to the file specified. Special values are: + 'syslog', 'journald'. See the documentation for more + details. + -V, --version show program's version number and exit + -c PATH, --config PATH + Specify configuration file (default: + `userdir/config.json` or `config.json` whichever + exists). Multiple --config options may be used. Can be + set to `-` to read config from stdin. + -d PATH, --datadir PATH + Path to directory with historical backtesting data. + --userdir PATH, --user-data-dir PATH + Path to userdata directory. + +``` + +#### Example trade-to-ohlcv conversion + +``` bash +freqtrade trades-to-ohlcv --exchange kraken -t 5m 1h 1d --pairs BTC/EUR ETH/EUR +``` + ### Sub-command list-data You can get a list of downloaded data using the `list-data` sub-command. diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 2fadf047e..9643705a5 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -172,14 +172,13 @@ class Arguments: self._build_args(optionlist=['version'], parser=self.parser) from freqtrade.commands import (start_backtesting, start_convert_data, start_convert_trades, - start_create_userdir, - start_download_data, start_edge, start_hyperopt, - start_hyperopt_list, start_hyperopt_show, start_install_ui, - start_list_data, start_list_exchanges, start_list_markets, - start_list_strategies, start_list_timeframes, - start_new_config, start_new_strategy, start_plot_dataframe, - start_plot_profit, start_show_trades, start_test_pairlist, - start_trading, start_webserver) + start_create_userdir, start_download_data, start_edge, + start_hyperopt, start_hyperopt_list, start_hyperopt_show, + start_install_ui, start_list_data, start_list_exchanges, + start_list_markets, start_list_strategies, + start_list_timeframes, start_new_config, start_new_strategy, + start_plot_dataframe, start_plot_profit, start_show_trades, + start_test_pairlist, start_trading, start_webserver) subparsers = self.parser.add_subparsers(dest='command', # Use custom message when no subhandler is added From bd27993e797c8d83d54ac76b278a9779e9c4eee5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 30 Sep 2021 06:42:42 +0200 Subject: [PATCH 43/76] Add documentation segment about indicator libraries --- docs/strategy-customization.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index 110365208..0bfc0a2f6 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -122,6 +122,16 @@ def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame Look into the [user_data/strategies/sample_strategy.py](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_strategy.py). Then uncomment indicators you need. +#### Indicator libraries + +Out of the box, freqtrade installs the following technical libraries: + +* [ta-lib](http://mrjbq7.github.io/ta-lib/) +* [pandas-ta](https://twopirllc.github.io/pandas-ta/) +* [technical](https://github.com/freqtrade/technical/) + +Additional technical libraries can be installed as necessary, or custom indicators may be written / invented by the strategy author. + ### Strategy startup period Most indicators have an instable startup period, in which they are either not available, or the calculation is incorrect. This can lead to inconsistencies, since Freqtrade does not know how long this instable period should be. From 5f23af580248a86a56d60e050bd5d0a7f5424236 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 30 Sep 2021 07:24:16 +0200 Subject: [PATCH 44/76] Rename update_open_trades to clarify it's only called at startup --- freqtrade/freqtradebot.py | 4 ++-- tests/test_freqtradebot.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 3a9b21b7c..bf4742fdc 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -139,7 +139,7 @@ class FreqtradeBot(LoggingMixin): # Only update open orders on startup # This will update the database after the initial migration - self.update_open_orders() + self.startup_update_open_orders() def process(self) -> None: """ @@ -237,7 +237,7 @@ class FreqtradeBot(LoggingMixin): open_trades = len(Trade.get_open_trades()) return max(0, self.config['max_open_trades'] - open_trades) - def update_open_orders(self): + def startup_update_open_orders(self): """ Updates open orders based on order list kept in the database. Mainly updates the state of orders - but may also close trades diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 760a9dee7..d312bdb11 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -4033,16 +4033,16 @@ def test_check_for_open_trades(mocker, default_conf, fee): @pytest.mark.usefixtures("init_persistence") -def test_update_open_orders(mocker, default_conf, fee, caplog): +def test_startup_update_open_orders(mocker, default_conf, fee, caplog): freqtrade = get_patched_freqtradebot(mocker, default_conf) create_mock_trades(fee) - freqtrade.update_open_orders() + freqtrade.startup_update_open_orders() assert not log_has_re(r"Error updating Order .*", caplog) caplog.clear() freqtrade.config['dry_run'] = False - freqtrade.update_open_orders() + freqtrade.startup_update_open_orders() assert log_has_re(r"Error updating Order .*", caplog) caplog.clear() @@ -4053,7 +4053,7 @@ def test_update_open_orders(mocker, default_conf, fee, caplog): 'status': 'closed', }) mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=matching_buy_order) - freqtrade.update_open_orders() + freqtrade.startup_update_open_orders() # Only stoploss and sell orders are kept open assert len(Order.get_open_orders()) == 2 From 15df5fd9c5c8533b14809147570e2a66d79241fe Mon Sep 17 00:00:00 2001 From: Robert Davey Date: Fri, 1 Oct 2021 13:49:16 +0100 Subject: [PATCH 45/76] Fix pair_candles to point to correct API call pair_candles pointed to available_pairs RPC call instead of pair_candles --- scripts/rest_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/rest_client.py b/scripts/rest_client.py index ece0a253e..713b398c3 100755 --- a/scripts/rest_client.py +++ b/scripts/rest_client.py @@ -312,7 +312,7 @@ class FtRestClient(): :param limit: Limit result to the last n candles. :return: json object """ - return self._get("available_pairs", params={ + return self._get("pair_candles", params={ "pair": pair, "timeframe": timeframe, "limit": limit, From f69cb39a170a4a223de4f154c902c69903188a36 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 1 Oct 2021 19:26:51 +0200 Subject: [PATCH 46/76] Fix missing comma in kucoin template closes #5646 --- freqtrade/templates/subtemplates/exchange_kucoin.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/templates/subtemplates/exchange_kucoin.j2 b/freqtrade/templates/subtemplates/exchange_kucoin.j2 index f9dfff663..9882c51c7 100644 --- a/freqtrade/templates/subtemplates/exchange_kucoin.j2 +++ b/freqtrade/templates/subtemplates/exchange_kucoin.j2 @@ -4,7 +4,7 @@ "secret": "{{ exchange_secret }}", "password": "{{ exchange_key_password }}", "ccxt_config": { - "enableRateLimit": true + "enableRateLimit": true, "rateLimit": 200 }, "ccxt_async_config": { From dadd134200bdcca66456e0795d92c12841fb8e87 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Fri, 17 Sep 2021 02:25:58 -0600 Subject: [PATCH 47/76] changes some tests to use usdt values --- tests/conftest.py | 106 ++++++- tests/conftest_trades_usdt.py | 305 ++++++++++++++++++ tests/test_freqtradebot.py | 575 +++++++++++++++++----------------- 3 files changed, 699 insertions(+), 287 deletions(-) create mode 100644 tests/conftest_trades_usdt.py diff --git a/tests/conftest.py b/tests/conftest.py index c908c0cb0..c1032a215 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -25,6 +25,8 @@ from freqtrade.resolvers import ExchangeResolver from freqtrade.worker import Worker from tests.conftest_trades import (mock_trade_1, mock_trade_2, mock_trade_3, mock_trade_4, mock_trade_5, mock_trade_6) +from tests.conftest_trades_usdt import (mock_trade_usdt_1, mock_trade_usdt_2, mock_trade_usdt_3, + mock_trade_usdt_4, mock_trade_usdt_5, mock_trade_usdt_6) logging.getLogger('').setLevel(logging.INFO) @@ -227,6 +229,39 @@ def create_mock_trades(fee, use_db: bool = True): Trade.query.session.flush() +def create_mock_trades_usdt(fee, use_db: bool = True): + """ + Create some fake trades ... + """ + def add_trade(trade): + if use_db: + Trade.query.session.add(trade) + else: + LocalTrade.add_bt_trade(trade) + + # Simulate dry_run entries + trade = mock_trade_usdt_1(fee) + add_trade(trade) + + trade = mock_trade_usdt_2(fee) + add_trade(trade) + + trade = mock_trade_usdt_3(fee) + add_trade(trade) + + trade = mock_trade_usdt_4(fee) + add_trade(trade) + + trade = mock_trade_usdt_5(fee) + add_trade(trade) + + trade = mock_trade_usdt_6(fee) + add_trade(trade) + + if use_db: + Trade.query.session.flush() + + @pytest.fixture(autouse=True) def patch_coingekko(mocker) -> None: """ @@ -303,7 +338,8 @@ def get_default_conf(testdatadir): "ETH/BTC", "LTC/BTC", "XRP/BTC", - "NEO/BTC" + "NEO/BTC", + "ADA/USDT" ], "pair_blacklist": [ "DOGE/BTC", @@ -372,6 +408,33 @@ def ticker_sell_down(): }) +@pytest.fixture +def ticker_usdt(): + return MagicMock(return_value={ + 'bid': 1.99, + 'ask': 2.0, + 'last': 1.99, + }) + + +@pytest.fixture +def ticker_usdt_sell_up(): + return MagicMock(return_value={ + 'bid': 2.19, + 'ask': 2.2, + 'last': 2.19, + }) + + +@pytest.fixture +def ticker_usdt_sell_down(): + return MagicMock(return_value={ + 'bid': 2.01, + 'ask': 2.0, + 'last': 2.01, + }) + + @pytest.fixture def markets(): return get_markets() @@ -406,6 +469,31 @@ def get_markets(): }, 'info': {}, }, + 'ADA/USDT': { + 'id': 'ethbtc', + 'symbol': 'ADA/USDT', + 'base': 'USDT', + 'quote': 'ADA', + 'active': True, + 'precision': { + 'price': 8, + 'amount': 8, + 'cost': 8, + }, + 'lot': 0.00000001, + 'limits': { + 'amount': { + 'min': 0.01, + 'max': 1000, + }, + 'price': 500000, + 'cost': { + 'min': 0.0001, + 'max': 500000, + }, + }, + 'info': {}, + }, 'TKN/BTC': { 'id': 'tknbtc', 'symbol': 'TKN/BTC', @@ -1821,6 +1909,22 @@ def open_trade(): ) +@pytest.fixture(scope="function") +def open_trade_usdt(): + return Trade( + pair='ADA/USDT', + open_rate=2.0, + exchange='binance', + open_order_id='123456789', + amount=30.0, + fee_open=0.0, + fee_close=0.0, + stake_amount=60.0, + open_date=arrow.utcnow().shift(minutes=-601).datetime, + is_open=True + ) + + @pytest.fixture def saved_hyperopt_results(): hyperopt_res = [ diff --git a/tests/conftest_trades_usdt.py b/tests/conftest_trades_usdt.py new file mode 100644 index 000000000..1a03f0381 --- /dev/null +++ b/tests/conftest_trades_usdt.py @@ -0,0 +1,305 @@ +from datetime import datetime, timedelta, timezone + +from freqtrade.persistence.models import Order, Trade + + +MOCK_TRADE_COUNT = 6 + + +def mock_order_usdt_1(): + return { + 'id': '1234', + 'symbol': 'ADA/USDT', + 'status': 'closed', + 'side': 'buy', + 'type': 'limit', + 'price': 2.0, + 'amount': 10.0, + 'filled': 10.0, + 'remaining': 0.0, + } + + +def mock_trade_usdt_1(fee): + trade = Trade( + pair='ADA/USDT', + stake_amount=20.0, + amount=10.0, + amount_requested=10.0, + fee_open=fee.return_value, + fee_close=fee.return_value, + is_open=True, + open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=17), + open_rate=2.0, + exchange='binance', + open_order_id='dry_run_buy_12345', + strategy='StrategyTestV2', + timeframe=5, + ) + o = Order.parse_from_ccxt_object(mock_order_usdt_1(), 'ADA/USDT', 'buy') + trade.orders.append(o) + return trade + + +def mock_order_usdt_2(): + return { + 'id': '1235', + 'symbol': 'ETC/USDT', + 'status': 'closed', + 'side': 'buy', + 'type': 'limit', + 'price': 2.0, + 'amount': 100.0, + 'filled': 100.0, + 'remaining': 0.0, + } + + +def mock_order_usdt_2_sell(): + return { + 'id': '12366', + 'symbol': 'ETC/USDT', + 'status': 'closed', + 'side': 'sell', + 'type': 'limit', + 'price': 2.05, + 'amount': 100.0, + 'filled': 100.0, + 'remaining': 0.0, + } + + +def mock_trade_usdt_2(fee): + """ + Closed trade... + """ + trade = Trade( + pair='ETC/USDT', + stake_amount=200.0, + amount=100.0, + amount_requested=100.0, + fee_open=fee.return_value, + fee_close=fee.return_value, + open_rate=2.0, + close_rate=2.05, + close_profit=5.0, + close_profit_abs=3.9875, + exchange='binance', + is_open=False, + open_order_id='dry_run_sell_12345', + strategy='StrategyTestV2', + timeframe=5, + sell_reason='sell_signal', + open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), + close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2), + ) + o = Order.parse_from_ccxt_object(mock_order_usdt_2(), 'ETC/USDT', 'buy') + trade.orders.append(o) + o = Order.parse_from_ccxt_object(mock_order_usdt_2_sell(), 'ETC/USDT', 'sell') + trade.orders.append(o) + return trade + + +def mock_order_usdt_3(): + return { + 'id': '41231a12a', + 'symbol': 'XRP/USDT', + 'status': 'closed', + 'side': 'buy', + 'type': 'limit', + 'price': 1.0, + 'amount': 30.0, + 'filled': 30.0, + 'remaining': 0.0, + } + + +def mock_order_usdt_3_sell(): + return { + 'id': '41231a666a', + 'symbol': 'XRP/USDT', + 'status': 'closed', + 'side': 'sell', + 'type': 'stop_loss_limit', + 'price': 1.1, + 'average': 1.1, + 'amount': 30.0, + 'filled': 30.0, + 'remaining': 0.0, + } + + +def mock_trade_usdt_3(fee): + """ + Closed trade + """ + trade = Trade( + pair='XRP/USDT', + stake_amount=30.0, + amount=30.0, + amount_requested=30.0, + fee_open=fee.return_value, + fee_close=fee.return_value, + open_rate=1.0, + close_rate=1.1, + close_profit=10.0, + close_profit_abs=9.8425, + exchange='binance', + is_open=False, + strategy='StrategyTestV2', + timeframe=5, + sell_reason='roi', + open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), + close_date=datetime.now(tz=timezone.utc), + ) + o = Order.parse_from_ccxt_object(mock_order_usdt_3(), 'XRP/USDT', 'buy') + trade.orders.append(o) + o = Order.parse_from_ccxt_object(mock_order_usdt_3_sell(), 'XRP/USDT', 'sell') + trade.orders.append(o) + return trade + + +def mock_order_usdt_4(): + return { + 'id': 'prod_buy_12345', + 'symbol': 'ETC/USDT', + 'status': 'open', + 'side': 'buy', + 'type': 'limit', + 'price': 2.0, + 'amount': 10.0, + 'filled': 0.0, + 'remaining': 30.0, + } + + +def mock_trade_usdt_4(fee): + """ + Simulate prod entry + """ + trade = Trade( + pair='ETC/USDT', + stake_amount=20.0, + amount=10.0, + amount_requested=10.01, + fee_open=fee.return_value, + fee_close=fee.return_value, + open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=14), + is_open=True, + open_rate=2.0, + exchange='binance', + open_order_id='prod_buy_12345', + strategy='StrategyTestV2', + timeframe=5, + ) + o = Order.parse_from_ccxt_object(mock_order_usdt_4(), 'ETC/USDT', 'buy') + trade.orders.append(o) + return trade + + +def mock_order_usdt_5(): + return { + 'id': 'prod_buy_3455', + 'symbol': 'XRP/USDT', + 'status': 'closed', + 'side': 'buy', + 'type': 'limit', + 'price': 2.0, + 'amount': 10.0, + 'filled': 10.0, + 'remaining': 0.0, + } + + +def mock_order_usdt_5_stoploss(): + return { + 'id': 'prod_stoploss_3455', + 'symbol': 'XRP/USDT', + 'status': 'open', + 'side': 'sell', + 'type': 'stop_loss_limit', + 'price': 2.0, + 'amount': 10.0, + 'filled': 0.0, + 'remaining': 30.0, + } + + +def mock_trade_usdt_5(fee): + """ + Simulate prod entry with stoploss + """ + trade = Trade( + pair='XRP/USDT', + stake_amount=20.0, + amount=10.0, + amount_requested=10.01, + fee_open=fee.return_value, + fee_close=fee.return_value, + open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=12), + is_open=True, + open_rate=2.0, + exchange='binance', + strategy='SampleStrategy', + stoploss_order_id='prod_stoploss_3455', + timeframe=5, + ) + o = Order.parse_from_ccxt_object(mock_order_usdt_5(), 'XRP/USDT', 'buy') + trade.orders.append(o) + o = Order.parse_from_ccxt_object(mock_order_usdt_5_stoploss(), 'XRP/USDT', 'stoploss') + trade.orders.append(o) + return trade + + +def mock_order_usdt_6(): + return { + 'id': 'prod_buy_6', + 'symbol': 'LTC/USDT', + 'status': 'closed', + 'side': 'buy', + 'type': 'limit', + 'price': 10.0, + 'amount': 2.0, + 'filled': 2.0, + 'remaining': 0.0, + } + + +def mock_order_usdt_6_sell(): + return { + 'id': 'prod_sell_6', + 'symbol': 'LTC/USDT', + 'status': 'open', + 'side': 'sell', + 'type': 'limit', + 'price': 12.0, + 'amount': 2.0, + 'filled': 0.0, + 'remaining': 2.0, + } + + +def mock_trade_usdt_6(fee): + """ + Simulate prod entry with open sell order + """ + trade = Trade( + pair='LTC/USDT', + stake_amount=20.0, + amount=2.0, + amount_requested=2.0, + open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=5), + fee_open=fee.return_value, + fee_close=fee.return_value, + is_open=True, + open_rate=10.0, + exchange='binance', + strategy='SampleStrategy', + open_order_id="prod_sell_6", + timeframe=5, + ) + o = Order.parse_from_ccxt_object(mock_order_usdt_6(), 'LTC/USDT', 'buy') + trade.orders.append(o) + o = Order.parse_from_ccxt_object(mock_order_usdt_6_sell(), 'LTC/USDT', 'sell') + trade.orders.append(o) + return trade diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index d312bdb11..7ddb90657 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -23,9 +23,9 @@ from freqtrade.worker import Worker from tests.conftest import (create_mock_trades, get_patched_freqtradebot, get_patched_worker, log_has, log_has_re, patch_edge, patch_exchange, patch_get_signal, patch_wallet, patch_whitelist) -from tests.conftest_trades import (MOCK_TRADE_COUNT, mock_order_1, mock_order_2, mock_order_2_sell, - mock_order_3, mock_order_3_sell, mock_order_4, - mock_order_5_stoploss, mock_order_6_sell) +from tests.conftest_trades import ( + MOCK_TRADE_COUNT, mock_order_1, mock_order_2, mock_order_2_sell, mock_order_3, + mock_order_3_sell, mock_order_4, mock_order_5_stoploss, mock_order_6_sell) def patch_RPCManager(mocker) -> MagicMock: @@ -135,14 +135,14 @@ def test_get_trade_stake_amount(default_conf, ticker, mocker) -> None: (True, 0.0027, 3, 0.5, [0.001, 0.001, 0.000673]), (True, 0.0022, 3, 1, [0.001, 0.001, 0.0]), ]) -def test_check_available_stake_amount(default_conf, ticker, mocker, fee, limit_buy_order_open, +def test_check_available_stake_amount(default_conf, ticker, mocker, fee, limit_buy_order_usdt_open, amend_last, wallet, max_open, lsamr, expected) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, - create_order=MagicMock(return_value=limit_buy_order_open), + create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee ) default_conf['dry_run_wallet'] = wallet @@ -155,7 +155,7 @@ def test_check_available_stake_amount(default_conf, ticker, mocker, fee, limit_b for i in range(0, max_open): if expected[i] is not None: - limit_buy_order_open['id'] = str(i) + limit_buy_order_usdt_open['id'] = str(i) result = freqtrade.wallets.get_trade_stake_amount('ETH/BTC') assert pytest.approx(result) == expected[i] freqtrade.execute_entry('ETH/BTC', result) @@ -198,7 +198,7 @@ def test_edge_overrides_stake_amount(mocker, edge_conf) -> None: # Override strategy stoploss (0.85, True) ]) -def test_edge_overrides_stoploss(limit_buy_order, fee, caplog, mocker, +def test_edge_overrides_stoploss(limit_buy_order_usdt, fee, caplog, mocker, buy_price_mult, ignore_strat_sl, edge_conf) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -209,7 +209,7 @@ def test_edge_overrides_stoploss(limit_buy_order, fee, caplog, mocker, # Thus, if price falls 21%, stoploss should be triggered # # mocking the ticker: price is falling ... - buy_price = limit_buy_order['price'] + buy_price = limit_buy_order_usdt['price'] mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ @@ -221,14 +221,14 @@ def test_edge_overrides_stoploss(limit_buy_order, fee, caplog, mocker, ) ############################################# - # Create a trade with "limit_buy_order" price + # Create a trade with "limit_buy_order_usdt" price freqtrade = FreqtradeBot(edge_conf) freqtrade.active_pair_whitelist = ['NEO/BTC'] patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) freqtrade.enter_positions() trade = Trade.query.first() - trade.update(limit_buy_order) + trade.update(limit_buy_order_usdt) ############################################# # stoploss shoud be hit @@ -270,7 +270,7 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker, fee) -> None: assert Trade.total_open_trades_stakes() == 1.97502e-03 -def test_create_trade(default_conf, ticker, limit_buy_order, fee, mocker) -> None: +def test_create_trade(default_conf, ticker, limit_buy_order_usdt, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -294,15 +294,15 @@ def test_create_trade(default_conf, ticker, limit_buy_order, fee, mocker) -> Non assert trade.exchange == 'binance' # Simulate fulfilled LIMIT_BUY order for trade - trade.update(limit_buy_order) + trade.update(limit_buy_order_usdt) - assert trade.open_rate == 0.00001099 - assert trade.amount == 90.99181073 + assert trade.open_rate == 2.0 + assert trade.amount == 30.0 assert whitelist == default_conf['exchange']['pair_whitelist'] -def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order, +def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order_usdt, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -326,12 +326,12 @@ def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order, (UNLIMITED_STAKE_AMOUNT, False, True, 0), ]) def test_create_trade_minimal_amount( - default_conf, ticker, limit_buy_order_open, fee, mocker, + default_conf, ticker, limit_buy_order_usdt_open, fee, mocker, stake_amount, create, amount_enough, max_open_trades, caplog ) -> None: patch_RPCManager(mocker) patch_exchange(mocker) - buy_mock = MagicMock(return_value=limit_buy_order_open) + buy_mock = MagicMock(return_value=limit_buy_order_usdt_open) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, @@ -363,14 +363,14 @@ def test_create_trade_minimal_amount( (["ETH/BTC"], 1), # No pairs left ([], 0), # No pairs in whitelist ]) -def test_enter_positions_no_pairs_left(default_conf, ticker, limit_buy_order_open, fee, +def test_enter_positions_no_pairs_left(default_conf, ticker, limit_buy_order_usdt_open, fee, whitelist, positions, mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, - create_order=MagicMock(return_value=limit_buy_order_open), + create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) default_conf['exchange']['pair_whitelist'] = whitelist @@ -390,14 +390,14 @@ def test_enter_positions_no_pairs_left(default_conf, ticker, limit_buy_order_ope @pytest.mark.usefixtures("init_persistence") -def test_enter_positions_global_pairlock(default_conf, ticker, limit_buy_order, fee, +def test_enter_positions_global_pairlock(default_conf, ticker, limit_buy_order_usdt, fee, mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, - create_order=MagicMock(return_value={'id': limit_buy_order['id']}), + create_order=MagicMock(return_value={'id': limit_buy_order_usdt['id']}), get_fee=fee, ) freqtrade = FreqtradeBot(default_conf) @@ -459,7 +459,7 @@ def test_create_trade_no_signal(default_conf, fee, mocker) -> None: @pytest.mark.parametrize("max_open", range(0, 5)) @pytest.mark.parametrize("tradable_balance_ratio,modifier", [(1.0, 1), (0.99, 0.8), (0.5, 0.5)]) -def test_create_trades_multiple_trades(default_conf, ticker, fee, mocker, limit_buy_order_open, +def test_create_trades_multiple_trades(default_conf, ticker, fee, mocker, limit_buy_order_usdt_open, max_open, tradable_balance_ratio, modifier) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -470,7 +470,7 @@ def test_create_trades_multiple_trades(default_conf, ticker, fee, mocker, limit_ mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, - create_order=MagicMock(return_value=limit_buy_order_open), + create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) freqtrade = FreqtradeBot(default_conf) @@ -484,14 +484,14 @@ def test_create_trades_multiple_trades(default_conf, ticker, fee, mocker, limit_ assert len(trades) == max(int(max_open * modifier), 0) -def test_create_trades_preopen(default_conf, ticker, fee, mocker, limit_buy_order_open) -> None: +def test_create_trades_preopen(default_conf, ticker, fee, mocker, limit_buy_order_usdt_open) -> None: patch_RPCManager(mocker) patch_exchange(mocker) default_conf['max_open_trades'] = 4 mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, - create_order=MagicMock(return_value=limit_buy_order_open), + create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) freqtrade = FreqtradeBot(default_conf) @@ -503,7 +503,7 @@ def test_create_trades_preopen(default_conf, ticker, fee, mocker, limit_buy_orde assert len(Trade.get_open_trades()) == 2 # Change order_id for new orders - limit_buy_order_open['id'] = '123444' + limit_buy_order_usdt_open['id'] = '123444' # Create 2 new trades using create_trades assert freqtrade.create_trade('ETH/BTC') @@ -513,15 +513,15 @@ def test_create_trades_preopen(default_conf, ticker, fee, mocker, limit_buy_orde assert len(trades) == 4 -def test_process_trade_creation(default_conf, ticker, limit_buy_order, limit_buy_order_open, +def test_process_trade_creation(default_conf, ticker, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, - create_order=MagicMock(return_value=limit_buy_order_open), - fetch_order=MagicMock(return_value=limit_buy_order), + create_order=MagicMock(return_value=limit_buy_order_usdt_open), + fetch_order=MagicMock(return_value=limit_buy_order_usdt), get_fee=fee, ) freqtrade = FreqtradeBot(default_conf) @@ -584,14 +584,14 @@ def test_process_operational_exception(default_conf, ticker, mocker) -> None: assert 'OperationalException' in msg_mock.call_args_list[-1][0][0]['status'] -def test_process_trade_handling(default_conf, ticker, limit_buy_order_open, fee, mocker) -> None: +def test_process_trade_handling(default_conf, ticker, limit_buy_order_usdt_open, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, - create_order=MagicMock(return_value=limit_buy_order_open), - fetch_order=MagicMock(return_value=limit_buy_order_open), + create_order=MagicMock(return_value=limit_buy_order_usdt_open), + fetch_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) freqtrade = FreqtradeBot(default_conf) @@ -609,7 +609,7 @@ def test_process_trade_handling(default_conf, ticker, limit_buy_order_open, fee, assert len(trades) == 1 -def test_process_trade_no_whitelist_pair(default_conf, ticker, limit_buy_order, +def test_process_trade_no_whitelist_pair(default_conf, ticker, limit_buy_order_usdt, fee, mocker) -> None: """ Test process with trade not in pair list """ patch_RPCManager(mocker) @@ -617,8 +617,8 @@ def test_process_trade_no_whitelist_pair(default_conf, ticker, limit_buy_order, mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, - create_order=MagicMock(return_value={'id': limit_buy_order['id']}), - fetch_order=MagicMock(return_value=limit_buy_order), + create_order=MagicMock(return_value={'id': limit_buy_order_usdt['id']}), + fetch_order=MagicMock(return_value=limit_buy_order_usdt), get_fee=fee, ) freqtrade = FreqtradeBot(default_conf) @@ -690,7 +690,7 @@ def test_process_informative_pairs_added(default_conf, ticker, mocker) -> None: assert ("ETH/BTC", default_conf["timeframe"]) in refresh_mock.call_args[0][0] -def test_execute_entry(mocker, default_conf, fee, limit_buy_order, limit_buy_order_open) -> None: +def test_execute_entry(mocker, default_conf, fee, limit_buy_order_usdt, limit_buy_order_usdt_open) -> None: patch_RPCManager(mocker) patch_exchange(mocker) freqtrade = FreqtradeBot(default_conf) @@ -698,14 +698,14 @@ def test_execute_entry(mocker, default_conf, fee, limit_buy_order, limit_buy_ord stake_amount = 2 bid = 0.11 buy_rate_mock = MagicMock(return_value=bid) - buy_mm = MagicMock(return_value=limit_buy_order_open) + buy_mm = MagicMock(return_value=limit_buy_order_usdt_open) mocker.patch.multiple( 'freqtrade.exchange.Exchange', get_rate=buy_rate_mock, fetch_ticker=MagicMock(return_value={ - 'bid': 0.00001172, - 'ask': 0.00001173, - 'last': 0.00001172 + 'bid': 1.9, + 'ask': 2.2, + 'last': 1.9 }), create_order=buy_mm, get_min_pair_stake_amount=MagicMock(return_value=1), @@ -719,7 +719,7 @@ def test_execute_entry(mocker, default_conf, fee, limit_buy_order, limit_buy_ord assert freqtrade.strategy.confirm_trade_entry.call_count == 1 buy_rate_mock.reset_mock() - limit_buy_order_open['id'] = '22' + limit_buy_order_usdt_open['id'] = '22' freqtrade.strategy.confirm_trade_entry = MagicMock(return_value=True) assert freqtrade.execute_entry(pair, stake_amount) assert buy_rate_mock.call_count == 1 @@ -738,7 +738,7 @@ def test_execute_entry(mocker, default_conf, fee, limit_buy_order, limit_buy_ord assert trade.open_order_id == '22' # Test calling with price - limit_buy_order_open['id'] = '33' + limit_buy_order_usdt_open['id'] = '33' fix_price = 0.06 assert freqtrade.execute_entry(pair, stake_amount, fix_price) # Make sure get_rate wasn't called again @@ -751,13 +751,13 @@ def test_execute_entry(mocker, default_conf, fee, limit_buy_order, limit_buy_ord assert call_args['amount'] == round(stake_amount / fix_price, 8) # In case of closed order - limit_buy_order['status'] = 'closed' - limit_buy_order['price'] = 10 - limit_buy_order['cost'] = 100 - limit_buy_order['id'] = '444' + limit_buy_order_usdt['status'] = 'closed' + limit_buy_order_usdt['price'] = 10 + limit_buy_order_usdt['cost'] = 100 + limit_buy_order_usdt['id'] = '444' mocker.patch('freqtrade.exchange.Exchange.create_order', - MagicMock(return_value=limit_buy_order)) + MagicMock(return_value=limit_buy_order_usdt)) assert freqtrade.execute_entry(pair, stake_amount) trade = Trade.query.all()[2] assert trade @@ -766,15 +766,15 @@ def test_execute_entry(mocker, default_conf, fee, limit_buy_order, limit_buy_ord assert trade.stake_amount == 100 # In case of rejected or expired order and partially filled - limit_buy_order['status'] = 'expired' - limit_buy_order['amount'] = 90.99181073 - limit_buy_order['filled'] = 80.99181073 - limit_buy_order['remaining'] = 10.00 - limit_buy_order['price'] = 0.5 - limit_buy_order['cost'] = 40.495905365 - limit_buy_order['id'] = '555' + limit_buy_order_usdt['status'] = 'expired' + limit_buy_order_usdt['amount'] = 30.0 + limit_buy_order_usdt['filled'] = 80.99181073 + limit_buy_order_usdt['remaining'] = 10.00 + limit_buy_order_usdt['price'] = 0.5 + limit_buy_order_usdt['cost'] = 40.495905365 + limit_buy_order_usdt['id'] = '555' mocker.patch('freqtrade.exchange.Exchange.create_order', - MagicMock(return_value=limit_buy_order)) + MagicMock(return_value=limit_buy_order_usdt)) assert freqtrade.execute_entry(pair, stake_amount) trade = Trade.query.all()[3] assert trade @@ -783,8 +783,8 @@ def test_execute_entry(mocker, default_conf, fee, limit_buy_order, limit_buy_ord assert trade.stake_amount == 40.495905365 # Test with custom stake - limit_buy_order['status'] = 'open' - limit_buy_order['id'] = '556' + limit_buy_order_usdt['status'] = 'open' + limit_buy_order_usdt['id'] = '556' freqtrade.strategy.custom_stake_amount = lambda **kwargs: 150.0 assert freqtrade.execute_entry(pair, stake_amount) @@ -793,7 +793,7 @@ def test_execute_entry(mocker, default_conf, fee, limit_buy_order, limit_buy_ord assert trade.stake_amount == 150 # Exception case - limit_buy_order['id'] = '557' + limit_buy_order_usdt['id'] = '557' freqtrade.strategy.custom_stake_amount = lambda **kwargs: 20 / 0 assert freqtrade.execute_entry(pair, stake_amount) trade = Trade.query.all()[5] @@ -801,15 +801,15 @@ def test_execute_entry(mocker, default_conf, fee, limit_buy_order, limit_buy_ord assert trade.stake_amount == 2.0 # In case of the order is rejected and not filled at all - limit_buy_order['status'] = 'rejected' - limit_buy_order['amount'] = 90.99181073 - limit_buy_order['filled'] = 0.0 - limit_buy_order['remaining'] = 90.99181073 - limit_buy_order['price'] = 0.5 - limit_buy_order['cost'] = 0.0 - limit_buy_order['id'] = '66' + limit_buy_order_usdt['status'] = 'rejected' + limit_buy_order_usdt['amount'] = 30.0 + limit_buy_order_usdt['filled'] = 0.0 + limit_buy_order_usdt['remaining'] = 30.0 + limit_buy_order_usdt['price'] = 0.5 + limit_buy_order_usdt['cost'] = 0.0 + limit_buy_order_usdt['id'] = '66' mocker.patch('freqtrade.exchange.Exchange.create_order', - MagicMock(return_value=limit_buy_order)) + MagicMock(return_value=limit_buy_order_usdt)) assert not freqtrade.execute_entry(pair, stake_amount) # Fail to get price... @@ -820,8 +820,8 @@ def test_execute_entry(mocker, default_conf, fee, limit_buy_order, limit_buy_ord # In case of custom entry price mocker.patch('freqtrade.exchange.Exchange.get_rate', return_value=0.50) - limit_buy_order['status'] = 'open' - limit_buy_order['id'] = '5566' + limit_buy_order_usdt['status'] = 'open' + limit_buy_order_usdt['id'] = '5566' freqtrade.strategy.custom_entry_price = lambda **kwargs: 0.508 assert freqtrade.execute_entry(pair, stake_amount) trade = Trade.query.all()[6] @@ -829,8 +829,8 @@ def test_execute_entry(mocker, default_conf, fee, limit_buy_order, limit_buy_ord assert trade.open_rate_requested == 0.508 # In case of custom entry price set to None - limit_buy_order['status'] = 'open' - limit_buy_order['id'] = '5567' + limit_buy_order_usdt['status'] = 'open' + limit_buy_order_usdt['id'] = '5567' freqtrade.strategy.custom_entry_price = lambda **kwargs: None mocker.patch.multiple( @@ -844,8 +844,8 @@ def test_execute_entry(mocker, default_conf, fee, limit_buy_order, limit_buy_ord assert trade.open_rate_requested == 10 # In case of custom entry price not float type - limit_buy_order['status'] = 'open' - limit_buy_order['id'] = '5568' + limit_buy_order_usdt['status'] = 'open' + limit_buy_order_usdt['id'] = '5568' freqtrade.strategy.custom_entry_price = lambda **kwargs: "string price" assert freqtrade.execute_entry(pair, stake_amount) trade = Trade.query.all()[8] @@ -853,16 +853,16 @@ def test_execute_entry(mocker, default_conf, fee, limit_buy_order, limit_buy_ord assert trade.open_rate_requested == 10 -def test_execute_entry_confirm_error(mocker, default_conf, fee, limit_buy_order) -> None: +def test_execute_entry_confirm_error(mocker, default_conf, fee, limit_buy_order_usdt) -> None: freqtrade = get_patched_freqtradebot(mocker, default_conf) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00001172, - 'ask': 0.00001173, - 'last': 0.00001172 + 'bid': 1.9, + 'ask': 2.2, + 'last': 1.9 }), - create_order=MagicMock(return_value=limit_buy_order), + create_order=MagicMock(return_value=limit_buy_order_usdt), get_rate=MagicMock(return_value=0.11), get_min_pair_stake_amount=MagicMock(return_value=1), get_fee=fee, @@ -873,11 +873,11 @@ def test_execute_entry_confirm_error(mocker, default_conf, fee, limit_buy_order) freqtrade.strategy.confirm_trade_entry = MagicMock(side_effect=ValueError) assert freqtrade.execute_entry(pair, stake_amount) - limit_buy_order['id'] = '222' + limit_buy_order_usdt['id'] = '222' freqtrade.strategy.confirm_trade_entry = MagicMock(side_effect=Exception) assert freqtrade.execute_entry(pair, stake_amount) - limit_buy_order['id'] = '2223' + limit_buy_order_usdt['id'] = '2223' freqtrade.strategy.confirm_trade_entry = MagicMock(return_value=True) assert freqtrade.execute_entry(pair, stake_amount) @@ -885,14 +885,14 @@ def test_execute_entry_confirm_error(mocker, default_conf, fee, limit_buy_order) assert not freqtrade.execute_entry(pair, stake_amount) -def test_add_stoploss_on_exchange(mocker, default_conf, limit_buy_order) -> None: +def test_add_stoploss_on_exchange(mocker, default_conf, limit_buy_order_usdt) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True)) - mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order) + mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order_usdt) mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[]) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', - return_value=limit_buy_order['amount']) + return_value=limit_buy_order_usdt['amount']) stoploss = MagicMock(return_value={'id': 13434334}) mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss) @@ -913,20 +913,20 @@ def test_add_stoploss_on_exchange(mocker, default_conf, limit_buy_order) -> None def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, - limit_buy_order, limit_sell_order) -> None: + limit_buy_order_usdt, limit_sell_order_usdt) -> None: stoploss = MagicMock(return_value={'id': 13434334}) patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00001172, - 'ask': 0.00001173, - 'last': 0.00001172 + 'bid': 1.9, + 'ask': 2.2, + 'last': 1.9 }), create_order=MagicMock(side_effect=[ - {'id': limit_buy_order['id']}, - {'id': limit_sell_order['id']}, + {'id': limit_buy_order_usdt['id']}, + {'id': limit_sell_order_usdt['id']}, ]), get_fee=fee, ) @@ -993,7 +993,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, 'type': 'stop_loss_limit', 'price': 3, 'average': 2, - 'amount': limit_buy_order['amount'], + 'amount': limit_buy_order_usdt['amount'], }) mocker.patch('freqtrade.exchange.Binance.fetch_stoploss_order', stoploss_order_hit) assert freqtrade.handle_stoploss_on_exchange(trade) is True @@ -1033,20 +1033,20 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog, - limit_buy_order, limit_sell_order) -> None: + limit_buy_order_usdt, limit_sell_order_usdt) -> None: # Sixth case: stoploss order was cancelled but couldn't create new one patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00001172, - 'ask': 0.00001173, - 'last': 0.00001172 + 'bid': 1.9, + 'ask': 2.2, + 'last': 1.9 }), create_order=MagicMock(side_effect=[ - {'id': limit_buy_order['id']}, - {'id': limit_sell_order['id']}, + {'id': limit_buy_order_usdt['id']}, + {'id': limit_sell_order_usdt['id']}, ]), get_fee=fee, ) @@ -1072,19 +1072,19 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog, def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee, - limit_buy_order_open, limit_sell_order): + limit_buy_order_usdt_open, limit_sell_order_usdt): rpc_mock = patch_RPCManager(mocker) patch_exchange(mocker) create_order_mock = MagicMock(side_effect=[ - limit_buy_order_open, - {'id': limit_sell_order['id']} + limit_buy_order_usdt_open, + {'id': limit_sell_order_usdt['id']} ]) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00001172, - 'ask': 0.00001173, - 'last': 0.00001172 + 'bid': 1.9, + 'ask': 2.2, + 'last': 1.9 }), create_order=create_order_mock, get_fee=fee, @@ -1120,20 +1120,20 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee, def test_create_stoploss_order_insufficient_funds(mocker, default_conf, caplog, fee, - limit_buy_order_open, limit_sell_order): - sell_mock = MagicMock(return_value={'id': limit_sell_order['id']}) + limit_buy_order_usdt_open, limit_sell_order_usdt): + sell_mock = MagicMock(return_value={'id': limit_sell_order_usdt['id']}) freqtrade = get_patched_freqtradebot(mocker, default_conf) mock_insuf = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_insufficient_funds') mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00001172, - 'ask': 0.00001173, - 'last': 0.00001172 + 'bid': 1.9, + 'ask': 2.2, + 'last': 1.9 }), create_order=MagicMock(side_effect=[ - limit_buy_order_open, + limit_buy_order_usdt_open, sell_mock, ]), get_fee=fee, @@ -1164,20 +1164,20 @@ def test_create_stoploss_order_insufficient_funds(mocker, default_conf, caplog, @pytest.mark.usefixtures("init_persistence") def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, - limit_buy_order, limit_sell_order) -> None: + limit_buy_order_usdt, limit_sell_order_usdt) -> None: # When trailing stoploss is set stoploss = MagicMock(return_value={'id': 13434334}) patch_RPCManager(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00001172, - 'ask': 0.00001173, - 'last': 0.00001172 + 'bid': 2.19, + 'ask': 2.2, + 'last': 2.19 }), create_order=MagicMock(side_effect=[ - {'id': limit_buy_order['id']}, - {'id': limit_sell_order['id']}, + {'id': limit_buy_order_usdt['id']}, + {'id': limit_sell_order_usdt['id']}, ]), get_fee=fee, ) @@ -1219,7 +1219,7 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, 'price': 3, 'average': 2, 'info': { - 'stopPrice': '0.000011134' + 'stopPrice': '2.0805' } }) @@ -1230,11 +1230,14 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, assert freqtrade.handle_stoploss_on_exchange(trade) is False # price jumped 2x - mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ - 'bid': 0.00002344, - 'ask': 0.00002346, - 'last': 0.00002344 - })) + mocker.patch( + 'freqtrade.exchange.Exchange.fetch_ticker', + MagicMock(return_value={ + 'bid': 4.38, + 'ask': 4.4, + 'last': 4.38 + }) + ) cancel_order_mock = MagicMock() stoploss_order_mock = MagicMock(return_value={'id': 13434334}) @@ -1248,7 +1251,7 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, stoploss_order_mock.assert_not_called() assert freqtrade.handle_trade(trade) is False - assert trade.stop_loss == 0.00002346 * 0.95 + assert trade.stop_loss == 4.4 * 0.95 # setting stoploss_on_exchange_interval to 0 seconds freqtrade.strategy.order_types['stoploss_on_exchange_interval'] = 0 @@ -1256,22 +1259,24 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, assert freqtrade.handle_stoploss_on_exchange(trade) is False cancel_order_mock.assert_called_once_with(100, 'ETH/BTC') - stoploss_order_mock.assert_called_once_with(amount=85.32423208, - pair='ETH/BTC', - order_types=freqtrade.strategy.order_types, - stop_price=0.00002346 * 0.95) + stoploss_order_mock.assert_called_once_with( + amount=30.0, + pair='ETH/BTC', + order_types=freqtrade.strategy.order_types, + stop_price=4.4 * 0.95 + ) # price fell below stoploss, so dry-run sells trade. mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ - 'bid': 0.00002144, - 'ask': 0.00002146, - 'last': 0.00002144 + 'bid': 4.1712, + 'ask': 4.1921, + 'last': 4.1712 })) assert freqtrade.handle_trade(trade) is True def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, caplog, - limit_buy_order, limit_sell_order) -> None: + limit_buy_order_usdt, limit_sell_order_usdt) -> None: # When trailing stoploss is set stoploss = MagicMock(return_value={'id': 13434334}) patch_exchange(mocker) @@ -1279,13 +1284,13 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00001172, - 'ask': 0.00001173, - 'last': 0.00001172 + 'bid': 1.9, + 'ask': 2.2, + 'last': 1.9 }), create_order=MagicMock(side_effect=[ - {'id': limit_buy_order['id']}, - {'id': limit_sell_order['id']}, + {'id': limit_buy_order_usdt['id']}, + {'id': limit_sell_order_usdt['id']}, ]), get_fee=fee, ) @@ -1347,20 +1352,20 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c @pytest.mark.usefixtures("init_persistence") def test_handle_stoploss_on_exchange_custom_stop(mocker, default_conf, fee, - limit_buy_order, limit_sell_order) -> None: + limit_buy_order_usdt, limit_sell_order_usdt) -> None: # When trailing stoploss is set stoploss = MagicMock(return_value={'id': 13434334}) patch_RPCManager(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00001172, - 'ask': 0.00001173, - 'last': 0.00001172 + 'bid': 1.9, + 'ask': 2.2, + 'last': 1.9 }), create_order=MagicMock(side_effect=[ - {'id': limit_buy_order['id']}, - {'id': limit_sell_order['id']}, + {'id': limit_buy_order_usdt['id']}, + {'id': limit_sell_order_usdt['id']}, ]), get_fee=fee, ) @@ -1413,9 +1418,9 @@ def test_handle_stoploss_on_exchange_custom_stop(mocker, default_conf, fee, # price jumped 2x mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ - 'bid': 0.00002344, - 'ask': 0.00002346, - 'last': 0.00002344 + 'bid': 4.38, + 'ask': 4.4, + 'last': 4.38 })) cancel_order_mock = MagicMock() @@ -1454,7 +1459,7 @@ def test_handle_stoploss_on_exchange_custom_stop(mocker, default_conf, fee, def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, - limit_buy_order, limit_sell_order) -> None: + limit_buy_order_usdt, limit_sell_order_usdt) -> None: # When trailing stoploss is set stoploss = MagicMock(return_value={'id': 13434334}) @@ -1467,13 +1472,13 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00001172, - 'ask': 0.00001173, - 'last': 0.00001172 + 'bid': 1.9, + 'ask': 2.2, + 'last': 1.9 }), create_order=MagicMock(side_effect=[ - {'id': limit_buy_order['id']}, - {'id': limit_sell_order['id']}, + {'id': limit_buy_order_usdt['id']}, + {'id': limit_sell_order_usdt['id']}, ]), get_fee=fee, stoploss=stoploss, @@ -1515,7 +1520,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, 'price': 3, 'average': 2, 'info': { - 'stopPrice': '0.000009384' + 'stopPrice': '2.178' } }) @@ -1524,7 +1529,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, # stoploss initially at 20% as edge dictated it. assert freqtrade.handle_trade(trade) is False assert freqtrade.handle_stoploss_on_exchange(trade) is False - assert trade.stop_loss == 0.000009384 + assert trade.stop_loss == 2.178 cancel_order_mock = MagicMock() stoploss_order_mock = MagicMock() @@ -1533,16 +1538,16 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, # price goes down 5% mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ - 'bid': 0.00001172 * 0.95, - 'ask': 0.00001173 * 0.95, - 'last': 0.00001172 * 0.95 + 'bid': 1.9 * 0.95, + 'ask': 2.2 * 0.95, + 'last': 1.9 * 0.95 })) assert freqtrade.handle_trade(trade) is False assert freqtrade.handle_stoploss_on_exchange(trade) is False # stoploss should remain the same - assert trade.stop_loss == 0.000009384 + assert trade.stop_loss == 2.178 # stoploss on exchange should not be canceled cancel_order_mock.assert_not_called() @@ -1589,14 +1594,14 @@ def test_enter_positions(mocker, default_conf, return_value, side_effect, assert mock_ct.call_count == len(default_conf['exchange']['pair_whitelist']) -def test_exit_positions(mocker, default_conf, limit_buy_order, caplog) -> None: +def test_exit_positions(mocker, default_conf, limit_buy_order_usdt, caplog) -> None: freqtrade = get_patched_freqtradebot(mocker, default_conf) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True)) - mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order) + mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order_usdt) mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[]) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', - return_value=limit_buy_order['amount']) + return_value=limit_buy_order_usdt['amount']) trade = MagicMock() trade.open_order_id = '123' @@ -1606,7 +1611,7 @@ def test_exit_positions(mocker, default_conf, limit_buy_order, caplog) -> None: assert n == 0 # Test amount not modified by fee-logic assert not log_has( - 'Applying fee to amount for Trade {} from 90.99181073 to 90.81'.format(trade), caplog + 'Applying fee to amount for Trade {} from 30.0 to 90.81'.format(trade), caplog ) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', return_value=90.81) @@ -1615,9 +1620,9 @@ def test_exit_positions(mocker, default_conf, limit_buy_order, caplog) -> None: assert n == 0 -def test_exit_positions_exception(mocker, default_conf, limit_buy_order, caplog) -> None: +def test_exit_positions_exception(mocker, default_conf, limit_buy_order_usdt, caplog) -> None: freqtrade = get_patched_freqtradebot(mocker, default_conf) - mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order) + mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order_usdt) trade = MagicMock() trade.open_order_id = None @@ -1635,14 +1640,14 @@ def test_exit_positions_exception(mocker, default_conf, limit_buy_order, caplog) assert log_has('Unable to sell trade ETH/BTC: ', caplog) -def test_update_trade_state(mocker, default_conf, limit_buy_order, caplog) -> None: +def test_update_trade_state(mocker, default_conf, limit_buy_order_usdt, caplog) -> None: freqtrade = get_patched_freqtradebot(mocker, default_conf) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True)) - mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order) + mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order_usdt) mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[]) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', - return_value=limit_buy_order['amount']) + return_value=limit_buy_order_usdt['amount']) trade = Trade( open_order_id=123, @@ -1662,7 +1667,7 @@ def test_update_trade_state(mocker, default_conf, limit_buy_order, caplog) -> No 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'] + assert trade.amount == limit_buy_order_usdt['amount'] trade.open_order_id = '123' mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', return_value=90.81) @@ -1681,10 +1686,10 @@ def test_update_trade_state(mocker, default_conf, limit_buy_order, caplog) -> No @pytest.mark.parametrize('initial_amount,has_rounding_fee', [ - (90.99181073 + 1e-14, True), + (30.0 + 1e-14, True), (8.0, False) ]) -def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_buy_order, fee, +def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_buy_order_usdt, fee, mocker, initial_amount, has_rounding_fee, caplog): trades_for_order[0]['amount'] = initial_amount mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) @@ -1704,17 +1709,17 @@ def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_ open_order_id="123456", is_open=True, ) - freqtrade.update_trade_state(trade, '123456', limit_buy_order) + freqtrade.update_trade_state(trade, '123456', limit_buy_order_usdt) assert trade.amount != amount - assert trade.amount == limit_buy_order['amount'] + assert trade.amount == limit_buy_order_usdt['amount'] if has_rounding_fee: assert log_has_re(r'Applying fee on amount for .*', caplog) def test_update_trade_state_exception(mocker, default_conf, - limit_buy_order, caplog) -> None: + limit_buy_order_usdt, caplog) -> None: freqtrade = get_patched_freqtradebot(mocker, default_conf) - mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order) + mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order_usdt) trade = MagicMock() trade.open_order_id = '123' @@ -1745,8 +1750,8 @@ def test_update_trade_state_orderexception(mocker, default_conf, caplog) -> None assert log_has(f'Unable to fetch order {trade.open_order_id}: ', caplog) -def test_update_trade_state_sell(default_conf, trades_for_order, limit_sell_order_open, - limit_sell_order, mocker): +def test_update_trade_state_sell(default_conf, trades_for_order, limit_sell_order_usdt_open, + limit_sell_order_usdt, mocker): mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) # fetch_order should not be called!! mocker.patch('freqtrade.exchange.Exchange.fetch_order', MagicMock(side_effect=ValueError)) @@ -1754,7 +1759,7 @@ def test_update_trade_state_sell(default_conf, trades_for_order, limit_sell_orde mocker.patch('freqtrade.wallets.Wallets.update', wallet_mock) patch_exchange(mocker) - amount = limit_sell_order["amount"] + amount = limit_sell_order_usdt["amount"] freqtrade = get_patched_freqtradebot(mocker, default_conf) wallet_mock.reset_mock() trade = Trade( @@ -1768,11 +1773,11 @@ def test_update_trade_state_sell(default_conf, trades_for_order, limit_sell_orde open_order_id="123456", is_open=True, ) - order = Order.parse_from_ccxt_object(limit_sell_order_open, 'LTC/ETH', 'sell') + order = Order.parse_from_ccxt_object(limit_sell_order_usdt_open, 'LTC/ETH', 'sell') trade.orders.append(order) assert order.status == 'open' - freqtrade.update_trade_state(trade, trade.open_order_id, limit_sell_order) - assert trade.amount == limit_sell_order['amount'] + freqtrade.update_trade_state(trade, trade.open_order_id, limit_sell_order_usdt) + assert trade.amount == limit_sell_order_usdt['amount'] # Wallet needs to be updated after closing a limit-sell order to reenable buying assert wallet_mock.call_count == 1 assert not trade.is_open @@ -1780,20 +1785,20 @@ def test_update_trade_state_sell(default_conf, trades_for_order, limit_sell_orde assert order.status == 'closed' -def test_handle_trade(default_conf, limit_buy_order, limit_sell_order_open, limit_sell_order, +def test_handle_trade(default_conf, limit_buy_order_usdt, limit_sell_order_usdt_open, limit_sell_order_usdt, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00001172, - 'ask': 0.00001173, - 'last': 0.00001172 + 'bid': 1.9, + 'ask': 2.2, + 'last': 1.9 }), create_order=MagicMock(side_effect=[ - limit_buy_order, - limit_sell_order_open, + limit_buy_order_usdt, + limit_sell_order_usdt_open, ]), get_fee=fee, ) @@ -1806,24 +1811,24 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order_open, limi assert trade time.sleep(0.01) # Race condition fix - trade.update(limit_buy_order) + trade.update(limit_buy_order_usdt) assert trade.is_open is True freqtrade.wallets.update() patch_get_signal(freqtrade, value=(False, True, None)) assert freqtrade.handle_trade(trade) is True - assert trade.open_order_id == limit_sell_order['id'] + assert trade.open_order_id == limit_sell_order_usdt['id'] # Simulate fulfilled LIMIT_SELL order for trade - trade.update(limit_sell_order) + trade.update(limit_sell_order_usdt) - assert trade.close_rate == 0.00001173 - assert trade.close_profit == 0.06201058 - assert trade.calc_profit() == 0.00006217 + assert trade.close_rate == 2.2 + assert trade.close_profit == 0.09451372 + assert trade.calc_profit() == 5.685 assert trade.close_date is not None -def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open, +def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_usdt_open, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -1831,7 +1836,7 @@ def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open, 'freqtrade.exchange.Exchange', fetch_ticker=ticker, create_order=MagicMock(side_effect=[ - limit_buy_order_open, + limit_buy_order_usdt_open, {'id': 1234553382}, ]), get_fee=fee, @@ -1878,7 +1883,7 @@ def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open, assert freqtrade.handle_trade(trades[0]) is True -def test_handle_trade_roi(default_conf, ticker, limit_buy_order_open, +def test_handle_trade_roi(default_conf, ticker, limit_buy_order_usdt_open, fee, mocker, caplog) -> None: caplog.set_level(logging.DEBUG) @@ -1887,7 +1892,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order_open, 'freqtrade.exchange.Exchange', fetch_ticker=ticker, create_order=MagicMock(side_effect=[ - limit_buy_order_open, + limit_buy_order_usdt_open, {'id': 1234553382}, ]), get_fee=fee, @@ -1913,8 +1918,8 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order_open, caplog) -def test_handle_trade_use_sell_signal(default_conf, ticker, limit_buy_order_open, - limit_sell_order_open, fee, mocker, caplog) -> None: +def test_handle_trade_use_sell_signal(default_conf, ticker, limit_buy_order_usdt_open, + limit_sell_order_usdt_open, fee, mocker, caplog) -> None: # use_sell_signal is True buy default caplog.set_level(logging.DEBUG) patch_RPCManager(mocker) @@ -1922,8 +1927,8 @@ def test_handle_trade_use_sell_signal(default_conf, ticker, limit_buy_order_open 'freqtrade.exchange.Exchange', fetch_ticker=ticker, create_order=MagicMock(side_effect=[ - limit_buy_order_open, - limit_sell_order_open, + limit_buy_order_usdt_open, + limit_sell_order_usdt_open, ]), get_fee=fee, ) @@ -1945,14 +1950,14 @@ def test_handle_trade_use_sell_signal(default_conf, ticker, limit_buy_order_open caplog) -def test_close_trade(default_conf, ticker, limit_buy_order, limit_buy_order_open, limit_sell_order, +def test_close_trade(default_conf, ticker, limit_buy_order_usdt, limit_buy_order_usdt_open, limit_sell_order_usdt, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, - create_order=MagicMock(return_value=limit_buy_order_open), + create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) freqtrade = FreqtradeBot(default_conf) @@ -1964,8 +1969,8 @@ def test_close_trade(default_conf, ticker, limit_buy_order, limit_buy_order_open trade = Trade.query.first() assert trade - trade.update(limit_buy_order) - trade.update(limit_sell_order) + trade.update(limit_buy_order_usdt) + trade.update(limit_sell_order_usdt) assert trade.is_open is False with pytest.raises(DependencyException, match=r'.*closed trade.*'): @@ -2341,7 +2346,7 @@ def test_check_handle_timedout_partial_except(default_conf, ticker, open_trade, assert trades[0].fee_open == fee() -def test_check_handle_timedout_exception(default_conf, ticker, open_trade, mocker, caplog) -> None: +def test_check_handle_timedout_exception(default_conf, ticker, open_trade_usdt, mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) cancel_order_mock = MagicMock() @@ -2359,20 +2364,20 @@ def test_check_handle_timedout_exception(default_conf, ticker, open_trade, mocke ) freqtrade = FreqtradeBot(default_conf) - Trade.query.session.add(open_trade) + Trade.query.session.add(open_trade_usdt) freqtrade.check_handle_timedout() - assert log_has_re(r"Cannot query order for Trade\(id=1, pair=ETH/BTC, amount=90.99181073, " - r"open_rate=0.00001099, open_since=" - f"{open_trade.open_date.strftime('%Y-%m-%d %H:%M:%S')}" + assert log_has_re(r"Cannot query order for Trade\(id=1, pair=ADA/USDT, amount=30.00000000, " + r"open_rate=2.00000000, open_since=" + f"{open_trade_usdt.open_date.strftime('%Y-%m-%d %H:%M:%S')}" r"\) due to Traceback \(most recent call last\):\n*", caplog) -def test_handle_cancel_enter(mocker, caplog, default_conf, limit_buy_order) -> None: +def test_handle_cancel_enter(mocker, caplog, default_conf, limit_buy_order_usdt) -> None: patch_RPCManager(mocker) patch_exchange(mocker) - cancel_buy_order = deepcopy(limit_buy_order) + cancel_buy_order = deepcopy(limit_buy_order_usdt) cancel_buy_order['status'] = 'canceled' del cancel_buy_order['filled'] @@ -2385,30 +2390,30 @@ def test_handle_cancel_enter(mocker, caplog, default_conf, limit_buy_order) -> N trade = MagicMock() trade.pair = 'LTC/USDT' trade.open_rate = 200 - limit_buy_order['filled'] = 0.0 - limit_buy_order['status'] = 'open' + limit_buy_order_usdt['filled'] = 0.0 + limit_buy_order_usdt['status'] = 'open' reason = CANCEL_REASON['TIMEOUT'] - assert freqtrade.handle_cancel_enter(trade, limit_buy_order, reason) + assert freqtrade.handle_cancel_enter(trade, limit_buy_order_usdt, reason) assert cancel_order_mock.call_count == 1 cancel_order_mock.reset_mock() caplog.clear() - limit_buy_order['filled'] = 0.01 - assert not freqtrade.handle_cancel_enter(trade, limit_buy_order, reason) + limit_buy_order_usdt['filled'] = 0.01 + assert not freqtrade.handle_cancel_enter(trade, limit_buy_order_usdt, reason) assert cancel_order_mock.call_count == 0 assert log_has_re("Order .* for .* not cancelled, as the filled amount.* unsellable.*", caplog) caplog.clear() cancel_order_mock.reset_mock() - limit_buy_order['filled'] = 2 - assert not freqtrade.handle_cancel_enter(trade, limit_buy_order, reason) + limit_buy_order_usdt['filled'] = 2 + assert not freqtrade.handle_cancel_enter(trade, limit_buy_order_usdt, reason) assert cancel_order_mock.call_count == 1 # Order remained open for some reason (cancel failed) cancel_buy_order['status'] = 'open' cancel_order_mock = MagicMock(return_value=cancel_buy_order) mocker.patch('freqtrade.exchange.Exchange.cancel_order_with_result', cancel_order_mock) - assert not freqtrade.handle_cancel_enter(trade, limit_buy_order, reason) + assert not freqtrade.handle_cancel_enter(trade, limit_buy_order_usdt, reason) assert log_has_re(r"Order .* for .* not cancelled.", caplog) @@ -2439,7 +2444,7 @@ def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf, 'String Return value', 123 ]) -def test_handle_cancel_enter_corder_empty(mocker, default_conf, limit_buy_order, +def test_handle_cancel_enter_corder_empty(mocker, default_conf, limit_buy_order_usdt, cancelorder) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -2455,15 +2460,15 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf, limit_buy_order, trade = MagicMock() trade.pair = 'LTC/USDT' trade.open_rate = 200 - limit_buy_order['filled'] = 0.0 - limit_buy_order['status'] = 'open' + limit_buy_order_usdt['filled'] = 0.0 + limit_buy_order_usdt['status'] = 'open' reason = CANCEL_REASON['TIMEOUT'] - assert freqtrade.handle_cancel_enter(trade, limit_buy_order, reason) + assert freqtrade.handle_cancel_enter(trade, limit_buy_order_usdt, reason) assert cancel_order_mock.call_count == 1 cancel_order_mock.reset_mock() - limit_buy_order['filled'] = 1.0 - assert not freqtrade.handle_cancel_enter(trade, limit_buy_order, reason) + limit_buy_order_usdt['filled'] = 1.0 + assert not freqtrade.handle_cancel_enter(trade, limit_buy_order_usdt, reason) assert cancel_order_mock.call_count == 1 @@ -3021,7 +3026,7 @@ def test_execute_trade_exit_insufficient_funds_error(default_conf, ticker, fee, @pytest.mark.parametrize('profit_only,bid,ask,handle_first,handle_second,sell_type', [ # Enable profit - (True, 0.00001172, 0.00001173, False, True, SellType.SELL_SIGNAL.value), + (True, 1.9, 2.2, False, True, SellType.SELL_SIGNAL.value), # Disable profit (False, 0.00002172, 0.00002173, True, False, SellType.SELL_SIGNAL.value), # Enable loss @@ -3031,7 +3036,7 @@ def test_execute_trade_exit_insufficient_funds_error(default_conf, ticker, fee, (False, 0.00000172, 0.00000173, True, False, SellType.SELL_SIGNAL.value), ]) def test_sell_profit_only( - default_conf, limit_buy_order, limit_buy_order_open, + default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, mocker, profit_only, bid, ask, handle_first, handle_second, sell_type) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -3043,7 +3048,7 @@ def test_sell_profit_only( 'last': bid }), create_order=MagicMock(side_effect=[ - limit_buy_order_open, + limit_buy_order_usdt_open, {'id': 1234553382}, ]), get_fee=fee, @@ -3063,7 +3068,7 @@ def test_sell_profit_only( freqtrade.enter_positions() trade = Trade.query.first() - trade.update(limit_buy_order) + trade.update(limit_buy_order_usdt) freqtrade.wallets.update() patch_get_signal(freqtrade, value=(False, True, None)) assert freqtrade.handle_trade(trade) is handle_first @@ -3072,10 +3077,8 @@ def test_sell_profit_only( freqtrade.strategy.sell_profit_offset = 0.0 assert freqtrade.handle_trade(trade) is True - assert trade.sell_reason == sell_type - -def test_sell_not_enough_balance(default_conf, limit_buy_order, limit_buy_order_open, +def test_sell_not_enough_balance(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -3087,7 +3090,7 @@ def test_sell_not_enough_balance(default_conf, limit_buy_order, limit_buy_order_ 'last': 0.00002172 }), create_order=MagicMock(side_effect=[ - limit_buy_order_open, + limit_buy_order_usdt_open, {'id': 1234553382}, ]), get_fee=fee, @@ -3101,7 +3104,7 @@ def test_sell_not_enough_balance(default_conf, limit_buy_order, limit_buy_order_ trade = Trade.query.first() amnt = trade.amount - trade.update(limit_buy_order) + trade.update(limit_buy_order_usdt) patch_get_signal(freqtrade, value=(False, True, None)) mocker.patch('freqtrade.wallets.Wallets.get_free', MagicMock(return_value=trade.amount * 0.985)) @@ -3182,7 +3185,7 @@ def test_locked_pairs(default_conf, ticker, fee, ticker_sell_down, mocker, caplo assert log_has_re(f"Pair {trade.pair} is still locked.*", caplog) -def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_buy_order_open, +def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -3194,7 +3197,7 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_buy_order 'last': 0.0000172 }), create_order=MagicMock(side_effect=[ - limit_buy_order_open, + limit_buy_order_usdt_open, {'id': 1234553382}, ]), get_fee=fee, @@ -3208,7 +3211,7 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_buy_order freqtrade.enter_positions() trade = Trade.query.first() - trade.update(limit_buy_order) + trade.update(limit_buy_order_usdt) freqtrade.wallets.update() patch_get_signal(freqtrade, value=(True, True, None)) assert freqtrade.handle_trade(trade) is False @@ -3219,19 +3222,19 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_buy_order assert trade.sell_reason == SellType.ROI.value -def test_trailing_stop_loss(default_conf, limit_buy_order_open, limit_buy_order, +def test_trailing_stop_loss(default_conf, limit_buy_order_usdt_open, limit_buy_order_usdt, fee, caplog, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00001099, - 'ask': 0.00001099, - 'last': 0.00001099 + 'bid': 2.0, + 'ask': 2.0, + 'last': 2.0 }), create_order=MagicMock(side_effect=[ - limit_buy_order_open, + limit_buy_order_usdt_open, {'id': 1234553382}, ]), get_fee=fee, @@ -3249,9 +3252,9 @@ def test_trailing_stop_loss(default_conf, limit_buy_order_open, limit_buy_order, # Raise ticker above buy price mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ - 'bid': 0.00001099 * 1.5, - 'ask': 0.00001099 * 1.5, - 'last': 0.00001099 * 1.5 + 'bid': 2.0 * 1.5, + 'ask': 2.0 * 1.5, + 'last': 2.0 * 1.5 })) # Stoploss should be adjusted @@ -3260,9 +3263,9 @@ def test_trailing_stop_loss(default_conf, limit_buy_order_open, limit_buy_order, # Price fell mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ - 'bid': 0.00001099 * 1.1, - 'ask': 0.00001099 * 1.1, - 'last': 0.00001099 * 1.1 + 'bid': 2.0 * 1.1, + 'ask': 2.0 * 1.1, + 'last': 2.0 * 1.1 })) caplog.set_level(logging.DEBUG) @@ -3273,9 +3276,9 @@ def test_trailing_stop_loss(default_conf, limit_buy_order_open, limit_buy_order, assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value -def test_trailing_stop_loss_positive(default_conf, limit_buy_order, limit_buy_order_open, fee, +def test_trailing_stop_loss_positive(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, caplog, mocker) -> None: - buy_price = limit_buy_order['price'] + buy_price = limit_buy_order_usdt['price'] patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -3286,7 +3289,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, limit_buy_or 'last': buy_price - 0.000001 }), create_order=MagicMock(side_effect=[ - limit_buy_order_open, + limit_buy_order_usdt_open, {'id': 1234553382}, ]), get_fee=fee, @@ -3301,7 +3304,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, limit_buy_or freqtrade.enter_positions() trade = Trade.query.first() - trade.update(limit_buy_order) + trade.update(limit_buy_order_usdt) caplog.set_level(logging.DEBUG) # stop-loss not reached assert freqtrade.handle_trade(trade) is False @@ -3334,9 +3337,9 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, limit_buy_or f"initial stoploss was at 0.000010, trade opened at 0.000011", caplog) -def test_trailing_stop_loss_offset(default_conf, limit_buy_order, limit_buy_order_open, fee, +def test_trailing_stop_loss_offset(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, caplog, mocker) -> None: - buy_price = limit_buy_order['price'] + buy_price = limit_buy_order_usdt['price'] patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -3347,7 +3350,7 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, limit_buy_orde 'last': buy_price - 0.000001 }), create_order=MagicMock(side_effect=[ - limit_buy_order_open, + limit_buy_order_usdt_open, {'id': 1234553382}, ]), get_fee=fee, @@ -3362,7 +3365,7 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, limit_buy_orde freqtrade.enter_positions() trade = Trade.query.first() - trade.update(limit_buy_order) + trade.update(limit_buy_order_usdt) caplog.set_level(logging.DEBUG) # stop-loss not reached assert freqtrade.handle_trade(trade) is False @@ -3396,10 +3399,10 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, limit_buy_orde assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value -def test_tsl_only_offset_reached(default_conf, limit_buy_order, limit_buy_order_open, fee, +def test_tsl_only_offset_reached(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, caplog, mocker) -> None: - buy_price = limit_buy_order['price'] - # buy_price: 0.00001099 + buy_price = limit_buy_order_usdt['price'] + # buy_price: 2.0 patch_RPCManager(mocker) patch_exchange(mocker) @@ -3410,7 +3413,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, limit_buy_order_ 'ask': buy_price, 'last': buy_price }), - create_order=MagicMock(return_value=limit_buy_order_open), + create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) patch_whitelist(mocker, default_conf) @@ -3425,11 +3428,11 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, limit_buy_order_ freqtrade.enter_positions() trade = Trade.query.first() - trade.update(limit_buy_order) + trade.update(limit_buy_order_usdt) caplog.set_level(logging.DEBUG) # stop-loss not reached assert freqtrade.handle_trade(trade) is False - assert trade.stop_loss == 0.0000098910 + assert trade.stop_loss == 1.8 # Raise ticker above buy price mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', @@ -3443,7 +3446,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, limit_buy_order_ assert freqtrade.handle_trade(trade) is False assert not log_has("ETH/BTC - Adjusting stoploss...", caplog) - assert trade.stop_loss == 0.0000098910 + assert trade.stop_loss == 1.8 caplog.clear() # price rises above the offset (rises 12% when the offset is 5.5%) @@ -3460,7 +3463,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, limit_buy_order_ assert trade.stop_loss == 0.0000117705 -def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_buy_order_open, +def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -3472,7 +3475,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_b 'last': 0.00000172 }), create_order=MagicMock(side_effect=[ - limit_buy_order_open, + limit_buy_order_usdt_open, {'id': 1234553382}, {'id': 1234553383} ]), @@ -3489,7 +3492,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_b freqtrade.enter_positions() trade = Trade.query.first() - trade.update(limit_buy_order) + trade.update(limit_buy_order_usdt) # Sell due to min_roi_reached patch_get_signal(freqtrade, value=(True, True, None)) assert freqtrade.handle_trade(trade) is True @@ -3678,8 +3681,8 @@ def test_get_real_amount_multi( def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order_fee, fee, mocker): - limit_buy_order = deepcopy(buy_order_fee) - limit_buy_order['fee'] = {'cost': 0.004} + limit_buy_order_usdt = deepcopy(buy_order_fee) + limit_buy_order_usdt['fee'] = {'cost': 0.004} mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[]) amount = float(sum(x['amount'] for x in trades_for_order)) @@ -3695,12 +3698,12 @@ def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order freqtrade = get_patched_freqtradebot(mocker, default_conf) # Amount does not change - assert freqtrade.get_real_amount(trade, limit_buy_order) == amount + assert freqtrade.get_real_amount(trade, limit_buy_order_usdt) == amount def test_get_real_amount_wrong_amount(default_conf, trades_for_order, buy_order_fee, fee, mocker): - limit_buy_order = deepcopy(buy_order_fee) - limit_buy_order['amount'] = limit_buy_order['amount'] - 0.001 + limit_buy_order_usdt = deepcopy(buy_order_fee) + limit_buy_order_usdt['amount'] = limit_buy_order_usdt['amount'] - 0.001 mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) amount = float(sum(x['amount'] for x in trades_for_order)) @@ -3717,13 +3720,13 @@ def test_get_real_amount_wrong_amount(default_conf, trades_for_order, buy_order_ # Amount does not change with pytest.raises(DependencyException, match=r"Half bought\? Amounts don't match"): - freqtrade.get_real_amount(trade, limit_buy_order) + freqtrade.get_real_amount(trade, limit_buy_order_usdt) def test_get_real_amount_wrong_amount_rounding(default_conf, trades_for_order, buy_order_fee, fee, mocker): # Floats should not be compared directly. - limit_buy_order = deepcopy(buy_order_fee) + limit_buy_order_usdt = deepcopy(buy_order_fee) trades_for_order[0]['amount'] = trades_for_order[0]['amount'] + 1e-15 mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) @@ -3740,7 +3743,7 @@ def test_get_real_amount_wrong_amount_rounding(default_conf, trades_for_order, b freqtrade = get_patched_freqtradebot(mocker, default_conf) # Amount changes by fee amount. - assert isclose(freqtrade.get_real_amount(trade, limit_buy_order), amount - (amount * 0.001), + assert isclose(freqtrade.get_real_amount(trade, limit_buy_order_usdt), amount - (amount * 0.001), abs_tol=MATH_CLOSE_PREC,) @@ -3798,7 +3801,7 @@ def test_apply_fee_conditional(default_conf, fee, caplog, mocker, (0.1, False), (100, True), ]) -def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order_open, limit_buy_order, +def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order_usdt_open, limit_buy_order_usdt, fee, mocker, order_book_l2, delta, is_high_delta): default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = delta @@ -3808,7 +3811,7 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order_open, mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, - create_order=MagicMock(return_value=limit_buy_order_open), + create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) @@ -3831,9 +3834,9 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order_open, assert len(Trade.query.all()) == 1 # Simulate fulfilled LIMIT_BUY order for trade - trade.update(limit_buy_order) + trade.update(limit_buy_order_usdt) - assert trade.open_rate == 0.00001099 + assert trade.open_rate == 2.0 assert whitelist == default_conf['exchange']['pair_whitelist'] @@ -3890,8 +3893,8 @@ def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2) -> None: assert freqtrade._check_depth_of_market_buy('ETH/BTC', conf) is False -def test_order_book_ask_strategy(default_conf, limit_buy_order_open, limit_buy_order, fee, - limit_sell_order_open, mocker, order_book_l2, caplog) -> None: +def test_order_book_ask_strategy(default_conf, limit_buy_order_usdt_open, limit_buy_order_usdt, fee, + limit_sell_order_usdt_open, mocker, order_book_l2, caplog) -> None: """ test order book ask strategy """ @@ -3905,13 +3908,13 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order_open, limit_buy_o mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00001172, - 'ask': 0.00001173, - 'last': 0.00001172 + 'bid': 1.9, + 'ask': 2.2, + 'last': 1.9 }), create_order=MagicMock(side_effect=[ - limit_buy_order_open, - limit_sell_order_open, + limit_buy_order_usdt_open, + limit_sell_order_usdt_open, ]), get_fee=fee, ) @@ -3924,7 +3927,7 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order_open, limit_buy_o assert trade time.sleep(0.01) # Race condition fix - trade.update(limit_buy_order) + trade.update(limit_buy_order_usdt) freqtrade.wallets.update() assert trade.is_open is True @@ -3967,7 +3970,7 @@ def test_startup_trade_reinit(default_conf, edge_conf, mocker): @pytest.mark.usefixtures("init_persistence") -def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order_open, caplog): +def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order_usdt_open, caplog): default_conf['dry_run'] = True # Initialize to 2 times stake amount default_conf['dry_run_wallet'] = 0.002 @@ -3977,7 +3980,7 @@ def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order_ mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, - create_order=MagicMock(return_value=limit_buy_order_open), + create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) @@ -3999,11 +4002,11 @@ def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order_ @pytest.mark.usefixtures("init_persistence") -def test_cancel_all_open_orders(mocker, default_conf, fee, limit_buy_order, limit_sell_order): +def test_cancel_all_open_orders(mocker, default_conf, fee, limit_buy_order_usdt, limit_sell_order_usdt): default_conf['cancel_open_orders_on_exit'] = True mocker.patch('freqtrade.exchange.Exchange.fetch_order', side_effect=[ - ExchangeError(), limit_sell_order, limit_buy_order, limit_sell_order]) + ExchangeError(), limit_sell_order_usdt, limit_buy_order_usdt, limit_sell_order_usdt]) buy_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_enter') sell_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_exit') From 8d7f75c4de748f9d0784dc20b276b97d19e4a979 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Fri, 17 Sep 2021 22:18:14 -0600 Subject: [PATCH 48/76] Fixed a bunch of freqtradebot tests --- tests/conftest.py | 28 +--- tests/test_freqtradebot.py | 266 +++++++++++++------------------------ 2 files changed, 94 insertions(+), 200 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index c1032a215..adb344ffc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -338,8 +338,7 @@ def get_default_conf(testdatadir): "ETH/BTC", "LTC/BTC", "XRP/BTC", - "NEO/BTC", - "ADA/USDT" + "NEO/BTC" ], "pair_blacklist": [ "DOGE/BTC", @@ -469,31 +468,6 @@ def get_markets(): }, 'info': {}, }, - 'ADA/USDT': { - 'id': 'ethbtc', - 'symbol': 'ADA/USDT', - 'base': 'USDT', - 'quote': 'ADA', - 'active': True, - 'precision': { - 'price': 8, - 'amount': 8, - 'cost': 8, - }, - 'lot': 0.00000001, - 'limits': { - 'amount': { - 'min': 0.01, - 'max': 1000, - }, - 'price': 500000, - 'cost': { - 'min': 0.0001, - 'max': 500000, - }, - }, - 'info': {}, - }, 'TKN/BTC': { 'id': 'tknbtc', 'symbol': 'TKN/BTC', diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 7ddb90657..c030aca0f 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1267,11 +1267,14 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, ) # price fell below stoploss, so dry-run sells trade. - mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ - 'bid': 4.1712, - 'ask': 4.1921, - 'last': 4.1712 - })) + mocker.patch( + 'freqtrade.exchange.Exchange.fetch_ticker', + MagicMock(return_value={ + 'bid': 4.1712, + 'ask': 4.1921, + 'last': 4.1712 + }) + ) assert freqtrade.handle_trade(trade) is True @@ -1407,7 +1410,7 @@ def test_handle_stoploss_on_exchange_custom_stop(mocker, default_conf, fee, 'price': 3, 'average': 2, 'info': { - 'stopPrice': '0.000011134' + 'stopPrice': '2.0805' } }) @@ -1417,11 +1420,14 @@ def test_handle_stoploss_on_exchange_custom_stop(mocker, default_conf, fee, assert freqtrade.handle_stoploss_on_exchange(trade) is False # price jumped 2x - mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ - 'bid': 4.38, - 'ask': 4.4, - 'last': 4.38 - })) + mocker.patch( + 'freqtrade.exchange.Exchange.fetch_ticker', + MagicMock(return_value={ + 'bid': 4.38, + 'ask': 4.4, + 'last': 4.38 + }) + ) cancel_order_mock = MagicMock() stoploss_order_mock = MagicMock(return_value={'id': 13434334}) @@ -1435,7 +1441,7 @@ def test_handle_stoploss_on_exchange_custom_stop(mocker, default_conf, fee, stoploss_order_mock.assert_not_called() assert freqtrade.handle_trade(trade) is False - assert trade.stop_loss == 0.00002346 * 0.96 + assert trade.stop_loss == 4.4 * 0.96 assert trade.stop_loss_pct == -0.04 # setting stoploss_on_exchange_interval to 0 seconds @@ -1444,17 +1450,22 @@ def test_handle_stoploss_on_exchange_custom_stop(mocker, default_conf, fee, assert freqtrade.handle_stoploss_on_exchange(trade) is False cancel_order_mock.assert_called_once_with(100, 'ETH/BTC') - stoploss_order_mock.assert_called_once_with(amount=85.32423208, - pair='ETH/BTC', - order_types=freqtrade.strategy.order_types, - stop_price=0.00002346 * 0.96) + stoploss_order_mock.assert_called_once_with( + amount=100.0, + pair='ETH/BTC', + order_types=freqtrade.strategy.order_types, + stop_price=4.4 * 0.96 + ) # price fell below stoploss, so dry-run sells trade. - mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ - 'bid': 0.00002144, - 'ask': 0.00002146, - 'last': 0.00002144 - })) + mocker.patch( + 'freqtrade.exchange.Exchange.fetch_ticker', + MagicMock(return_value={ + 'bid': 4.1712, + 'ask': 4.1921, + 'last': 4.1712 + }) + ) assert freqtrade.handle_trade(trade) is True @@ -3192,9 +3203,9 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order_usdt, limit_buy_ mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.0000172, - 'ask': 0.0000173, - 'last': 0.0000172 + 'bid': 2.19, + 'ask': 2.2, + 'last': 2.19 }), create_order=MagicMock(side_effect=[ limit_buy_order_usdt_open, @@ -3259,7 +3270,7 @@ def test_trailing_stop_loss(default_conf, limit_buy_order_usdt_open, limit_buy_o # Stoploss should be adjusted assert freqtrade.handle_trade(trade) is False - + caplog.clear() # Price fell mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ @@ -3271,22 +3282,28 @@ def test_trailing_stop_loss(default_conf, limit_buy_order_usdt_open, limit_buy_o caplog.set_level(logging.DEBUG) # Sell as trailing-stop is reached assert freqtrade.handle_trade(trade) is True - 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) + # TODO: Does this make sense? How is stoploss 2.7? + assert log_has("ETH/BTC - HIT STOP: current price at 2.200000, stoploss is 2.700000, " + "initial stoploss was at 1.800000, trade opened at 2.000000", caplog) assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value -def test_trailing_stop_loss_positive(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, - caplog, mocker) -> None: +@pytest.mark.parametrize('offset,trail_if_reached,second_sl', [ + (0, False, 2.0394), + (0.011, False, 2.0394), + (0.055, True, 1.8), +]) +def test_trailing_stop_loss_positive(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, + offset, fee, caplog, mocker, trail_if_reached, second_sl) -> None: buy_price = limit_buy_order_usdt['price'] patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': buy_price - 0.000001, - 'ask': buy_price - 0.000001, - 'last': buy_price - 0.000001 + 'bid': buy_price - 0.01, + 'ask': buy_price - 0.01, + 'last': buy_price - 0.01 }), create_order=MagicMock(side_effect=[ limit_buy_order_usdt_open, @@ -3296,6 +3313,9 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order_usdt, limit_b ) default_conf['trailing_stop'] = True default_conf['trailing_stop_positive'] = 0.01 + if offset: + default_conf['trailing_stop_positive_offset'] = offset + default_conf['trailing_only_offset_is_reached'] = trail_if_reached patch_whitelist(mocker, default_conf) freqtrade = FreqtradeBot(default_conf) @@ -3310,159 +3330,59 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order_usdt, limit_b assert freqtrade.handle_trade(trade) is False # Raise ticker above buy price - mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', - MagicMock(return_value={ - 'bid': buy_price + 0.000003, - 'ask': buy_price + 0.000003, - 'last': buy_price + 0.000003 - })) - # stop-loss not reached, adjusted stoploss - assert freqtrade.handle_trade(trade) is False - 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={ - 'bid': buy_price + 0.000002, - 'ask': buy_price + 0.000002, - 'last': buy_price + 0.000002 - })) - # Lower price again (but still positive) - assert freqtrade.handle_trade(trade) is True - assert log_has( - 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) - - -def test_trailing_stop_loss_offset(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, - caplog, mocker) -> None: - buy_price = limit_buy_order_usdt['price'] - patch_RPCManager(mocker) - patch_exchange(mocker) - mocker.patch.multiple( - 'freqtrade.exchange.Exchange', - fetch_ticker=MagicMock(return_value={ - 'bid': buy_price - 0.000001, - 'ask': buy_price - 0.000001, - 'last': buy_price - 0.000001 - }), - create_order=MagicMock(side_effect=[ - limit_buy_order_usdt_open, - {'id': 1234553382}, - ]), - get_fee=fee, + mocker.patch( + 'freqtrade.exchange.Exchange.fetch_ticker', + MagicMock(return_value={ + 'bid': buy_price + 0.06, + 'ask': buy_price + 0.06, + 'last': buy_price + 0.06 + }) ) - patch_whitelist(mocker, default_conf) - default_conf['trailing_stop'] = True - default_conf['trailing_stop_positive'] = 0.01 - default_conf['trailing_stop_positive_offset'] = 0.011 - freqtrade = FreqtradeBot(default_conf) - patch_get_signal(freqtrade) - freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.enter_positions() - - trade = Trade.query.first() - trade.update(limit_buy_order_usdt) - caplog.set_level(logging.DEBUG) - # stop-loss not reached - assert freqtrade.handle_trade(trade) is False - - # Raise ticker above buy price - mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', - MagicMock(return_value={ - 'bid': buy_price + 0.000003, - 'ask': buy_price + 0.000003, - 'last': buy_price + 0.000003 - })) # stop-loss not reached, adjusted stoploss assert freqtrade.handle_trade(trade) is False - 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 + # TODO: is 0.0249% correct? Shouldn't it be higher? + caplog_text = f"ETH/BTC - Using positive stoploss: 0.01 offset: {offset} profit: 0.0249%" + if trail_if_reached: + assert not log_has(caplog_text, caplog) + assert not log_has("ETH/BTC - Adjusting stoploss...", caplog) + else: + assert log_has(caplog_text, caplog) + assert log_has("ETH/BTC - Adjusting stoploss...", caplog) + assert trade.stop_loss == second_sl caplog.clear() - mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', - MagicMock(return_value={ - 'bid': buy_price + 0.000002, - 'ask': buy_price + 0.000002, - 'last': buy_price + 0.000002 - })) + mocker.patch( + 'freqtrade.exchange.Exchange.fetch_ticker', + MagicMock(return_value={ + 'bid': buy_price + 0.125, + 'ask': buy_price + 0.125, + 'last': buy_price + 0.125, + }) + ) + assert freqtrade.handle_trade(trade) is False + assert log_has( + f"ETH/BTC - Using positive stoploss: 0.01 offset: {offset} profit: 0.0572%", + caplog + ) + assert log_has("ETH/BTC - Adjusting stoploss...", caplog) + + mocker.patch( + 'freqtrade.exchange.Exchange.fetch_ticker', + MagicMock(return_value={ + 'bid': buy_price + 0.02, + 'ask': buy_price + 0.02, + 'last': buy_price + 0.02 + }) + ) # Lower price again (but still positive) assert freqtrade.handle_trade(trade) is True assert log_has( - f"ETH/BTC - HIT STOP: current price at {buy_price + 0.000002:.6f}, " + f"ETH/BTC - HIT STOP: current price at {buy_price + 0.02:.6f}, " f"stoploss is {trade.stop_loss:.6f}, " - f"initial stoploss was at 0.000010, trade opened at 0.000011", caplog) + f"initial stoploss was at 1.800000, trade opened at 2.000000", caplog) assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value -def test_tsl_only_offset_reached(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, - caplog, mocker) -> None: - buy_price = limit_buy_order_usdt['price'] - # buy_price: 2.0 - - patch_RPCManager(mocker) - patch_exchange(mocker) - mocker.patch.multiple( - 'freqtrade.exchange.Exchange', - fetch_ticker=MagicMock(return_value={ - 'bid': buy_price, - 'ask': buy_price, - 'last': buy_price - }), - create_order=MagicMock(return_value=limit_buy_order_usdt_open), - get_fee=fee, - ) - patch_whitelist(mocker, default_conf) - default_conf['trailing_stop'] = True - default_conf['trailing_stop_positive'] = 0.05 - default_conf['trailing_stop_positive_offset'] = 0.055 - default_conf['trailing_only_offset_is_reached'] = True - - freqtrade = FreqtradeBot(default_conf) - patch_get_signal(freqtrade) - freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.enter_positions() - - trade = Trade.query.first() - trade.update(limit_buy_order_usdt) - caplog.set_level(logging.DEBUG) - # stop-loss not reached - assert freqtrade.handle_trade(trade) is False - assert trade.stop_loss == 1.8 - - # Raise ticker above buy price - mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', - MagicMock(return_value={ - 'bid': buy_price + 0.0000004, - 'ask': buy_price + 0.0000004, - 'last': buy_price + 0.0000004 - })) - - # stop-loss should not be adjusted as offset is not reached yet - assert freqtrade.handle_trade(trade) is False - - assert not log_has("ETH/BTC - Adjusting stoploss...", caplog) - assert trade.stop_loss == 1.8 - caplog.clear() - - # price rises above the offset (rises 12% when the offset is 5.5%) - mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', - MagicMock(return_value={ - 'bid': buy_price + 0.0000014, - 'ask': buy_price + 0.0000014, - 'last': buy_price + 0.0000014 - })) - - assert freqtrade.handle_trade(trade) is False - 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 - - def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, mocker) -> None: patch_RPCManager(mocker) From d1e3d480751e53a240a3c137770fd18f60a67607 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sun, 26 Sep 2021 02:43:47 -0600 Subject: [PATCH 49/76] changed test_update_trade_state_withorderdict to usdt --- tests/conftest.py | 49 ++++++++++++++++++++++---------------- tests/test_freqtradebot.py | 8 +++++-- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index adb344ffc..09725213f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1598,27 +1598,34 @@ def result(testdatadir): @pytest.fixture(scope="function") def trades_for_order(): - return [{'info': {'id': 34567, - 'orderId': 123456, - 'price': '0.24544100', - 'qty': '8.00000000', - 'commission': '0.00800000', - 'commissionAsset': 'LTC', - 'time': 1521663363189, - 'isBuyer': True, - 'isMaker': False, - 'isBestMatch': True}, - 'timestamp': 1521663363189, - 'datetime': '2018-03-21T20:16:03.189Z', - 'symbol': 'LTC/ETH', - 'id': '34567', - 'order': '123456', - 'type': None, - 'side': 'buy', - 'price': 0.245441, - 'cost': 1.963528, - 'amount': 8.0, - 'fee': {'cost': 0.008, 'currency': 'LTC'}}] + return [{ + 'info': { + 'id': 34567, + 'orderId': 123456, + 'price': '0.24544100', + 'qty': '8.00000000', + 'commission': '0.00800000', + 'commissionAsset': 'LTC', + 'time': 1521663363189, + 'isBuyer': True, + 'isMaker': False, + 'isBestMatch': True + }, + 'timestamp': 1521663363189, + 'datetime': '2018-03-21T20:16:03.189Z', + 'symbol': 'LTC/USDT', + 'id': '34567', + 'order': '123456', + 'type': None, + 'side': 'buy', + 'price': 2.0, + 'cost': 16.0, + 'amount': 8.0, + 'fee': { + 'cost': 0.008, + 'currency': 'LTC' + } + }] @pytest.fixture(scope="function") diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index c030aca0f..dc5688122 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1207,6 +1207,7 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, patch_get_signal(freqtrade) freqtrade.enter_positions() + # TODO-lev: Get this trade switched to the usdt trades trade = Trade.query.first() trade.is_open = True trade.open_order_id = None @@ -1709,17 +1710,20 @@ def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_ patch_exchange(mocker) amount = sum(x['amount'] for x in trades_for_order) freqtrade = get_patched_freqtradebot(mocker, default_conf) + caplog.clear() trade = Trade( - pair='LTC/ETH', + pair='LTC/USDT', amount=amount, exchange='binance', - open_rate=0.245441, + open_rate=2.0, open_date=arrow.utcnow().datetime, fee_open=fee.return_value, fee_close=fee.return_value, open_order_id="123456", is_open=True, ) + # TODO-lev: caplog.text has Amount 60.00000000000001 does not match amount 60.00000000000001 + # TODO-lev: but they are the exact same freqtrade.update_trade_state(trade, '123456', limit_buy_order_usdt) assert trade.amount != amount assert trade.amount == limit_buy_order_usdt['amount'] From 6fdcf8cd73151291910f3ac87af80c4d743fa0cd Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sun, 26 Sep 2021 10:09:10 -0600 Subject: [PATCH 50/76] created default_conf_usdt and init_persistence_usdt so that these tests pass: test_handle_stoploss_on_exchange_trailing, test_handle_stoploss_on_exchange_custom_stop, test_update_trade_state_withorderdict --- tests/conftest.py | 33 ++++++++++++++++++++-- tests/test_freqtradebot.py | 56 ++++++++++++++++++-------------------- 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 09725213f..c4ed05254 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -289,11 +289,21 @@ def init_persistence(default_conf): init_db(default_conf['db_url'], default_conf['dry_run']) +@pytest.fixture(scope='function') +def init_persistence_usdt(default_conf_usdt): + init_db(default_conf_usdt['db_url'], default_conf_usdt['dry_run']) + + @pytest.fixture(scope="function") def default_conf(testdatadir): return get_default_conf(testdatadir) +@pytest.fixture(scope="function") +def default_conf_usdt(testdatadir): + return get_default_conf_usdt(testdatadir) + + def get_default_conf(testdatadir): """ Returns validated configuration suitable for most tests """ configuration = { @@ -368,6 +378,15 @@ def get_default_conf(testdatadir): return configuration +def get_default_conf_usdt(testdatadir): + configuration = get_default_conf(testdatadir) + configuration.update({ + "stake_amount": 60.0, + "stake_currency": "USDT", + }) + return configuration + + @pytest.fixture def update(): _update = Update(0) @@ -1602,7 +1621,7 @@ def trades_for_order(): 'info': { 'id': 34567, 'orderId': 123456, - 'price': '0.24544100', + 'price': '2.0', 'qty': '8.00000000', 'commission': '0.00800000', 'commissionAsset': 'LTC', @@ -1811,6 +1830,14 @@ def edge_conf(default_conf): return conf +@pytest.fixture(scope="function") +def edge_conf_usdt(edge_conf): + edge_conf.update({ + "stake_currency": "USDT", + }) + return edge_conf + + @pytest.fixture def rpc_balance(): return { @@ -2049,7 +2076,7 @@ def saved_hyperopt_results(): @pytest.fixture(scope='function') def limit_buy_order_usdt_open(): return { - 'id': 'mocked_limit_buy', + 'id': 'mocked_limit_buy_usdt', 'type': 'limit', 'side': 'buy', 'symbol': 'mocked', @@ -2076,7 +2103,7 @@ def limit_buy_order_usdt(limit_buy_order_usdt_open): @pytest.fixture def limit_sell_order_usdt_open(): return { - 'id': 'mocked_limit_sell', + 'id': 'mocked_limit_sell_usdt', 'type': 'limit', 'side': 'sell', 'pair': 'mocked', diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index dc5688122..24ed3d509 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1162,8 +1162,8 @@ def test_create_stoploss_order_insufficient_funds(mocker, default_conf, caplog, assert mock_insuf.call_count == 1 -@pytest.mark.usefixtures("init_persistence") -def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, +@pytest.mark.usefixtures("init_persistence_usdt") +def test_handle_stoploss_on_exchange_trailing(mocker, default_conf_usdt, fee, limit_buy_order_usdt, limit_sell_order_usdt) -> None: # When trailing stoploss is set stoploss = MagicMock(return_value={'id': 13434334}) @@ -1188,12 +1188,12 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, ) # enabling TSL - default_conf['trailing_stop'] = True + default_conf_usdt['trailing_stop'] = True # disabling ROI - default_conf['minimal_roi']['0'] = 999999999 + default_conf_usdt['minimal_roi']['0'] = 999999999 - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) # enabling stoploss on exchange freqtrade.strategy.order_types['stoploss_on_exchange'] = True @@ -1207,7 +1207,6 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, patch_get_signal(freqtrade) freqtrade.enter_positions() - # TODO-lev: Get this trade switched to the usdt trades trade = Trade.query.first() trade.is_open = True trade.open_order_id = None @@ -1261,7 +1260,7 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, cancel_order_mock.assert_called_once_with(100, 'ETH/BTC') stoploss_order_mock.assert_called_once_with( - amount=30.0, + amount=27.39726027, pair='ETH/BTC', order_types=freqtrade.strategy.order_types, stop_price=4.4 * 0.95 @@ -1271,9 +1270,9 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, mocker.patch( 'freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ - 'bid': 4.1712, - 'ask': 4.1921, - 'last': 4.1712 + 'bid': 4.16, + 'ask': 4.17, + 'last': 4.16 }) ) assert freqtrade.handle_trade(trade) is True @@ -1354,9 +1353,9 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c assert log_has_re(r"Could not create trailing stoploss order for pair ETH/BTC\..*", caplog) -@pytest.mark.usefixtures("init_persistence") -def test_handle_stoploss_on_exchange_custom_stop(mocker, default_conf, fee, - limit_buy_order_usdt, limit_sell_order_usdt) -> None: +@pytest.mark.usefixtures("init_persistence_usdt") +def test_handle_stoploss_on_exchange_custom_stop( + mocker, default_conf_usdt, fee, limit_buy_order_usdt, limit_sell_order_usdt) -> None: # When trailing stoploss is set stoploss = MagicMock(return_value={'id': 13434334}) patch_RPCManager(mocker) @@ -1380,12 +1379,12 @@ def test_handle_stoploss_on_exchange_custom_stop(mocker, default_conf, fee, ) # enabling TSL - default_conf['use_custom_stoploss'] = True + default_conf_usdt['use_custom_stoploss'] = True # disabling ROI - default_conf['minimal_roi']['0'] = 999999999 + default_conf_usdt['minimal_roi']['0'] = 999999999 - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) # enabling stoploss on exchange freqtrade.strategy.order_types['stoploss_on_exchange'] = True @@ -1452,7 +1451,7 @@ def test_handle_stoploss_on_exchange_custom_stop(mocker, default_conf, fee, cancel_order_mock.assert_called_once_with(100, 'ETH/BTC') stoploss_order_mock.assert_called_once_with( - amount=100.0, + amount=31.57894736, pair='ETH/BTC', order_types=freqtrade.strategy.order_types, stop_price=4.4 * 0.96 @@ -1462,9 +1461,9 @@ def test_handle_stoploss_on_exchange_custom_stop(mocker, default_conf, fee, mocker.patch( 'freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ - 'bid': 4.1712, - 'ask': 4.1921, - 'last': 4.1712 + 'bid': 4.17, + 'ask': 4.19, + 'last': 4.17 }) ) assert freqtrade.handle_trade(trade) is True @@ -1554,7 +1553,6 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, 'ask': 2.2 * 0.95, 'last': 1.9 * 0.95 })) - assert freqtrade.handle_trade(trade) is False assert freqtrade.handle_stoploss_on_exchange(trade) is False @@ -1566,21 +1564,21 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, # price jumped 2x mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ - 'bid': 0.00002344, - 'ask': 0.00002346, - 'last': 0.00002344 + 'bid': 4.38, + 'ask': 4.4, + 'last': 4.38 })) assert freqtrade.handle_trade(trade) is False assert freqtrade.handle_stoploss_on_exchange(trade) is False # stoploss should be set to 1% as trailing is on - assert trade.stop_loss == 0.00002346 * 0.99 + assert trade.stop_loss == 4.4 * 0.99 cancel_order_mock.assert_called_once_with(100, 'NEO/BTC') stoploss_order_mock.assert_called_once_with(amount=2132892.49146757, pair='NEO/BTC', order_types=freqtrade.strategy.order_types, - stop_price=0.00002346 * 0.99) + stop_price=4.4 * 0.99) @pytest.mark.parametrize('return_value,side_effect,log_message', [ @@ -1701,7 +1699,7 @@ def test_update_trade_state(mocker, default_conf, limit_buy_order_usdt, caplog) (30.0 + 1e-14, True), (8.0, False) ]) -def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_buy_order_usdt, fee, +def test_update_trade_state_withorderdict(default_conf_usdt, trades_for_order, limit_buy_order_usdt, fee, mocker, initial_amount, has_rounding_fee, caplog): trades_for_order[0]['amount'] = initial_amount mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) @@ -1709,7 +1707,7 @@ def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_ mocker.patch('freqtrade.exchange.Exchange.fetch_order', MagicMock(side_effect=ValueError)) patch_exchange(mocker) amount = sum(x['amount'] for x in trades_for_order) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) caplog.clear() trade = Trade( pair='LTC/USDT', @@ -1722,8 +1720,6 @@ def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_ open_order_id="123456", is_open=True, ) - # TODO-lev: caplog.text has Amount 60.00000000000001 does not match amount 60.00000000000001 - # TODO-lev: but they are the exact same freqtrade.update_trade_state(trade, '123456', limit_buy_order_usdt) assert trade.amount != amount assert trade.amount == limit_buy_order_usdt['amount'] From ffa9a3ac7d057a56c1b47ec0380bfd5a230011ec Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sun, 26 Sep 2021 10:18:22 -0600 Subject: [PATCH 51/76] changed default_conf_usdt stake_amount to 10 --- tests/conftest.py | 2 +- tests/test_freqtradebot.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index c4ed05254..13628a66d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -381,7 +381,7 @@ def get_default_conf(testdatadir): def get_default_conf_usdt(testdatadir): configuration = get_default_conf(testdatadir) configuration.update({ - "stake_amount": 60.0, + "stake_amount": 10.0, "stake_currency": "USDT", }) return configuration diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 24ed3d509..282fd68ea 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1260,7 +1260,7 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf_usdt, fee, cancel_order_mock.assert_called_once_with(100, 'ETH/BTC') stoploss_order_mock.assert_called_once_with( - amount=27.39726027, + amount=4.56621004, pair='ETH/BTC', order_types=freqtrade.strategy.order_types, stop_price=4.4 * 0.95 @@ -1451,7 +1451,7 @@ def test_handle_stoploss_on_exchange_custom_stop( cancel_order_mock.assert_called_once_with(100, 'ETH/BTC') stoploss_order_mock.assert_called_once_with( - amount=31.57894736, + amount=5.26315789, pair='ETH/BTC', order_types=freqtrade.strategy.order_types, stop_price=4.4 * 0.96 From 5ce09c751935f5436732c8e05dd209a42bd95976 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sun, 26 Sep 2021 10:25:26 -0600 Subject: [PATCH 52/76] updated test_reupdate_enter_order_fees to usdt --- tests/test_freqtradebot.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 282fd68ea..2d0e0a776 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -4043,9 +4043,9 @@ def test_update_closed_trades_without_assigned_fees(mocker, default_conf, fee): assert trade.fee_close_currency is not None -@pytest.mark.usefixtures("init_persistence") -def test_reupdate_enter_order_fees(mocker, default_conf, fee, caplog): - freqtrade = get_patched_freqtradebot(mocker, default_conf) +@pytest.mark.usefixtures("init_persistence_usdt") +def test_reupdate_enter_order_fees(mocker, default_conf_usdt, fee, caplog): + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mock_uts = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.update_trade_state') create_mock_trades(fee) @@ -4063,13 +4063,13 @@ def test_reupdate_enter_order_fees(mocker, default_conf, fee, caplog): # Test with trade without orders trade = Trade( pair='XRP/ETH', - stake_amount=0.001, + stake_amount=60.0, fee_open=fee.return_value, fee_close=fee.return_value, open_date=arrow.utcnow().datetime, is_open=True, - amount=20, - open_rate=0.01, + amount=30, + open_rate=2.0, exchange='binance', ) Trade.query.session.add(trade) From d0e0d0ee01cc0d4f008f598c2bdd477a15b40d9d Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sun, 26 Sep 2021 11:56:44 -0600 Subject: [PATCH 53/76] Removed init_persistence_usdt --- tests/conftest.py | 5 ----- tests/test_freqtradebot.py | 6 +++--- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 13628a66d..3e88c88aa 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -289,11 +289,6 @@ def init_persistence(default_conf): init_db(default_conf['db_url'], default_conf['dry_run']) -@pytest.fixture(scope='function') -def init_persistence_usdt(default_conf_usdt): - init_db(default_conf_usdt['db_url'], default_conf_usdt['dry_run']) - - @pytest.fixture(scope="function") def default_conf(testdatadir): return get_default_conf(testdatadir) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 2d0e0a776..a000829dd 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1162,7 +1162,7 @@ def test_create_stoploss_order_insufficient_funds(mocker, default_conf, caplog, assert mock_insuf.call_count == 1 -@pytest.mark.usefixtures("init_persistence_usdt") +@pytest.mark.usefixtures("init_persistence") def test_handle_stoploss_on_exchange_trailing(mocker, default_conf_usdt, fee, limit_buy_order_usdt, limit_sell_order_usdt) -> None: # When trailing stoploss is set @@ -1353,7 +1353,7 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c assert log_has_re(r"Could not create trailing stoploss order for pair ETH/BTC\..*", caplog) -@pytest.mark.usefixtures("init_persistence_usdt") +@pytest.mark.usefixtures("init_persistence") def test_handle_stoploss_on_exchange_custom_stop( mocker, default_conf_usdt, fee, limit_buy_order_usdt, limit_sell_order_usdt) -> None: # When trailing stoploss is set @@ -4043,7 +4043,7 @@ def test_update_closed_trades_without_assigned_fees(mocker, default_conf, fee): assert trade.fee_close_currency is not None -@pytest.mark.usefixtures("init_persistence_usdt") +@pytest.mark.usefixtures("init_persistence") def test_reupdate_enter_order_fees(mocker, default_conf_usdt, fee, caplog): freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mock_uts = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.update_trade_state') From 26fdad84685de96cb7f3eb9b7986317f3b8b990a Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sun, 26 Sep 2021 11:58:55 -0600 Subject: [PATCH 54/76] Removed edge_conf_usdt --- tests/conftest.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 3e88c88aa..898dcfbfd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1825,14 +1825,6 @@ def edge_conf(default_conf): return conf -@pytest.fixture(scope="function") -def edge_conf_usdt(edge_conf): - edge_conf.update({ - "stake_currency": "USDT", - }) - return edge_conf - - @pytest.fixture def rpc_balance(): return { From 755cc9cda1d5d75a6487b19a0daf289c2a0902b7 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sun, 26 Sep 2021 12:39:30 -0600 Subject: [PATCH 55/76] Updated test_check_available_stake_amount to use default_conf_usdt --- tests/test_freqtradebot.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index a000829dd..d8cc2214a 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -126,16 +126,16 @@ def test_get_trade_stake_amount(default_conf, ticker, mocker) -> None: @pytest.mark.parametrize("amend_last,wallet,max_open,lsamr,expected", [ - (False, 0.002, 2, 0.5, [0.001, None]), - (True, 0.002, 2, 0.5, [0.001, 0.00098]), - (False, 0.003, 3, 0.5, [0.001, 0.001, None]), - (True, 0.003, 3, 0.5, [0.001, 0.001, 0.00097]), - (False, 0.0022, 3, 0.5, [0.001, 0.001, None]), - (True, 0.0022, 3, 0.5, [0.001, 0.001, 0.0]), - (True, 0.0027, 3, 0.5, [0.001, 0.001, 0.000673]), - (True, 0.0022, 3, 1, [0.001, 0.001, 0.0]), + (False, 20, 2, 0.5, [10, None]), + (True, 20, 2, 0.5, [10, 9.8]), + (False, 30, 3, 0.5, [10, 10, None]), + (True, 30, 3, 0.5, [10, 10, 9.7]), + (False, 22, 3, 0.5, [10, 10, None]), + (True, 22, 3, 0.5, [10, 10, 0.0]), + (True, 27, 3, 0.5, [10, 10, 6.73]), + (True, 22, 3, 1, [10, 10, 0.0]), ]) -def test_check_available_stake_amount(default_conf, ticker, mocker, fee, limit_buy_order_usdt_open, +def test_check_available_stake_amount(default_conf_usdt, ticker, mocker, fee, limit_buy_order_usdt_open, amend_last, wallet, max_open, lsamr, expected) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -145,12 +145,12 @@ def test_check_available_stake_amount(default_conf, ticker, mocker, fee, limit_b create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee ) - default_conf['dry_run_wallet'] = wallet + default_conf_usdt['dry_run_wallet'] = wallet - default_conf['amend_last_stake_amount'] = amend_last - default_conf['last_stake_amount_min_ratio'] = lsamr + default_conf_usdt['amend_last_stake_amount'] = amend_last + default_conf_usdt['last_stake_amount_min_ratio'] = lsamr - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) for i in range(0, max_open): From 7eebb6bb2d305ab24f08d1e640efcc88913152c0 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sun, 26 Sep 2021 12:41:09 -0600 Subject: [PATCH 56/76] updated test_create_trade to use default_conf_usdt --- tests/test_freqtradebot.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index d8cc2214a..280d2ce97 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -270,7 +270,7 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker, fee) -> None: assert Trade.total_open_trades_stakes() == 1.97502e-03 -def test_create_trade(default_conf, ticker, limit_buy_order_usdt, fee, mocker) -> None: +def test_create_trade(default_conf_usdt, ticker, limit_buy_order_usdt, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -281,14 +281,14 @@ def test_create_trade(default_conf, ticker, limit_buy_order_usdt, fee, mocker) - ) # Save state of current whitelist - whitelist = deepcopy(default_conf['exchange']['pair_whitelist']) - freqtrade = FreqtradeBot(default_conf) + whitelist = deepcopy(default_conf_usdt['exchange']['pair_whitelist']) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) freqtrade.create_trade('ETH/BTC') trade = Trade.query.first() assert trade is not None - assert trade.stake_amount == 0.001 + assert trade.stake_amount == 10.0 assert trade.is_open assert trade.open_date is not None assert trade.exchange == 'binance' @@ -299,7 +299,7 @@ def test_create_trade(default_conf, ticker, limit_buy_order_usdt, fee, mocker) - assert trade.open_rate == 2.0 assert trade.amount == 30.0 - assert whitelist == default_conf['exchange']['pair_whitelist'] + assert whitelist == default_conf_usdt['exchange']['pair_whitelist'] def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order_usdt, From ba5d78f005210d51416387e65fa30c7a38623395 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sun, 26 Sep 2021 13:04:58 -0600 Subject: [PATCH 57/76] swapped default_conf for default_conf_usdt and ticker for ticker_usdt --- tests/conftest.py | 22 +- tests/test_freqtradebot.py | 788 ++++++++++++++++++------------------- 2 files changed, 413 insertions(+), 397 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 898dcfbfd..f2da68dd2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -378,6 +378,22 @@ def get_default_conf_usdt(testdatadir): configuration.update({ "stake_amount": 10.0, "stake_currency": "USDT", + "exchange": { + "name": "binance", + "enabled": True, + "key": "key", + "secret": "secret", + "pair_whitelist": [ + "ETH/USDT", + "LTC/USDT", + "XRP/USDT", + "NEO/USDT" + ], + "pair_blacklist": [ + "DOGE/USDT", + "HOT/USDT", + ] + }, }) return configuration @@ -424,9 +440,9 @@ def ticker_sell_down(): @pytest.fixture def ticker_usdt(): return MagicMock(return_value={ - 'bid': 1.99, - 'ask': 2.0, - 'last': 1.99, + 'bid': 2.0, + 'ask': 2.01, + 'last': 2.0, }) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 280d2ce97..2a96783bc 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -41,33 +41,33 @@ def patch_RPCManager(mocker) -> MagicMock: # Unit tests -def test_freqtradebot_state(mocker, default_conf, markets) -> None: +def test_freqtradebot_state(mocker, default_conf_usdt, markets) -> None: mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets)) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) assert freqtrade.state is State.RUNNING - default_conf.pop('initial_state') - freqtrade = FreqtradeBot(default_conf) + default_conf_usdt.pop('initial_state') + freqtrade = FreqtradeBot(default_conf_usdt) assert freqtrade.state is State.STOPPED -def test_process_stopped(mocker, default_conf) -> None: +def test_process_stopped(mocker, default_conf_usdt) -> None: - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) coo_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.cancel_all_open_orders') freqtrade.process_stopped() assert coo_mock.call_count == 0 - default_conf['cancel_open_orders_on_exit'] = True - freqtrade = get_patched_freqtradebot(mocker, default_conf) + default_conf_usdt['cancel_open_orders_on_exit'] = True + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) freqtrade.process_stopped() assert coo_mock.call_count == 1 -def test_bot_cleanup(mocker, default_conf, caplog) -> None: +def test_bot_cleanup(mocker, default_conf_usdt, caplog) -> None: mock_cleanup = mocker.patch('freqtrade.freqtradebot.cleanup_db') coo_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.cancel_all_open_orders') - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) freqtrade.cleanup() assert log_has('Cleaning up modules ...', caplog) assert mock_cleanup.call_count == 1 @@ -82,10 +82,10 @@ def test_bot_cleanup(mocker, default_conf, caplog) -> None: RunMode.DRY_RUN, RunMode.LIVE ]) -def test_order_dict(default_conf, mocker, runmode, caplog) -> None: +def test_order_dict(default_conf_usdt, mocker, runmode, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) - conf = default_conf.copy() + conf = default_conf_usdt.copy() conf['runmode'] = runmode conf['order_types'] = { 'buy': 'market', @@ -102,7 +102,7 @@ def test_order_dict(default_conf, mocker, runmode, caplog) -> None: caplog.clear() # is left untouched - conf = default_conf.copy() + conf = default_conf_usdt.copy() conf['runmode'] = runmode conf['order_types'] = { 'buy': 'market', @@ -115,14 +115,14 @@ def test_order_dict(default_conf, mocker, runmode, caplog) -> None: assert not log_has_re(".*stoploss_on_exchange .* dry-run", caplog) -def test_get_trade_stake_amount(default_conf, ticker, mocker) -> None: +def test_get_trade_stake_amount(default_conf_usdt, ticker_usdt, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) - result = freqtrade.wallets.get_trade_stake_amount('ETH/BTC') - assert result == default_conf['stake_amount'] + result = freqtrade.wallets.get_trade_stake_amount('ETH/USDT') + assert result == default_conf_usdt['stake_amount'] @pytest.mark.parametrize("amend_last,wallet,max_open,lsamr,expected", [ @@ -135,13 +135,13 @@ def test_get_trade_stake_amount(default_conf, ticker, mocker) -> None: (True, 27, 3, 0.5, [10, 10, 6.73]), (True, 22, 3, 1, [10, 10, 0.0]), ]) -def test_check_available_stake_amount(default_conf_usdt, ticker, mocker, fee, limit_buy_order_usdt_open, +def test_check_available_stake_amount(default_conf_usdt, ticker_usdt, mocker, fee, limit_buy_order_usdt_open, amend_last, wallet, max_open, lsamr, expected) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee ) @@ -156,12 +156,12 @@ def test_check_available_stake_amount(default_conf_usdt, ticker, mocker, fee, li if expected[i] is not None: limit_buy_order_usdt_open['id'] = str(i) - result = freqtrade.wallets.get_trade_stake_amount('ETH/BTC') + result = freqtrade.wallets.get_trade_stake_amount('ETH/USDT') assert pytest.approx(result) == expected[i] - freqtrade.execute_entry('ETH/BTC', result) + freqtrade.execute_entry('ETH/USDT', result) else: with pytest.raises(DependencyException): - freqtrade.wallets.get_trade_stake_amount('ETH/BTC') + freqtrade.wallets.get_trade_stake_amount('ETH/USDT') def test_edge_called_in_process(mocker, edge_conf) -> None: @@ -169,7 +169,7 @@ def test_edge_called_in_process(mocker, edge_conf) -> None: patch_edge(mocker) def _refresh_whitelist(list): - return ['ETH/BTC', 'LTC/BTC', 'XRP/BTC', 'NEO/BTC'] + return ['ETH/USDT', 'LTC/BTC', 'XRP/BTC', 'NEO/BTC'] patch_exchange(mocker) freqtrade = FreqtradeBot(edge_conf) @@ -208,7 +208,7 @@ def test_edge_overrides_stoploss(limit_buy_order_usdt, fee, caplog, mocker, # Strategy stoploss is -0.1 but Edge imposes a stoploss at -0.2 # Thus, if price falls 21%, stoploss should be triggered # - # mocking the ticker: price is falling ... + # mocking the ticker_usdt: price is falling ... buy_price = limit_buy_order_usdt['price'] mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -238,24 +238,24 @@ def test_edge_overrides_stoploss(limit_buy_order_usdt, fee, caplog, mocker, assert trade.sell_reason == SellType.STOP_LOSS.value -def test_total_open_trades_stakes(mocker, default_conf, ticker, fee) -> None: +def test_total_open_trades_stakes(mocker, default_conf_usdt, ticker_usdt, fee) -> None: patch_RPCManager(mocker) patch_exchange(mocker) - default_conf['stake_amount'] = 0.00098751 - default_conf['max_open_trades'] = 2 + default_conf_usdt['stake_amount'] = 10.0 + default_conf_usdt['max_open_trades'] = 2 mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, get_fee=fee, _is_dry_limit_order_filled=MagicMock(return_value=False), ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) freqtrade.enter_positions() trade = Trade.query.first() assert trade is not None - assert trade.stake_amount == 0.00098751 + assert trade.stake_amount == 10.0 assert trade.is_open assert trade.open_date is not None @@ -263,19 +263,19 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker, fee) -> None: trade = Trade.query.order_by(Trade.id.desc()).first() assert trade is not None - assert trade.stake_amount == 0.00098751 + assert trade.stake_amount == 10.0 assert trade.is_open assert trade.open_date is not None - assert Trade.total_open_trades_stakes() == 1.97502e-03 + assert Trade.total_open_trades_stakes() == 20.0 -def test_create_trade(default_conf_usdt, ticker, limit_buy_order_usdt, fee, mocker) -> None: +def test_create_trade(default_conf_usdt, ticker_usdt, limit_buy_order_usdt, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, get_fee=fee, _is_dry_limit_order_filled=MagicMock(return_value=False), ) @@ -284,7 +284,7 @@ def test_create_trade(default_conf_usdt, ticker, limit_buy_order_usdt, fee, mock whitelist = deepcopy(default_conf_usdt['exchange']['pair_whitelist']) freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) - freqtrade.create_trade('ETH/BTC') + freqtrade.create_trade('ETH/USDT') trade = Trade.query.first() assert trade is not None @@ -302,21 +302,21 @@ def test_create_trade(default_conf_usdt, ticker, limit_buy_order_usdt, fee, mock assert whitelist == default_conf_usdt['exchange']['pair_whitelist'] -def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order_usdt, +def test_create_trade_no_stake_amount(default_conf_usdt, ticker_usdt, limit_buy_order_usdt, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) - patch_wallet(mocker, free=default_conf['stake_amount'] * 0.5) + patch_wallet(mocker, free=default_conf_usdt['stake_amount'] * 0.5) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, get_fee=fee, ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) with pytest.raises(DependencyException, match=r'.*stake amount.*'): - freqtrade.create_trade('ETH/BTC') + freqtrade.create_trade('ETH/USDT') @pytest.mark.parametrize('stake_amount,create,amount_enough,max_open_trades', [ @@ -326,7 +326,7 @@ def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order_usdt (UNLIMITED_STAKE_AMOUNT, False, True, 0), ]) def test_create_trade_minimal_amount( - default_conf, ticker, limit_buy_order_usdt_open, fee, mocker, + default_conf_usdt, ticker_usdt, limit_buy_order_usdt_open, fee, mocker, stake_amount, create, amount_enough, max_open_trades, caplog ) -> None: patch_RPCManager(mocker) @@ -334,47 +334,47 @@ def test_create_trade_minimal_amount( buy_mock = MagicMock(return_value=limit_buy_order_usdt_open) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=buy_mock, get_fee=fee, ) - default_conf['max_open_trades'] = max_open_trades - freqtrade = FreqtradeBot(default_conf) + default_conf_usdt['max_open_trades'] = max_open_trades + freqtrade = FreqtradeBot(default_conf_usdt) freqtrade.config['stake_amount'] = stake_amount patch_get_signal(freqtrade) if create: - assert freqtrade.create_trade('ETH/BTC') + assert freqtrade.create_trade('ETH/USDT') if amount_enough: rate, amount = buy_mock.call_args[1]['rate'], buy_mock.call_args[1]['amount'] - assert rate * amount <= default_conf['stake_amount'] + assert rate * amount <= default_conf_usdt['stake_amount'] else: assert log_has_re( r"Stake amount for pair .* is too small.*", caplog ) else: - assert not freqtrade.create_trade('ETH/BTC') + assert not freqtrade.create_trade('ETH/USDT') if not max_open_trades: - assert freqtrade.wallets.get_trade_stake_amount('ETH/BTC', freqtrade.edge) == 0 + assert freqtrade.wallets.get_trade_stake_amount('ETH/USDT', freqtrade.edge) == 0 @pytest.mark.parametrize('whitelist,positions', [ - (["ETH/BTC"], 1), # No pairs left + (["ETH/USDT"], 1), # No pairs left ([], 0), # No pairs in whitelist ]) -def test_enter_positions_no_pairs_left(default_conf, ticker, limit_buy_order_usdt_open, fee, +def test_enter_positions_no_pairs_left(default_conf_usdt, ticker_usdt, limit_buy_order_usdt_open, fee, whitelist, positions, mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) - default_conf['exchange']['pair_whitelist'] = whitelist - freqtrade = FreqtradeBot(default_conf) + default_conf_usdt['exchange']['pair_whitelist'] = whitelist + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) n = freqtrade.enter_positions() @@ -390,17 +390,17 @@ def test_enter_positions_no_pairs_left(default_conf, ticker, limit_buy_order_usd @pytest.mark.usefixtures("init_persistence") -def test_enter_positions_global_pairlock(default_conf, ticker, limit_buy_order_usdt, fee, +def test_enter_positions_global_pairlock(default_conf_usdt, ticker_usdt, limit_buy_order_usdt, fee, mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(return_value={'id': limit_buy_order_usdt['id']}), get_fee=fee, ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) n = freqtrade.enter_positions() message = r"Global pairlock active until.* Not creating new trades." @@ -416,8 +416,8 @@ def test_enter_positions_global_pairlock(default_conf, ticker, limit_buy_order_u assert log_has_re(message, caplog) -def test_handle_protections(mocker, default_conf, fee): - default_conf['protections'] = [ +def test_handle_protections(mocker, default_conf_usdt, fee): + default_conf_usdt['protections'] = [ {"method": "CooldownPeriod", "stop_duration": 60}, { "method": "StoplossGuard", @@ -428,7 +428,7 @@ def test_handle_protections(mocker, default_conf, fee): } ] - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) freqtrade.protections._protection_handlers[1].global_stop = MagicMock( return_value=(True, arrow.utcnow().shift(hours=1).datetime, "asdf")) create_mock_trades(fee) @@ -439,8 +439,8 @@ def test_handle_protections(mocker, default_conf, fee): assert send_msg_mock.call_args_list[1][0][0]['type'] == RPCMessageType.PROTECTION_TRIGGER_GLOBAL -def test_create_trade_no_signal(default_conf, fee, mocker) -> None: - default_conf['dry_run'] = True +def test_create_trade_no_signal(default_conf_usdt, fee, mocker) -> None: + default_conf_usdt['dry_run'] = True patch_RPCManager(mocker) patch_exchange(mocker) @@ -448,32 +448,32 @@ def test_create_trade_no_signal(default_conf, fee, mocker) -> None: 'freqtrade.exchange.Exchange', get_fee=fee, ) - default_conf['stake_amount'] = 10 - freqtrade = FreqtradeBot(default_conf) + default_conf_usdt['stake_amount'] = 10 + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade, value=(False, False, None)) Trade.query = MagicMock() Trade.query.filter = MagicMock() - assert not freqtrade.create_trade('ETH/BTC') + assert not freqtrade.create_trade('ETH/USDT') @pytest.mark.parametrize("max_open", range(0, 5)) @pytest.mark.parametrize("tradable_balance_ratio,modifier", [(1.0, 1), (0.99, 0.8), (0.5, 0.5)]) -def test_create_trades_multiple_trades(default_conf, ticker, fee, mocker, limit_buy_order_usdt_open, +def test_create_trades_multiple_trades(default_conf_usdt, ticker_usdt, fee, mocker, limit_buy_order_usdt_open, max_open, tradable_balance_ratio, modifier) -> None: patch_RPCManager(mocker) patch_exchange(mocker) - default_conf['max_open_trades'] = max_open - default_conf['tradable_balance_ratio'] = tradable_balance_ratio - default_conf['dry_run_wallet'] = 0.001 * max_open + default_conf_usdt['max_open_trades'] = max_open + default_conf_usdt['tradable_balance_ratio'] = tradable_balance_ratio + default_conf_usdt['dry_run_wallet'] = 10.0 * max_open mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) n = freqtrade.enter_positions() @@ -484,47 +484,47 @@ def test_create_trades_multiple_trades(default_conf, ticker, fee, mocker, limit_ assert len(trades) == max(int(max_open * modifier), 0) -def test_create_trades_preopen(default_conf, ticker, fee, mocker, limit_buy_order_usdt_open) -> None: +def test_create_trades_preopen(default_conf_usdt, ticker_usdt, fee, mocker, limit_buy_order_usdt_open) -> None: patch_RPCManager(mocker) patch_exchange(mocker) - default_conf['max_open_trades'] = 4 + default_conf_usdt['max_open_trades'] = 4 mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) # Create 2 existing trades - freqtrade.execute_entry('ETH/BTC', default_conf['stake_amount']) - freqtrade.execute_entry('NEO/BTC', default_conf['stake_amount']) + freqtrade.execute_entry('ETH/USDT', default_conf_usdt['stake_amount']) + freqtrade.execute_entry('NEO/BTC', default_conf_usdt['stake_amount']) assert len(Trade.get_open_trades()) == 2 # Change order_id for new orders limit_buy_order_usdt_open['id'] = '123444' # Create 2 new trades using create_trades - assert freqtrade.create_trade('ETH/BTC') + assert freqtrade.create_trade('ETH/USDT') assert freqtrade.create_trade('NEO/BTC') trades = Trade.get_open_trades() assert len(trades) == 4 -def test_process_trade_creation(default_conf, ticker, limit_buy_order_usdt, limit_buy_order_usdt_open, +def test_process_trade_creation(default_conf_usdt, ticker_usdt, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(return_value=limit_buy_order_usdt_open), fetch_order=MagicMock(return_value=limit_buy_order_usdt), get_fee=fee, ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) trades = Trade.query.filter(Trade.is_open.is_(True)).all() @@ -536,45 +536,45 @@ def test_process_trade_creation(default_conf, ticker, limit_buy_order_usdt, limi assert len(trades) == 1 trade = trades[0] assert trade is not None - assert trade.stake_amount == default_conf['stake_amount'] + assert trade.stake_amount == default_conf_usdt['stake_amount'] assert trade.is_open assert trade.open_date is not None assert trade.exchange == 'binance' - assert trade.open_rate == 0.00001098 - assert trade.amount == 91.07468123 + assert trade.open_rate == 2.0 + assert trade.amount == 5.0 assert log_has( - 'Buy signal found: about create a new trade for ETH/BTC with stake_amount: 0.001 ...', + 'Buy signal found: about create a new trade for ETH/USDT with stake_amount: 10.0 ...', caplog ) -def test_process_exchange_failures(default_conf, ticker, mocker) -> None: +def test_process_exchange_failures(default_conf_usdt, ticker_usdt, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(side_effect=TemporaryError) ) sleep_mock = mocker.patch('time.sleep', side_effect=lambda _: None) - worker = Worker(args=None, config=default_conf) + worker = Worker(args=None, config=default_conf_usdt) patch_get_signal(worker.freqtrade) worker._process_running() assert sleep_mock.has_calls() -def test_process_operational_exception(default_conf, ticker, mocker) -> None: +def test_process_operational_exception(default_conf_usdt, ticker_usdt, mocker) -> None: msg_mock = patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(side_effect=OperationalException) ) - worker = Worker(args=None, config=default_conf) + worker = Worker(args=None, config=default_conf_usdt) patch_get_signal(worker.freqtrade) assert worker.freqtrade.state == State.RUNNING @@ -584,17 +584,17 @@ def test_process_operational_exception(default_conf, ticker, mocker) -> None: assert 'OperationalException' in msg_mock.call_args_list[-1][0][0]['status'] -def test_process_trade_handling(default_conf, ticker, limit_buy_order_usdt_open, fee, mocker) -> None: +def test_process_trade_handling(default_conf_usdt, ticker_usdt, limit_buy_order_usdt_open, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(return_value=limit_buy_order_usdt_open), fetch_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) trades = Trade.query.filter(Trade.is_open.is_(True)).all() @@ -609,23 +609,23 @@ def test_process_trade_handling(default_conf, ticker, limit_buy_order_usdt_open, assert len(trades) == 1 -def test_process_trade_no_whitelist_pair(default_conf, ticker, limit_buy_order_usdt, +def test_process_trade_no_whitelist_pair(default_conf_usdt, ticker_usdt, limit_buy_order_usdt, fee, mocker) -> None: """ Test process with trade not in pair list """ patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(return_value={'id': limit_buy_order_usdt['id']}), fetch_order=MagicMock(return_value=limit_buy_order_usdt), get_fee=fee, ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) pair = 'BLK/BTC' # Ensure the pair is not in the whitelist! - assert pair not in default_conf['exchange']['pair_whitelist'] + assert pair not in default_conf_usdt['exchange']['pair_whitelist'] # create open trade not in whitelist Trade.query.session.add(Trade( @@ -639,7 +639,7 @@ def test_process_trade_no_whitelist_pair(default_conf, ticker, limit_buy_order_u exchange='binance', )) Trade.query.session.add(Trade( - pair='ETH/BTC', + pair='ETH/USDT', stake_amount=0.001, fee_open=fee.return_value, fee_close=fee.return_value, @@ -656,17 +656,17 @@ def test_process_trade_no_whitelist_pair(default_conf, ticker, limit_buy_order_u assert len(freqtrade.active_pair_whitelist) == len(set(freqtrade.active_pair_whitelist)) -def test_process_informative_pairs_added(default_conf, ticker, mocker) -> None: +def test_process_informative_pairs_added(default_conf_usdt, ticker_usdt, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) def _refresh_whitelist(list): - return ['ETH/BTC', 'LTC/BTC', 'XRP/BTC', 'NEO/BTC'] + return ['ETH/USDT', 'LTC/BTC', 'XRP/BTC', 'NEO/BTC'] refresh_mock = MagicMock() mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(side_effect=TemporaryError), refresh_latest_ohlcv=refresh_mock, ) @@ -677,7 +677,7 @@ def test_process_informative_pairs_added(default_conf, ticker, mocker) -> None: ) mocker.patch('time.sleep', return_value=None) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) freqtrade.pairlists._validate_whitelist = _refresh_whitelist freqtrade.strategy.informative_pairs = inf_pairs # patch_get_signal(freqtrade) @@ -687,13 +687,13 @@ def test_process_informative_pairs_added(default_conf, ticker, mocker) -> None: assert refresh_mock.call_count == 1 assert ("BTC/ETH", "1m") in refresh_mock.call_args[0][0] assert ("ETH/USDT", "1h") in refresh_mock.call_args[0][0] - assert ("ETH/BTC", default_conf["timeframe"]) in refresh_mock.call_args[0][0] + assert ("ETH/USDT", default_conf_usdt["timeframe"]) in refresh_mock.call_args[0][0] -def test_execute_entry(mocker, default_conf, fee, limit_buy_order_usdt, limit_buy_order_usdt_open) -> None: +def test_execute_entry(mocker, default_conf_usdt, fee, limit_buy_order_usdt, limit_buy_order_usdt_open) -> None: patch_RPCManager(mocker) patch_exchange(mocker) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) freqtrade.strategy.confirm_trade_entry = MagicMock(return_value=False) stake_amount = 2 bid = 0.11 @@ -711,7 +711,7 @@ def test_execute_entry(mocker, default_conf, fee, limit_buy_order_usdt, limit_bu get_min_pair_stake_amount=MagicMock(return_value=1), get_fee=fee, ) - pair = 'ETH/BTC' + pair = 'ETH/USDT' assert not freqtrade.execute_entry(pair, stake_amount) assert buy_rate_mock.call_count == 1 @@ -853,8 +853,8 @@ def test_execute_entry(mocker, default_conf, fee, limit_buy_order_usdt, limit_bu assert trade.open_rate_requested == 10 -def test_execute_entry_confirm_error(mocker, default_conf, fee, limit_buy_order_usdt) -> None: - freqtrade = get_patched_freqtradebot(mocker, default_conf) +def test_execute_entry_confirm_error(mocker, default_conf_usdt, fee, limit_buy_order_usdt) -> None: + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ @@ -868,7 +868,7 @@ def test_execute_entry_confirm_error(mocker, default_conf, fee, limit_buy_order_ get_fee=fee, ) stake_amount = 2 - pair = 'ETH/BTC' + pair = 'ETH/USDT' freqtrade.strategy.confirm_trade_entry = MagicMock(side_effect=ValueError) assert freqtrade.execute_entry(pair, stake_amount) @@ -885,7 +885,7 @@ def test_execute_entry_confirm_error(mocker, default_conf, fee, limit_buy_order_ assert not freqtrade.execute_entry(pair, stake_amount) -def test_add_stoploss_on_exchange(mocker, default_conf, limit_buy_order_usdt) -> None: +def test_add_stoploss_on_exchange(mocker, default_conf_usdt, limit_buy_order_usdt) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True)) @@ -897,7 +897,7 @@ def test_add_stoploss_on_exchange(mocker, default_conf, limit_buy_order_usdt) -> stoploss = MagicMock(return_value={'id': 13434334}) mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) freqtrade.strategy.order_types['stoploss_on_exchange'] = True trade = MagicMock() @@ -912,7 +912,7 @@ def test_add_stoploss_on_exchange(mocker, default_conf, limit_buy_order_usdt) -> assert trade.is_open is True -def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, +def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, limit_buy_order_usdt, limit_sell_order_usdt) -> None: stoploss = MagicMock(return_value={'id': 13434334}) patch_RPCManager(mocker) @@ -934,7 +934,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, 'freqtrade.exchange.Binance', stoploss=stoploss ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) # First case: when stoploss is not yet set but the order is open @@ -1032,7 +1032,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, assert stoploss.call_count == 0 -def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog, +def test_handle_sle_cancel_cant_recreate(mocker, default_conf_usdt, fee, caplog, limit_buy_order_usdt, limit_sell_order_usdt) -> None: # Sixth case: stoploss order was cancelled but couldn't create new one patch_RPCManager(mocker) @@ -1055,7 +1055,7 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog, fetch_stoploss_order=MagicMock(return_value={'status': 'canceled', 'id': 100}), stoploss=MagicMock(side_effect=ExchangeError()), ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) freqtrade.enter_positions() @@ -1071,7 +1071,7 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog, assert trade.is_open is True -def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee, +def test_create_stoploss_order_invalid_order(mocker, default_conf_usdt, caplog, fee, limit_buy_order_usdt_open, limit_sell_order_usdt): rpc_mock = patch_RPCManager(mocker) patch_exchange(mocker) @@ -1094,7 +1094,7 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee, fetch_order=MagicMock(return_value={'status': 'canceled'}), stoploss=MagicMock(side_effect=InvalidOrderException()), ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) freqtrade.strategy.order_types['stoploss_on_exchange'] = True @@ -1119,10 +1119,10 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee, assert rpc_mock.call_args_list[1][0][0]['order_type'] == 'market' -def test_create_stoploss_order_insufficient_funds(mocker, default_conf, caplog, fee, +def test_create_stoploss_order_insufficient_funds(mocker, default_conf_usdt, caplog, fee, limit_buy_order_usdt_open, limit_sell_order_usdt): sell_mock = MagicMock(return_value={'id': limit_sell_order_usdt['id']}) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mock_insuf = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_insufficient_funds') mocker.patch.multiple( @@ -1258,10 +1258,10 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf_usdt, fee, assert freqtrade.handle_stoploss_on_exchange(trade) is False - cancel_order_mock.assert_called_once_with(100, 'ETH/BTC') + cancel_order_mock.assert_called_once_with(100, 'ETH/USDT') stoploss_order_mock.assert_called_once_with( amount=4.56621004, - pair='ETH/BTC', + pair='ETH/USDT', order_types=freqtrade.strategy.order_types, stop_price=4.4 * 0.95 ) @@ -1278,7 +1278,7 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf_usdt, fee, assert freqtrade.handle_trade(trade) is True -def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, caplog, +def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf_usdt, fee, caplog, limit_buy_order_usdt, limit_sell_order_usdt) -> None: # When trailing stoploss is set stoploss = MagicMock(return_value={'id': 13434334}) @@ -1304,9 +1304,9 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c ) # enabling TSL - default_conf['trailing_stop'] = True + default_conf_usdt['trailing_stop'] = True - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) # enabling stoploss on exchange freqtrade.strategy.order_types['stoploss_on_exchange'] = True @@ -1339,7 +1339,7 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c mocker.patch('freqtrade.exchange.Binance.fetch_stoploss_order', return_value=stoploss_order_hanging) freqtrade.handle_trailing_stoploss_on_exchange(trade, stoploss_order_hanging) - assert log_has_re(r"Could not cancel stoploss order abcd for pair ETH/BTC.*", caplog) + assert log_has_re(r"Could not cancel stoploss order abcd for pair ETH/USDT.*", caplog) # Still try to create order assert stoploss.call_count == 1 @@ -1350,7 +1350,7 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c mocker.patch("freqtrade.exchange.Binance.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/BTC\..*", caplog) + assert log_has_re(r"Could not create trailing stoploss order for pair ETH/USDT\..*", caplog) @pytest.mark.usefixtures("init_persistence") @@ -1449,10 +1449,10 @@ def test_handle_stoploss_on_exchange_custom_stop( assert freqtrade.handle_stoploss_on_exchange(trade) is False - cancel_order_mock.assert_called_once_with(100, 'ETH/BTC') + cancel_order_mock.assert_called_once_with(100, 'ETH/USDT') stoploss_order_mock.assert_called_once_with( amount=5.26315789, - pair='ETH/BTC', + pair='ETH/USDT', order_types=freqtrade.strategy.order_types, stop_price=4.4 * 0.96 ) @@ -1583,12 +1583,12 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, @pytest.mark.parametrize('return_value,side_effect,log_message', [ (False, None, 'Found no buy signals for whitelisted currencies. Trying again...'), - (None, DependencyException, 'Unable to create trade for ETH/BTC: ') + (None, DependencyException, 'Unable to create trade for ETH/USDT: ') ]) -def test_enter_positions(mocker, default_conf, return_value, side_effect, +def test_enter_positions(mocker, default_conf_usdt, return_value, side_effect, log_message, caplog) -> None: caplog.set_level(logging.DEBUG) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mock_ct = mocker.patch( 'freqtrade.freqtradebot.FreqtradeBot.create_trade', @@ -1601,11 +1601,11 @@ def test_enter_positions(mocker, default_conf, return_value, side_effect, assert n == 0 assert log_has(log_message, caplog) # create_trade should be called once for every pair in the whitelist. - assert mock_ct.call_count == len(default_conf['exchange']['pair_whitelist']) + assert mock_ct.call_count == len(default_conf_usdt['exchange']['pair_whitelist']) -def test_exit_positions(mocker, default_conf, limit_buy_order_usdt, caplog) -> None: - freqtrade = get_patched_freqtradebot(mocker, default_conf) +def test_exit_positions(mocker, default_conf_usdt, limit_buy_order_usdt, caplog) -> None: + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True)) mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order_usdt) @@ -1630,14 +1630,14 @@ def test_exit_positions(mocker, default_conf, limit_buy_order_usdt, caplog) -> N assert n == 0 -def test_exit_positions_exception(mocker, default_conf, limit_buy_order_usdt, caplog) -> None: - freqtrade = get_patched_freqtradebot(mocker, default_conf) +def test_exit_positions_exception(mocker, default_conf_usdt, limit_buy_order_usdt, caplog) -> None: + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order_usdt) trade = MagicMock() trade.open_order_id = None trade.open_fee = 0.001 - trade.pair = 'ETH/BTC' + trade.pair = 'ETH/USDT' trades = [trade] # Test raise of DependencyException exception @@ -1647,11 +1647,11 @@ def test_exit_positions_exception(mocker, default_conf, limit_buy_order_usdt, ca ) n = freqtrade.exit_positions(trades) assert n == 0 - assert log_has('Unable to sell trade ETH/BTC: ', caplog) + assert log_has('Unable to sell trade ETH/USDT: ', caplog) -def test_update_trade_state(mocker, default_conf, limit_buy_order_usdt, caplog) -> None: - freqtrade = get_patched_freqtradebot(mocker, default_conf) +def test_update_trade_state(mocker, default_conf_usdt, limit_buy_order_usdt, caplog) -> None: + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True)) mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order_usdt) @@ -1727,9 +1727,9 @@ def test_update_trade_state_withorderdict(default_conf_usdt, trades_for_order, l assert log_has_re(r'Applying fee on amount for .*', caplog) -def test_update_trade_state_exception(mocker, default_conf, +def test_update_trade_state_exception(mocker, default_conf_usdt, limit_buy_order_usdt, caplog) -> None: - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order_usdt) trade = MagicMock() @@ -1745,8 +1745,8 @@ def test_update_trade_state_exception(mocker, default_conf, assert log_has('Could not update trade amount: ', caplog) -def test_update_trade_state_orderexception(mocker, default_conf, caplog) -> None: - freqtrade = get_patched_freqtradebot(mocker, default_conf) +def test_update_trade_state_orderexception(mocker, default_conf_usdt, caplog) -> None: + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mocker.patch('freqtrade.exchange.Exchange.fetch_order', MagicMock(side_effect=InvalidOrderException)) @@ -1761,7 +1761,7 @@ def test_update_trade_state_orderexception(mocker, default_conf, caplog) -> None assert log_has(f'Unable to fetch order {trade.open_order_id}: ', caplog) -def test_update_trade_state_sell(default_conf, trades_for_order, limit_sell_order_usdt_open, +def test_update_trade_state_sell(default_conf_usdt, trades_for_order, limit_sell_order_usdt_open, limit_sell_order_usdt, mocker): mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) # fetch_order should not be called!! @@ -1771,7 +1771,7 @@ def test_update_trade_state_sell(default_conf, trades_for_order, limit_sell_orde patch_exchange(mocker) amount = limit_sell_order_usdt["amount"] - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) wallet_mock.reset_mock() trade = Trade( pair='LTC/ETH', @@ -1796,7 +1796,7 @@ def test_update_trade_state_sell(default_conf, trades_for_order, limit_sell_orde assert order.status == 'closed' -def test_handle_trade(default_conf, limit_buy_order_usdt, limit_sell_order_usdt_open, limit_sell_order_usdt, +def test_handle_trade(default_conf_usdt, limit_buy_order_usdt, limit_sell_order_usdt_open, limit_sell_order_usdt, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -1813,7 +1813,7 @@ def test_handle_trade(default_conf, limit_buy_order_usdt, limit_sell_order_usdt_ ]), get_fee=fee, ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) freqtrade.enter_positions() @@ -1839,13 +1839,13 @@ def test_handle_trade(default_conf, limit_buy_order_usdt, limit_sell_order_usdt_ assert trade.close_date is not None -def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_usdt_open, +def test_handle_overlapping_signals(default_conf_usdt, ticker_usdt, limit_buy_order_usdt_open, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(side_effect=[ limit_buy_order_usdt_open, {'id': 1234553382}, @@ -1853,7 +1853,7 @@ def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_usdt_o get_fee=fee, ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade, value=(True, True, None)) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) @@ -1894,14 +1894,14 @@ def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_usdt_o assert freqtrade.handle_trade(trades[0]) is True -def test_handle_trade_roi(default_conf, ticker, limit_buy_order_usdt_open, +def test_handle_trade_roi(default_conf_usdt, ticker_usdt, limit_buy_order_usdt_open, fee, mocker, caplog) -> None: caplog.set_level(logging.DEBUG) patch_RPCManager(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(side_effect=[ limit_buy_order_usdt_open, {'id': 1234553382}, @@ -1909,7 +1909,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order_usdt_open, get_fee=fee, ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=True) @@ -1925,18 +1925,18 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order_usdt_open, # if ROI is reached we must sell patch_get_signal(freqtrade, value=(False, True, None)) assert freqtrade.handle_trade(trade) - assert log_has("ETH/BTC - Required profit reached. sell_type=SellType.ROI", + assert log_has("ETH/USDT - Required profit reached. sell_type=SellType.ROI", caplog) -def test_handle_trade_use_sell_signal(default_conf, ticker, limit_buy_order_usdt_open, +def test_handle_trade_use_sell_signal(default_conf_usdt, ticker_usdt, limit_buy_order_usdt_open, limit_sell_order_usdt_open, fee, mocker, caplog) -> None: # use_sell_signal is True buy default caplog.set_level(logging.DEBUG) patch_RPCManager(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(side_effect=[ limit_buy_order_usdt_open, limit_sell_order_usdt_open, @@ -1944,7 +1944,7 @@ def test_handle_trade_use_sell_signal(default_conf, ticker, limit_buy_order_usdt get_fee=fee, ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) freqtrade.enter_positions() @@ -1957,21 +1957,21 @@ def test_handle_trade_use_sell_signal(default_conf, ticker, limit_buy_order_usdt patch_get_signal(freqtrade, value=(False, True, None)) assert freqtrade.handle_trade(trade) - assert log_has("ETH/BTC - Sell signal received. sell_type=SellType.SELL_SIGNAL", + assert log_has("ETH/USDT - Sell signal received. sell_type=SellType.SELL_SIGNAL", caplog) -def test_close_trade(default_conf, ticker, limit_buy_order_usdt, limit_buy_order_usdt_open, limit_sell_order_usdt, +def test_close_trade(default_conf_usdt, ticker_usdt, limit_buy_order_usdt, limit_buy_order_usdt_open, limit_sell_order_usdt, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) # Create trade and sell it @@ -1988,8 +1988,8 @@ def test_close_trade(default_conf, ticker, limit_buy_order_usdt, limit_buy_order freqtrade.handle_trade(trade) -def test_bot_loop_start_called_once(mocker, default_conf, caplog): - ftbot = get_patched_freqtradebot(mocker, default_conf) +def test_bot_loop_start_called_once(mocker, default_conf_usdt, caplog): + ftbot = get_patched_freqtradebot(mocker, default_conf_usdt) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.create_trade') patch_get_signal(ftbot) ftbot.strategy.bot_loop_start = MagicMock(side_effect=ValueError) @@ -2001,9 +2001,9 @@ def test_bot_loop_start_called_once(mocker, default_conf, caplog): assert ftbot.strategy.analyze.call_count == 1 -def test_check_handle_timedout_buy_usercustom(default_conf, ticker, limit_buy_order_old, open_trade, +def test_check_handle_timedout_buy_usercustom(default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, fee, mocker) -> None: - default_conf["unfilledtimeout"] = {"buy": 1400, "sell": 30} + default_conf_usdt["unfilledtimeout"] = {"buy": 1400, "sell": 30} rpc_mock = patch_RPCManager(mocker) cancel_order_mock = MagicMock(return_value=limit_buy_order_old) @@ -2014,13 +2014,13 @@ def test_check_handle_timedout_buy_usercustom(default_conf, ticker, limit_buy_or patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, fetch_order=MagicMock(return_value=limit_buy_order_old), cancel_order_with_result=cancel_order_wr_mock, cancel_order=cancel_order_mock, get_fee=fee ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) Trade.query.session.add(open_trade) @@ -2057,7 +2057,7 @@ def test_check_handle_timedout_buy_usercustom(default_conf, ticker, limit_buy_or assert freqtrade.strategy.check_buy_timeout.call_count == 1 -def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, open_trade, +def test_check_handle_timedout_buy(default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, fee, mocker) -> None: rpc_mock = patch_RPCManager(mocker) limit_buy_cancel = deepcopy(limit_buy_order_old) @@ -2066,12 +2066,12 @@ def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, op patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, fetch_order=MagicMock(return_value=limit_buy_order_old), cancel_order_with_result=cancel_order_mock, get_fee=fee ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) Trade.query.session.add(open_trade) @@ -2087,7 +2087,7 @@ def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, op assert freqtrade.strategy.check_buy_timeout.call_count == 0 -def test_check_handle_cancelled_buy(default_conf, ticker, limit_buy_order_old, open_trade, +def test_check_handle_cancelled_buy(default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, fee, mocker, caplog) -> None: """ Handle Buy order cancelled on exchange""" rpc_mock = patch_RPCManager(mocker) @@ -2096,12 +2096,12 @@ def test_check_handle_cancelled_buy(default_conf, ticker, limit_buy_order_old, o limit_buy_order_old.update({"status": "canceled", 'filled': 0.0}) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, fetch_order=MagicMock(return_value=limit_buy_order_old), cancel_order=cancel_order_mock, get_fee=fee ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) Trade.query.session.add(open_trade) @@ -2115,7 +2115,7 @@ def test_check_handle_cancelled_buy(default_conf, ticker, limit_buy_order_old, o assert log_has_re("Buy order cancelled on exchange for Trade.*", caplog) -def test_check_handle_timedout_buy_exception(default_conf, ticker, limit_buy_order_old, open_trade, +def test_check_handle_timedout_buy_exception(default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, fee, mocker) -> None: rpc_mock = patch_RPCManager(mocker) cancel_order_mock = MagicMock() @@ -2123,12 +2123,12 @@ def test_check_handle_timedout_buy_exception(default_conf, ticker, limit_buy_ord mocker.patch.multiple( 'freqtrade.exchange.Exchange', validate_pairs=MagicMock(), - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, fetch_order=MagicMock(side_effect=ExchangeError), cancel_order=cancel_order_mock, get_fee=fee ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) Trade.query.session.add(open_trade) @@ -2141,19 +2141,19 @@ def test_check_handle_timedout_buy_exception(default_conf, ticker, limit_buy_ord assert nb_trades == 1 -def test_check_handle_timedout_sell_usercustom(default_conf, ticker, limit_sell_order_old, mocker, +def test_check_handle_timedout_sell_usercustom(default_conf_usdt, ticker_usdt, limit_sell_order_old, mocker, open_trade) -> None: - default_conf["unfilledtimeout"] = {"buy": 1440, "sell": 1440} + default_conf_usdt["unfilledtimeout"] = {"buy": 1440, "sell": 1440} rpc_mock = patch_RPCManager(mocker) cancel_order_mock = MagicMock() patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, fetch_order=MagicMock(return_value=limit_sell_order_old), cancel_order=cancel_order_mock ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) open_trade.open_date = arrow.utcnow().shift(hours=-5).datetime open_trade.close_date = arrow.utcnow().shift(minutes=-601).datetime @@ -2190,18 +2190,18 @@ def test_check_handle_timedout_sell_usercustom(default_conf, ticker, limit_sell_ assert freqtrade.strategy.check_sell_timeout.call_count == 1 -def test_check_handle_timedout_sell(default_conf, ticker, limit_sell_order_old, mocker, +def test_check_handle_timedout_sell(default_conf_usdt, ticker_usdt, limit_sell_order_old, mocker, open_trade) -> None: rpc_mock = patch_RPCManager(mocker) cancel_order_mock = MagicMock() patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, fetch_order=MagicMock(return_value=limit_sell_order_old), cancel_order=cancel_order_mock ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) open_trade.open_date = arrow.utcnow().shift(hours=-5).datetime open_trade.close_date = arrow.utcnow().shift(minutes=-601).datetime @@ -2220,7 +2220,7 @@ def test_check_handle_timedout_sell(default_conf, ticker, limit_sell_order_old, assert freqtrade.strategy.check_sell_timeout.call_count == 0 -def test_check_handle_cancelled_sell(default_conf, ticker, limit_sell_order_old, open_trade, +def test_check_handle_cancelled_sell(default_conf_usdt, ticker_usdt, limit_sell_order_old, open_trade, mocker, caplog) -> None: """ Handle sell order cancelled on exchange""" rpc_mock = patch_RPCManager(mocker) @@ -2229,11 +2229,11 @@ def test_check_handle_cancelled_sell(default_conf, ticker, limit_sell_order_old, patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, fetch_order=MagicMock(return_value=limit_sell_order_old), cancel_order_with_result=cancel_order_mock ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) open_trade.open_date = arrow.utcnow().shift(hours=-5).datetime open_trade.close_date = arrow.utcnow().shift(minutes=-601).datetime @@ -2249,7 +2249,7 @@ def test_check_handle_cancelled_sell(default_conf, ticker, limit_sell_order_old, assert log_has_re("Sell order cancelled on exchange for Trade.*", caplog) -def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old_partial, +def test_check_handle_timedout_partial(default_conf_usdt, ticker_usdt, limit_buy_order_old_partial, open_trade, mocker) -> None: rpc_mock = patch_RPCManager(mocker) limit_buy_canceled = deepcopy(limit_buy_order_old_partial) @@ -2259,11 +2259,11 @@ def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, fetch_order=MagicMock(return_value=limit_buy_order_old_partial), cancel_order_with_result=cancel_order_mock ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) Trade.query.session.add(open_trade) @@ -2278,7 +2278,7 @@ def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old assert trades[0].stake_amount == open_trade.open_rate * trades[0].amount -def test_check_handle_timedout_partial_fee(default_conf, ticker, open_trade, caplog, fee, +def test_check_handle_timedout_partial_fee(default_conf_usdt, ticker_usdt, open_trade, caplog, fee, limit_buy_order_old_partial, trades_for_order, limit_buy_order_old_partial_canceled, mocker) -> None: rpc_mock = patch_RPCManager(mocker) @@ -2287,12 +2287,12 @@ def test_check_handle_timedout_partial_fee(default_conf, ticker, open_trade, cap patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, fetch_order=MagicMock(return_value=limit_buy_order_old_partial), cancel_order_with_result=cancel_order_mock, get_trades_for_order=MagicMock(return_value=trades_for_order), ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) assert open_trade.amount == limit_buy_order_old_partial['amount'] @@ -2317,7 +2317,7 @@ def test_check_handle_timedout_partial_fee(default_conf, ticker, open_trade, cap assert pytest.approx(trades[0].fee_open) == 0.001 -def test_check_handle_timedout_partial_except(default_conf, ticker, open_trade, caplog, fee, +def test_check_handle_timedout_partial_except(default_conf_usdt, ticker_usdt, open_trade, caplog, fee, limit_buy_order_old_partial, trades_for_order, limit_buy_order_old_partial_canceled, mocker) -> None: rpc_mock = patch_RPCManager(mocker) @@ -2325,14 +2325,14 @@ def test_check_handle_timedout_partial_except(default_conf, ticker, open_trade, patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, fetch_order=MagicMock(return_value=limit_buy_order_old_partial), cancel_order_with_result=cancel_order_mock, get_trades_for_order=MagicMock(return_value=trades_for_order), ) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', MagicMock(side_effect=DependencyException)) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) assert open_trade.amount == limit_buy_order_old_partial['amount'] @@ -2357,7 +2357,7 @@ def test_check_handle_timedout_partial_except(default_conf, ticker, open_trade, assert trades[0].fee_open == fee() -def test_check_handle_timedout_exception(default_conf, ticker, open_trade_usdt, mocker, caplog) -> None: +def test_check_handle_timedout_exception(default_conf_usdt, ticker_usdt, open_trade_usdt, mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) cancel_order_mock = MagicMock() @@ -2369,11 +2369,11 @@ def test_check_handle_timedout_exception(default_conf, ticker, open_trade_usdt, ) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, fetch_order=MagicMock(side_effect=ExchangeError('Oh snap')), cancel_order=cancel_order_mock ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) Trade.query.session.add(open_trade_usdt) @@ -2385,7 +2385,7 @@ def test_check_handle_timedout_exception(default_conf, ticker, open_trade_usdt, caplog) -def test_handle_cancel_enter(mocker, caplog, default_conf, limit_buy_order_usdt) -> None: +def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_buy_order_usdt) -> None: patch_RPCManager(mocker) patch_exchange(mocker) cancel_buy_order = deepcopy(limit_buy_order_usdt) @@ -2395,7 +2395,7 @@ def test_handle_cancel_enter(mocker, caplog, default_conf, limit_buy_order_usdt) cancel_order_mock = MagicMock(return_value=cancel_buy_order) mocker.patch('freqtrade.exchange.Exchange.cancel_order_with_result', cancel_order_mock) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) freqtrade._notify_enter_cancel = MagicMock() trade = MagicMock() @@ -2430,7 +2430,7 @@ def test_handle_cancel_enter(mocker, caplog, default_conf, limit_buy_order_usdt) @pytest.mark.parametrize("limit_buy_order_canceled_empty", ['binance', 'ftx', 'kraken', 'bittrex'], indirect=['limit_buy_order_canceled_empty']) -def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf, +def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf_usdt, limit_buy_order_canceled_empty) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -2438,7 +2438,7 @@ def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf, 'freqtrade.exchange.Exchange.cancel_order_with_result', return_value=limit_buy_order_canceled_empty) nofiy_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot._notify_enter_cancel') - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) reason = CANCEL_REASON['TIMEOUT'] trade = MagicMock() @@ -2455,7 +2455,7 @@ def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf, 'String Return value', 123 ]) -def test_handle_cancel_enter_corder_empty(mocker, default_conf, limit_buy_order_usdt, +def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_buy_order_usdt, cancelorder) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -2465,7 +2465,7 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf, limit_buy_order_ cancel_order=cancel_order_mock ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) freqtrade._notify_enter_cancel = MagicMock() trade = MagicMock() @@ -2483,7 +2483,7 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf, limit_buy_order_ assert cancel_order_mock.call_count == 1 -def test_handle_cancel_exit_limit(mocker, default_conf, fee) -> None: +def test_handle_cancel_exit_limit(mocker, default_conf_usdt, fee) -> None: send_msg_mock = patch_RPCManager(mocker) patch_exchange(mocker) cancel_order_mock = MagicMock() @@ -2493,7 +2493,7 @@ def test_handle_cancel_exit_limit(mocker, default_conf, fee) -> None: ) mocker.patch('freqtrade.exchange.Exchange.get_rate', return_value=0.245441) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) trade = Trade( pair='LTC/ETH', @@ -2528,13 +2528,13 @@ def test_handle_cancel_exit_limit(mocker, default_conf, fee) -> None: assert send_msg_mock.call_count == 1 -def test_handle_cancel_exit_cancel_exception(mocker, default_conf) -> None: +def test_handle_cancel_exit_cancel_exception(mocker, default_conf_usdt) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch( 'freqtrade.exchange.Exchange.cancel_order_with_result', side_effect=InvalidOrderException()) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) trade = MagicMock() reason = CANCEL_REASON['TIMEOUT'] @@ -2544,17 +2544,17 @@ def test_handle_cancel_exit_cancel_exception(mocker, default_conf) -> None: assert freqtrade.handle_cancel_exit(trade, order, reason) == 'error cancelling order' -def test_execute_trade_exit_up(default_conf, ticker, fee, ticker_sell_up, mocker) -> None: +def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_up, mocker) -> None: rpc_mock = patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, get_fee=fee, _is_dry_limit_order_filled=MagicMock(return_value=False), ) - patch_whitelist(mocker, default_conf) - freqtrade = FreqtradeBot(default_conf) + patch_whitelist(mocker, default_conf_usdt) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) freqtrade.strategy.confirm_trade_exit = MagicMock(return_value=False) @@ -2569,10 +2569,10 @@ def test_execute_trade_exit_up(default_conf, ticker, fee, ticker_sell_up, mocker # Increase the price and sell it mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker_sell_up + fetch_ticker=ticker_usdt_sell_up ) # Prevented sell ... - freqtrade.execute_trade_exit(trade=trade, limit=ticker_sell_up()['bid'], + freqtrade.execute_trade_exit(trade=trade, limit=ticker_usdt_sell_up()['bid'], sell_reason=SellCheckTuple(sell_type=SellType.ROI)) assert rpc_mock.call_count == 0 assert freqtrade.strategy.confirm_trade_exit.call_count == 1 @@ -2580,7 +2580,7 @@ def test_execute_trade_exit_up(default_conf, ticker, fee, ticker_sell_up, mocker # Repatch with true freqtrade.strategy.confirm_trade_exit = MagicMock(return_value=True) - freqtrade.execute_trade_exit(trade=trade, limit=ticker_sell_up()['bid'], + freqtrade.execute_trade_exit(trade=trade, limit=ticker_usdt_sell_up()['bid'], sell_reason=SellCheckTuple(sell_type=SellType.ROI)) assert freqtrade.strategy.confirm_trade_exit.call_count == 1 @@ -2590,7 +2590,7 @@ def test_execute_trade_exit_up(default_conf, ticker, fee, ticker_sell_up, mocker 'trade_id': 1, 'type': RPCMessageType.SELL, 'exchange': 'Binance', - 'pair': 'ETH/BTC', + 'pair': 'ETH/USDT', 'gain': 'profit', 'limit': 1.172e-05, 'amount': 91.07468123, @@ -2608,17 +2608,17 @@ def test_execute_trade_exit_up(default_conf, ticker, fee, ticker_sell_up, mocker } == last_msg -def test_execute_trade_exit_down(default_conf, ticker, fee, ticker_sell_down, mocker) -> None: +def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_down, mocker) -> None: rpc_mock = patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, get_fee=fee, _is_dry_limit_order_filled=MagicMock(return_value=False), ) - patch_whitelist(mocker, default_conf) - freqtrade = FreqtradeBot(default_conf) + patch_whitelist(mocker, default_conf_usdt) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) # Create some test data @@ -2630,10 +2630,10 @@ def test_execute_trade_exit_down(default_conf, ticker, fee, ticker_sell_down, mo # Decrease the price and sell it mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker_sell_down + fetch_ticker=ticker_usdt_sell_down ) - freqtrade.execute_trade_exit(trade=trade, limit=ticker_sell_down()['bid'], + freqtrade.execute_trade_exit(trade=trade, limit=ticker_usdt_sell_down()['bid'], sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS)) assert rpc_mock.call_count == 2 @@ -2642,7 +2642,7 @@ def test_execute_trade_exit_down(default_conf, ticker, fee, ticker_sell_down, mo 'type': RPCMessageType.SELL, 'trade_id': 1, 'exchange': 'Binance', - 'pair': 'ETH/BTC', + 'pair': 'ETH/USDT', 'gain': 'loss', 'limit': 1.044e-05, 'amount': 91.07468123, @@ -2660,18 +2660,18 @@ def test_execute_trade_exit_down(default_conf, ticker, fee, ticker_sell_down, mo } == last_msg -def test_execute_trade_exit_custom_exit_price(default_conf, ticker, fee, ticker_sell_up, +def test_execute_trade_exit_custom_exit_price(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_up, mocker) -> None: rpc_mock = patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, get_fee=fee, _is_dry_limit_order_filled=MagicMock(return_value=False), ) - patch_whitelist(mocker, default_conf) - freqtrade = FreqtradeBot(default_conf) + patch_whitelist(mocker, default_conf_usdt) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) freqtrade.strategy.confirm_trade_exit = MagicMock(return_value=False) @@ -2686,7 +2686,7 @@ def test_execute_trade_exit_custom_exit_price(default_conf, ticker, fee, ticker_ # Increase the price and sell it mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker_sell_up + fetch_ticker=ticker_usdt_sell_up ) freqtrade.strategy.confirm_trade_exit = MagicMock(return_value=True) @@ -2694,7 +2694,7 @@ def test_execute_trade_exit_custom_exit_price(default_conf, ticker, fee, ticker_ # Set a custom exit price freqtrade.strategy.custom_exit_price = lambda **kwargs: 1.170e-05 - freqtrade.execute_trade_exit(trade=trade, limit=ticker_sell_up()['bid'], + freqtrade.execute_trade_exit(trade=trade, limit=ticker_usdt_sell_up()['bid'], sell_reason=SellCheckTuple(sell_type=SellType.SELL_SIGNAL)) # Sell price must be different to default bid price @@ -2707,7 +2707,7 @@ def test_execute_trade_exit_custom_exit_price(default_conf, ticker, fee, ticker_ 'trade_id': 1, 'type': RPCMessageType.SELL, 'exchange': 'Binance', - 'pair': 'ETH/BTC', + 'pair': 'ETH/USDT', 'gain': 'profit', 'limit': 1.170e-05, 'amount': 91.07468123, @@ -2725,18 +2725,18 @@ def test_execute_trade_exit_custom_exit_price(default_conf, ticker, fee, ticker_ } == last_msg -def test_execute_trade_exit_down_stoploss_on_exchange_dry_run(default_conf, ticker, fee, - ticker_sell_down, mocker) -> None: +def test_execute_trade_exit_down_stoploss_on_exchange_dry_run(default_conf_usdt, ticker_usdt, fee, + ticker_usdt_sell_down, mocker) -> None: rpc_mock = patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, get_fee=fee, _is_dry_limit_order_filled=MagicMock(return_value=False), ) - patch_whitelist(mocker, default_conf) - freqtrade = FreqtradeBot(default_conf) + patch_whitelist(mocker, default_conf_usdt) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) # Create some test data @@ -2748,15 +2748,15 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run(default_conf, tick # Decrease the price and sell it mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker_sell_down + fetch_ticker=ticker_usdt_sell_down ) - default_conf['dry_run'] = True + default_conf_usdt['dry_run'] = True freqtrade.strategy.order_types['stoploss_on_exchange'] = True # Setting trade stoploss to 0.01 trade.stop_loss = 0.00001099 * 0.99 - freqtrade.execute_trade_exit(trade=trade, limit=ticker_sell_down()['bid'], + freqtrade.execute_trade_exit(trade=trade, limit=ticker_usdt_sell_down()['bid'], sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS)) assert rpc_mock.call_count == 2 @@ -2766,7 +2766,7 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run(default_conf, tick 'type': RPCMessageType.SELL, 'trade_id': 1, 'exchange': 'Binance', - 'pair': 'ETH/BTC', + 'pair': 'ETH/USDT', 'gain': 'loss', 'limit': 1.08801e-05, 'amount': 91.07468123, @@ -2785,8 +2785,8 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run(default_conf, tick def test_execute_trade_exit_sloe_cancel_exception( - mocker, default_conf, ticker, fee, caplog) -> None: - freqtrade = get_patched_freqtradebot(mocker, default_conf) + mocker, default_conf_usdt, ticker_usdt, fee, caplog) -> None: + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mocker.patch('freqtrade.exchange.Exchange.cancel_stoploss_order', side_effect=InvalidOrderException()) mocker.patch('freqtrade.wallets.Wallets.get_free', MagicMock(return_value=300)) @@ -2797,7 +2797,7 @@ def test_execute_trade_exit_sloe_cancel_exception( patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, get_fee=fee, create_order=create_order_mock, ) @@ -2818,10 +2818,10 @@ def test_execute_trade_exit_sloe_cancel_exception( assert log_has('Could not cancel stoploss order abcd', caplog) -def test_execute_trade_exit_with_stoploss_on_exchange(default_conf, ticker, fee, ticker_sell_up, +def test_execute_trade_exit_with_stoploss_on_exchange(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_up, mocker) -> None: - default_conf['exchange']['name'] = 'binance' + default_conf_usdt['exchange']['name'] = 'binance' rpc_mock = patch_RPCManager(mocker) patch_exchange(mocker) stoploss = MagicMock(return_value={ @@ -2834,7 +2834,7 @@ def test_execute_trade_exit_with_stoploss_on_exchange(default_conf, ticker, fee, cancel_order = MagicMock(return_value=True) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, get_fee=fee, amount_to_precision=lambda s, x, y: y, price_to_precision=lambda s, x, y: y, @@ -2843,7 +2843,7 @@ def test_execute_trade_exit_with_stoploss_on_exchange(default_conf, ticker, fee, _is_dry_limit_order_filled=MagicMock(side_effect=[True, False]), ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) freqtrade.strategy.order_types['stoploss_on_exchange'] = True patch_get_signal(freqtrade) @@ -2860,10 +2860,10 @@ def test_execute_trade_exit_with_stoploss_on_exchange(default_conf, ticker, fee, # Increase the price and sell it mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker_sell_up + fetch_ticker=ticker_usdt_sell_up ) - freqtrade.execute_trade_exit(trade=trade, limit=ticker_sell_up()['bid'], + freqtrade.execute_trade_exit(trade=trade, limit=ticker_usdt_sell_up()['bid'], sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS)) trade = Trade.query.first() @@ -2872,14 +2872,14 @@ def test_execute_trade_exit_with_stoploss_on_exchange(default_conf, ticker, fee, assert rpc_mock.call_count == 3 -def test_may_execute_trade_exit_after_stoploss_on_exchange_hit(default_conf, ticker, fee, +def test_may_execute_trade_exit_after_stoploss_on_exchange_hit(default_conf_usdt, ticker_usdt, fee, mocker) -> None: - default_conf['exchange']['name'] = 'binance' + default_conf_usdt['exchange']['name'] = 'binance' rpc_mock = patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, get_fee=fee, amount_to_precision=lambda s, x, y: y, price_to_precision=lambda s, x, y: y, @@ -2895,7 +2895,7 @@ def test_may_execute_trade_exit_after_stoploss_on_exchange_hit(default_conf, tic mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) freqtrade.strategy.order_types['stoploss_on_exchange'] = True patch_get_signal(freqtrade) @@ -2944,18 +2944,18 @@ def test_may_execute_trade_exit_after_stoploss_on_exchange_hit(default_conf, tic assert rpc_mock.call_args_list[2][0][0]['type'] == RPCMessageType.SELL -def test_execute_trade_exit_market_order(default_conf, ticker, fee, - ticker_sell_up, mocker) -> None: +def test_execute_trade_exit_market_order(default_conf_usdt, ticker_usdt, fee, + ticker_usdt_sell_up, mocker) -> None: rpc_mock = patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, get_fee=fee, _is_dry_limit_order_filled=MagicMock(return_value=False), ) - patch_whitelist(mocker, default_conf) - freqtrade = FreqtradeBot(default_conf) + patch_whitelist(mocker, default_conf_usdt) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) # Create some test data @@ -2967,11 +2967,11 @@ def test_execute_trade_exit_market_order(default_conf, ticker, fee, # Increase the price and sell it mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker_sell_up + fetch_ticker=ticker_usdt_sell_up ) freqtrade.config['order_types']['sell'] = 'market' - freqtrade.execute_trade_exit(trade=trade, limit=ticker_sell_up()['bid'], + freqtrade.execute_trade_exit(trade=trade, limit=ticker_usdt_sell_up()['bid'], sell_reason=SellCheckTuple(sell_type=SellType.ROI)) assert not trade.is_open @@ -2983,7 +2983,7 @@ def test_execute_trade_exit_market_order(default_conf, ticker, fee, 'type': RPCMessageType.SELL, 'trade_id': 1, 'exchange': 'Binance', - 'pair': 'ETH/BTC', + 'pair': 'ETH/USDT', 'gain': 'profit', 'limit': 1.172e-05, 'amount': 91.07468123, @@ -3002,13 +3002,13 @@ def test_execute_trade_exit_market_order(default_conf, ticker, fee, } == last_msg -def test_execute_trade_exit_insufficient_funds_error(default_conf, ticker, fee, - ticker_sell_up, mocker) -> None: - freqtrade = get_patched_freqtradebot(mocker, default_conf) +def test_execute_trade_exit_insufficient_funds_error(default_conf_usdt, ticker_usdt, fee, + ticker_usdt_sell_up, mocker) -> None: + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mock_insuf = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_insufficient_funds') mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, get_fee=fee, create_order=MagicMock(side_effect=[ {'id': 1234553382}, @@ -3026,11 +3026,11 @@ def test_execute_trade_exit_insufficient_funds_error(default_conf, ticker, fee, # Increase the price and sell it mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker_sell_up + fetch_ticker=ticker_usdt_sell_up ) sell_reason = SellCheckTuple(sell_type=SellType.ROI) - assert not freqtrade.execute_trade_exit(trade=trade, limit=ticker_sell_up()['bid'], + assert not freqtrade.execute_trade_exit(trade=trade, limit=ticker_usdt_sell_up()['bid'], sell_reason=sell_reason) assert mock_insuf.call_count == 1 @@ -3047,7 +3047,7 @@ def test_execute_trade_exit_insufficient_funds_error(default_conf, ticker, fee, (False, 0.00000172, 0.00000173, True, False, SellType.SELL_SIGNAL.value), ]) def test_sell_profit_only( - default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, + default_conf_usdt, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, mocker, profit_only, bid, ask, handle_first, handle_second, sell_type) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -3064,12 +3064,12 @@ def test_sell_profit_only( ]), get_fee=fee, ) - default_conf.update({ + default_conf_usdt.update({ 'use_sell_signal': True, 'sell_profit_only': profit_only, 'sell_profit_offset': 0.1, }) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) if sell_type == SellType.SELL_SIGNAL.value: freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) @@ -3089,7 +3089,7 @@ def test_sell_profit_only( assert freqtrade.handle_trade(trade) is True -def test_sell_not_enough_balance(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, +def test_sell_not_enough_balance(default_conf_usdt, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -3107,7 +3107,7 @@ def test_sell_not_enough_balance(default_conf, limit_buy_order_usdt, limit_buy_o get_fee=fee, ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) @@ -3128,7 +3128,7 @@ def test_sell_not_enough_balance(default_conf, limit_buy_order_usdt, limit_buy_o (95.29, False), (91.29, True) ]) -def test__safe_exit_amount(default_conf, fee, caplog, mocker, amount_wallet, has_err): +def test__safe_exit_amount(default_conf_usdt, fee, caplog, mocker, amount_wallet, has_err): patch_RPCManager(mocker) patch_exchange(mocker) amount = 95.33 @@ -3144,7 +3144,7 @@ def test__safe_exit_amount(default_conf, fee, caplog, mocker, amount_wallet, has fee_open=fee.return_value, fee_close=fee.return_value, ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) if has_err: with pytest.raises(DependencyException, match=r"Not enough amount to sell."): @@ -3161,15 +3161,15 @@ def test__safe_exit_amount(default_conf, fee, caplog, mocker, amount_wallet, has assert wallet_update.call_count == 1 -def test_locked_pairs(default_conf, ticker, fee, ticker_sell_down, mocker, caplog) -> None: +def test_locked_pairs(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_down, mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, get_fee=fee, ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) # Create some test data @@ -3181,12 +3181,12 @@ def test_locked_pairs(default_conf, ticker, fee, ticker_sell_down, mocker, caplo # Decrease the price and sell it mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker_sell_down + fetch_ticker=ticker_usdt_sell_down ) - freqtrade.execute_trade_exit(trade=trade, limit=ticker_sell_down()['bid'], + freqtrade.execute_trade_exit(trade=trade, limit=ticker_usdt_sell_down()['bid'], sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS)) - trade.close(ticker_sell_down()['bid']) + trade.close(ticker_usdt_sell_down()['bid']) assert freqtrade.strategy.is_pair_locked(trade.pair) # reinit - should buy other pair. @@ -3196,7 +3196,7 @@ def test_locked_pairs(default_conf, ticker, fee, ticker_sell_down, mocker, caplo assert log_has_re(f"Pair {trade.pair} is still locked.*", caplog) -def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, +def test_ignore_roi_if_buy_signal(default_conf_usdt, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -3213,9 +3213,9 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order_usdt, limit_buy_ ]), get_fee=fee, ) - default_conf['ignore_roi_if_buy_signal'] = True + default_conf_usdt['ignore_roi_if_buy_signal'] = True - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=True) @@ -3233,7 +3233,7 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order_usdt, limit_buy_ assert trade.sell_reason == SellType.ROI.value -def test_trailing_stop_loss(default_conf, limit_buy_order_usdt_open, limit_buy_order_usdt, +def test_trailing_stop_loss(default_conf_usdt, limit_buy_order_usdt_open, limit_buy_order_usdt, fee, caplog, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -3250,9 +3250,9 @@ def test_trailing_stop_loss(default_conf, limit_buy_order_usdt_open, limit_buy_o ]), get_fee=fee, ) - default_conf['trailing_stop'] = True - patch_whitelist(mocker, default_conf) - freqtrade = FreqtradeBot(default_conf) + default_conf_usdt['trailing_stop'] = True + patch_whitelist(mocker, default_conf_usdt) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) @@ -3260,7 +3260,7 @@ def test_trailing_stop_loss(default_conf, limit_buy_order_usdt_open, limit_buy_o trade = Trade.query.first() assert freqtrade.handle_trade(trade) is False - # Raise ticker above buy price + # Raise ticker_usdt above buy price mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ 'bid': 2.0 * 1.5, @@ -3283,7 +3283,7 @@ def test_trailing_stop_loss(default_conf, limit_buy_order_usdt_open, limit_buy_o # Sell as trailing-stop is reached assert freqtrade.handle_trade(trade) is True # TODO: Does this make sense? How is stoploss 2.7? - assert log_has("ETH/BTC - HIT STOP: current price at 2.200000, stoploss is 2.700000, " + assert log_has("ETH/USDT - HIT STOP: current price at 2.200000, stoploss is 2.700000, " "initial stoploss was at 1.800000, trade opened at 2.000000", caplog) assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value @@ -3293,7 +3293,7 @@ def test_trailing_stop_loss(default_conf, limit_buy_order_usdt_open, limit_buy_o (0.011, False, 2.0394), (0.055, True, 1.8), ]) -def test_trailing_stop_loss_positive(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, +def test_trailing_stop_loss_positive(default_conf_usdt, limit_buy_order_usdt, limit_buy_order_usdt_open, offset, fee, caplog, mocker, trail_if_reached, second_sl) -> None: buy_price = limit_buy_order_usdt['price'] patch_RPCManager(mocker) @@ -3311,14 +3311,14 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order_usdt, limit_b ]), get_fee=fee, ) - default_conf['trailing_stop'] = True - default_conf['trailing_stop_positive'] = 0.01 + default_conf_usdt['trailing_stop'] = True + default_conf_usdt['trailing_stop_positive'] = 0.01 if offset: - default_conf['trailing_stop_positive_offset'] = offset - default_conf['trailing_only_offset_is_reached'] = trail_if_reached - patch_whitelist(mocker, default_conf) + default_conf_usdt['trailing_stop_positive_offset'] = offset + default_conf_usdt['trailing_only_offset_is_reached'] = trail_if_reached + patch_whitelist(mocker, default_conf_usdt) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) freqtrade.enter_positions() @@ -3329,7 +3329,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order_usdt, limit_b # stop-loss not reached assert freqtrade.handle_trade(trade) is False - # Raise ticker above buy price + # Raise ticker_usdt above buy price mocker.patch( 'freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ @@ -3341,13 +3341,13 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order_usdt, limit_b # stop-loss not reached, adjusted stoploss assert freqtrade.handle_trade(trade) is False # TODO: is 0.0249% correct? Shouldn't it be higher? - caplog_text = f"ETH/BTC - Using positive stoploss: 0.01 offset: {offset} profit: 0.0249%" + caplog_text = f"ETH/USDT - Using positive stoploss: 0.01 offset: {offset} profit: 0.0249%" if trail_if_reached: assert not log_has(caplog_text, caplog) - assert not log_has("ETH/BTC - Adjusting stoploss...", caplog) + assert not log_has("ETH/USDT - Adjusting stoploss...", caplog) else: assert log_has(caplog_text, caplog) - assert log_has("ETH/BTC - Adjusting stoploss...", caplog) + assert log_has("ETH/USDT - Adjusting stoploss...", caplog) assert trade.stop_loss == second_sl caplog.clear() @@ -3361,10 +3361,10 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order_usdt, limit_b ) assert freqtrade.handle_trade(trade) is False assert log_has( - f"ETH/BTC - Using positive stoploss: 0.01 offset: {offset} profit: 0.0572%", + f"ETH/USDT - Using positive stoploss: 0.01 offset: {offset} profit: 0.0572%", caplog ) - assert log_has("ETH/BTC - Adjusting stoploss...", caplog) + assert log_has("ETH/USDT - Adjusting stoploss...", caplog) mocker.patch( 'freqtrade.exchange.Exchange.fetch_ticker', @@ -3377,13 +3377,13 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order_usdt, limit_b # Lower price again (but still positive) assert freqtrade.handle_trade(trade) is True assert log_has( - f"ETH/BTC - HIT STOP: current price at {buy_price + 0.02:.6f}, " + f"ETH/USDT - HIT STOP: current price at {buy_price + 0.02:.6f}, " f"stoploss is {trade.stop_loss:.6f}, " f"initial stoploss was at 1.800000, trade opened at 2.000000", caplog) assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value -def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order_usdt, limit_buy_order_usdt_open, +def test_disable_ignore_roi_if_buy_signal(default_conf_usdt, limit_buy_order_usdt, limit_buy_order_usdt_open, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -3402,10 +3402,10 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order_usdt, li get_fee=fee, _is_dry_limit_order_filled=MagicMock(return_value=False), ) - default_conf['ask_strategy'] = { + default_conf_usdt['ask_strategy'] = { 'ignore_roi_if_buy_signal': False } - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=True) @@ -3423,7 +3423,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order_usdt, li assert trade.sell_reason == SellType.SELL_SIGNAL.value -def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, fee, caplog, mocker): +def test_get_real_amount_quote(default_conf_usdt, trades_for_order, buy_order_fee, fee, caplog, mocker): mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) amount = sum(x['amount'] for x in trades_for_order) trade = Trade( @@ -3435,7 +3435,7 @@ def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, fe fee_close=fee.return_value, open_order_id="123456" ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) # Amount is reduced by "fee" assert freqtrade.get_real_amount(trade, buy_order_fee) == amount - (amount * 0.001) @@ -3444,7 +3444,7 @@ def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, fe caplog) -def test_get_real_amount_quote_dust(default_conf, trades_for_order, buy_order_fee, fee, +def test_get_real_amount_quote_dust(default_conf_usdt, trades_for_order, buy_order_fee, fee, caplog, mocker): mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) walletmock = mocker.patch('freqtrade.wallets.Wallets.update') @@ -3459,7 +3459,7 @@ def test_get_real_amount_quote_dust(default_conf, trades_for_order, buy_order_fe fee_close=fee.return_value, open_order_id="123456" ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) walletmock.reset_mock() # Amount is kept as is @@ -3469,7 +3469,7 @@ def test_get_real_amount_quote_dust(default_conf, trades_for_order, buy_order_fe '- Eating Fee 0.008 into dust', caplog) -def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, fee): +def test_get_real_amount_no_trade(default_conf_usdt, buy_order_fee, caplog, mocker, fee): mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[]) amount = buy_order_fee['amount'] @@ -3482,7 +3482,7 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, f fee_close=fee.return_value, open_order_id="123456" ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) # Amount is reduced by "fee" assert freqtrade.get_real_amount(trade, buy_order_fee) == amount @@ -3492,7 +3492,7 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, f @pytest.mark.parametrize( - 'fee_par,fee_reduction_amount,use_ticker_rate,expected_log', [ + 'fee_par,fee_reduction_amount,use_ticker_usdt_rate,expected_log', [ # basic, amount does not change ({'cost': 0.008, 'currency': 'ETH'}, 0, False, None), # no currency in fee @@ -3511,8 +3511,8 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, f ({'cost': 0.008, 'currency': None}, 0, True, None), ]) def test_get_real_amount( - default_conf, trades_for_order, buy_order_fee, fee, mocker, caplog, - fee_par, fee_reduction_amount, use_ticker_rate, expected_log + default_conf_usdt, trades_for_order, buy_order_fee, fee, mocker, caplog, + fee_par, fee_reduction_amount, use_ticker_usdt_rate, expected_log ): buy_order = deepcopy(buy_order_fee) @@ -3530,9 +3530,9 @@ def test_get_real_amount( open_rate=0.245441, open_order_id="123456" ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) - if not use_ticker_rate: + if not use_ticker_usdt_rate: mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', side_effect=ExchangeError) caplog.clear() @@ -3550,7 +3550,7 @@ def test_get_real_amount( (0.02, 'BNB', 0.0005, 0.001518575, 7.996), ]) def test_get_real_amount_multi( - default_conf, trades_for_order2, buy_order_fee, caplog, fee, mocker, markets, + default_conf_usdt, trades_for_order2, buy_order_fee, caplog, fee, mocker, markets, fee_cost, fee_currency, fee_reduction_amount, expected_fee, expected_log_amount, ): @@ -3562,7 +3562,7 @@ def test_get_real_amount_multi( mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) amount = float(sum(x['amount'] for x in trades_for_order)) - default_conf['stake_currency'] = "ETH" + default_conf_usdt['stake_currency'] = "ETH" trade = Trade( pair='LTC/ETH', @@ -3575,8 +3575,8 @@ def test_get_real_amount_multi( ) # Fake markets entry to enable fee parsing - markets['BNB/ETH'] = markets['ETH/BTC'] - freqtrade = get_patched_freqtradebot(mocker, default_conf) + markets['BNB/ETH'] = markets['ETH/USDT'] + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets)) mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', return_value={'ask': 0.19, 'last': 0.2}) @@ -3600,7 +3600,7 @@ def test_get_real_amount_multi( assert trade.fee_close_currency is None -def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order_fee, fee, mocker): +def test_get_real_amount_invalid_order(default_conf_usdt, trades_for_order, buy_order_fee, fee, mocker): limit_buy_order_usdt = deepcopy(buy_order_fee) limit_buy_order_usdt['fee'] = {'cost': 0.004} @@ -3615,13 +3615,13 @@ def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order open_rate=0.245441, open_order_id="123456" ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) # Amount does not change assert freqtrade.get_real_amount(trade, limit_buy_order_usdt) == amount -def test_get_real_amount_wrong_amount(default_conf, trades_for_order, buy_order_fee, fee, mocker): +def test_get_real_amount_wrong_amount(default_conf_usdt, trades_for_order, buy_order_fee, fee, mocker): limit_buy_order_usdt = deepcopy(buy_order_fee) limit_buy_order_usdt['amount'] = limit_buy_order_usdt['amount'] - 0.001 @@ -3636,14 +3636,14 @@ def test_get_real_amount_wrong_amount(default_conf, trades_for_order, buy_order_ fee_close=fee.return_value, open_order_id="123456" ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) # Amount does not change with pytest.raises(DependencyException, match=r"Half bought\? Amounts don't match"): freqtrade.get_real_amount(trade, limit_buy_order_usdt) -def test_get_real_amount_wrong_amount_rounding(default_conf, trades_for_order, buy_order_fee, fee, +def test_get_real_amount_wrong_amount_rounding(default_conf_usdt, trades_for_order, buy_order_fee, fee, mocker): # Floats should not be compared directly. limit_buy_order_usdt = deepcopy(buy_order_fee) @@ -3660,14 +3660,14 @@ def test_get_real_amount_wrong_amount_rounding(default_conf, trades_for_order, b open_rate=0.245441, open_order_id="123456" ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) # Amount changes by fee amount. assert isclose(freqtrade.get_real_amount(trade, limit_buy_order_usdt), amount - (amount * 0.001), abs_tol=MATH_CLOSE_PREC,) -def test_get_real_amount_open_trade(default_conf, fee, mocker): +def test_get_real_amount_open_trade(default_conf_usdt, fee, mocker): amount = 12345 trade = Trade( pair='LTC/ETH', @@ -3684,7 +3684,7 @@ def test_get_real_amount_open_trade(default_conf, fee, mocker): 'status': 'open', 'side': 'buy', } - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) assert freqtrade.get_real_amount(trade, order) == amount @@ -3696,7 +3696,7 @@ def test_get_real_amount_open_trade(default_conf, fee, mocker): (8.0, 0.1, 8.0, 8.0), (8.0, 0.1, 7.9, 7.9), ]) -def test_apply_fee_conditional(default_conf, fee, caplog, mocker, +def test_apply_fee_conditional(default_conf_usdt, fee, caplog, mocker, amount, fee_abs, wallet, amount_exp): walletmock = mocker.patch('freqtrade.wallets.Wallets.update') mocker.patch('freqtrade.wallets.Wallets.get_free', return_value=wallet) @@ -3709,7 +3709,7 @@ def test_apply_fee_conditional(default_conf, fee, caplog, mocker, fee_close=fee.return_value, open_order_id="123456" ) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) walletmock.reset_mock() # Amount is kept as is @@ -3721,23 +3721,23 @@ def test_apply_fee_conditional(default_conf, fee, caplog, mocker, (0.1, False), (100, True), ]) -def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order_usdt_open, limit_buy_order_usdt, +def test_order_book_depth_of_market(default_conf_usdt, ticker_usdt, limit_buy_order_usdt_open, limit_buy_order_usdt, fee, mocker, order_book_l2, delta, is_high_delta): - default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True - default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = delta + default_conf_usdt['bid_strategy']['check_depth_of_market']['enabled'] = True + default_conf_usdt['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = delta patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) # Save state of current whitelist - whitelist = deepcopy(default_conf['exchange']['pair_whitelist']) - freqtrade = FreqtradeBot(default_conf) + whitelist = deepcopy(default_conf_usdt['exchange']['pair_whitelist']) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) freqtrade.enter_positions() @@ -3746,7 +3746,7 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order_usdt_o assert trade is None else: assert trade is not None - assert trade.stake_amount == 0.001 + assert trade.stake_amount == 10.0 assert trade.is_open assert trade.open_date is not None assert trade.exchange == 'binance' @@ -3757,43 +3757,43 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order_usdt_o trade.update(limit_buy_order_usdt) assert trade.open_rate == 2.0 - assert whitelist == default_conf['exchange']['pair_whitelist'] + assert whitelist == default_conf_usdt['exchange']['pair_whitelist'] @pytest.mark.parametrize('exception_thrown,ask,last,order_book_top,order_book', [ (False, 0.045, 0.046, 2, None), (True, 0.042, 0.046, 1, {'bids': [[]], 'asks': [[]]}) ]) -def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2, exception_thrown, +def test_order_book_bid_strategy1(mocker, default_conf_usdt, order_book_l2, exception_thrown, ask, last, order_book_top, order_book, caplog) -> None: """ test if function get_rate will return the order book price instead of the ask rate """ patch_exchange(mocker) - ticker_mock = MagicMock(return_value={'ask': ask, 'last': last}) + ticker_usdt_mock = MagicMock(return_value={'ask': ask, 'last': last}) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_l2_order_book=MagicMock(return_value=order_book) if order_book else order_book_l2, - fetch_ticker=ticker_mock, + fetch_ticker=ticker_usdt_mock, ) - default_conf['exchange']['name'] = 'binance' - default_conf['bid_strategy']['use_order_book'] = True - default_conf['bid_strategy']['order_book_top'] = order_book_top - default_conf['bid_strategy']['ask_last_balance'] = 0 - default_conf['telegram']['enabled'] = False + default_conf_usdt['exchange']['name'] = 'binance' + default_conf_usdt['bid_strategy']['use_order_book'] = True + default_conf_usdt['bid_strategy']['order_book_top'] = order_book_top + default_conf_usdt['bid_strategy']['ask_last_balance'] = 0 + default_conf_usdt['telegram']['enabled'] = False - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) if exception_thrown: with pytest.raises(PricingError): - freqtrade.exchange.get_rate('ETH/BTC', refresh=True, side="buy") + freqtrade.exchange.get_rate('ETH/USDT', refresh=True, side="buy") assert log_has_re( r'Buy Price at location 1 from orderbook could not be determined.', caplog) else: - assert freqtrade.exchange.get_rate('ETH/BTC', refresh=True, side="buy") == 0.043935 - assert ticker_mock.call_count == 0 + assert freqtrade.exchange.get_rate('ETH/USDT', refresh=True, side="buy") == 0.043935 + assert ticker_usdt_mock.call_count == 0 -def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2) -> None: +def test_check_depth_of_market_buy(default_conf_usdt, mocker, order_book_l2) -> None: """ test check depth of market """ @@ -3802,27 +3802,27 @@ def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2) -> None: 'freqtrade.exchange.Exchange', fetch_l2_order_book=order_book_l2 ) - default_conf['telegram']['enabled'] = False - default_conf['exchange']['name'] = 'binance' - default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True + default_conf_usdt['telegram']['enabled'] = False + default_conf_usdt['exchange']['name'] = 'binance' + default_conf_usdt['bid_strategy']['check_depth_of_market']['enabled'] = True # delta is 100 which is impossible to reach. hence function will return false - default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 100 - freqtrade = FreqtradeBot(default_conf) + default_conf_usdt['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 100 + freqtrade = FreqtradeBot(default_conf_usdt) - conf = default_conf['bid_strategy']['check_depth_of_market'] - assert freqtrade._check_depth_of_market_buy('ETH/BTC', conf) is False + conf = default_conf_usdt['bid_strategy']['check_depth_of_market'] + assert freqtrade._check_depth_of_market_buy('ETH/USDT', conf) is False -def test_order_book_ask_strategy(default_conf, limit_buy_order_usdt_open, limit_buy_order_usdt, fee, +def test_order_book_ask_strategy(default_conf_usdt, limit_buy_order_usdt_open, limit_buy_order_usdt, fee, limit_sell_order_usdt_open, mocker, order_book_l2, caplog) -> None: """ test order book ask strategy """ mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2) - default_conf['exchange']['name'] = 'binance' - default_conf['ask_strategy']['use_order_book'] = True - default_conf['ask_strategy']['order_book_top'] = 1 - default_conf['telegram']['enabled'] = False + default_conf_usdt['exchange']['name'] = 'binance' + default_conf_usdt['ask_strategy']['use_order_book'] = True + default_conf_usdt['ask_strategy']['order_book_top'] = 1 + default_conf_usdt['telegram']['enabled'] = False patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -3838,7 +3838,7 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order_usdt_open, limit_ ]), get_fee=fee, ) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade) freqtrade.enter_positions() @@ -3863,22 +3863,22 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order_usdt_open, limit_ caplog) -def test_startup_state(default_conf, mocker): - default_conf['pairlist'] = {'method': 'VolumePairList', - 'config': {'number_assets': 20} - } +def test_startup_state(default_conf_usdt, mocker): + default_conf_usdt['pairlist'] = {'method': 'VolumePairList', + 'config': {'number_assets': 20} + } mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) - worker = get_patched_worker(mocker, default_conf) + worker = get_patched_worker(mocker, default_conf_usdt) assert worker.freqtrade.state is State.RUNNING -def test_startup_trade_reinit(default_conf, edge_conf, mocker): +def test_startup_trade_reinit(default_conf_usdt, edge_conf, mocker): mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) reinit_mock = MagicMock() mocker.patch('freqtrade.persistence.Trade.stoploss_reinitialization', reinit_mock) - ftbot = get_patched_freqtradebot(mocker, default_conf) + ftbot = get_patched_freqtradebot(mocker, default_conf_usdt) ftbot.startup() assert reinit_mock.call_count == 1 @@ -3890,21 +3890,21 @@ def test_startup_trade_reinit(default_conf, edge_conf, mocker): @pytest.mark.usefixtures("init_persistence") -def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order_usdt_open, caplog): - default_conf['dry_run'] = True +def test_sync_wallet_dry_run(mocker, default_conf_usdt, ticker_usdt, fee, limit_buy_order_usdt_open, caplog): + default_conf_usdt['dry_run'] = True # Initialize to 2 times stake amount - default_conf['dry_run_wallet'] = 0.002 - default_conf['max_open_trades'] = 2 - default_conf['tradable_balance_ratio'] = 1.0 + default_conf_usdt['dry_run_wallet'] = 0.002 + default_conf_usdt['max_open_trades'] = 2 + default_conf_usdt['tradable_balance_ratio'] = 1.0 patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, create_order=MagicMock(return_value=limit_buy_order_usdt_open), get_fee=fee, ) - bot = get_patched_freqtradebot(mocker, default_conf) + bot = get_patched_freqtradebot(mocker, default_conf_usdt) patch_get_signal(bot) assert bot.wallets.get_free('BTC') == 0.002 @@ -3922,15 +3922,15 @@ def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order_ @pytest.mark.usefixtures("init_persistence") -def test_cancel_all_open_orders(mocker, default_conf, fee, limit_buy_order_usdt, limit_sell_order_usdt): - default_conf['cancel_open_orders_on_exit'] = True +def test_cancel_all_open_orders(mocker, default_conf_usdt, fee, limit_buy_order_usdt, limit_sell_order_usdt): + default_conf_usdt['cancel_open_orders_on_exit'] = True mocker.patch('freqtrade.exchange.Exchange.fetch_order', side_effect=[ ExchangeError(), limit_sell_order_usdt, limit_buy_order_usdt, limit_sell_order_usdt]) buy_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_enter') sell_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_exit') - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) create_mock_trades(fee) trades = Trade.query.all() assert len(trades) == MOCK_TRADE_COUNT @@ -3940,8 +3940,8 @@ def test_cancel_all_open_orders(mocker, default_conf, fee, limit_buy_order_usdt, @pytest.mark.usefixtures("init_persistence") -def test_check_for_open_trades(mocker, default_conf, fee): - freqtrade = get_patched_freqtradebot(mocker, default_conf) +def test_check_for_open_trades(mocker, default_conf_usdt, fee): + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) freqtrade.check_for_open_trades() assert freqtrade.rpc.send_msg.call_count == 0 @@ -3956,8 +3956,8 @@ def test_check_for_open_trades(mocker, default_conf, fee): @pytest.mark.usefixtures("init_persistence") -def test_startup_update_open_orders(mocker, default_conf, fee, caplog): - freqtrade = get_patched_freqtradebot(mocker, default_conf) +def test_startup_update_open_orders(mocker, default_conf_usdt, fee, caplog): + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) create_mock_trades(fee) freqtrade.startup_update_open_orders() @@ -3982,8 +3982,8 @@ def test_startup_update_open_orders(mocker, default_conf, fee, caplog): @pytest.mark.usefixtures("init_persistence") -def test_update_closed_trades_without_assigned_fees(mocker, default_conf, fee): - freqtrade = get_patched_freqtradebot(mocker, default_conf) +def test_update_closed_trades_without_assigned_fees(mocker, default_conf_usdt, fee): + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) def patch_with_fee(order): order.update({'fee': {'cost': 0.1, 'rate': 0.01, @@ -4081,8 +4081,8 @@ def test_reupdate_enter_order_fees(mocker, default_conf_usdt, fee, caplog): @pytest.mark.usefixtures("init_persistence") -def test_handle_insufficient_funds(mocker, default_conf, fee): - freqtrade = get_patched_freqtradebot(mocker, default_conf) +def test_handle_insufficient_funds(mocker, default_conf_usdt, fee): + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mock_rlo = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.refind_lost_order') mock_bof = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.reupdate_enter_order_fees') create_mock_trades(fee) @@ -4119,9 +4119,9 @@ def test_handle_insufficient_funds(mocker, default_conf, fee): @pytest.mark.usefixtures("init_persistence") -def test_refind_lost_order(mocker, default_conf, fee, caplog): +def test_refind_lost_order(mocker, default_conf_usdt, fee, caplog): caplog.set_level(logging.DEBUG) - freqtrade = get_patched_freqtradebot(mocker, default_conf) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mock_uts = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.update_trade_state') mock_fo = mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order', @@ -4217,10 +4217,10 @@ def test_refind_lost_order(mocker, default_conf, fee, caplog): assert log_has(f"Error updating {order['id']}.", caplog) -def test_get_valid_price(mocker, default_conf) -> None: +def test_get_valid_price(mocker, default_conf_usdt) -> None: patch_RPCManager(mocker) patch_exchange(mocker) - freqtrade = FreqtradeBot(default_conf) + freqtrade = FreqtradeBot(default_conf_usdt) freqtrade.config['custom_price_max_distance_ratio'] = 0.02 custom_price_string = "10" From 43339f1660557f6538f05addb464a502ac074b5f Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sun, 26 Sep 2021 13:43:01 -0600 Subject: [PATCH 58/76] A lot of the usdt freqtradebot tests pass now --- tests/conftest.py | 8 ++-- tests/test_freqtradebot.py | 90 ++++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 47 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index f2da68dd2..4ef0dfcb4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -441,7 +441,7 @@ def ticker_sell_down(): def ticker_usdt(): return MagicMock(return_value={ 'bid': 2.0, - 'ask': 2.01, + 'ask': 2.1, 'last': 2.0, }) @@ -449,9 +449,9 @@ def ticker_usdt(): @pytest.fixture def ticker_usdt_sell_up(): return MagicMock(return_value={ - 'bid': 2.19, - 'ask': 2.2, - 'last': 2.19, + 'bid': 2.2, + 'ask': 2.3, + 'last': 2.2, }) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 2a96783bc..07f1288ed 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -320,8 +320,8 @@ def test_create_trade_no_stake_amount(default_conf_usdt, ticker_usdt, limit_buy_ @pytest.mark.parametrize('stake_amount,create,amount_enough,max_open_trades', [ - (0.0005, True, True, 99), - (0.000000005, True, False, 99), + (5.0, True, True, 99), + (0.00005, True, False, 99), (0, False, True, 99), (UNLIMITED_STAKE_AMOUNT, False, True, 0), ]) @@ -2592,14 +2592,15 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_ 'exchange': 'Binance', 'pair': 'ETH/USDT', 'gain': 'profit', - 'limit': 1.172e-05, - 'amount': 91.07468123, + 'limit': 2.2, + 'amount': 5.0, 'order_type': 'limit', - 'open_rate': 1.098e-05, - 'current_rate': 1.173e-05, - 'profit_amount': 6.223e-05, - 'profit_ratio': 0.0620716, - 'stake_currency': 'BTC', + 'open_rate': 2.0, + 'current_rate': 2.3, + # TODO: Double check that profit_amount and profit_ratio are correct + 'profit_amount': 0.9475, + 'profit_ratio': 0.09451372, + 'stake_currency': 'USDT', 'fiat_currency': 'USD', 'sell_reason': SellType.ROI.value, 'open_date': ANY, @@ -2638,20 +2639,21 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd assert rpc_mock.call_count == 2 last_msg = rpc_mock.call_args_list[-1][0][0] + # TODO: Should be a loss, but comes out as a gain assert { 'type': RPCMessageType.SELL, 'trade_id': 1, 'exchange': 'Binance', 'pair': 'ETH/USDT', 'gain': 'loss', - 'limit': 1.044e-05, - 'amount': 91.07468123, + 'limit': 2.01, + 'amount': 5.0, 'order_type': 'limit', - 'open_rate': 1.098e-05, - 'current_rate': 1.043e-05, - 'profit_amount': -5.406e-05, - 'profit_ratio': -0.05392257, - 'stake_currency': 'BTC', + 'open_rate': 2.0, + 'current_rate': 2.0, + 'profit_amount': -0.000125, + 'profit_ratio': -1.247e-05, + 'stake_currency': 'USDT', 'fiat_currency': 'USD', 'sell_reason': SellType.STOP_LOSS.value, 'open_date': ANY, @@ -2692,7 +2694,7 @@ def test_execute_trade_exit_custom_exit_price(default_conf_usdt, ticker_usdt, fe freqtrade.strategy.confirm_trade_exit = MagicMock(return_value=True) # Set a custom exit price - freqtrade.strategy.custom_exit_price = lambda **kwargs: 1.170e-05 + freqtrade.strategy.custom_exit_price = lambda **kwargs: 2.25 freqtrade.execute_trade_exit(trade=trade, limit=ticker_usdt_sell_up()['bid'], sell_reason=SellCheckTuple(sell_type=SellType.SELL_SIGNAL)) @@ -2709,14 +2711,14 @@ def test_execute_trade_exit_custom_exit_price(default_conf_usdt, ticker_usdt, fe 'exchange': 'Binance', 'pair': 'ETH/USDT', 'gain': 'profit', - 'limit': 1.170e-05, - 'amount': 91.07468123, + 'limit': 2.25, + 'amount': 5.0, 'order_type': 'limit', - 'open_rate': 1.098e-05, - 'current_rate': 1.173e-05, + 'open_rate': 2.0, + 'current_rate': 2.3, 'profit_amount': 6.041e-05, - 'profit_ratio': 0.06025919, - 'stake_currency': 'BTC', + 'profit_ratio': 0.07262344, + 'stake_currency': 'USDT', 'fiat_currency': 'USD', 'sell_reason': SellType.SELL_SIGNAL.value, 'open_date': ANY, @@ -2755,27 +2757,28 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run(default_conf_usdt, freqtrade.strategy.order_types['stoploss_on_exchange'] = True # Setting trade stoploss to 0.01 - trade.stop_loss = 0.00001099 * 0.99 + trade.stop_loss = 2.0 * 0.99 freqtrade.execute_trade_exit(trade=trade, limit=ticker_usdt_sell_down()['bid'], sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS)) assert rpc_mock.call_count == 2 last_msg = rpc_mock.call_args_list[-1][0][0] + # TODO: Are these values correct? assert { 'type': RPCMessageType.SELL, 'trade_id': 1, 'exchange': 'Binance', 'pair': 'ETH/USDT', 'gain': 'loss', - 'limit': 1.08801e-05, - 'amount': 91.07468123, + 'limit': 1.98, + 'amount': 5.0, 'order_type': 'limit', - 'open_rate': 1.098e-05, - 'current_rate': 1.043e-05, - 'profit_amount': -1.408e-05, - 'profit_ratio': -0.01404051, - 'stake_currency': 'BTC', + 'open_rate': 2.0, + 'current_rate': 2.0, + 'profit_amount': -0.14975, + 'profit_ratio': -0.01493766, + 'stake_currency': 'USDT', 'fiat_currency': 'USD', 'sell_reason': SellType.STOP_LOSS.value, 'open_date': ANY, @@ -2975,24 +2978,25 @@ def test_execute_trade_exit_market_order(default_conf_usdt, ticker_usdt, fee, sell_reason=SellCheckTuple(sell_type=SellType.ROI)) assert not trade.is_open - assert trade.close_profit == 0.0620716 + assert trade.close_profit == 0.09451372 # TODO: Check this is correct assert rpc_mock.call_count == 3 last_msg = rpc_mock.call_args_list[-1][0][0] + # TODO: Is this correct? assert { 'type': RPCMessageType.SELL, 'trade_id': 1, 'exchange': 'Binance', 'pair': 'ETH/USDT', 'gain': 'profit', - 'limit': 1.172e-05, - 'amount': 91.07468123, + 'limit': 2.2, + 'amount': 5.0, 'order_type': 'market', - 'open_rate': 1.098e-05, - 'current_rate': 1.173e-05, - 'profit_amount': 6.223e-05, - 'profit_ratio': 0.0620716, - 'stake_currency': 'BTC', + 'open_rate': 2.0, + 'current_rate': 2.3, + 'profit_amount': 0.9475, + 'profit_ratio': 0.09451372, + 'stake_currency': 'USDT', 'fiat_currency': 'USD', 'sell_reason': SellType.ROI.value, 'open_date': ANY, @@ -3893,7 +3897,7 @@ def test_startup_trade_reinit(default_conf_usdt, edge_conf, mocker): def test_sync_wallet_dry_run(mocker, default_conf_usdt, ticker_usdt, fee, limit_buy_order_usdt_open, caplog): default_conf_usdt['dry_run'] = True # Initialize to 2 times stake amount - default_conf_usdt['dry_run_wallet'] = 0.002 + default_conf_usdt['dry_run_wallet'] = 20.0 default_conf_usdt['max_open_trades'] = 2 default_conf_usdt['tradable_balance_ratio'] = 1.0 patch_exchange(mocker) @@ -3906,7 +3910,7 @@ def test_sync_wallet_dry_run(mocker, default_conf_usdt, ticker_usdt, fee, limit_ bot = get_patched_freqtradebot(mocker, default_conf_usdt) patch_get_signal(bot) - assert bot.wallets.get_free('BTC') == 0.002 + assert bot.wallets.get_free('USDT') == 20.0 n = bot.enter_positions() assert n == 2 @@ -3916,8 +3920,8 @@ def test_sync_wallet_dry_run(mocker, default_conf_usdt, ticker_usdt, fee, limit_ bot.config['max_open_trades'] = 3 n = bot.enter_positions() assert n == 0 - 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\)", + assert log_has_re(r"Unable to create trade for XRP/USDT: " + r"Available balance \(0.0 USDT\) is lower than stake amount \(10.0 USDT\)", caplog) From 2ee87f8c66cb4b998ba986acd2dfc8729ece5e8f Mon Sep 17 00:00:00 2001 From: Rokas Kupstys Date: Thu, 30 Sep 2021 10:00:56 +0300 Subject: [PATCH 59/76] Fix failing USDT tests due to not enough open markets. --- tests/conftest.py | 78 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 4ef0dfcb4..9c500e05c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -387,7 +387,8 @@ def get_default_conf_usdt(testdatadir): "ETH/USDT", "LTC/USDT", "XRP/USDT", - "NEO/USDT" + "NEO/USDT", + "TKN/USDT", ], "pair_blacklist": [ "DOGE/USDT", @@ -696,6 +697,81 @@ def get_markets(): }, 'info': {}, }, + 'XRP/USDT': { + 'id': 'xrpusdt', + 'symbol': 'XRP/USDT', + 'base': 'XRP', + 'quote': 'USDT', + 'active': True, + 'precision': { + 'price': 8, + 'amount': 8, + 'cost': 8, + }, + 'lot': 0.00000001, + 'limits': { + 'amount': { + 'min': 0.01, + 'max': 1000, + }, + 'price': 500000, + 'cost': { + 'min': 0.0001, + 'max': 500000, + }, + }, + 'info': {}, + }, + 'NEO/USDT': { + 'id': 'neousdt', + 'symbol': 'NEO/USDT', + 'base': 'NEO', + 'quote': 'USDT', + 'active': True, + 'precision': { + 'price': 8, + 'amount': 8, + 'cost': 8, + }, + 'lot': 0.00000001, + 'limits': { + 'amount': { + 'min': 0.01, + 'max': 1000, + }, + 'price': 500000, + 'cost': { + 'min': 0.0001, + 'max': 500000, + }, + }, + 'info': {}, + }, + 'TKN/USDT': { + 'id': 'tknusdt', + 'symbol': 'TKN/USDT', + 'base': 'TKN', + 'quote': 'USDT', + 'active': True, + 'precision': { + 'price': 8, + 'amount': 8, + 'cost': 8, + }, + 'lot': 0.00000001, + 'limits': { + 'amount': { + 'min': 0.01, + 'max': 1000, + }, + 'price': 500000, + 'cost': { + 'min': 0.0001, + 'max': 500000, + }, + }, + 'info': {}, + }, 'LTC/USD': { 'id': 'USD-LTC', 'symbol': 'LTC/USD', From 89613702697de80c1ecbd3f7cd75271b4116dea8 Mon Sep 17 00:00:00 2001 From: Rokas Kupstys Date: Thu, 30 Sep 2021 10:01:25 +0300 Subject: [PATCH 60/76] Fix failing test due to not updated expected values. --- tests/test_freqtradebot.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 07f1288ed..579dc1b43 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2672,8 +2672,10 @@ def test_execute_trade_exit_custom_exit_price(default_conf_usdt, ticker_usdt, fe get_fee=fee, _is_dry_limit_order_filled=MagicMock(return_value=False), ) - patch_whitelist(mocker, default_conf_usdt) - freqtrade = FreqtradeBot(default_conf_usdt) + config = deepcopy(default_conf_usdt) + config['custom_price_max_distance_ratio'] = 0.1 + patch_whitelist(mocker, config) + freqtrade = FreqtradeBot(config) patch_get_signal(freqtrade) freqtrade.strategy.confirm_trade_exit = MagicMock(return_value=False) @@ -2716,8 +2718,8 @@ def test_execute_trade_exit_custom_exit_price(default_conf_usdt, ticker_usdt, fe 'order_type': 'limit', 'open_rate': 2.0, 'current_rate': 2.3, - 'profit_amount': 6.041e-05, - 'profit_ratio': 0.07262344, + 'profit_amount': 1.196875, + 'profit_ratio': 0.11938903, 'stake_currency': 'USDT', 'fiat_currency': 'USD', 'sell_reason': SellType.SELL_SIGNAL.value, From c820db4c60f6973554e232b52c06ed6e726dd8d0 Mon Sep 17 00:00:00 2001 From: Rokas Kupstys Date: Thu, 30 Sep 2021 11:12:15 +0300 Subject: [PATCH 61/76] Fix couple more usdt tests which failed due to ticker prices causing roi being hit, but tests did not expect that to happen. --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 9c500e05c..0e5e7c933 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -442,7 +442,7 @@ def ticker_sell_down(): def ticker_usdt(): return MagicMock(return_value={ 'bid': 2.0, - 'ask': 2.1, + 'ask': 2.02, 'last': 2.0, }) From 107fa911a5ef371e675a5d679ab511f1a93579b5 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Thu, 30 Sep 2021 02:34:00 -0600 Subject: [PATCH 62/76] Fixed test_tsl_on_exchange_compatible_with_edge --- tests/test_freqtradebot.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 579dc1b43..bfa3ac353 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1483,9 +1483,9 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 1.9, + 'bid': 2.19, 'ask': 2.2, - 'last': 1.9 + 'last': 2.19 }), create_order=MagicMock(side_effect=[ {'id': limit_buy_order_usdt['id']}, @@ -1540,7 +1540,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, # stoploss initially at 20% as edge dictated it. assert freqtrade.handle_trade(trade) is False assert freqtrade.handle_stoploss_on_exchange(trade) is False - assert trade.stop_loss == 2.178 + assert isclose(trade.stop_loss, 1.76) cancel_order_mock = MagicMock() stoploss_order_mock = MagicMock() @@ -1549,15 +1549,15 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, # price goes down 5% mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ - 'bid': 1.9 * 0.95, + 'bid': 2.19 * 0.95, 'ask': 2.2 * 0.95, - 'last': 1.9 * 0.95 + 'last': 2.19 * 0.95 })) assert freqtrade.handle_trade(trade) is False assert freqtrade.handle_stoploss_on_exchange(trade) is False # stoploss should remain the same - assert trade.stop_loss == 2.178 + assert isclose(trade.stop_loss, 1.76) # stoploss on exchange should not be canceled cancel_order_mock.assert_not_called() @@ -1575,10 +1575,12 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, # stoploss should be set to 1% as trailing is on assert trade.stop_loss == 4.4 * 0.99 cancel_order_mock.assert_called_once_with(100, 'NEO/BTC') - stoploss_order_mock.assert_called_once_with(amount=2132892.49146757, - pair='NEO/BTC', - order_types=freqtrade.strategy.order_types, - stop_price=4.4 * 0.99) + stoploss_order_mock.assert_called_once_with( + amount=11.41438356, + pair='NEO/BTC', + order_types=freqtrade.strategy.order_types, + stop_price=4.4 * 0.99 + ) @pytest.mark.parametrize('return_value,side_effect,log_message', [ From 6f8e66117bcc0babd0aeef9c03a15b9ee6fc2e11 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Thu, 30 Sep 2021 03:19:28 -0600 Subject: [PATCH 63/76] flake8 isort --- tests/test_freqtradebot.py | 153 ++++++++++++++++++++++--------------- 1 file changed, 91 insertions(+), 62 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index bfa3ac353..6f0fe5e90 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -23,9 +23,9 @@ from freqtrade.worker import Worker from tests.conftest import (create_mock_trades, get_patched_freqtradebot, get_patched_worker, log_has, log_has_re, patch_edge, patch_exchange, patch_get_signal, patch_wallet, patch_whitelist) -from tests.conftest_trades import ( - MOCK_TRADE_COUNT, mock_order_1, mock_order_2, mock_order_2_sell, mock_order_3, - mock_order_3_sell, mock_order_4, mock_order_5_stoploss, mock_order_6_sell) +from tests.conftest_trades import (MOCK_TRADE_COUNT, mock_order_1, mock_order_2, mock_order_2_sell, + mock_order_3, mock_order_3_sell, mock_order_4, + mock_order_5_stoploss, mock_order_6_sell) def patch_RPCManager(mocker) -> MagicMock: @@ -135,8 +135,10 @@ def test_get_trade_stake_amount(default_conf_usdt, ticker_usdt, mocker) -> None: (True, 27, 3, 0.5, [10, 10, 6.73]), (True, 22, 3, 1, [10, 10, 0.0]), ]) -def test_check_available_stake_amount(default_conf_usdt, ticker_usdt, mocker, fee, limit_buy_order_usdt_open, - amend_last, wallet, max_open, lsamr, expected) -> None: +def test_check_available_stake_amount( + default_conf_usdt, ticker_usdt, mocker, fee, limit_buy_order_usdt_open, + amend_last, wallet, max_open, lsamr, expected +) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -363,8 +365,8 @@ def test_create_trade_minimal_amount( (["ETH/USDT"], 1), # No pairs left ([], 0), # No pairs in whitelist ]) -def test_enter_positions_no_pairs_left(default_conf_usdt, ticker_usdt, limit_buy_order_usdt_open, fee, - whitelist, positions, mocker, caplog) -> None: +def test_enter_positions_no_pairs_left(default_conf_usdt, ticker_usdt, limit_buy_order_usdt_open, + fee, whitelist, positions, mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -459,8 +461,10 @@ def test_create_trade_no_signal(default_conf_usdt, fee, mocker) -> None: @pytest.mark.parametrize("max_open", range(0, 5)) @pytest.mark.parametrize("tradable_balance_ratio,modifier", [(1.0, 1), (0.99, 0.8), (0.5, 0.5)]) -def test_create_trades_multiple_trades(default_conf_usdt, ticker_usdt, fee, mocker, limit_buy_order_usdt_open, - max_open, tradable_balance_ratio, modifier) -> None: +def test_create_trades_multiple_trades( + default_conf_usdt, ticker_usdt, fee, mocker, limit_buy_order_usdt_open, + max_open, tradable_balance_ratio, modifier +) -> None: patch_RPCManager(mocker) patch_exchange(mocker) default_conf_usdt['max_open_trades'] = max_open @@ -484,7 +488,8 @@ def test_create_trades_multiple_trades(default_conf_usdt, ticker_usdt, fee, mock assert len(trades) == max(int(max_open * modifier), 0) -def test_create_trades_preopen(default_conf_usdt, ticker_usdt, fee, mocker, limit_buy_order_usdt_open) -> None: +def test_create_trades_preopen(default_conf_usdt, ticker_usdt, fee, mocker, + limit_buy_order_usdt_open) -> None: patch_RPCManager(mocker) patch_exchange(mocker) default_conf_usdt['max_open_trades'] = 4 @@ -513,8 +518,8 @@ def test_create_trades_preopen(default_conf_usdt, ticker_usdt, fee, mocker, limi assert len(trades) == 4 -def test_process_trade_creation(default_conf_usdt, ticker_usdt, limit_buy_order_usdt, limit_buy_order_usdt_open, - fee, mocker, caplog) -> None: +def test_process_trade_creation(default_conf_usdt, ticker_usdt, limit_buy_order_usdt, + limit_buy_order_usdt_open, fee, mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -584,7 +589,8 @@ def test_process_operational_exception(default_conf_usdt, ticker_usdt, mocker) - assert 'OperationalException' in msg_mock.call_args_list[-1][0][0]['status'] -def test_process_trade_handling(default_conf_usdt, ticker_usdt, limit_buy_order_usdt_open, fee, mocker) -> None: +def test_process_trade_handling(default_conf_usdt, ticker_usdt, limit_buy_order_usdt_open, fee, + mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -690,7 +696,8 @@ def test_process_informative_pairs_added(default_conf_usdt, ticker_usdt, mocker) assert ("ETH/USDT", default_conf_usdt["timeframe"]) in refresh_mock.call_args[0][0] -def test_execute_entry(mocker, default_conf_usdt, fee, limit_buy_order_usdt, limit_buy_order_usdt_open) -> None: +def test_execute_entry(mocker, default_conf_usdt, fee, limit_buy_order_usdt, + limit_buy_order_usdt_open) -> None: patch_RPCManager(mocker) patch_exchange(mocker) freqtrade = FreqtradeBot(default_conf_usdt) @@ -1278,8 +1285,9 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf_usdt, fee, assert freqtrade.handle_trade(trade) is True -def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf_usdt, fee, caplog, - limit_buy_order_usdt, limit_sell_order_usdt) -> None: +def test_handle_stoploss_on_exchange_trailing_error( + mocker, default_conf_usdt, fee, caplog, limit_buy_order_usdt, limit_sell_order_usdt +) -> None: # When trailing stoploss is set stoploss = MagicMock(return_value={'id': 13434334}) patch_exchange(mocker) @@ -1701,8 +1709,8 @@ def test_update_trade_state(mocker, default_conf_usdt, limit_buy_order_usdt, cap (30.0 + 1e-14, True), (8.0, False) ]) -def test_update_trade_state_withorderdict(default_conf_usdt, trades_for_order, limit_buy_order_usdt, fee, - mocker, initial_amount, has_rounding_fee, caplog): +def test_update_trade_state_withorderdict(default_conf_usdt, trades_for_order, limit_buy_order_usdt, + fee, mocker, initial_amount, has_rounding_fee, caplog): trades_for_order[0]['amount'] = initial_amount mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) # fetch_order should not be called!! @@ -1798,8 +1806,8 @@ def test_update_trade_state_sell(default_conf_usdt, trades_for_order, limit_sell assert order.status == 'closed' -def test_handle_trade(default_conf_usdt, limit_buy_order_usdt, limit_sell_order_usdt_open, limit_sell_order_usdt, - fee, mocker) -> None: +def test_handle_trade(default_conf_usdt, limit_buy_order_usdt, limit_sell_order_usdt_open, + limit_sell_order_usdt, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -1963,8 +1971,8 @@ def test_handle_trade_use_sell_signal(default_conf_usdt, ticker_usdt, limit_buy_ caplog) -def test_close_trade(default_conf_usdt, ticker_usdt, limit_buy_order_usdt, limit_buy_order_usdt_open, limit_sell_order_usdt, - fee, mocker) -> None: +def test_close_trade(default_conf_usdt, ticker_usdt, limit_buy_order_usdt, + limit_buy_order_usdt_open, limit_sell_order_usdt, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -2003,8 +2011,8 @@ def test_bot_loop_start_called_once(mocker, default_conf_usdt, caplog): assert ftbot.strategy.analyze.call_count == 1 -def test_check_handle_timedout_buy_usercustom(default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, - fee, mocker) -> None: +def test_check_handle_timedout_buy_usercustom(default_conf_usdt, ticker_usdt, limit_buy_order_old, + open_trade, fee, mocker) -> None: default_conf_usdt["unfilledtimeout"] = {"buy": 1400, "sell": 30} rpc_mock = patch_RPCManager(mocker) @@ -2117,8 +2125,8 @@ def test_check_handle_cancelled_buy(default_conf_usdt, ticker_usdt, limit_buy_or assert log_has_re("Buy order cancelled on exchange for Trade.*", caplog) -def test_check_handle_timedout_buy_exception(default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, - fee, mocker) -> None: +def test_check_handle_timedout_buy_exception(default_conf_usdt, ticker_usdt, limit_buy_order_old, + open_trade, fee, mocker) -> None: rpc_mock = patch_RPCManager(mocker) cancel_order_mock = MagicMock() patch_exchange(mocker) @@ -2143,8 +2151,8 @@ def test_check_handle_timedout_buy_exception(default_conf_usdt, ticker_usdt, lim assert nb_trades == 1 -def test_check_handle_timedout_sell_usercustom(default_conf_usdt, ticker_usdt, limit_sell_order_old, mocker, - open_trade) -> None: +def test_check_handle_timedout_sell_usercustom(default_conf_usdt, ticker_usdt, limit_sell_order_old, + mocker, open_trade) -> None: default_conf_usdt["unfilledtimeout"] = {"buy": 1440, "sell": 1440} rpc_mock = patch_RPCManager(mocker) cancel_order_mock = MagicMock() @@ -2222,8 +2230,8 @@ def test_check_handle_timedout_sell(default_conf_usdt, ticker_usdt, limit_sell_o assert freqtrade.strategy.check_sell_timeout.call_count == 0 -def test_check_handle_cancelled_sell(default_conf_usdt, ticker_usdt, limit_sell_order_old, open_trade, - mocker, caplog) -> None: +def test_check_handle_cancelled_sell(default_conf_usdt, ticker_usdt, limit_sell_order_old, + open_trade, mocker, caplog) -> None: """ Handle sell order cancelled on exchange""" rpc_mock = patch_RPCManager(mocker) cancel_order_mock = MagicMock() @@ -2319,8 +2327,8 @@ def test_check_handle_timedout_partial_fee(default_conf_usdt, ticker_usdt, open_ assert pytest.approx(trades[0].fee_open) == 0.001 -def test_check_handle_timedout_partial_except(default_conf_usdt, ticker_usdt, open_trade, caplog, fee, - limit_buy_order_old_partial, trades_for_order, +def test_check_handle_timedout_partial_except(default_conf_usdt, ticker_usdt, open_trade, caplog, + fee, limit_buy_order_old_partial, trades_for_order, limit_buy_order_old_partial_canceled, mocker) -> None: rpc_mock = patch_RPCManager(mocker) cancel_order_mock = MagicMock(return_value=limit_buy_order_old_partial_canceled) @@ -2359,7 +2367,8 @@ def test_check_handle_timedout_partial_except(default_conf_usdt, ticker_usdt, op assert trades[0].fee_open == fee() -def test_check_handle_timedout_exception(default_conf_usdt, ticker_usdt, open_trade_usdt, mocker, caplog) -> None: +def test_check_handle_timedout_exception(default_conf_usdt, ticker_usdt, open_trade_usdt, mocker, + caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) cancel_order_mock = MagicMock() @@ -2546,7 +2555,8 @@ def test_handle_cancel_exit_cancel_exception(mocker, default_conf_usdt) -> None: assert freqtrade.handle_cancel_exit(trade, order, reason) == 'error cancelling order' -def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_up, mocker) -> None: +def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_up, mocker + ) -> None: rpc_mock = patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -2611,7 +2621,8 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_ } == last_msg -def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_down, mocker) -> None: +def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_down, + mocker) -> None: rpc_mock = patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -2664,8 +2675,8 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd } == last_msg -def test_execute_trade_exit_custom_exit_price(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_up, - mocker) -> None: +def test_execute_trade_exit_custom_exit_price(default_conf_usdt, ticker_usdt, fee, + ticker_usdt_sell_up, mocker) -> None: rpc_mock = patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -2731,8 +2742,8 @@ def test_execute_trade_exit_custom_exit_price(default_conf_usdt, ticker_usdt, fe } == last_msg -def test_execute_trade_exit_down_stoploss_on_exchange_dry_run(default_conf_usdt, ticker_usdt, fee, - ticker_usdt_sell_down, mocker) -> None: +def test_execute_trade_exit_down_stoploss_on_exchange_dry_run( + default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_down, mocker) -> None: rpc_mock = patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -2825,8 +2836,8 @@ def test_execute_trade_exit_sloe_cancel_exception( assert log_has('Could not cancel stoploss order abcd', caplog) -def test_execute_trade_exit_with_stoploss_on_exchange(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_up, - mocker) -> None: +def test_execute_trade_exit_with_stoploss_on_exchange(default_conf_usdt, ticker_usdt, fee, + ticker_usdt_sell_up, mocker) -> None: default_conf_usdt['exchange']['name'] = 'binance' rpc_mock = patch_RPCManager(mocker) @@ -3169,7 +3180,8 @@ def test__safe_exit_amount(default_conf_usdt, fee, caplog, mocker, amount_wallet assert wallet_update.call_count == 1 -def test_locked_pairs(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_down, mocker, caplog) -> None: +def test_locked_pairs(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_down, mocker, + caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -3204,8 +3216,8 @@ def test_locked_pairs(default_conf_usdt, ticker_usdt, fee, ticker_usdt_sell_down assert log_has_re(f"Pair {trade.pair} is still locked.*", caplog) -def test_ignore_roi_if_buy_signal(default_conf_usdt, limit_buy_order_usdt, limit_buy_order_usdt_open, - fee, mocker) -> None: +def test_ignore_roi_if_buy_signal(default_conf_usdt, limit_buy_order_usdt, + limit_buy_order_usdt_open, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -3301,8 +3313,10 @@ def test_trailing_stop_loss(default_conf_usdt, limit_buy_order_usdt_open, limit_ (0.011, False, 2.0394), (0.055, True, 1.8), ]) -def test_trailing_stop_loss_positive(default_conf_usdt, limit_buy_order_usdt, limit_buy_order_usdt_open, - offset, fee, caplog, mocker, trail_if_reached, second_sl) -> None: +def test_trailing_stop_loss_positive( + default_conf_usdt, limit_buy_order_usdt, limit_buy_order_usdt_open, + offset, fee, caplog, mocker, trail_if_reached, second_sl +) -> None: buy_price = limit_buy_order_usdt['price'] patch_RPCManager(mocker) patch_exchange(mocker) @@ -3391,8 +3405,8 @@ def test_trailing_stop_loss_positive(default_conf_usdt, limit_buy_order_usdt, li assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value -def test_disable_ignore_roi_if_buy_signal(default_conf_usdt, limit_buy_order_usdt, limit_buy_order_usdt_open, - fee, mocker) -> None: +def test_disable_ignore_roi_if_buy_signal(default_conf_usdt, limit_buy_order_usdt, + limit_buy_order_usdt_open, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -3431,7 +3445,8 @@ def test_disable_ignore_roi_if_buy_signal(default_conf_usdt, limit_buy_order_usd assert trade.sell_reason == SellType.SELL_SIGNAL.value -def test_get_real_amount_quote(default_conf_usdt, trades_for_order, buy_order_fee, fee, caplog, mocker): +def test_get_real_amount_quote(default_conf_usdt, trades_for_order, buy_order_fee, fee, caplog, + mocker): mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order) amount = sum(x['amount'] for x in trades_for_order) trade = Trade( @@ -3608,7 +3623,8 @@ def test_get_real_amount_multi( assert trade.fee_close_currency is None -def test_get_real_amount_invalid_order(default_conf_usdt, trades_for_order, buy_order_fee, fee, mocker): +def test_get_real_amount_invalid_order(default_conf_usdt, trades_for_order, buy_order_fee, fee, + mocker): limit_buy_order_usdt = deepcopy(buy_order_fee) limit_buy_order_usdt['fee'] = {'cost': 0.004} @@ -3629,7 +3645,8 @@ def test_get_real_amount_invalid_order(default_conf_usdt, trades_for_order, buy_ assert freqtrade.get_real_amount(trade, limit_buy_order_usdt) == amount -def test_get_real_amount_wrong_amount(default_conf_usdt, trades_for_order, buy_order_fee, fee, mocker): +def test_get_real_amount_wrong_amount(default_conf_usdt, trades_for_order, buy_order_fee, fee, + mocker): limit_buy_order_usdt = deepcopy(buy_order_fee) limit_buy_order_usdt['amount'] = limit_buy_order_usdt['amount'] - 0.001 @@ -3651,8 +3668,8 @@ def test_get_real_amount_wrong_amount(default_conf_usdt, trades_for_order, buy_o freqtrade.get_real_amount(trade, limit_buy_order_usdt) -def test_get_real_amount_wrong_amount_rounding(default_conf_usdt, trades_for_order, buy_order_fee, fee, - mocker): +def test_get_real_amount_wrong_amount_rounding(default_conf_usdt, trades_for_order, buy_order_fee, + fee, mocker): # Floats should not be compared directly. limit_buy_order_usdt = deepcopy(buy_order_fee) trades_for_order[0]['amount'] = trades_for_order[0]['amount'] + 1e-15 @@ -3671,8 +3688,11 @@ def test_get_real_amount_wrong_amount_rounding(default_conf_usdt, trades_for_ord freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) # Amount changes by fee amount. - assert isclose(freqtrade.get_real_amount(trade, limit_buy_order_usdt), amount - (amount * 0.001), - abs_tol=MATH_CLOSE_PREC,) + assert isclose( + freqtrade.get_real_amount(trade, limit_buy_order_usdt), + amount - (amount * 0.001), + abs_tol=MATH_CLOSE_PREC, + ) def test_get_real_amount_open_trade(default_conf_usdt, fee, mocker): @@ -3729,8 +3749,10 @@ def test_apply_fee_conditional(default_conf_usdt, fee, caplog, mocker, (0.1, False), (100, True), ]) -def test_order_book_depth_of_market(default_conf_usdt, ticker_usdt, limit_buy_order_usdt_open, limit_buy_order_usdt, - fee, mocker, order_book_l2, delta, is_high_delta): +def test_order_book_depth_of_market( + default_conf_usdt, ticker_usdt, limit_buy_order_usdt_open, limit_buy_order_usdt, + fee, mocker, order_book_l2, delta, is_high_delta +): default_conf_usdt['bid_strategy']['check_depth_of_market']['enabled'] = True default_conf_usdt['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = delta patch_RPCManager(mocker) @@ -3821,8 +3843,9 @@ def test_check_depth_of_market_buy(default_conf_usdt, mocker, order_book_l2) -> assert freqtrade._check_depth_of_market_buy('ETH/USDT', conf) is False -def test_order_book_ask_strategy(default_conf_usdt, limit_buy_order_usdt_open, limit_buy_order_usdt, fee, - limit_sell_order_usdt_open, mocker, order_book_l2, caplog) -> None: +def test_order_book_ask_strategy( + default_conf_usdt, limit_buy_order_usdt_open, limit_buy_order_usdt, fee, + limit_sell_order_usdt_open, mocker, order_book_l2, caplog) -> None: """ test order book ask strategy """ @@ -3898,7 +3921,8 @@ def test_startup_trade_reinit(default_conf_usdt, edge_conf, mocker): @pytest.mark.usefixtures("init_persistence") -def test_sync_wallet_dry_run(mocker, default_conf_usdt, ticker_usdt, fee, limit_buy_order_usdt_open, caplog): +def test_sync_wallet_dry_run(mocker, default_conf_usdt, ticker_usdt, fee, limit_buy_order_usdt_open, + caplog): default_conf_usdt['dry_run'] = True # Initialize to 2 times stake amount default_conf_usdt['dry_run_wallet'] = 20.0 @@ -3930,11 +3954,16 @@ def test_sync_wallet_dry_run(mocker, default_conf_usdt, ticker_usdt, fee, limit_ @pytest.mark.usefixtures("init_persistence") -def test_cancel_all_open_orders(mocker, default_conf_usdt, fee, limit_buy_order_usdt, limit_sell_order_usdt): +def test_cancel_all_open_orders(mocker, default_conf_usdt, fee, limit_buy_order_usdt, + limit_sell_order_usdt): default_conf_usdt['cancel_open_orders_on_exit'] = True mocker.patch('freqtrade.exchange.Exchange.fetch_order', side_effect=[ - ExchangeError(), limit_sell_order_usdt, limit_buy_order_usdt, limit_sell_order_usdt]) + ExchangeError(), + limit_sell_order_usdt, + limit_buy_order_usdt, + limit_sell_order_usdt + ]) buy_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_enter') sell_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_exit') From 96d09b5615c14fd442394060d844be2c898056a6 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Fri, 1 Oct 2021 03:10:43 -0600 Subject: [PATCH 64/76] Fixed breaking rpc tests --- tests/rpc/test_rpc.py | 2 +- tests/rpc/test_rpc_apiserver.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 0ba42c4ce..f8c923958 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -1003,7 +1003,7 @@ def test_rpc_blacklist(mocker, default_conf) -> None: assert len(ret['blacklist']) == 4 assert ret['blacklist'] == default_conf['exchange']['pair_blacklist'] assert ret['blacklist'] == ['DOGE/BTC', 'HOT/BTC', 'ETH/BTC', 'XRP/.*'] - assert ret['blacklist_expanded'] == ['ETH/BTC', 'XRP/BTC'] + assert ret['blacklist_expanded'] == ['ETH/BTC', 'XRP/BTC', 'XRP/USDT'] assert 'errors' in ret assert isinstance(ret['errors'], dict) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 7c98b2df7..045f91bb8 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -937,7 +937,7 @@ def test_api_blacklist(botclient, mocker): data='{"blacklist": ["XRP/.*"]}') assert_response(rc) assert rc.json() == {"blacklist": ["DOGE/BTC", "HOT/BTC", "ETH/BTC", "XRP/.*"], - "blacklist_expanded": ["ETH/BTC", "XRP/BTC"], + "blacklist_expanded": ["ETH/BTC", "XRP/BTC", "XRP/USDT"], "length": 4, "method": ["StaticPairList"], "errors": {}, From e5e1e49f5327753ed9e7525c5cdca838e2c3ab66 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 2 Oct 2021 08:58:33 +0200 Subject: [PATCH 65/76] Remove some unused test parameters --- tests/test_freqtradebot.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 6f0fe5e90..02c913bc3 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -115,7 +115,7 @@ def test_order_dict(default_conf_usdt, mocker, runmode, caplog) -> None: assert not log_has_re(".*stoploss_on_exchange .* dry-run", caplog) -def test_get_trade_stake_amount(default_conf_usdt, ticker_usdt, mocker) -> None: +def test_get_trade_stake_amount(default_conf_usdt, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -243,7 +243,6 @@ def test_edge_overrides_stoploss(limit_buy_order_usdt, fee, caplog, mocker, def test_total_open_trades_stakes(mocker, default_conf_usdt, ticker_usdt, fee) -> None: patch_RPCManager(mocker) patch_exchange(mocker) - default_conf_usdt['stake_amount'] = 10.0 default_conf_usdt['max_open_trades'] = 2 mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -304,8 +303,7 @@ def test_create_trade(default_conf_usdt, ticker_usdt, limit_buy_order_usdt, fee, assert whitelist == default_conf_usdt['exchange']['pair_whitelist'] -def test_create_trade_no_stake_amount(default_conf_usdt, ticker_usdt, limit_buy_order_usdt, - fee, mocker) -> None: +def test_create_trade_no_stake_amount(default_conf_usdt, ticker_usdt, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) patch_wallet(mocker, free=default_conf_usdt['stake_amount'] * 0.5) @@ -1477,7 +1475,7 @@ def test_handle_stoploss_on_exchange_custom_stop( assert freqtrade.handle_trade(trade) is True -def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, +def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, limit_buy_order_usdt, limit_sell_order_usdt) -> None: # When trailing stoploss is set @@ -2125,7 +2123,7 @@ def test_check_handle_cancelled_buy(default_conf_usdt, ticker_usdt, limit_buy_or assert log_has_re("Buy order cancelled on exchange for Trade.*", caplog) -def test_check_handle_timedout_buy_exception(default_conf_usdt, ticker_usdt, limit_buy_order_old, +def test_check_handle_timedout_buy_exception(default_conf_usdt, ticker_usdt, open_trade, fee, mocker) -> None: rpc_mock = patch_RPCManager(mocker) cancel_order_mock = MagicMock() @@ -3253,7 +3251,7 @@ def test_ignore_roi_if_buy_signal(default_conf_usdt, limit_buy_order_usdt, assert trade.sell_reason == SellType.ROI.value -def test_trailing_stop_loss(default_conf_usdt, limit_buy_order_usdt_open, limit_buy_order_usdt, +def test_trailing_stop_loss(default_conf_usdt, limit_buy_order_usdt_open, fee, caplog, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -3724,7 +3722,7 @@ def test_get_real_amount_open_trade(default_conf_usdt, fee, mocker): (8.0, 0.1, 8.0, 8.0), (8.0, 0.1, 7.9, 7.9), ]) -def test_apply_fee_conditional(default_conf_usdt, fee, caplog, mocker, +def test_apply_fee_conditional(default_conf_usdt, fee, mocker, amount, fee_abs, wallet, amount_exp): walletmock = mocker.patch('freqtrade.wallets.Wallets.update') mocker.patch('freqtrade.wallets.Wallets.get_free', return_value=wallet) From 022839b728fafdf2f1a83d514fb0c9acd027db54 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 2 Oct 2021 13:17:10 +0200 Subject: [PATCH 66/76] remove unnecessary test --- tests/test_freqtradebot.py | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 02c913bc3..c169d8597 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1612,32 +1612,6 @@ def test_enter_positions(mocker, default_conf_usdt, return_value, side_effect, assert mock_ct.call_count == len(default_conf_usdt['exchange']['pair_whitelist']) -def test_exit_positions(mocker, default_conf_usdt, limit_buy_order_usdt, caplog) -> None: - freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) - - mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True)) - mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order_usdt) - mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[]) - mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', - return_value=limit_buy_order_usdt['amount']) - - trade = MagicMock() - trade.open_order_id = '123' - trade.open_fee = 0.001 - trades = [trade] - n = freqtrade.exit_positions(trades) - assert n == 0 - # Test amount not modified by fee-logic - assert not log_has( - 'Applying fee to amount for Trade {} from 30.0 to 90.81'.format(trade), caplog - ) - - mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', return_value=90.81) - # test amount modified by fee-logic - n = freqtrade.exit_positions(trades) - assert n == 0 - - def test_exit_positions_exception(mocker, default_conf_usdt, limit_buy_order_usdt, caplog) -> None: freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mocker.patch('freqtrade.exchange.Exchange.fetch_order', return_value=limit_buy_order_usdt) From 5fdeca812d28891a915507362ffcc9f36ccb4cb0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 2 Oct 2021 14:30:24 +0200 Subject: [PATCH 67/76] Combine most hyperopt-loss tests to one --- tests/optimize/conftest.py | 13 ++-- tests/optimize/test_hyperoptloss.py | 92 +++++------------------------ 2 files changed, 23 insertions(+), 82 deletions(-) diff --git a/tests/optimize/conftest.py b/tests/optimize/conftest.py index 5c5171c3a..690934b07 100644 --- a/tests/optimize/conftest.py +++ b/tests/optimize/conftest.py @@ -39,16 +39,17 @@ def hyperopt(hyperopt_conf, mocker): def hyperopt_results(): return pd.DataFrame( { - 'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC'], - 'profit_ratio': [-0.1, 0.2, 0.3], - 'profit_abs': [-0.2, 0.4, 0.6], - 'trade_duration': [10, 30, 10], - 'sell_reason': [SellType.STOP_LOSS, SellType.ROI, SellType.ROI], + 'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC', 'ETH/BTC'], + 'profit_ratio': [-0.1, 0.2, -0.1, 0.3], + 'profit_abs': [-0.2, 0.4, -0.2, 0.6], + 'trade_duration': [10, 30, 10, 10], + 'sell_reason': [SellType.STOP_LOSS, SellType.ROI, SellType.STOP_LOSS, SellType.ROI], 'close_date': [ datetime(2019, 1, 1, 9, 26, 3, 478039), datetime(2019, 2, 1, 9, 26, 3, 478039), - datetime(2019, 3, 1, 9, 26, 3, 478039) + datetime(2019, 3, 1, 9, 26, 3, 478039), + datetime(2019, 4, 1, 9, 26, 3, 478039), ] } ) diff --git a/tests/optimize/test_hyperoptloss.py b/tests/optimize/test_hyperoptloss.py index 0082bcc34..923e3fc32 100644 --- a/tests/optimize/test_hyperoptloss.py +++ b/tests/optimize/test_hyperoptloss.py @@ -35,6 +35,7 @@ def test_hyperoptlossresolver_wrongname(default_conf) -> None: def test_loss_calculation_prefer_correct_trade_count(hyperopt_conf, hyperopt_results) -> None: + hyperopt_conf.update({'hyperopt_loss': "ShortTradeDurHyperOptLoss"}) hl = HyperOptLossResolver.load_hyperoptloss(hyperopt_conf) correct = hl.hyperopt_loss_function(hyperopt_results, 600, datetime(2019, 1, 1), datetime(2019, 5, 1)) @@ -50,6 +51,7 @@ def test_loss_calculation_prefer_shorter_trades(hyperopt_conf, hyperopt_results) resultsb = hyperopt_results.copy() resultsb.loc[1, 'trade_duration'] = 20 + hyperopt_conf.update({'hyperopt_loss': "ShortTradeDurHyperOptLoss"}) hl = HyperOptLossResolver.load_hyperoptloss(hyperopt_conf) longer = hl.hyperopt_loss_function(hyperopt_results, 100, datetime(2019, 1, 1), datetime(2019, 5, 1)) @@ -64,6 +66,7 @@ def test_loss_calculation_has_limited_profit(hyperopt_conf, hyperopt_results) -> results_under = hyperopt_results.copy() results_under['profit_ratio'] = hyperopt_results['profit_ratio'] / 2 + hyperopt_conf.update({'hyperopt_loss': "ShortTradeDurHyperOptLoss"}) hl = HyperOptLossResolver.load_hyperoptloss(hyperopt_conf) correct = hl.hyperopt_loss_function(hyperopt_results, 600, datetime(2019, 1, 1), datetime(2019, 5, 1)) @@ -75,91 +78,28 @@ def test_loss_calculation_has_limited_profit(hyperopt_conf, hyperopt_results) -> assert under > correct -def test_sharpe_loss_prefers_higher_profits(default_conf, hyperopt_results) -> None: - results_over = hyperopt_results.copy() - results_over['profit_ratio'] = hyperopt_results['profit_ratio'] * 2 - results_under = hyperopt_results.copy() - results_under['profit_ratio'] = hyperopt_results['profit_ratio'] / 2 - - default_conf.update({'hyperopt_loss': 'SharpeHyperOptLoss'}) - hl = HyperOptLossResolver.load_hyperoptloss(default_conf) - correct = hl.hyperopt_loss_function(hyperopt_results, len(hyperopt_results), - datetime(2019, 1, 1), datetime(2019, 5, 1)) - over = hl.hyperopt_loss_function(results_over, len(hyperopt_results), - datetime(2019, 1, 1), datetime(2019, 5, 1)) - under = hl.hyperopt_loss_function(results_under, len(hyperopt_results), - datetime(2019, 1, 1), datetime(2019, 5, 1)) - assert over < correct - assert under > correct - - -def test_sharpe_loss_daily_prefers_higher_profits(default_conf, hyperopt_results) -> None: - results_over = hyperopt_results.copy() - results_over['profit_ratio'] = hyperopt_results['profit_ratio'] * 2 - results_under = hyperopt_results.copy() - results_under['profit_ratio'] = hyperopt_results['profit_ratio'] / 2 - - default_conf.update({'hyperopt_loss': 'SharpeHyperOptLossDaily'}) - hl = HyperOptLossResolver.load_hyperoptloss(default_conf) - correct = hl.hyperopt_loss_function(hyperopt_results, len(hyperopt_results), - datetime(2019, 1, 1), datetime(2019, 5, 1)) - over = hl.hyperopt_loss_function(results_over, len(hyperopt_results), - datetime(2019, 1, 1), datetime(2019, 5, 1)) - under = hl.hyperopt_loss_function(results_under, len(hyperopt_results), - datetime(2019, 1, 1), datetime(2019, 5, 1)) - assert over < correct - assert under > correct - - -def test_sortino_loss_prefers_higher_profits(default_conf, hyperopt_results) -> None: - results_over = hyperopt_results.copy() - results_over['profit_ratio'] = hyperopt_results['profit_ratio'] * 2 - results_under = hyperopt_results.copy() - results_under['profit_ratio'] = hyperopt_results['profit_ratio'] / 2 - - default_conf.update({'hyperopt_loss': 'SortinoHyperOptLoss'}) - hl = HyperOptLossResolver.load_hyperoptloss(default_conf) - correct = hl.hyperopt_loss_function(hyperopt_results, len(hyperopt_results), - datetime(2019, 1, 1), datetime(2019, 5, 1)) - over = hl.hyperopt_loss_function(results_over, len(hyperopt_results), - datetime(2019, 1, 1), datetime(2019, 5, 1)) - under = hl.hyperopt_loss_function(results_under, len(hyperopt_results), - datetime(2019, 1, 1), datetime(2019, 5, 1)) - assert over < correct - assert under > correct - - -def test_sortino_loss_daily_prefers_higher_profits(default_conf, hyperopt_results) -> None: - results_over = hyperopt_results.copy() - results_over['profit_ratio'] = hyperopt_results['profit_ratio'] * 2 - results_under = hyperopt_results.copy() - results_under['profit_ratio'] = hyperopt_results['profit_ratio'] / 2 - - default_conf.update({'hyperopt_loss': 'SortinoHyperOptLossDaily'}) - hl = HyperOptLossResolver.load_hyperoptloss(default_conf) - correct = hl.hyperopt_loss_function(hyperopt_results, len(hyperopt_results), - datetime(2019, 1, 1), datetime(2019, 5, 1)) - over = hl.hyperopt_loss_function(results_over, len(hyperopt_results), - datetime(2019, 1, 1), datetime(2019, 5, 1)) - under = hl.hyperopt_loss_function(results_under, len(hyperopt_results), - datetime(2019, 1, 1), datetime(2019, 5, 1)) - assert over < correct - assert under > correct - - -def test_onlyprofit_loss_prefers_higher_profits(default_conf, hyperopt_results) -> None: +@pytest.mark.parametrize('lossfunction', [ + "OnlyProfitHyperOptLoss", + "SortinoHyperOptLoss", + "SortinoHyperOptLossDaily", + "SharpeHyperOptLoss", + "SharpeHyperOptLossDaily", +]) +def test_loss_functions_better_profits(default_conf, hyperopt_results, lossfunction) -> None: results_over = hyperopt_results.copy() results_over['profit_abs'] = hyperopt_results['profit_abs'] * 2 + results_over['profit_ratio'] = hyperopt_results['profit_ratio'] * 2 results_under = hyperopt_results.copy() results_under['profit_abs'] = hyperopt_results['profit_abs'] / 2 + results_under['profit_ratio'] = hyperopt_results['profit_ratio'] / 2 - default_conf.update({'hyperopt_loss': 'OnlyProfitHyperOptLoss'}) + default_conf.update({'hyperopt_loss': lossfunction}) hl = HyperOptLossResolver.load_hyperoptloss(default_conf) correct = hl.hyperopt_loss_function(hyperopt_results, len(hyperopt_results), datetime(2019, 1, 1), datetime(2019, 5, 1)) - over = hl.hyperopt_loss_function(results_over, len(hyperopt_results), + over = hl.hyperopt_loss_function(results_over, len(results_over), datetime(2019, 1, 1), datetime(2019, 5, 1)) - under = hl.hyperopt_loss_function(results_under, len(hyperopt_results), + under = hl.hyperopt_loss_function(results_under, len(results_under), datetime(2019, 1, 1), datetime(2019, 5, 1)) assert over < correct assert under > correct From 77388eb423f8867aa63860ace494dd85505dd416 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 2 Oct 2021 15:23:48 +0200 Subject: [PATCH 68/76] Improve generate_test_data to make it easier to use --- tests/optimize/conftest.py | 20 ++++++++++++++------ tests/strategy/test_strategy_helpers.py | 4 ++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/optimize/conftest.py b/tests/optimize/conftest.py index 690934b07..13d90b36f 100644 --- a/tests/optimize/conftest.py +++ b/tests/optimize/conftest.py @@ -39,17 +39,25 @@ def hyperopt(hyperopt_conf, mocker): def hyperopt_results(): return pd.DataFrame( { - 'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC', 'ETH/BTC'], + 'pair': ['ETH/USDT', 'ETH/USDT', 'ETH/USDT', 'ETH/USDT'], 'profit_ratio': [-0.1, 0.2, -0.1, 0.3], 'profit_abs': [-0.2, 0.4, -0.2, 0.6], 'trade_duration': [10, 30, 10, 10], + 'amount': [0.1, 0.1, 0.1, 0.1], 'sell_reason': [SellType.STOP_LOSS, SellType.ROI, SellType.STOP_LOSS, SellType.ROI], + 'open_date': + [ + datetime(2019, 1, 1, 9, 15, 0), + datetime(2019, 2, 1, 8, 55, 0), + datetime(2019, 3, 1, 9, 15, 0), + datetime(2019, 4, 1, 9, 15, 0), + ], 'close_date': [ - datetime(2019, 1, 1, 9, 26, 3, 478039), - datetime(2019, 2, 1, 9, 26, 3, 478039), - datetime(2019, 3, 1, 9, 26, 3, 478039), - datetime(2019, 4, 1, 9, 26, 3, 478039), - ] + datetime(2019, 1, 1, 9, 25, 0), + datetime(2019, 2, 1, 9, 25, 0), + datetime(2019, 3, 1, 9, 25, 0), + datetime(2019, 4, 1, 9, 25, 0), + ], } ) diff --git a/tests/strategy/test_strategy_helpers.py b/tests/strategy/test_strategy_helpers.py index a01b55050..cb7cf97a1 100644 --- a/tests/strategy/test_strategy_helpers.py +++ b/tests/strategy/test_strategy_helpers.py @@ -9,13 +9,13 @@ from freqtrade.strategy import (merge_informative_pair, stoploss_from_absolute, timeframe_to_minutes) -def generate_test_data(timeframe: str, size: int): +def generate_test_data(timeframe: str, size: int, start: str = '2020-07-05'): np.random.seed(42) tf_mins = timeframe_to_minutes(timeframe) base = np.random.normal(20, 2, size=size) - date = pd.period_range('2020-07-05', periods=size, freq=f'{tf_mins}min').to_timestamp() + date = pd.date_range(start, periods=size, freq=f'{tf_mins}min', tz='UTC') df = pd.DataFrame({ 'date': date, 'open': base, From 3b5cc5f01584329b3d9b0bd47cc71dbf97e8e3d1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 2 Oct 2021 15:36:51 +0200 Subject: [PATCH 69/76] Improve dates used for hyperopt tests --- tests/optimize/conftest.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/optimize/conftest.py b/tests/optimize/conftest.py index 13d90b36f..8c7fa3ac9 100644 --- a/tests/optimize/conftest.py +++ b/tests/optimize/conftest.py @@ -48,16 +48,16 @@ def hyperopt_results(): 'open_date': [ datetime(2019, 1, 1, 9, 15, 0), - datetime(2019, 2, 1, 8, 55, 0), - datetime(2019, 3, 1, 9, 15, 0), - datetime(2019, 4, 1, 9, 15, 0), + datetime(2019, 1, 2, 8, 55, 0), + datetime(2019, 1, 3, 9, 15, 0), + datetime(2019, 1, 4, 9, 15, 0), ], 'close_date': [ datetime(2019, 1, 1, 9, 25, 0), - datetime(2019, 2, 1, 9, 25, 0), - datetime(2019, 3, 1, 9, 25, 0), - datetime(2019, 4, 1, 9, 25, 0), + datetime(2019, 1, 2, 9, 25, 0), + datetime(2019, 1, 3, 9, 25, 0), + datetime(2019, 1, 4, 9, 25, 0), ], } ) From 057a187231bf5d90d0d2494d66934593d01133e8 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sat, 2 Oct 2021 20:32:51 -0600 Subject: [PATCH 70/76] Removed uneccessary TODOs --- tests/test_freqtradebot.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index c169d8597..f80ffeba2 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2581,7 +2581,6 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_ 'order_type': 'limit', 'open_rate': 2.0, 'current_rate': 2.3, - # TODO: Double check that profit_amount and profit_ratio are correct 'profit_amount': 0.9475, 'profit_ratio': 0.09451372, 'stake_currency': 'USDT', @@ -2624,7 +2623,6 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd assert rpc_mock.call_count == 2 last_msg = rpc_mock.call_args_list[-1][0][0] - # TODO: Should be a loss, but comes out as a gain assert { 'type': RPCMessageType.SELL, 'trade_id': 1, @@ -2751,7 +2749,6 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run( assert rpc_mock.call_count == 2 last_msg = rpc_mock.call_args_list[-1][0][0] - # TODO: Are these values correct? assert { 'type': RPCMessageType.SELL, 'trade_id': 1, @@ -3274,7 +3271,6 @@ def test_trailing_stop_loss(default_conf_usdt, limit_buy_order_usdt_open, caplog.set_level(logging.DEBUG) # Sell as trailing-stop is reached assert freqtrade.handle_trade(trade) is True - # TODO: Does this make sense? How is stoploss 2.7? assert log_has("ETH/USDT - HIT STOP: current price at 2.200000, stoploss is 2.700000, " "initial stoploss was at 1.800000, trade opened at 2.000000", caplog) assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value From 93679db7c4bc63d9c6541d90e36dd361e6b26568 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sat, 2 Oct 2021 20:33:46 -0600 Subject: [PATCH 71/76] Removed ... TODOs --- tests/test_freqtradebot.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index f80ffeba2..97f8e92c8 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2962,11 +2962,10 @@ def test_execute_trade_exit_market_order(default_conf_usdt, ticker_usdt, fee, sell_reason=SellCheckTuple(sell_type=SellType.ROI)) assert not trade.is_open - assert trade.close_profit == 0.09451372 # TODO: Check this is correct + assert trade.close_profit == 0.09451372 assert rpc_mock.call_count == 3 last_msg = rpc_mock.call_args_list[-1][0][0] - # TODO: Is this correct? assert { 'type': RPCMessageType.SELL, 'trade_id': 1, @@ -3330,7 +3329,6 @@ def test_trailing_stop_loss_positive( ) # stop-loss not reached, adjusted stoploss assert freqtrade.handle_trade(trade) is False - # TODO: is 0.0249% correct? Shouldn't it be higher? caplog_text = f"ETH/USDT - Using positive stoploss: 0.01 offset: {offset} profit: 0.0249%" if trail_if_reached: assert not log_has(caplog_text, caplog) From 908dee961d091b4ec9bb299d658011a557540c69 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sat, 2 Oct 2021 20:37:05 -0600 Subject: [PATCH 72/76] Changed test values in test_sell_profit_only to usdt like values --- tests/test_freqtradebot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 97f8e92c8..3f14c75c4 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3026,12 +3026,12 @@ def test_execute_trade_exit_insufficient_funds_error(default_conf_usdt, ticker_u # Enable profit (True, 1.9, 2.2, False, True, SellType.SELL_SIGNAL.value), # Disable profit - (False, 0.00002172, 0.00002173, True, False, SellType.SELL_SIGNAL.value), + (False, 2.9, 3.2, True, False, SellType.SELL_SIGNAL.value), # Enable loss # * Shouldn't this be SellType.STOP_LOSS.value - (True, 0.00000172, 0.00000173, False, False, None), + (True, 0.19, 0.22, False, False, None), # Disable loss - (False, 0.00000172, 0.00000173, True, False, SellType.SELL_SIGNAL.value), + (False, 0.10, 0.22, True, False, SellType.SELL_SIGNAL.value), ]) def test_sell_profit_only( default_conf_usdt, limit_buy_order_usdt, limit_buy_order_usdt_open, From 058c7b3e992971bf53f752309ff0dcc91cefe542 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sat, 2 Oct 2021 20:43:32 -0600 Subject: [PATCH 73/76] Fixed odd test_execute_entry where the filled coins were higher than the amount --- tests/test_freqtradebot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 3f14c75c4..b518c02ad 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -773,10 +773,10 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_buy_order_usdt, # In case of rejected or expired order and partially filled limit_buy_order_usdt['status'] = 'expired' limit_buy_order_usdt['amount'] = 30.0 - limit_buy_order_usdt['filled'] = 80.99181073 + limit_buy_order_usdt['filled'] = 20.0 limit_buy_order_usdt['remaining'] = 10.00 limit_buy_order_usdt['price'] = 0.5 - limit_buy_order_usdt['cost'] = 40.495905365 + limit_buy_order_usdt['cost'] = 15.0 limit_buy_order_usdt['id'] = '555' mocker.patch('freqtrade.exchange.Exchange.create_order', MagicMock(return_value=limit_buy_order_usdt)) @@ -785,7 +785,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_buy_order_usdt, assert trade assert trade.open_order_id == '555' assert trade.open_rate == 0.5 - assert trade.stake_amount == 40.495905365 + assert trade.stake_amount == 15.0 # Test with custom stake limit_buy_order_usdt['status'] = 'open' From 9e77a739fa18218de4d5efc89bd910a5ac7cdc02 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 3 Oct 2021 09:22:50 +0200 Subject: [PATCH 74/76] Change usdt stake_amount to 60$ --- tests/conftest.py | 2 +- tests/test_freqtradebot.py | 62 +++++++++++++++++++------------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 0e5e7c933..49534c88d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -376,7 +376,7 @@ def get_default_conf(testdatadir): def get_default_conf_usdt(testdatadir): configuration = get_default_conf(testdatadir) configuration.update({ - "stake_amount": 10.0, + "stake_amount": 60.0, "stake_currency": "USDT", "exchange": { "name": "binance", diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index b518c02ad..f57e35ca1 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -126,14 +126,14 @@ def test_get_trade_stake_amount(default_conf_usdt, mocker) -> None: @pytest.mark.parametrize("amend_last,wallet,max_open,lsamr,expected", [ - (False, 20, 2, 0.5, [10, None]), - (True, 20, 2, 0.5, [10, 9.8]), - (False, 30, 3, 0.5, [10, 10, None]), - (True, 30, 3, 0.5, [10, 10, 9.7]), - (False, 22, 3, 0.5, [10, 10, None]), - (True, 22, 3, 0.5, [10, 10, 0.0]), - (True, 27, 3, 0.5, [10, 10, 6.73]), - (True, 22, 3, 1, [10, 10, 0.0]), + (False, 120, 2, 0.5, [60, None]), + (True, 120, 2, 0.5, [60, 58.8]), + (False, 180, 3, 0.5, [60, 60, None]), + (True, 180, 3, 0.5, [60, 60, 58.2]), + (False, 122, 3, 0.5, [60, 60, None]), + (True, 122, 3, 0.5, [60, 60, 0.0]), + (True, 167, 3, 0.5, [60, 60, 45.33]), + (True, 122, 3, 1, [60, 60, 0.0]), ]) def test_check_available_stake_amount( default_conf_usdt, ticker_usdt, mocker, fee, limit_buy_order_usdt_open, @@ -256,7 +256,7 @@ def test_total_open_trades_stakes(mocker, default_conf_usdt, ticker_usdt, fee) - trade = Trade.query.first() assert trade is not None - assert trade.stake_amount == 10.0 + assert trade.stake_amount == 60.0 assert trade.is_open assert trade.open_date is not None @@ -264,11 +264,11 @@ def test_total_open_trades_stakes(mocker, default_conf_usdt, ticker_usdt, fee) - trade = Trade.query.order_by(Trade.id.desc()).first() assert trade is not None - assert trade.stake_amount == 10.0 + assert trade.stake_amount == 60.0 assert trade.is_open assert trade.open_date is not None - assert Trade.total_open_trades_stakes() == 20.0 + assert Trade.total_open_trades_stakes() == 120.0 def test_create_trade(default_conf_usdt, ticker_usdt, limit_buy_order_usdt, fee, mocker) -> None: @@ -289,7 +289,7 @@ def test_create_trade(default_conf_usdt, ticker_usdt, limit_buy_order_usdt, fee, trade = Trade.query.first() assert trade is not None - assert trade.stake_amount == 10.0 + assert trade.stake_amount == 60.0 assert trade.is_open assert trade.open_date is not None assert trade.exchange == 'binance' @@ -467,7 +467,7 @@ def test_create_trades_multiple_trades( patch_exchange(mocker) default_conf_usdt['max_open_trades'] = max_open default_conf_usdt['tradable_balance_ratio'] = tradable_balance_ratio - default_conf_usdt['dry_run_wallet'] = 10.0 * max_open + default_conf_usdt['dry_run_wallet'] = 60.0 * max_open mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -544,10 +544,10 @@ def test_process_trade_creation(default_conf_usdt, ticker_usdt, limit_buy_order_ assert trade.open_date is not None assert trade.exchange == 'binance' assert trade.open_rate == 2.0 - assert trade.amount == 5.0 + assert trade.amount == 30.0 assert log_has( - 'Buy signal found: about create a new trade for ETH/USDT with stake_amount: 10.0 ...', + 'Buy signal found: about create a new trade for ETH/USDT with stake_amount: 60.0 ...', caplog ) @@ -1265,7 +1265,7 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf_usdt, fee, cancel_order_mock.assert_called_once_with(100, 'ETH/USDT') stoploss_order_mock.assert_called_once_with( - amount=4.56621004, + amount=27.39726027, pair='ETH/USDT', order_types=freqtrade.strategy.order_types, stop_price=4.4 * 0.95 @@ -1457,7 +1457,7 @@ def test_handle_stoploss_on_exchange_custom_stop( cancel_order_mock.assert_called_once_with(100, 'ETH/USDT') stoploss_order_mock.assert_called_once_with( - amount=5.26315789, + amount=31.57894736, pair='ETH/USDT', order_types=freqtrade.strategy.order_types, stop_price=4.4 * 0.96 @@ -2577,11 +2577,11 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_ 'pair': 'ETH/USDT', 'gain': 'profit', 'limit': 2.2, - 'amount': 5.0, + 'amount': 30.0, 'order_type': 'limit', 'open_rate': 2.0, 'current_rate': 2.3, - 'profit_amount': 0.9475, + 'profit_amount': 5.685, 'profit_ratio': 0.09451372, 'stake_currency': 'USDT', 'fiat_currency': 'USD', @@ -2630,11 +2630,11 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd 'pair': 'ETH/USDT', 'gain': 'loss', 'limit': 2.01, - 'amount': 5.0, + 'amount': 30.0, 'order_type': 'limit', 'open_rate': 2.0, 'current_rate': 2.0, - 'profit_amount': -0.000125, + 'profit_amount': -0.00075, 'profit_ratio': -1.247e-05, 'stake_currency': 'USDT', 'fiat_currency': 'USD', @@ -2697,11 +2697,11 @@ def test_execute_trade_exit_custom_exit_price(default_conf_usdt, ticker_usdt, fe 'pair': 'ETH/USDT', 'gain': 'profit', 'limit': 2.25, - 'amount': 5.0, + 'amount': 30.0, 'order_type': 'limit', 'open_rate': 2.0, 'current_rate': 2.3, - 'profit_amount': 1.196875, + 'profit_amount': 7.18125, 'profit_ratio': 0.11938903, 'stake_currency': 'USDT', 'fiat_currency': 'USD', @@ -2756,11 +2756,11 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run( 'pair': 'ETH/USDT', 'gain': 'loss', 'limit': 1.98, - 'amount': 5.0, + 'amount': 30.0, 'order_type': 'limit', 'open_rate': 2.0, 'current_rate': 2.0, - 'profit_amount': -0.14975, + 'profit_amount': -0.8985, 'profit_ratio': -0.01493766, 'stake_currency': 'USDT', 'fiat_currency': 'USD', @@ -2973,11 +2973,11 @@ def test_execute_trade_exit_market_order(default_conf_usdt, ticker_usdt, fee, 'pair': 'ETH/USDT', 'gain': 'profit', 'limit': 2.2, - 'amount': 5.0, + 'amount': 30.0, 'order_type': 'market', 'open_rate': 2.0, 'current_rate': 2.3, - 'profit_amount': 0.9475, + 'profit_amount': 5.685, 'profit_ratio': 0.09451372, 'stake_currency': 'USDT', 'fiat_currency': 'USD', @@ -3742,7 +3742,7 @@ def test_order_book_depth_of_market( assert trade is None else: assert trade is not None - assert trade.stake_amount == 10.0 + assert trade.stake_amount == 60.0 assert trade.is_open assert trade.open_date is not None assert trade.exchange == 'binance' @@ -3891,7 +3891,7 @@ def test_sync_wallet_dry_run(mocker, default_conf_usdt, ticker_usdt, fee, limit_ caplog): default_conf_usdt['dry_run'] = True # Initialize to 2 times stake amount - default_conf_usdt['dry_run_wallet'] = 20.0 + default_conf_usdt['dry_run_wallet'] = 120.0 default_conf_usdt['max_open_trades'] = 2 default_conf_usdt['tradable_balance_ratio'] = 1.0 patch_exchange(mocker) @@ -3904,7 +3904,7 @@ def test_sync_wallet_dry_run(mocker, default_conf_usdt, ticker_usdt, fee, limit_ bot = get_patched_freqtradebot(mocker, default_conf_usdt) patch_get_signal(bot) - assert bot.wallets.get_free('USDT') == 20.0 + assert bot.wallets.get_free('USDT') == 120.0 n = bot.enter_positions() assert n == 2 @@ -3915,7 +3915,7 @@ def test_sync_wallet_dry_run(mocker, default_conf_usdt, ticker_usdt, fee, limit_ n = bot.enter_positions() assert n == 0 assert log_has_re(r"Unable to create trade for XRP/USDT: " - r"Available balance \(0.0 USDT\) is lower than stake amount \(10.0 USDT\)", + r"Available balance \(0.0 USDT\) is lower than stake amount \(60.0 USDT\)", caplog) From 126c29198888508c563536a8d5e6221d2bcb36e9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 3 Oct 2021 09:32:53 +0200 Subject: [PATCH 75/76] Improve docs closes #5654 --- docs/docker_quickstart.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docker_quickstart.md b/docs/docker_quickstart.md index 2f350d207..27a9091b1 100644 --- a/docs/docker_quickstart.md +++ b/docs/docker_quickstart.md @@ -109,6 +109,7 @@ All freqtrade arguments will be available by running `docker-compose run --rm fr !!! Warning "`docker-compose` for trade commands" Trade commands (`freqtrade trade <...>`) should not be ran via `docker-compose run` - but should use `docker-compose up -d` instead. This makes sure that the container is properly started (including port forwardings) and will make sure that the container will restart after a system reboot. + If you intend to use freqUI, please also ensure to adjust the [configuration accordingly](rest-api.md#configuration-with-docker), otherwise the UI will not be available. !!! Note "`docker-compose run --rm`" Including `--rm` will remove the container after completion, and is highly recommended for all modes except trading mode (running with `freqtrade trade` command). From dcb9ce95131e3a8f045d2e35298b47e72142a0e7 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sun, 3 Oct 2021 02:14:52 -0600 Subject: [PATCH 76/76] isort --- tests/conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/conftest.py b/tests/conftest.py index 86135c1a3..aa6a6b05e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -30,6 +30,7 @@ from tests.conftest_trades import (leverage_trade, mock_trade_1, mock_trade_2, m from tests.conftest_trades_usdt import (mock_trade_usdt_1, mock_trade_usdt_2, mock_trade_usdt_3, mock_trade_usdt_4, mock_trade_usdt_5, mock_trade_usdt_6) + logging.getLogger('').setLevel(logging.INFO)