diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 24d3d97f7..ea0896aa1 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -731,14 +731,14 @@ class Exchange: """ return amount_to_precision(amount, self.get_precision_amount(pair), self.precisionMode) - def price_to_precision(self, pair: str, price: float, rounding_mode: int = ROUND) -> float: + def price_to_precision(self, pair: str, price: float, *, rounding_mode: int = ROUND) -> float: """ Returns the price rounded to the precision the Exchange accepts. The default price_rounding_mode in conf is ROUND. For stoploss calculations, must use ROUND_UP for longs, and ROUND_DOWN for shorts. """ return price_to_precision(price, self.get_precision_price(pair), - self.precisionMode, rounding_mode) + self.precisionMode, rounding_mode=rounding_mode) def price_get_one_pip(self, pair: str, price: float) -> float: """ @@ -1179,11 +1179,11 @@ class Exchange: user_order_type = order_types.get('stoploss', 'market') ordertype, user_order_type = self._get_stop_order_type(user_order_type) round_mode = ROUND_DOWN if side == 'buy' else ROUND_UP - stop_price_norm = self.price_to_precision(pair, stop_price, round_mode) + stop_price_norm = self.price_to_precision(pair, stop_price, rounding_mode=round_mode) limit_rate = None if user_order_type == 'limit': limit_rate = self._get_stop_limit_rate(stop_price, order_types, side) - limit_rate = self.price_to_precision(pair, limit_rate, round_mode) + limit_rate = self.price_to_precision(pair, limit_rate, rounding_mode=round_mode) if self._config['dry_run']: dry_order = self.create_dry_run_order( diff --git a/freqtrade/exchange/exchange_utils.py b/freqtrade/exchange/exchange_utils.py index 8d6bb3838..83d2a214d 100644 --- a/freqtrade/exchange/exchange_utils.py +++ b/freqtrade/exchange/exchange_utils.py @@ -224,6 +224,7 @@ def price_to_precision( price: float, price_precision: Optional[float], precisionMode: Optional[int], + *, rounding_mode: int = ROUND, ) -> float: """ diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index e2bcd9a90..c41bb6d56 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -118,11 +118,11 @@ class Kraken(Exchange): limit_rate = stop_price * limit_price_pct else: limit_rate = stop_price * (2 - limit_price_pct) - params['price2'] = self.price_to_precision(pair, limit_rate, round_mode) + params['price2'] = self.price_to_precision(pair, limit_rate, rounding_mode=round_mode) else: ordertype = "stop-loss" - stop_price = self.price_to_precision(pair, stop_price, round_mode) + stop_price = self.price_to_precision(pair, stop_price, rounding_mode=round_mode) if self._config['dry_run']: dry_order = self.create_dry_run_order( diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index da56e9a39..ee4286c33 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1232,7 +1232,8 @@ class FreqtradeBot(LoggingMixin): :return: None """ stoploss_norm = self.exchange.price_to_precision( - trade.pair, trade.stoploss_or_liquidation, ROUND_DOWN if trade.is_short else ROUND_UP) + trade.pair, trade.stoploss_or_liquidation, + rounding_mode=ROUND_DOWN if trade.is_short else ROUND_UP) if self.exchange.stoploss_adjust(stoploss_norm, order, side=trade.exit_side): # we check if the update is necessary diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index c9fdf745b..e20a2b477 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -599,7 +599,7 @@ class LocalTrade(): Method used internally to set self.stop_loss. """ stop_loss_norm = price_to_precision(stop_loss, self.price_precision, self.precision_mode, - ROUND_DOWN if self.is_short else ROUND_UP) + rounding_mode=ROUND_DOWN if self.is_short else ROUND_UP) if not self.stop_loss: self.initial_stop_loss = stop_loss_norm self.stop_loss = stop_loss_norm @@ -630,7 +630,8 @@ class LocalTrade(): if self.initial_stop_loss_pct is None or refresh: self.__set_stop_loss(new_loss, stoploss) self.initial_stop_loss = price_to_precision( - new_loss, self.price_precision, self.precision_mode) + new_loss, self.price_precision, self.precision_mode, + rounding_mode=ROUND_DOWN if self.is_short else ROUND_UP) self.initial_stop_loss_pct = -1 * abs(stoploss) # evaluate if the stop loss needs to be updated diff --git a/freqtrade/plugins/pairlist/PrecisionFilter.py b/freqtrade/plugins/pairlist/PrecisionFilter.py index 478eaec20..2e74aa293 100644 --- a/freqtrade/plugins/pairlist/PrecisionFilter.py +++ b/freqtrade/plugins/pairlist/PrecisionFilter.py @@ -6,6 +6,7 @@ from typing import Any, Dict, Optional from freqtrade.constants import Config from freqtrade.exceptions import OperationalException +from freqtrade.exchange import ROUND_UP from freqtrade.exchange.types import Ticker from freqtrade.plugins.pairlist.IPairList import IPairList @@ -61,9 +62,10 @@ class PrecisionFilter(IPairList): stop_price = ticker['last'] * self._stoploss # Adjust stop-prices to precision - sp = self._exchange.price_to_precision(pair, stop_price) + sp = self._exchange.price_to_precision(pair, stop_price, rounding_mode=ROUND_UP) - stop_gap_price = self._exchange.price_to_precision(pair, stop_price * 0.99) + stop_gap_price = self._exchange.price_to_precision(pair, stop_price * 0.99, + rounding_mode=ROUND_UP) logger.debug(f"{pair} - {sp} : {stop_gap_price}") if sp <= stop_gap_price: diff --git a/tests/exchange/test_binance.py b/tests/exchange/test_binance.py index 273860e15..eaec3d70f 100644 --- a/tests/exchange/test_binance.py +++ b/tests/exchange/test_binance.py @@ -48,7 +48,7 @@ def test_create_stoploss_order_binance(default_conf, mocker, limitratio, expecte default_conf['margin_mode'] = MarginMode.ISOLATED default_conf['trading_mode'] = trademode mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y) - mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y) + mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y, **kwargs: y) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance') @@ -127,7 +127,7 @@ def test_create_stoploss_order_dry_run_binance(default_conf, mocker): order_type = 'stop_loss_limit' default_conf['dry_run'] = True mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y) - mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y) + mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y, **kwargs: y) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance') diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index a6138f6db..9aa04ff1f 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -353,7 +353,8 @@ def test_amount_to_precision(amount, precision_mode, precision, expected,): (234.26, TICK_SIZE, 0.5, 234.5, ROUND), ]) def test_price_to_precision(price, precision_mode, precision, expected, rounding_mode): - assert price_to_precision(price, precision, precision_mode, rounding_mode) == expected + assert price_to_precision( + price, precision, precision_mode, rounding_mode=rounding_mode) == expected @pytest.mark.parametrize("price,precision_mode,precision,expected", [ @@ -5277,7 +5278,7 @@ def test_stoploss_contract_size(mocker, default_conf, contract_size, order_amoun }) default_conf['dry_run'] = False mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y) - mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y) + mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y, **kwargs: y) exchange = get_patched_exchange(mocker, default_conf, api_mock) exchange.get_contract_size = MagicMock(return_value=contract_size) @@ -5303,5 +5304,5 @@ def test_price_to_precision_with_default_conf(default_conf, mocker): conf = copy.deepcopy(default_conf) patched_ex = get_patched_exchange(mocker, conf) prec_price = patched_ex.price_to_precision("XRP/USDT", 1.0000000101) - assert prec_price == 1.00000002 + assert prec_price == 1.00000001 diff --git a/tests/exchange/test_huobi.py b/tests/exchange/test_huobi.py index 85d2ced9d..8be8ef8b3 100644 --- a/tests/exchange/test_huobi.py +++ b/tests/exchange/test_huobi.py @@ -27,7 +27,7 @@ def test_create_stoploss_order_huobi(default_conf, mocker, limitratio, expected, }) default_conf['dry_run'] = False mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y) - mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y) + mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y, **kwargs: y) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'huobi') @@ -80,7 +80,7 @@ def test_create_stoploss_order_dry_run_huobi(default_conf, mocker): order_type = 'stop-limit' default_conf['dry_run'] = True mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y) - mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y) + mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y, **kwargs: y) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'huobi') diff --git a/tests/exchange/test_kraken.py b/tests/exchange/test_kraken.py index 40a5a5b38..8fc23b94e 100644 --- a/tests/exchange/test_kraken.py +++ b/tests/exchange/test_kraken.py @@ -29,7 +29,7 @@ def test_buy_kraken_trading_agreement(default_conf, mocker): default_conf['dry_run'] = False mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y) - mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y) + mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y, **kwargs: y) exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kraken") order = exchange.create_order( @@ -192,7 +192,7 @@ def test_create_stoploss_order_kraken(default_conf, mocker, ordertype, side, adj default_conf['dry_run'] = False mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y) - mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y) + mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y, **kwargs: y) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kraken') @@ -263,7 +263,7 @@ def test_create_stoploss_order_dry_run_kraken(default_conf, mocker, side): api_mock = MagicMock() default_conf['dry_run'] = True mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y) - mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y) + mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y, **kwargs: y) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kraken') diff --git a/tests/exchange/test_kucoin.py b/tests/exchange/test_kucoin.py index 07f3fb6a3..741ee27be 100644 --- a/tests/exchange/test_kucoin.py +++ b/tests/exchange/test_kucoin.py @@ -27,7 +27,7 @@ def test_create_stoploss_order_kucoin(default_conf, mocker, limitratio, expected }) default_conf['dry_run'] = False mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y) - mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y) + mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y, **kwargs: y) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kucoin') if order_type == 'limit': @@ -88,7 +88,7 @@ def test_stoploss_order_dry_run_kucoin(default_conf, mocker): order_type = 'market' default_conf['dry_run'] = True mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y) - mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y: y) + mocker.patch(f'{EXMS}.price_to_precision', lambda s, x, y, **kwargs: y) exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kucoin') diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index ff10cd2f0..5b4335652 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1602,7 +1602,7 @@ def test_stoploss_on_exchange_price_rounding( EXMS, get_fee=fee, ) - price_mock = MagicMock(side_effect=lambda p, s: int(s)) + price_mock = MagicMock(side_effect=lambda p, s, **kwargs: int(s)) stoploss_mock = MagicMock(return_value={'id': '13434334'}) adjust_mock = MagicMock(return_value=False) mocker.patch.multiple(