Use kwarg for rounding_mode, update tests with additional parameter
This commit is contained in:
parent
d0d0cbe1d1
commit
0cb28f3d82
@ -731,14 +731,14 @@ class Exchange:
|
|||||||
"""
|
"""
|
||||||
return amount_to_precision(amount, self.get_precision_amount(pair), self.precisionMode)
|
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.
|
Returns the price rounded to the precision the Exchange accepts.
|
||||||
The default price_rounding_mode in conf is ROUND.
|
The default price_rounding_mode in conf is ROUND.
|
||||||
For stoploss calculations, must use ROUND_UP for longs, and ROUND_DOWN for shorts.
|
For stoploss calculations, must use ROUND_UP for longs, and ROUND_DOWN for shorts.
|
||||||
"""
|
"""
|
||||||
return price_to_precision(price, self.get_precision_price(pair),
|
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:
|
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')
|
user_order_type = order_types.get('stoploss', 'market')
|
||||||
ordertype, user_order_type = self._get_stop_order_type(user_order_type)
|
ordertype, user_order_type = self._get_stop_order_type(user_order_type)
|
||||||
round_mode = ROUND_DOWN if side == 'buy' else ROUND_UP
|
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
|
limit_rate = None
|
||||||
if user_order_type == 'limit':
|
if user_order_type == 'limit':
|
||||||
limit_rate = self._get_stop_limit_rate(stop_price, order_types, side)
|
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']:
|
if self._config['dry_run']:
|
||||||
dry_order = self.create_dry_run_order(
|
dry_order = self.create_dry_run_order(
|
||||||
|
@ -224,6 +224,7 @@ def price_to_precision(
|
|||||||
price: float,
|
price: float,
|
||||||
price_precision: Optional[float],
|
price_precision: Optional[float],
|
||||||
precisionMode: Optional[int],
|
precisionMode: Optional[int],
|
||||||
|
*,
|
||||||
rounding_mode: int = ROUND,
|
rounding_mode: int = ROUND,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""
|
"""
|
||||||
|
@ -118,11 +118,11 @@ class Kraken(Exchange):
|
|||||||
limit_rate = stop_price * limit_price_pct
|
limit_rate = stop_price * limit_price_pct
|
||||||
else:
|
else:
|
||||||
limit_rate = stop_price * (2 - limit_price_pct)
|
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:
|
else:
|
||||||
ordertype = "stop-loss"
|
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']:
|
if self._config['dry_run']:
|
||||||
dry_order = self.create_dry_run_order(
|
dry_order = self.create_dry_run_order(
|
||||||
|
@ -1232,7 +1232,8 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
stoploss_norm = self.exchange.price_to_precision(
|
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):
|
if self.exchange.stoploss_adjust(stoploss_norm, order, side=trade.exit_side):
|
||||||
# we check if the update is necessary
|
# we check if the update is necessary
|
||||||
|
@ -599,7 +599,7 @@ class LocalTrade():
|
|||||||
Method used internally to set self.stop_loss.
|
Method used internally to set self.stop_loss.
|
||||||
"""
|
"""
|
||||||
stop_loss_norm = price_to_precision(stop_loss, self.price_precision, self.precision_mode,
|
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:
|
if not self.stop_loss:
|
||||||
self.initial_stop_loss = stop_loss_norm
|
self.initial_stop_loss = stop_loss_norm
|
||||||
self.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:
|
if self.initial_stop_loss_pct is None or refresh:
|
||||||
self.__set_stop_loss(new_loss, stoploss)
|
self.__set_stop_loss(new_loss, stoploss)
|
||||||
self.initial_stop_loss = price_to_precision(
|
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)
|
self.initial_stop_loss_pct = -1 * abs(stoploss)
|
||||||
|
|
||||||
# evaluate if the stop loss needs to be updated
|
# evaluate if the stop loss needs to be updated
|
||||||
|
@ -6,6 +6,7 @@ from typing import Any, Dict, Optional
|
|||||||
|
|
||||||
from freqtrade.constants import Config
|
from freqtrade.constants import Config
|
||||||
from freqtrade.exceptions import OperationalException
|
from freqtrade.exceptions import OperationalException
|
||||||
|
from freqtrade.exchange import ROUND_UP
|
||||||
from freqtrade.exchange.types import Ticker
|
from freqtrade.exchange.types import Ticker
|
||||||
from freqtrade.plugins.pairlist.IPairList import IPairList
|
from freqtrade.plugins.pairlist.IPairList import IPairList
|
||||||
|
|
||||||
@ -61,9 +62,10 @@ class PrecisionFilter(IPairList):
|
|||||||
stop_price = ticker['last'] * self._stoploss
|
stop_price = ticker['last'] * self._stoploss
|
||||||
|
|
||||||
# Adjust stop-prices to precision
|
# 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}")
|
logger.debug(f"{pair} - {sp} : {stop_gap_price}")
|
||||||
|
|
||||||
if sp <= stop_gap_price:
|
if sp <= stop_gap_price:
|
||||||
|
@ -48,7 +48,7 @@ def test_create_stoploss_order_binance(default_conf, mocker, limitratio, expecte
|
|||||||
default_conf['margin_mode'] = MarginMode.ISOLATED
|
default_conf['margin_mode'] = MarginMode.ISOLATED
|
||||||
default_conf['trading_mode'] = trademode
|
default_conf['trading_mode'] = trademode
|
||||||
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
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')
|
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'
|
order_type = 'stop_loss_limit'
|
||||||
default_conf['dry_run'] = True
|
default_conf['dry_run'] = True
|
||||||
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
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')
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
|
||||||
|
|
||||||
|
@ -353,7 +353,8 @@ def test_amount_to_precision(amount, precision_mode, precision, expected,):
|
|||||||
(234.26, TICK_SIZE, 0.5, 234.5, ROUND),
|
(234.26, TICK_SIZE, 0.5, 234.5, ROUND),
|
||||||
])
|
])
|
||||||
def test_price_to_precision(price, precision_mode, precision, expected, rounding_mode):
|
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", [
|
@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
|
default_conf['dry_run'] = False
|
||||||
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
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_patched_exchange(mocker, default_conf, api_mock)
|
||||||
exchange.get_contract_size = MagicMock(return_value=contract_size)
|
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)
|
conf = copy.deepcopy(default_conf)
|
||||||
patched_ex = get_patched_exchange(mocker, conf)
|
patched_ex = get_patched_exchange(mocker, conf)
|
||||||
prec_price = patched_ex.price_to_precision("XRP/USDT", 1.0000000101)
|
prec_price = patched_ex.price_to_precision("XRP/USDT", 1.0000000101)
|
||||||
assert prec_price == 1.00000002
|
assert prec_price == 1.00000001
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ def test_create_stoploss_order_huobi(default_conf, mocker, limitratio, expected,
|
|||||||
})
|
})
|
||||||
default_conf['dry_run'] = False
|
default_conf['dry_run'] = False
|
||||||
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
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')
|
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'
|
order_type = 'stop-limit'
|
||||||
default_conf['dry_run'] = True
|
default_conf['dry_run'] = True
|
||||||
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
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')
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'huobi')
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ def test_buy_kraken_trading_agreement(default_conf, mocker):
|
|||||||
default_conf['dry_run'] = False
|
default_conf['dry_run'] = False
|
||||||
|
|
||||||
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
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")
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kraken")
|
||||||
|
|
||||||
order = exchange.create_order(
|
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
|
default_conf['dry_run'] = False
|
||||||
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
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')
|
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()
|
api_mock = MagicMock()
|
||||||
default_conf['dry_run'] = True
|
default_conf['dry_run'] = True
|
||||||
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
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')
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kraken')
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ def test_create_stoploss_order_kucoin(default_conf, mocker, limitratio, expected
|
|||||||
})
|
})
|
||||||
default_conf['dry_run'] = False
|
default_conf['dry_run'] = False
|
||||||
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
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')
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kucoin')
|
||||||
if order_type == 'limit':
|
if order_type == 'limit':
|
||||||
@ -88,7 +88,7 @@ def test_stoploss_order_dry_run_kucoin(default_conf, mocker):
|
|||||||
order_type = 'market'
|
order_type = 'market'
|
||||||
default_conf['dry_run'] = True
|
default_conf['dry_run'] = True
|
||||||
mocker.patch(f'{EXMS}.amount_to_precision', lambda s, x, y: y)
|
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')
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kucoin')
|
||||||
|
|
||||||
|
@ -1602,7 +1602,7 @@ def test_stoploss_on_exchange_price_rounding(
|
|||||||
EXMS,
|
EXMS,
|
||||||
get_fee=fee,
|
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'})
|
stoploss_mock = MagicMock(return_value={'id': '13434334'})
|
||||||
adjust_mock = MagicMock(return_value=False)
|
adjust_mock = MagicMock(return_value=False)
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
|
Loading…
Reference in New Issue
Block a user