Add exception handlers for orderbook logic
This commit is contained in:
		| @@ -18,7 +18,7 @@ from freqtrade.configuration import validate_config_consistency | |||||||
| from freqtrade.data.converter import order_book_to_dataframe | from freqtrade.data.converter import order_book_to_dataframe | ||||||
| from freqtrade.data.dataprovider import DataProvider | from freqtrade.data.dataprovider import DataProvider | ||||||
| from freqtrade.edge import Edge | from freqtrade.edge import Edge | ||||||
| from freqtrade.exceptions import DependencyException, InvalidOrderException | from freqtrade.exceptions import DependencyException, InvalidOrderException, PricingException | ||||||
| from freqtrade.exchange import timeframe_to_minutes, timeframe_to_next_date | from freqtrade.exchange import timeframe_to_minutes, timeframe_to_next_date | ||||||
| from freqtrade.misc import safe_value_fallback | from freqtrade.misc import safe_value_fallback | ||||||
| from freqtrade.pairlist.pairlistmanager import PairListManager | from freqtrade.pairlist.pairlistmanager import PairListManager | ||||||
| @@ -263,9 +263,16 @@ class FreqtradeBot: | |||||||
|             order_book = self.exchange.get_order_book(pair, order_book_top) |             order_book = self.exchange.get_order_book(pair, order_book_top) | ||||||
|             logger.debug('order_book %s', order_book) |             logger.debug('order_book %s', order_book) | ||||||
|             # top 1 = index 0 |             # top 1 = index 0 | ||||||
|             order_book_rate = order_book[f"{bid_strategy['price_side']}s"][order_book_top - 1][0] |             try: | ||||||
|             logger.info(f'...top {order_book_top} order book buy rate {order_book_rate:.8f}') |                 rate_from_l2 = order_book[f"{bid_strategy['price_side']}s"][order_book_top - 1][0] | ||||||
|             used_rate = order_book_rate |             except (IndexError, KeyError) as e: | ||||||
|  |                 logger.warning( | ||||||
|  |                     "Buy Price from orderbook could not be determined." | ||||||
|  |                     f"Orderbook: {order_book}" | ||||||
|  |                  ) | ||||||
|  |                 raise PricingException from e | ||||||
|  |             logger.info(f'...top {order_book_top} order book buy rate {rate_from_l2:.8f}') | ||||||
|  |             used_rate = rate_from_l2 | ||||||
|         else: |         else: | ||||||
|             logger.info(f"Using Last {bid_strategy['price_side'].capitalize()} / Last Price") |             logger.info(f"Using Last {bid_strategy['price_side'].capitalize()} / Last Price") | ||||||
|             ticker = self.exchange.fetch_ticker(pair) |             ticker = self.exchange.fetch_ticker(pair) | ||||||
| @@ -662,8 +669,13 @@ class FreqtradeBot: | |||||||
|             logger.info( |             logger.info( | ||||||
|                 f"Getting price from order book {ask_strategy['price_side'].capitalize()} side." |                 f"Getting price from order book {ask_strategy['price_side'].capitalize()} side." | ||||||
|             ) |             ) | ||||||
|             rate = next(self._order_book_gen(pair, f"{ask_strategy['price_side']}s")) |             try: | ||||||
|  |                 rate = next(self._order_book_gen(pair, f"{ask_strategy['price_side']}s")) | ||||||
|  |             except (IndexError, KeyError) as e: | ||||||
|  |                 logger.warning( | ||||||
|  |                     f"Sell Price at location from orderbook could not be determined." | ||||||
|  |                 ) | ||||||
|  |                 raise PricingException from e | ||||||
|         else: |         else: | ||||||
|             rate = self.exchange.fetch_ticker(pair)[ask_strategy['price_side']] |             rate = self.exchange.fetch_ticker(pair)[ask_strategy['price_side']] | ||||||
|         self._sell_rate_cache[pair] = rate |         self._sell_rate_cache[pair] = rate | ||||||
| @@ -690,16 +702,23 @@ class FreqtradeBot: | |||||||
|                 self.dataprovider.ohlcv(trade.pair, self.strategy.ticker_interval)) |                 self.dataprovider.ohlcv(trade.pair, self.strategy.ticker_interval)) | ||||||
|  |  | ||||||
|         if config_ask_strategy.get('use_order_book', False): |         if config_ask_strategy.get('use_order_book', False): | ||||||
|             logger.debug(f'Using order book for selling {trade.pair}...') |  | ||||||
|             # logger.debug('Order book %s',orderBook) |             # logger.debug('Order book %s',orderBook) | ||||||
|             order_book_min = config_ask_strategy.get('order_book_min', 1) |             order_book_min = config_ask_strategy.get('order_book_min', 1) | ||||||
|             order_book_max = config_ask_strategy.get('order_book_max', 1) |             order_book_max = config_ask_strategy.get('order_book_max', 1) | ||||||
|  |             logger.info(f'Using order book between {order_book_min} and {order_book_max} ' | ||||||
|  |                         f'for selling {trade.pair}...') | ||||||
|  |  | ||||||
|             order_book = self._order_book_gen(trade.pair, f"{config_ask_strategy['price_side']}s", |             order_book = self._order_book_gen(trade.pair, f"{config_ask_strategy['price_side']}s", | ||||||
|                                               order_book_min=order_book_min, |                                               order_book_min=order_book_min, | ||||||
|                                               order_book_max=order_book_max) |                                               order_book_max=order_book_max) | ||||||
|             for i in range(order_book_min, order_book_max + 1): |             for i in range(order_book_min, order_book_max + 1): | ||||||
|                 sell_rate = next(order_book) |                 try: | ||||||
|  |                     sell_rate = next(order_book) | ||||||
|  |                 except (IndexError, KeyError) as e: | ||||||
|  |                     logger.warning( | ||||||
|  |                         f"Sell Price at location {i} from orderbook could not be determined." | ||||||
|  |                     ) | ||||||
|  |                     raise PricingException from e | ||||||
|                 logger.debug(f"  order book {config_ask_strategy['price_side']} top {i}: " |                 logger.debug(f"  order book {config_ask_strategy['price_side']} top {i}: " | ||||||
|                              f"{sell_rate:0.8f}") |                              f"{sell_rate:0.8f}") | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,18 +11,21 @@ import arrow | |||||||
| import pytest | import pytest | ||||||
| import requests | import requests | ||||||
|  |  | ||||||
| from freqtrade.constants import MATH_CLOSE_PREC, UNLIMITED_STAKE_AMOUNT, CANCEL_REASON | from freqtrade.constants import (CANCEL_REASON, MATH_CLOSE_PREC, | ||||||
|  |                                  UNLIMITED_STAKE_AMOUNT) | ||||||
| from freqtrade.exceptions import (DependencyException, InvalidOrderException, | from freqtrade.exceptions import (DependencyException, InvalidOrderException, | ||||||
|                                   OperationalException, TemporaryError) |                                   OperationalException, PricingException, | ||||||
|  |                                   TemporaryError) | ||||||
| from freqtrade.freqtradebot import FreqtradeBot | from freqtrade.freqtradebot import FreqtradeBot | ||||||
| from freqtrade.persistence import Trade | from freqtrade.persistence import Trade | ||||||
| from freqtrade.rpc import RPCMessageType | from freqtrade.rpc import RPCMessageType | ||||||
| from freqtrade.state import RunMode, State | from freqtrade.state import RunMode, State | ||||||
| from freqtrade.strategy.interface import SellCheckTuple, SellType | from freqtrade.strategy.interface import SellCheckTuple, SellType | ||||||
| from freqtrade.worker import Worker | from freqtrade.worker import Worker | ||||||
| from tests.conftest import (get_patched_freqtradebot, get_patched_worker, | from tests.conftest import (create_mock_trades, get_patched_freqtradebot, | ||||||
|                             log_has, log_has_re, patch_edge, patch_exchange, |                             get_patched_worker, log_has, log_has_re, | ||||||
|                             patch_get_signal, patch_wallet, patch_whitelist, create_mock_trades) |                             patch_edge, patch_exchange, patch_get_signal, | ||||||
|  |                             patch_wallet, patch_whitelist) | ||||||
|  |  | ||||||
|  |  | ||||||
| def patch_RPCManager(mocker) -> MagicMock: | def patch_RPCManager(mocker) -> MagicMock: | ||||||
| @@ -3772,29 +3775,26 @@ def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2) -> None: | |||||||
|     assert ticker_mock.call_count == 0 |     assert ticker_mock.call_count == 0 | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2) -> None: | def test_order_book_bid_strategy_exception(mocker, default_conf, caplog) -> None: | ||||||
|     """ |  | ||||||
|     test if function get_buy_rate will return the ask rate (since its value is lower) |  | ||||||
|     instead of the order book rate (even if enabled) |  | ||||||
|     """ |  | ||||||
|     patch_exchange(mocker) |     patch_exchange(mocker) | ||||||
|     ticker_mock = MagicMock(return_value={'ask': 0.042, 'last': 0.046}) |     ticker_mock = MagicMock(return_value={'ask': 0.042, 'last': 0.046}) | ||||||
|     mocker.patch.multiple( |     mocker.patch.multiple( | ||||||
|         'freqtrade.exchange.Exchange', |         'freqtrade.exchange.Exchange', | ||||||
|         get_order_book=order_book_l2, |         get_order_book=MagicMock(return_value={'bids': [[]], 'asks': [[]]}), | ||||||
|         fetch_ticker=ticker_mock, |         fetch_ticker=ticker_mock, | ||||||
|  |  | ||||||
|     ) |     ) | ||||||
|     default_conf['exchange']['name'] = 'binance' |     default_conf['exchange']['name'] = 'binance' | ||||||
|     default_conf['bid_strategy']['use_order_book'] = True |     default_conf['bid_strategy']['use_order_book'] = True | ||||||
|     default_conf['bid_strategy']['order_book_top'] = 2 |     default_conf['bid_strategy']['order_book_top'] = 1 | ||||||
|     default_conf['bid_strategy']['ask_last_balance'] = 0 |     default_conf['bid_strategy']['ask_last_balance'] = 0 | ||||||
|     default_conf['telegram']['enabled'] = False |     default_conf['telegram']['enabled'] = False | ||||||
|  |  | ||||||
|     freqtrade = FreqtradeBot(default_conf) |     freqtrade = FreqtradeBot(default_conf) | ||||||
|     # orderbook shall be used even if tickers would be lower. |     # orderbook shall be used even if tickers would be lower. | ||||||
|     assert freqtrade.get_buy_rate('ETH/BTC', True) != 0.042 |     with pytest.raises(PricingException): | ||||||
|     assert ticker_mock.call_count == 0 |         freqtrade.get_buy_rate('ETH/BTC', refresh=True) | ||||||
|  |     assert log_has_re(r'Buy Price from orderbook could not be determined.', caplog) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2) -> None: | def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2) -> None: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user