diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index a502ad034..a36183162 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1114,7 +1114,8 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(e) from e - def get_rate(self, pair: str, refresh: bool, side: str) -> float: + def get_rate(self, pair: str, refresh: bool, side: str, + order_book: Optional[dict] = None, ticker: Optional[dict] = None) -> float: """ Calculates bid/ask target bid rate - between current ask price and last price @@ -1141,23 +1142,25 @@ class Exchange: if conf_strategy.get('use_order_book', False) and ('use_order_book' in conf_strategy): order_book_top = conf_strategy.get('order_book_top', 1) - order_book = self.fetch_l2_order_book(pair, order_book_top) + if order_book is None: + order_book = self.fetch_l2_order_book(pair, order_book_top) logger.debug('order_book %s', order_book) # top 1 = index 0 try: rate = order_book[f"{conf_strategy['price_side']}s"][order_book_top - 1][0] except (IndexError, KeyError) as e: logger.warning( - f"{name} Price at location {order_book_top} from orderbook could not be " - f"determined. Orderbook: {order_book}" + f"{pair} - {name} Price at location {order_book_top} from orderbook " + f"could not be determined. Orderbook: {order_book}" ) raise PricingError from e price_side = {conf_strategy['price_side'].capitalize()} - logger.debug(f"{name} price from orderbook {price_side}" + logger.debug(f"{pair} - {name} price from orderbook {price_side}" f"side - top {order_book_top} order book {side} rate {rate:.8f}") else: logger.debug(f"Using Last {conf_strategy['price_side'].capitalize()} / Last Price") - ticker = self.fetch_ticker(pair) + if ticker is None: + ticker = self.fetch_ticker(pair) ticker_rate = ticker[conf_strategy['price_side']] if ticker['last'] and ticker_rate: if side == 'buy' and ticker_rate > ticker['last']: @@ -1174,6 +1177,28 @@ class Exchange: return rate + def get_rates(self, pair: str, refresh: bool) -> Tuple[float, float]: + buy_rate = sell_rate = None + if not refresh: + buy_rate, sell_rate = self._buy_rate_cache.get(pair), self._sell_rate_cache.get(pair) + + bid_strategy = self._config.get('bid_strategy', {}) + ask_strategy = self._config.get('ask_strategy', {}) + order_book = ticker = None + if bid_strategy.get('use_order_book', False) and ('use_order_book' in bid_strategy): + order_book_top = max(bid_strategy.get('order_book_top', 1), + ask_strategy.get('order_book_top', 1)) + order_book = self.fetch_l2_order_book(pair, order_book_top) + if not buy_rate: + buy_rate = self.get_rate(pair, refresh, 'buy', order_book=order_book) + else: + ticker = self.fetch_ticker(pair) + if not buy_rate: + buy_rate = self.get_rate(pair, refresh, 'buy', ticker=ticker) + if not sell_rate: + sell_rate = self.get_rate(pair, refresh, 'sell', order_book=order_book, ticker=ticker) + return buy_rate, sell_rate + # Fee handling @retrier diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 0d0b7e56d..a92bc4a90 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -452,8 +452,7 @@ class FreqtradeBot(LoggingMixin): If the strategy triggers the adjustment, a new order gets issued. Once that completes, the existing trade is modified to match new data. """ - current_entry_rate = self.exchange.get_rate(trade.pair, refresh=True, side="buy") - current_exit_rate = current_entry_rate + current_entry_rate, current_exit_rate = self.exchange.get_rates(trade.pair, True) current_rate = current_entry_rate # backward compatibilty current_profit = trade.calc_profit_ratio(current_rate) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index ff8383997..61fd55e49 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2055,7 +2055,7 @@ def test_get_sell_rate_orderbook_exception(default_conf, mocker, caplog): exchange = get_patched_exchange(mocker, default_conf) with pytest.raises(PricingError): exchange.get_rate(pair, refresh=True, side="sell") - assert log_has_re(r"Sell Price at location 1 from orderbook could not be determined\..*", + assert log_has_re(rf"{pair} - Sell Price at location 1 from orderbook could not be determined\..*", caplog) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 65e364113..666767c13 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3961,7 +3961,7 @@ def test_order_book_bid_strategy1(mocker, default_conf_usdt, order_book_l2, exce with pytest.raises(PricingError): 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) + r'ETH/USDT - Buy Price at location 1 from orderbook could not be determined.', caplog) else: assert freqtrade.exchange.get_rate('ETH/USDT', refresh=True, side="buy") == 0.043935 assert ticker_usdt_mock.call_count == 0 @@ -4035,8 +4035,10 @@ def test_order_book_ask_strategy( return_value={'bids': [[]], 'asks': [[]]}) with pytest.raises(PricingError): freqtrade.handle_trade(trade) - assert log_has_re(r'Sell Price at location 1 from orderbook could not be determined\..*', - caplog) + pair = limit_buy_order_usdt['symbol'] + assert log_has_re( + rf"{pair} - Sell Price at location 1 from orderbook could not be determined\..*", + caplog) def test_startup_state(default_conf_usdt, mocker):