Merge pull request #3381 from freqtrade/fix/orderbook_keyerror
Fix orderbook keyerror
This commit is contained in:
commit
a0556689ea
@ -110,12 +110,13 @@ class DataProvider:
|
|||||||
|
|
||||||
def orderbook(self, pair: str, maximum: int) -> Dict[str, List]:
|
def orderbook(self, pair: str, maximum: int) -> Dict[str, List]:
|
||||||
"""
|
"""
|
||||||
fetch latest orderbook data
|
Fetch latest l2 orderbook data
|
||||||
|
Warning: Does a network request - so use with common sense.
|
||||||
:param pair: pair to get the data for
|
:param pair: pair to get the data for
|
||||||
:param maximum: Maximum number of orderbook entries to query
|
:param maximum: Maximum number of orderbook entries to query
|
||||||
:return: dict including bids/asks with a total of `maximum` entries.
|
:return: dict including bids/asks with a total of `maximum` entries.
|
||||||
"""
|
"""
|
||||||
return self._exchange.get_order_book(pair, maximum)
|
return self._exchange.fetch_l2_order_book(pair, maximum)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def runmode(self) -> RunMode:
|
def runmode(self) -> RunMode:
|
||||||
|
@ -21,6 +21,14 @@ class DependencyException(FreqtradeException):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class PricingError(DependencyException):
|
||||||
|
"""
|
||||||
|
Subclass of DependencyException.
|
||||||
|
Indicates that the price could not be determined.
|
||||||
|
Implicitly a buy / sell operation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class InvalidOrderException(FreqtradeException):
|
class InvalidOrderException(FreqtradeException):
|
||||||
"""
|
"""
|
||||||
This is returned when the order is not valid. Example:
|
This is returned when the order is not valid. Example:
|
||||||
|
@ -20,7 +20,7 @@ class Binance(Exchange):
|
|||||||
"trades_pagination_arg": "fromId",
|
"trades_pagination_arg": "fromId",
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_order_book(self, pair: str, limit: int = 100) -> dict:
|
def fetch_l2_order_book(self, pair: str, limit: int = 100) -> dict:
|
||||||
"""
|
"""
|
||||||
get order book level 2 from exchange
|
get order book level 2 from exchange
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ class Binance(Exchange):
|
|||||||
# get next-higher step in the limit_range list
|
# get next-higher step in the limit_range list
|
||||||
limit = min(list(filter(lambda x: limit <= x, limit_range)))
|
limit = min(list(filter(lambda x: limit <= x, limit_range)))
|
||||||
|
|
||||||
return super().get_order_book(pair, limit)
|
return super().fetch_l2_order_book(pair, limit)
|
||||||
|
|
||||||
def stoploss_adjust(self, stop_loss: float, order: Dict) -> bool:
|
def stoploss_adjust(self, stop_loss: float, order: Dict) -> bool:
|
||||||
"""
|
"""
|
||||||
|
@ -998,7 +998,7 @@ class Exchange:
|
|||||||
raise OperationalException(e) from e
|
raise OperationalException(e) from e
|
||||||
|
|
||||||
@retrier
|
@retrier
|
||||||
def get_order_book(self, pair: str, limit: int = 100) -> dict:
|
def fetch_l2_order_book(self, pair: str, limit: int = 100) -> dict:
|
||||||
"""
|
"""
|
||||||
get order book level 2 from exchange
|
get order book level 2 from exchange
|
||||||
|
|
||||||
|
@ -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, PricingError
|
||||||
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
|
||||||
@ -260,12 +260,19 @@ class FreqtradeBot:
|
|||||||
f"Getting price from order book {bid_strategy['price_side'].capitalize()} side."
|
f"Getting price from order book {bid_strategy['price_side'].capitalize()} side."
|
||||||
)
|
)
|
||||||
order_book_top = bid_strategy.get('order_book_top', 1)
|
order_book_top = bid_strategy.get('order_book_top', 1)
|
||||||
order_book = self.exchange.get_order_book(pair, order_book_top)
|
order_book = self.exchange.fetch_l2_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 PricingError 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)
|
||||||
@ -446,7 +453,7 @@ class FreqtradeBot:
|
|||||||
"""
|
"""
|
||||||
conf_bids_to_ask_delta = conf.get('bids_to_ask_delta', 0)
|
conf_bids_to_ask_delta = conf.get('bids_to_ask_delta', 0)
|
||||||
logger.info(f"Checking depth of market for {pair} ...")
|
logger.info(f"Checking depth of market for {pair} ...")
|
||||||
order_book = self.exchange.get_order_book(pair, 1000)
|
order_book = self.exchange.fetch_l2_order_book(pair, 1000)
|
||||||
order_book_data_frame = order_book_to_dataframe(order_book['bids'], order_book['asks'])
|
order_book_data_frame = order_book_to_dataframe(order_book['bids'], order_book['asks'])
|
||||||
order_book_bids = order_book_data_frame['b_size'].sum()
|
order_book_bids = order_book_data_frame['b_size'].sum()
|
||||||
order_book_asks = order_book_data_frame['a_size'].sum()
|
order_book_asks = order_book_data_frame['a_size'].sum()
|
||||||
@ -635,7 +642,7 @@ class FreqtradeBot:
|
|||||||
"""
|
"""
|
||||||
Helper generator to query orderbook in loop (used for early sell-order placing)
|
Helper generator to query orderbook in loop (used for early sell-order placing)
|
||||||
"""
|
"""
|
||||||
order_book = self.exchange.get_order_book(pair, order_book_max)
|
order_book = self.exchange.fetch_l2_order_book(pair, 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):
|
||||||
yield order_book[side][i - 1][0]
|
yield order_book[side][i - 1][0]
|
||||||
|
|
||||||
@ -662,8 +669,11 @@ 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."
|
||||||
)
|
)
|
||||||
|
try:
|
||||||
rate = next(self._order_book_gen(pair, f"{ask_strategy['price_side']}s"))
|
rate = next(self._order_book_gen(pair, f"{ask_strategy['price_side']}s"))
|
||||||
|
except (IndexError, KeyError) as e:
|
||||||
|
logger.warning("Sell Price at location from orderbook could not be determined.")
|
||||||
|
raise PricingError 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 +700,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):
|
||||||
|
try:
|
||||||
sell_rate = next(order_book)
|
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 PricingError 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}")
|
||||||
|
|
||||||
|
@ -1413,13 +1413,13 @@ def test_refresh_latest_ohlcv_inv_result(default_conf, mocker, caplog):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
||||||
def test_get_order_book(default_conf, mocker, order_book_l2, exchange_name):
|
def test_fetch_l2_order_book(default_conf, mocker, order_book_l2, exchange_name):
|
||||||
default_conf['exchange']['name'] = exchange_name
|
default_conf['exchange']['name'] = exchange_name
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
|
|
||||||
api_mock.fetch_l2_order_book = order_book_l2
|
api_mock.fetch_l2_order_book = order_book_l2
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
order_book = exchange.get_order_book(pair='ETH/BTC', limit=10)
|
order_book = exchange.fetch_l2_order_book(pair='ETH/BTC', limit=10)
|
||||||
assert 'bids' in order_book
|
assert 'bids' in order_book
|
||||||
assert 'asks' in order_book
|
assert 'asks' in order_book
|
||||||
assert len(order_book['bids']) == 10
|
assert len(order_book['bids']) == 10
|
||||||
@ -1427,20 +1427,20 @@ def test_get_order_book(default_conf, mocker, order_book_l2, exchange_name):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
@pytest.mark.parametrize("exchange_name", EXCHANGES)
|
||||||
def test_get_order_book_exception(default_conf, mocker, exchange_name):
|
def test_fetch_l2_order_book_exception(default_conf, mocker, exchange_name):
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
with pytest.raises(OperationalException):
|
with pytest.raises(OperationalException):
|
||||||
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.NotSupported("Not supported"))
|
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.NotSupported("Not supported"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.get_order_book(pair='ETH/BTC', limit=50)
|
exchange.fetch_l2_order_book(pair='ETH/BTC', limit=50)
|
||||||
with pytest.raises(TemporaryError):
|
with pytest.raises(TemporaryError):
|
||||||
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.NetworkError("DeadBeef"))
|
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.NetworkError("DeadBeef"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.get_order_book(pair='ETH/BTC', limit=50)
|
exchange.fetch_l2_order_book(pair='ETH/BTC', limit=50)
|
||||||
with pytest.raises(OperationalException):
|
with pytest.raises(OperationalException):
|
||||||
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.BaseError("DeadBeef"))
|
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.BaseError("DeadBeef"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.get_order_book(pair='ETH/BTC', limit=50)
|
exchange.fetch_l2_order_book(pair='ETH/BTC', limit=50)
|
||||||
|
|
||||||
|
|
||||||
def make_fetch_ohlcv_mock(data):
|
def make_fetch_ohlcv_mock(data):
|
||||||
|
@ -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, PricingError,
|
||||||
|
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:
|
||||||
@ -3695,7 +3698,7 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee,
|
|||||||
default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 0.1
|
default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 0.1
|
||||||
patch_RPCManager(mocker)
|
patch_RPCManager(mocker)
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2)
|
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2)
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
'freqtrade.exchange.Exchange',
|
'freqtrade.exchange.Exchange',
|
||||||
fetch_ticker=ticker,
|
fetch_ticker=ticker,
|
||||||
@ -3732,7 +3735,7 @@ def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_o
|
|||||||
default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 100
|
default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 100
|
||||||
patch_RPCManager(mocker)
|
patch_RPCManager(mocker)
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2)
|
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2)
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
'freqtrade.exchange.Exchange',
|
'freqtrade.exchange.Exchange',
|
||||||
fetch_ticker=ticker,
|
fetch_ticker=ticker,
|
||||||
@ -3757,7 +3760,7 @@ def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2) -> None:
|
|||||||
ticker_mock = MagicMock(return_value={'ask': 0.045, 'last': 0.046})
|
ticker_mock = MagicMock(return_value={'ask': 0.045, 'last': 0.046})
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
'freqtrade.exchange.Exchange',
|
'freqtrade.exchange.Exchange',
|
||||||
get_order_book=order_book_l2,
|
fetch_l2_order_book=order_book_l2,
|
||||||
fetch_ticker=ticker_mock,
|
fetch_ticker=ticker_mock,
|
||||||
|
|
||||||
)
|
)
|
||||||
@ -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,
|
fetch_l2_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(PricingError):
|
||||||
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:
|
||||||
@ -3804,7 +3804,7 @@ def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2) -> None:
|
|||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
'freqtrade.exchange.Exchange',
|
'freqtrade.exchange.Exchange',
|
||||||
get_order_book=order_book_l2
|
fetch_l2_order_book=order_book_l2
|
||||||
)
|
)
|
||||||
default_conf['telegram']['enabled'] = False
|
default_conf['telegram']['enabled'] = False
|
||||||
default_conf['exchange']['name'] = 'binance'
|
default_conf['exchange']['name'] = 'binance'
|
||||||
@ -3818,11 +3818,11 @@ def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order,
|
def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order,
|
||||||
fee, mocker, order_book_l2) -> None:
|
fee, mocker, order_book_l2, caplog) -> None:
|
||||||
"""
|
"""
|
||||||
test order book ask strategy
|
test order book ask strategy
|
||||||
"""
|
"""
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2)
|
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2)
|
||||||
default_conf['exchange']['name'] = 'binance'
|
default_conf['exchange']['name'] = 'binance'
|
||||||
default_conf['ask_strategy']['use_order_book'] = True
|
default_conf['ask_strategy']['use_order_book'] = True
|
||||||
default_conf['ask_strategy']['order_book_min'] = 1
|
default_conf['ask_strategy']['order_book_min'] = 1
|
||||||
@ -3856,6 +3856,13 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order
|
|||||||
|
|
||||||
patch_get_signal(freqtrade, value=(False, True))
|
patch_get_signal(freqtrade, value=(False, True))
|
||||||
assert freqtrade.handle_trade(trade) is True
|
assert freqtrade.handle_trade(trade) is True
|
||||||
|
assert trade.close_rate_requested == order_book_l2.return_value['asks'][0][0]
|
||||||
|
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book',
|
||||||
|
return_value={'bids': [[]], 'asks': [[]]})
|
||||||
|
with pytest.raises(PricingError):
|
||||||
|
freqtrade.handle_trade(trade)
|
||||||
|
assert log_has('Sell Price at location 1 from orderbook could not be determined.', caplog)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('side,ask,bid,expected', [
|
@pytest.mark.parametrize('side,ask,bid,expected', [
|
||||||
@ -3896,9 +3903,8 @@ def test_get_sell_rate_orderbook(default_conf, mocker, caplog, side, expected, o
|
|||||||
default_conf['ask_strategy']['use_order_book'] = True
|
default_conf['ask_strategy']['use_order_book'] = True
|
||||||
default_conf['ask_strategy']['order_book_min'] = 1
|
default_conf['ask_strategy']['order_book_min'] = 1
|
||||||
default_conf['ask_strategy']['order_book_max'] = 2
|
default_conf['ask_strategy']['order_book_max'] = 2
|
||||||
# TODO: min/max is irrelevant for this test until refactoring
|
|
||||||
pair = "ETH/BTC"
|
pair = "ETH/BTC"
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2)
|
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2)
|
||||||
ft = get_patched_freqtradebot(mocker, default_conf)
|
ft = get_patched_freqtradebot(mocker, default_conf)
|
||||||
rate = ft.get_sell_rate(pair, True)
|
rate = ft.get_sell_rate(pair, True)
|
||||||
assert not log_has("Using cached sell rate for ETH/BTC.", caplog)
|
assert not log_has("Using cached sell rate for ETH/BTC.", caplog)
|
||||||
@ -3909,6 +3915,22 @@ def test_get_sell_rate_orderbook(default_conf, mocker, caplog, side, expected, o
|
|||||||
assert log_has("Using cached sell rate for ETH/BTC.", caplog)
|
assert log_has("Using cached sell rate for ETH/BTC.", caplog)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_sell_rate_orderbook_exception(default_conf, mocker, caplog):
|
||||||
|
# Test orderbook mode
|
||||||
|
default_conf['ask_strategy']['price_side'] = 'ask'
|
||||||
|
default_conf['ask_strategy']['use_order_book'] = True
|
||||||
|
default_conf['ask_strategy']['order_book_min'] = 1
|
||||||
|
default_conf['ask_strategy']['order_book_max'] = 2
|
||||||
|
pair = "ETH/BTC"
|
||||||
|
# Test What happens if the exchange returns an empty orderbook.
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book',
|
||||||
|
return_value={'bids': [[]], 'asks': [[]]})
|
||||||
|
ft = get_patched_freqtradebot(mocker, default_conf)
|
||||||
|
with pytest.raises(PricingError):
|
||||||
|
ft.get_sell_rate(pair, True)
|
||||||
|
assert log_has("Sell Price at location from orderbook could not be determined.", caplog)
|
||||||
|
|
||||||
|
|
||||||
def test_startup_state(default_conf, mocker):
|
def test_startup_state(default_conf, mocker):
|
||||||
default_conf['pairlist'] = {'method': 'VolumePairList',
|
default_conf['pairlist'] = {'method': 'VolumePairList',
|
||||||
'config': {'number_assets': 20}
|
'config': {'number_assets': 20}
|
||||||
|
Loading…
Reference in New Issue
Block a user