diff --git a/freqtrade/tests/rpc/test_rpc.py b/freqtrade/tests/rpc/test_rpc.py index efc136777..e1db34347 100644 --- a/freqtrade/tests/rpc/test_rpc.py +++ b/freqtrade/tests/rpc/test_rpc.py @@ -532,3 +532,79 @@ def test_rpc_count(mocker, default_conf, ticker, fee, markets) -> None: trades = rpc._rpc_count() nb_trades = len(trades) assert nb_trades == 1 + + +def test_rpcforcebuy(mocker, default_conf, ticker, fee, markets, limit_buy_order) -> None: + default_conf['forcebuy_enable'] = True + patch_coinmarketcap(mocker) + patch_exchange(mocker) + mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) + buy_mm = MagicMock(return_value={'id': limit_buy_order['id']}) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + get_balances=MagicMock(return_value=ticker), + get_ticker=ticker, + get_fee=fee, + get_markets=markets, + buy=buy_mm + ) + + freqtradebot = FreqtradeBot(default_conf) + patch_get_signal(freqtradebot, (True, False)) + rpc = RPC(freqtradebot) + pair = 'ETH/BTC' + trade = rpc._rpc_forcebuy(pair, None) + assert isinstance(trade, Trade) + assert trade.pair == pair + assert trade.open_rate == ticker()['ask'] + + # Test buy duplicate + with pytest.raises(RPCException, match=r'position for ETH/BTC already open - id: 1'): + rpc._rpc_forcebuy(pair, 0.0001) + pair = 'XRP/BTC' + trade = rpc._rpc_forcebuy(pair, 0.0001) + assert isinstance(trade, Trade) + assert trade.pair == pair + assert trade.open_rate == 0.0001 + + # Test buy pair not with stakes + with pytest.raises(RPCException, match=r'Wrong pair selected. Please pairs with stake.*'): + rpc._rpc_forcebuy('XRP/ETH', 0.0001) + pair = 'XRP/BTC' + + # Test not buying + default_conf['stake_amount'] = 0.0000001 + freqtradebot = FreqtradeBot(default_conf) + patch_get_signal(freqtradebot, (True, False)) + rpc = RPC(freqtradebot) + pair = 'TKN/BTC' + trade = rpc._rpc_forcebuy(pair, None) + assert trade is None + + +def test_rpcforcebuy_stopped(mocker, default_conf) -> None: + default_conf['forcebuy_enable'] = True + default_conf['initial_state'] = 'stopped' + patch_coinmarketcap(mocker) + patch_exchange(mocker) + mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) + + freqtradebot = FreqtradeBot(default_conf) + patch_get_signal(freqtradebot, (True, False)) + rpc = RPC(freqtradebot) + pair = 'ETH/BTC' + with pytest.raises(RPCException, match=r'trader is not running'): + rpc._rpc_forcebuy(pair, None) + + +def test_rpcforcebuy_disabled(mocker, default_conf) -> None: + patch_coinmarketcap(mocker) + patch_exchange(mocker) + mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) + + freqtradebot = FreqtradeBot(default_conf) + patch_get_signal(freqtradebot, (True, False)) + rpc = RPC(freqtradebot) + pair = 'ETH/BTC' + with pytest.raises(RPCException, match=r'Forcebuy not enabled.'): + rpc._rpc_forcebuy(pair, None) diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 182c1d2e7..25f2be350 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -71,8 +71,8 @@ def test_init(default_conf, mocker, caplog) -> None: assert start_polling.start_polling.call_count == 1 message_str = "rpc.telegram is listening for following commands: [['status'], ['profit'], " \ - "['balance'], ['start'], ['stop'], ['forcesell'], ['performance'], ['daily'], " \ - "['count'], ['reload_conf'], ['help'], ['version']]" + "['balance'], ['start'], ['stop'], ['forcesell'], ['forcebuy'], " \ + "['performance'], ['daily'], ['count'], ['reload_conf'], ['help'], ['version']]" assert log_has(message_str, caplog.record_tuples) @@ -855,6 +855,63 @@ def test_forcesell_handle_invalid(default_conf, update, mocker) -> None: assert 'invalid argument' in msg_mock.call_args_list[0][0][0] +def test_forcebuy_handle(default_conf, update, markets, mocker) -> None: + patch_coinmarketcap(mocker, value={'price_usd': 15000.0}) + mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) + mocker.patch('freqtrade.rpc.telegram.Telegram._send_msg', MagicMock()) + mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock()) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + _load_markets=MagicMock(return_value={}), + get_markets=markets + ) + fbuy_mock = MagicMock(return_value=None) + mocker.patch('freqtrade.rpc.RPC._rpc_forcebuy', fbuy_mock) + + freqtradebot = FreqtradeBot(default_conf) + patch_get_signal(freqtradebot, (True, False)) + telegram = Telegram(freqtradebot) + + update.message.text = '/forcebuy ETH/BTC' + telegram._forcebuy(bot=MagicMock(), update=update) + + assert fbuy_mock.call_count == 1 + assert fbuy_mock.call_args_list[0][0][0] == 'ETH/BTC' + assert fbuy_mock.call_args_list[0][0][1] is None + + # Reset and retry with specified price + fbuy_mock = MagicMock(return_value=None) + mocker.patch('freqtrade.rpc.RPC._rpc_forcebuy', fbuy_mock) + update.message.text = '/forcebuy ETH/BTC 0.055' + telegram._forcebuy(bot=MagicMock(), update=update) + + assert fbuy_mock.call_count == 1 + assert fbuy_mock.call_args_list[0][0][0] == 'ETH/BTC' + assert isinstance(fbuy_mock.call_args_list[0][0][1], float) + assert fbuy_mock.call_args_list[0][0][1] == 0.055 + + +def test_forcebuy_handle_exception(default_conf, update, markets, mocker) -> None: + patch_coinmarketcap(mocker, value={'price_usd': 15000.0}) + mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) + rpc_mock = mocker.patch('freqtrade.rpc.telegram.Telegram._send_msg', MagicMock()) + mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock()) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + _load_markets=MagicMock(return_value={}), + get_markets=markets + ) + freqtradebot = FreqtradeBot(default_conf) + patch_get_signal(freqtradebot, (True, False)) + telegram = Telegram(freqtradebot) + + update.message.text = '/forcebuy ETH/Nonepair' + telegram._forcebuy(bot=MagicMock(), update=update) + + assert rpc_mock.call_count == 1 + assert rpc_mock.call_args_list[0][0][0] == 'Forcebuy not enabled.' + + def test_performance_handle(default_conf, update, ticker, fee, limit_buy_order, limit_sell_order, markets, mocker) -> None: patch_coinmarketcap(mocker)