Add exception handlers for orderbook logic

This commit is contained in:
Matthias 2020-05-26 20:14:05 +02:00
parent 76e4e5897f
commit 7a7b26e840
2 changed files with 41 additions and 22 deletions

View File

@ -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}")

View File

@ -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: