Move get_sell_rate to exchange class

This commit is contained in:
Matthias
2021-06-02 11:39:18 +02:00
parent 12916243ec
commit bd1984386e
7 changed files with 172 additions and 177 deletions

View File

@@ -11,7 +11,7 @@ import pytest
from pandas import DataFrame
from freqtrade.exceptions import (DDosProtection, DependencyException, InvalidOrderException,
OperationalException, TemporaryError)
OperationalException, PricingError, TemporaryError)
from freqtrade.exchange import Binance, Bittrex, Exchange, Kraken
from freqtrade.exchange.common import (API_FETCH_ORDER_RETRY_COUNT, API_RETRY_COUNT,
calculate_backoff)
@@ -1728,6 +1728,108 @@ def test_get_buy_rate(mocker, default_conf, caplog, side, ask, bid,
assert not log_has("Using cached buy rate for ETH/BTC.", caplog)
@pytest.mark.parametrize('side,ask,bid,last,last_ab,expected', [
('bid', 12.0, 11.0, 11.5, 0.0, 11.0), # full bid side
('bid', 12.0, 11.0, 11.5, 1.0, 11.5), # full last side
('bid', 12.0, 11.0, 11.5, 0.5, 11.25), # between bid and lat
('bid', 12.0, 11.2, 10.5, 0.0, 11.2), # Last smaller than bid
('bid', 12.0, 11.2, 10.5, 1.0, 11.2), # Last smaller than bid - uses bid
('bid', 12.0, 11.2, 10.5, 0.5, 11.2), # Last smaller than bid - uses bid
('bid', 0.003, 0.002, 0.005, 0.0, 0.002),
('ask', 12.0, 11.0, 12.5, 0.0, 12.0), # full ask side
('ask', 12.0, 11.0, 12.5, 1.0, 12.5), # full last side
('ask', 12.0, 11.0, 12.5, 0.5, 12.25), # between bid and lat
('ask', 12.2, 11.2, 10.5, 0.0, 12.2), # Last smaller than ask
('ask', 12.0, 11.0, 10.5, 1.0, 12.0), # Last smaller than ask - uses ask
('ask', 12.0, 11.2, 10.5, 0.5, 12.0), # Last smaller than ask - uses ask
('ask', 10.0, 11.0, 11.0, 0.0, 10.0),
('ask', 10.11, 11.2, 11.0, 0.0, 10.11),
('ask', 0.001, 0.002, 11.0, 0.0, 0.001),
('ask', 0.006, 1.0, 11.0, 0.0, 0.006),
])
def test_get_sell_rate(default_conf, mocker, caplog, side, bid, ask,
last, last_ab, expected) -> None:
caplog.set_level(logging.DEBUG)
default_conf['ask_strategy']['price_side'] = side
default_conf['ask_strategy']['bid_last_balance'] = last_ab
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
return_value={'ask': ask, 'bid': bid, 'last': last})
pair = "ETH/BTC"
# Test regular mode
exchange = get_patched_exchange(mocker, default_conf)
rate = exchange.get_sell_rate(pair, True)
assert not log_has("Using cached sell rate for ETH/BTC.", caplog)
assert isinstance(rate, float)
assert rate == expected
# Use caching
rate = exchange.get_sell_rate(pair, False)
assert rate == expected
assert log_has("Using cached sell rate for ETH/BTC.", caplog)
@pytest.mark.parametrize('side,expected', [
('bid', 0.043936), # Value from order_book_l2 fiture - bids side
('ask', 0.043949), # Value from order_book_l2 fiture - asks side
])
def test_get_sell_rate_orderbook(default_conf, mocker, caplog, side, expected, order_book_l2):
caplog.set_level(logging.DEBUG)
# Test orderbook mode
default_conf['ask_strategy']['price_side'] = side
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"
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2)
exchange = get_patched_exchange(mocker, default_conf)
rate = exchange.get_sell_rate(pair, True)
assert not log_has("Using cached sell rate for ETH/BTC.", caplog)
assert isinstance(rate, float)
assert rate == expected
rate = exchange.get_sell_rate(pair, False)
assert rate == expected
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': [[]]})
exchange = get_patched_exchange(mocker, default_conf)
with pytest.raises(PricingError):
exchange.get_sell_rate(pair, True)
assert log_has("Sell Price at location from orderbook could not be determined.", caplog)
def test_get_sell_rate_exception(default_conf, mocker, caplog):
# Ticker on one side can be empty in certain circumstances.
default_conf['ask_strategy']['price_side'] = 'ask'
pair = "ETH/BTC"
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
return_value={'ask': None, 'bid': 0.12, 'last': None})
exchange = get_patched_exchange(mocker, default_conf)
with pytest.raises(PricingError, match=r"Sell-Rate for ETH/BTC was empty."):
exchange.get_sell_rate(pair, True)
exchange._config['ask_strategy']['price_side'] = 'bid'
assert exchange.get_sell_rate(pair, True) == 0.12
# Reverse sides
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
return_value={'ask': 0.13, 'bid': None, 'last': None})
with pytest.raises(PricingError, match=r"Sell-Rate for ETH/BTC was empty."):
exchange.get_sell_rate(pair, True)
exchange._config['ask_strategy']['price_side'] = 'ask'
assert exchange.get_sell_rate(pair, True) == 0.13
def make_fetch_ohlcv_mock(data):
def fetch_ohlcv_mock(pair, timeframe, since):
if since:

