diff --git a/freqtrade/constants.py b/freqtrade/constants.py index bff59f3c5..19abadc5f 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -180,7 +180,7 @@ CONF_SCHEMA = { 'maximum': 1, 'exclusiveMaximum': False, }, - 'price_side': {'type': 'string', 'enum': PRICING_SIDES, 'default': 'bid'}, + 'price_side': {'type': 'string', 'enum': PRICING_SIDES, 'default': 'same'}, 'use_order_book': {'type': 'boolean'}, 'order_book_top': {'type': 'integer', 'minimum': 1, 'maximum': 50, }, 'check_depth_of_market': { @@ -196,7 +196,7 @@ CONF_SCHEMA = { 'exit_pricing': { 'type': 'object', 'properties': { - 'price_side': {'type': 'string', 'enum': PRICING_SIDES, 'default': 'ask'}, + 'price_side': {'type': 'string', 'enum': PRICING_SIDES, 'default': 'same'}, 'bid_last_balance': { 'type': 'number', 'minimum': 0, diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 9610c546d..eb5536dd0 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1468,10 +1468,10 @@ class Exchange: if price_side in ('same', 'other'): price_map = { - ('enter', 'long', 'same'): 'bid', - ('enter', 'long', 'other'): 'ask', - ('enter', 'short', 'same'): 'ask', - ('enter', 'short', 'other'): 'bid', + ('entry', 'long', 'same'): 'bid', + ('entry', 'long', 'other'): 'ask', + ('entry', 'short', 'same'): 'ask', + ('entry', 'short', 'other'): 'bid', ('exit', 'long', 'same'): 'ask', ('exit', 'long', 'other'): 'bid', ('exit', 'short', 'same'): 'bid', @@ -1481,7 +1481,7 @@ class Exchange: price_side_word = price_side.capitalize() - if conf_strategy.get('use_order_book', True): + if conf_strategy.get('use_order_book', False): order_book_top = conf_strategy.get('order_book_top', 1) order_book = self.fetch_l2_order_book(pair, order_book_top) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index e6035f4f7..20ab86aeb 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -1491,7 +1491,7 @@ class Telegram(RPCHandler): f"*Max open Trades:* `{val['max_open_trades']}`\n" f"*Minimum ROI:* `{val['minimal_roi']}`\n" f"*Entry strategy:* ```\n{json.dumps(val['entry_pricing'])}```\n" - f"*Exit strategy:* ```\n{json.dumps(val['exit_strategy'])}```\n" + f"*Exit strategy:* ```\n{json.dumps(val['exit_pricing'])}```\n" f"{sl_info}" f"{pa_info}" f"*Timeframe:* `{val['timeframe']}`\n" diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index f3fd7364a..2e09d142d 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2301,8 +2301,8 @@ def test_fetch_l2_order_book_exception(default_conf, mocker, exchange_name): ('bid', 6, 5, None, 1, 5), # last not available - uses bid ('bid', 6, 5, None, 0, 5), # last not available - uses bid ]) -def test_get_buy_rate(mocker, default_conf, caplog, side, ask, bid, - last, last_ab, expected) -> None: +def test_get_entry_rate(mocker, default_conf, caplog, side, ask, bid, + last, last_ab, expected) -> None: caplog.set_level(logging.DEBUG) if last_ab is None: del default_conf['entry_pricing']['ask_last_balance'] @@ -2313,15 +2313,15 @@ def test_get_buy_rate(mocker, default_conf, caplog, side, ask, bid, mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', return_value={'ask': ask, 'last': last, 'bid': bid}) - assert exchange.get_rate('ETH/BTC', refresh=True, side="buy") == expected - assert not log_has("Using cached buy rate for ETH/BTC.", caplog) + assert exchange.get_rate('ETH/BTC', refresh=True, side="entry") == expected + assert not log_has("Using cached entry rate for ETH/BTC.", caplog) - assert exchange.get_rate('ETH/BTC', refresh=False, side="buy") == expected - assert log_has("Using cached buy rate for ETH/BTC.", caplog) + assert exchange.get_rate('ETH/BTC', refresh=False, side="entry") == expected + assert log_has("Using cached entry rate for ETH/BTC.", caplog) # Running a 2nd time with Refresh on! caplog.clear() - assert exchange.get_rate('ETH/BTC', refresh=True, side="buy") == expected - assert not log_has("Using cached buy rate for ETH/BTC.", caplog) + assert exchange.get_rate('ETH/BTC', refresh=True, side="entry") == expected + assert not log_has("Using cached entry rate for ETH/BTC.", caplog) @pytest.mark.parametrize('side,ask,bid,last,last_ab,expected', [ @@ -2345,7 +2345,7 @@ def test_get_buy_rate(mocker, default_conf, caplog, side, ask, bid, ('ask', 0.006, 1.0, 11.0, 0.0, 0.006), ('ask', 0.006, 1.0, 11.0, None, 0.006), ]) -def test_get_sell_rate(default_conf, mocker, caplog, side, bid, ask, +def test_get_exit_rate(default_conf, mocker, caplog, side, bid, ask, last, last_ab, expected) -> None: caplog.set_level(logging.DEBUG) @@ -2368,17 +2368,17 @@ def test_get_sell_rate(default_conf, mocker, caplog, side, bid, ask, assert log_has("Using cached sell rate for ETH/BTC.", caplog) -@pytest.mark.parametrize("entry,side,ask,bid,last,last_ab,expected", [ - ('buy', 'ask', None, 4, 4, 0, 4), # ask not available - ('buy', 'ask', None, None, 4, 0, 4), # ask not available - ('buy', 'bid', 6, None, 4, 0, 5), # bid not available - ('buy', 'bid', None, None, 4, 0, 5), # No rate available - ('sell', 'ask', None, 4, 4, 0, 4), # ask not available - ('sell', 'ask', None, None, 4, 0, 4), # ask not available - ('sell', 'bid', 6, None, 4, 0, 5), # bid not available - ('sell', 'bid', None, None, 4, 0, 5), # bid not available +@pytest.mark.parametrize("entry,is_short,side,ask,bid,last,last_ab,expected", [ + ('entry', False, 'ask', None, 4, 4, 0, 4), # ask not available + ('entry', False, 'ask', None, None, 4, 0, 4), # ask not available + ('entry', False, 'bid', 6, None, 4, 0, 5), # bid not available + ('entry', False, 'bid', None, None, 4, 0, 5), # No rate available + ('exit', False, 'ask', None, 4, 4, 0, 4), # ask not available + ('exit', False, 'ask', None, None, 4, 0, 4), # ask not available + ('exit', False, 'bid', 6, None, 4, 0, 5), # bid not available + ('exit', False, 'bid', None, None, 4, 0, 5), # bid not available ]) -def test_get_ticker_rate_error(mocker, entry, default_conf, caplog, side, ask, bid, +def test_get_ticker_rate_error(mocker, entry, default_conf, caplog, side, is_short, ask, bid, last, last_ab, expected) -> None: caplog.set_level(logging.DEBUG) default_conf['entry_pricing']['ask_last_balance'] = last_ab @@ -2390,14 +2390,21 @@ def test_get_ticker_rate_error(mocker, entry, default_conf, caplog, side, ask, b return_value={'ask': ask, 'last': last, 'bid': bid}) with pytest.raises(PricingError): - exchange.get_rate('ETH/BTC', refresh=True, side=entry) + exchange.get_rate('ETH/BTC', refresh=True, side=entry, is_short=is_short) -@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 +@pytest.mark.parametrize('is_short,side,expected', [ + (False, 'bid', 0.043936), # Value from order_book_l2 fitxure - bids side + (False, 'ask', 0.043949), # Value from order_book_l2 fitxure - asks side + (False, 'other', 0.043936), # Value from order_book_l2 fitxure - bids side + (False, 'same', 0.043949), # Value from order_book_l2 fitxure - asks side + (True, 'bid', 0.043936), # Value from order_book_l2 fitxure - bids side + (True, 'ask', 0.043949), # Value from order_book_l2 fitxure - asks side + (True, 'other', 0.043949), # Value from order_book_l2 fitxure - asks side + (True, 'same', 0.043936), # Value from order_book_l2 fitxure - bids side ]) -def test_get_sell_rate_orderbook(default_conf, mocker, caplog, side, expected, order_book_l2): +def test_get_exit_rate_orderbook( + default_conf, mocker, caplog, is_short, side, expected, order_book_l2): caplog.set_level(logging.DEBUG) # Test orderbook mode default_conf['exit_pricing']['price_side'] = side @@ -2406,16 +2413,16 @@ def test_get_sell_rate_orderbook(default_conf, mocker, caplog, side, expected, o 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_rate(pair, refresh=True, side="sell") - assert not log_has("Using cached sell rate for ETH/BTC.", caplog) + rate = exchange.get_rate(pair, refresh=True, side="exit", is_short=is_short) + assert not log_has("Using cached exit rate for ETH/BTC.", caplog) assert isinstance(rate, float) assert rate == expected - rate = exchange.get_rate(pair, refresh=False, side="sell") + rate = exchange.get_rate(pair, refresh=False, side="exit", is_short=is_short) assert rate == expected - assert log_has("Using cached sell rate for ETH/BTC.", caplog) + assert log_has("Using cached exit rate for ETH/BTC.", caplog) -def test_get_sell_rate_orderbook_exception(default_conf, mocker, caplog): +def test_get_exit_rate_orderbook_exception(default_conf, mocker, caplog): # Test orderbook mode default_conf['exit_pricing']['price_side'] = 'ask' default_conf['exit_pricing']['use_order_book'] = True @@ -2426,31 +2433,32 @@ def test_get_sell_rate_orderbook_exception(default_conf, mocker, caplog): return_value={'bids': [[]], 'asks': [[]]}) 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\..*", + exchange.get_rate(pair, refresh=True, side="exit", is_short=False) + assert log_has_re(r"Exit Price at location 1 from orderbook could not be determined\..*", caplog) -def test_get_sell_rate_exception(default_conf, mocker, caplog): +@pytest.mark.parametrize('is_short', [True, False]) +def test_get_exit_rate_exception(default_conf, mocker, is_short): # Ticker on one side can be empty in certain circumstances. default_conf['exit_pricing']['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_rate(pair, refresh=True, side="sell") + with pytest.raises(PricingError, match=r"Exit-Rate for ETH/BTC was empty."): + exchange.get_rate(pair, refresh=True, side="exit", is_short=is_short) exchange._config['exit_pricing']['price_side'] = 'bid' - assert exchange.get_rate(pair, refresh=True, side="sell") == 0.12 + assert exchange.get_rate(pair, refresh=True, side="exit", is_short=is_short) == 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_rate(pair, refresh=True, side="sell") + with pytest.raises(PricingError, match=r"Exit-Rate for ETH/BTC was empty."): + exchange.get_rate(pair, refresh=True, side="exit", is_short=is_short) exchange._config['exit_pricing']['price_side'] = 'ask' - assert exchange.get_rate(pair, refresh=True, side="sell") == 0.13 + assert exchange.get_rate(pair, refresh=True, side="exit", is_short=is_short) == 0.13 @pytest.mark.parametrize("exchange_name", EXCHANGES) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index a3a1b7da7..47ee29219 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -898,7 +898,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order, # Fail to get price... mocker.patch('freqtrade.exchange.Exchange.get_rate', MagicMock(return_value=0.0)) - with pytest.raises(PricingError, match=f"Could not determine {enter_side(is_short)} price."): + with pytest.raises(PricingError, match="Could not determine entry price."): freqtrade.execute_entry(pair, stake_amount, is_short=is_short) # In case of custom entry price @@ -4497,11 +4497,12 @@ def test_order_book_entry_pricing1(mocker, default_conf_usdt, order_book_l2, exc freqtrade = FreqtradeBot(default_conf_usdt) if exception_thrown: with pytest.raises(PricingError): - freqtrade.exchange.get_rate('ETH/USDT', refresh=True, side="buy") + freqtrade.exchange.get_rate('ETH/USDT', side="entry", is_short=False, refresh=True) assert log_has_re( - r'Buy Price at location 1 from orderbook could not be determined.', caplog) + r'Entry 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 freqtrade.exchange.get_rate( + 'ETH/USDT', side="entry", is_short=False, refresh=True) == 0.043935 assert ticker_usdt_mock.call_count == 0 @@ -4577,7 +4578,7 @@ def test_order_book_exit_pricing( 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\..*', + assert log_has_re(r'Exit Price at location 1 from orderbook could not be determined\..*', caplog)