From 62dcebee46d4b8f84e7b3b168066c87cdead0963 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 4 Mar 2022 07:07:34 +0100 Subject: [PATCH] Update stoploss method to new functionality --- freqtrade/exchange/exchange.py | 30 +++++++++++++++++++++--------- freqtrade/exchange/huobi.py | 2 +- freqtrade/exchange/kucoin.py | 2 +- tests/exchange/test_huobi.py | 6 +++--- tests/exchange/test_kucoin.py | 6 +++--- 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 39d62b1d1..70bc4a1d1 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1008,6 +1008,17 @@ class Exchange: """ raise OperationalException(f"stoploss is not implemented for {self.name}.") + def _get_stop_order_type(self, user_order_type) -> Tuple[str, str]: + + available_order_Types: Dict[str, str] = self._ft_has["stoploss_order_types"] + if user_order_type in available_order_Types.keys(): + ordertype = available_order_Types[user_order_type] + else: + # Otherwise pick only one available + ordertype = list(available_order_Types.values())[0] + user_order_type = list(available_order_Types.keys())[0] + return ordertype, user_order_type + def _get_stop_params(self, ordertype: str, stop_price: float) -> Dict: params = self._params.copy() # Verify if stopPrice works for your exchange! @@ -1015,7 +1026,8 @@ class Exchange: return params @retrier(retries=0) - def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict, side: str, leverage: float) -> Dict: + def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict, + side: str, leverage: float) -> Dict: """ creates a stoploss order. requires `_ft_has['stoploss_order_types']` to be set as a dict mapping limit and market @@ -1035,22 +1047,22 @@ class Exchange: raise OperationalException(f"stoploss is not implemented for {self.name}.") user_order_type = order_types.get('stoploss', 'market') - if user_order_type in self._ft_has["stoploss_order_types"].keys(): - ordertype = self._ft_has["stoploss_order_types"][user_order_type] - else: - # Otherwise pick only one available - ordertype = list(self._ft_has["stoploss_order_types"].values())[0] - user_order_type = list(self._ft_has["stoploss_order_types"].keys())[0] + ordertype, user_order_type = self._get_stop_order_type(user_order_type) stop_price_norm = self.price_to_precision(pair, stop_price) rate = None if user_order_type == 'limit': # Limit price threshold: As limit price should always be below stop-price limit_price_pct = order_types.get('stoploss_on_exchange_limit_ratio', 0.99) - rate = stop_price * limit_price_pct + if side == "sell": + # TODO: Name limit_rate in other exchange subclasses + rate = stop_price * limit_price_pct + else: + rate = stop_price * (2 - limit_price_pct) + bad_stop_price = (stop_price <= rate) if side == "sell" else (stop_price >= rate) # Ensure rate is less than stop price - if stop_price_norm <= rate: + if bad_stop_price: raise OperationalException( 'In stoploss limit order, stop price should be more than limit price') rate = self.price_to_precision(pair, rate) diff --git a/freqtrade/exchange/huobi.py b/freqtrade/exchange/huobi.py index d07e13497..71c4d1cf6 100644 --- a/freqtrade/exchange/huobi.py +++ b/freqtrade/exchange/huobi.py @@ -22,7 +22,7 @@ class Huobi(Exchange): "l2_limit_range_required": False, } - def stoploss_adjust(self, stop_loss: float, order: Dict) -> bool: + def stoploss_adjust(self, stop_loss: float, order: Dict, side: str) -> bool: """ Verify stop_loss against stoploss-order value (limit or price) Returns True if adjustment is necessary. diff --git a/freqtrade/exchange/kucoin.py b/freqtrade/exchange/kucoin.py index e55f49cce..59ddc435c 100644 --- a/freqtrade/exchange/kucoin.py +++ b/freqtrade/exchange/kucoin.py @@ -27,7 +27,7 @@ class Kucoin(Exchange): "time_in_force_parameter": "timeInForce", } - def stoploss_adjust(self, stop_loss: float, order: Dict) -> bool: + def stoploss_adjust(self, stop_loss: float, order: Dict, side: str) -> bool: """ Verify stop_loss against stoploss-order value (limit or price) Returns True if adjustment is necessary. diff --git a/tests/exchange/test_huobi.py b/tests/exchange/test_huobi.py index 31dc88e01..fc7c7cefb 100644 --- a/tests/exchange/test_huobi.py +++ b/tests/exchange/test_huobi.py @@ -110,8 +110,8 @@ def test_stoploss_adjust_huobi(mocker, default_conf): 'price': 1500, 'stopPrice': '1500', } - assert exchange.stoploss_adjust(1501, order) - assert not exchange.stoploss_adjust(1499, order) + assert exchange.stoploss_adjust(1501, order, 'sell') + assert not exchange.stoploss_adjust(1499, order, 'sell') # Test with invalid order case order['type'] = 'stop_loss' - assert not exchange.stoploss_adjust(1501, order) + assert not exchange.stoploss_adjust(1501, order, 'sell') diff --git a/tests/exchange/test_kucoin.py b/tests/exchange/test_kucoin.py index 527d85029..8af1e83a3 100644 --- a/tests/exchange/test_kucoin.py +++ b/tests/exchange/test_kucoin.py @@ -120,8 +120,8 @@ def test_stoploss_adjust_kucoin(mocker, default_conf): 'stopPrice': 1500, 'info': {'stopPrice': 1500, 'stop': "limit"}, } - assert exchange.stoploss_adjust(1501, order) - assert not exchange.stoploss_adjust(1499, order) + assert exchange.stoploss_adjust(1501, order, 'sell') + assert not exchange.stoploss_adjust(1499, order, 'sell') # Test with invalid order case order['info']['stop'] = None - assert not exchange.stoploss_adjust(1501, order) + assert not exchange.stoploss_adjust(1501, order, 'sell')