View File

@@ -109,7 +109,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
'exchange': 'binance',
}
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_sell_rate',
mocker.patch('freqtrade.exchange.Exchange.get_sell_rate',
MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
results = rpc._rpc_trade_status()
assert isnan(results[0]['current_profit'])
@@ -217,7 +217,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
assert '-0.41% (-0.06)' == result[0][3]
assert '-0.06' == f'{fiat_profit_sum:.2f}'
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_sell_rate',
mocker.patch('freqtrade.exchange.Exchange.get_sell_rate',
MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
result, headers, fiat_profit_sum = rpc._rpc_status_table(default_conf['stake_currency'], 'USD')
assert 'instantly' == result[0][2]
@@ -427,7 +427,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
assert prec_satoshi(stats['best_rate'], 6.2)
# Test non-available pair
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_sell_rate',
mocker.patch('freqtrade.exchange.Exchange.get_sell_rate',
MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)
assert stats['trade_count'] == 2

View File

@@ -834,7 +834,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets):
'exchange': 'binance',
}
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_sell_rate',
mocker.patch('freqtrade.exchange.Exchange.get_sell_rate',
MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
rc = client_get(client, f"{BASE_URI}/status")

View File

@@ -751,7 +751,6 @@ def test_process_informative_pairs_added(default_conf, ticker, mocker) -> None:
assert ("ETH/BTC", default_conf["timeframe"]) in refresh_mock.call_args[0][0]
def test_execute_buy(mocker, default_conf, fee, limit_buy_order, limit_buy_order_open) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
@@ -2480,7 +2479,7 @@ def test_handle_cancel_sell_limit(mocker, default_conf, fee) -> None:
'freqtrade.exchange.Exchange',
cancel_order=cancel_order_mock,
)
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_sell_rate', return_value=0.245441)
mocker.patch('freqtrade.exchange.Exchange.get_sell_rate', return_value=0.245441)
freqtrade = FreqtradeBot(default_conf)
@@ -4029,108 +4028,6 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order_open, limit_buy_o
assert log_has('Sell Price at location 1 from orderbook could not be determined.', caplog)
@pytest.mark.parametrize('side,ask,bid,last,last_ab,expected', [
('bid', 12.0, 11.0, 11.5, 0.0, 11.0), # full bid side
('bid', 12.0, 11.0, 11.5, 1.0, 11.5), # full last side
('bid', 12.0, 11.0, 11.5, 0.5, 11.25), # between bid and lat
('bid', 12.0, 11.2, 10.5, 0.0, 11.2), # Last smaller than bid
('bid', 12.0, 11.2, 10.5, 1.0, 11.2), # Last smaller than bid - uses bid
('bid', 12.0, 11.2, 10.5, 0.5, 11.2), # Last smaller than bid - uses bid
('bid', 0.003, 0.002, 0.005, 0.0, 0.002),
('ask', 12.0, 11.0, 12.5, 0.0, 12.0), # full ask side
('ask', 12.0, 11.0, 12.5, 1.0, 12.5), # full last side
('ask', 12.0, 11.0, 12.5, 0.5, 12.25), # between bid and lat
('ask', 12.2, 11.2, 10.5, 0.0, 12.2), # Last smaller than ask
('ask', 12.0, 11.0, 10.5, 1.0, 12.0), # Last smaller than ask - uses ask
('ask', 12.0, 11.2, 10.5, 0.5, 12.0), # Last smaller than ask - uses ask
('ask', 10.0, 11.0, 11.0, 0.0, 10.0),
('ask', 10.11, 11.2, 11.0, 0.0, 10.11),
('ask', 0.001, 0.002, 11.0, 0.0, 0.001),
('ask', 0.006, 1.0, 11.0, 0.0, 0.006),
])
def test_get_sell_rate(default_conf, mocker, caplog, side, bid, ask,
last, last_ab, expected) -> None:
caplog.set_level(logging.DEBUG)
default_conf['ask_strategy']['price_side'] = side
default_conf['ask_strategy']['bid_last_balance'] = last_ab
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
return_value={'ask': ask, 'bid': bid, 'last': last})
pair = "ETH/BTC"
# Test regular mode
ft = get_patched_freqtradebot(mocker, default_conf)
rate = ft.get_sell_rate(pair, True)
assert not log_has("Using cached sell rate for ETH/BTC.", caplog)
assert isinstance(rate, float)
assert rate == expected
# Use caching
rate = ft.get_sell_rate(pair, False)
assert rate == expected
assert log_has("Using cached sell rate for ETH/BTC.", caplog)
@pytest.mark.parametrize('side,expected', [
('bid', 0.043936), # Value from order_book_l2 fiture - bids side
('ask', 0.043949), # Value from order_book_l2 fiture - asks side
])
def test_get_sell_rate_orderbook(default_conf, mocker, caplog, side, expected, order_book_l2):
caplog.set_level(logging.DEBUG)
# Test orderbook mode
default_conf['ask_strategy']['price_side'] = side
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"
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2)
ft = get_patched_freqtradebot(mocker, default_conf)
rate = ft.get_sell_rate(pair, True)
assert not log_has("Using cached sell rate for ETH/BTC.", caplog)
assert isinstance(rate, float)
assert rate == expected
rate = ft.get_sell_rate(pair, False)
assert rate == expected
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_get_sell_rate_exception(default_conf, mocker, caplog):
# Ticker on one side can be empty in certain circumstances.
default_conf['ask_strategy']['price_side'] = 'ask'
pair = "ETH/BTC"
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
return_value={'ask': None, 'bid': 0.12, 'last': None})
ft = get_patched_freqtradebot(mocker, default_conf)
with pytest.raises(PricingError, match=r"Sell-Rate for ETH/BTC was empty."):
ft.get_sell_rate(pair, True)
ft.config['ask_strategy']['price_side'] = 'bid'
assert ft.get_sell_rate(pair, True) == 0.12
# Reverse sides
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
return_value={'ask': 0.13, 'bid': None, 'last': None})
with pytest.raises(PricingError, match=r"Sell-Rate for ETH/BTC was empty."):
ft.get_sell_rate(pair, True)
ft.config['ask_strategy']['price_side'] = 'ask'
assert ft.get_sell_rate(pair, True) == 0.13
def test_startup_state(default_conf, mocker):
default_conf['pairlist'] = {'method': 'VolumePairList',
'config': {'number_assets': 20}