From c769e9757d6454c921806b279c7fc5997b90381b Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 12 Feb 2022 20:13:12 +0100 Subject: [PATCH] Improve "order refind" to also work for stoploss orders --- freqtrade/freqtradebot.py | 28 ++------------ tests/test_freqtradebot.py | 77 ++++++++++---------------------------- 2 files changed, 23 insertions(+), 82 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 279bb6161..fce85baa3 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -298,28 +298,6 @@ class FreqtradeBot(LoggingMixin): self.update_trade_state(trade, order.order_id, send_msg=False) def handle_insufficient_funds(self, trade: Trade): - """ - Determine if we ever opened a sell order for this trade. - If not, try update buy fees - otherwise "refind" the open order we obviously lost. - """ - sell_order = trade.select_order('sell', None) - if sell_order: - self.refind_lost_order(trade) - else: - self.reupdate_enter_order_fees(trade) - - def reupdate_enter_order_fees(self, trade: Trade): - """ - Get buy order from database, and try to reupdate. - Handles trades where the initial fee-update did not work. - """ - logger.info(f"Trying to reupdate buy fees for {trade}") - order = trade.select_order('buy', False) - if order: - logger.info(f"Updating buy-fee on trade {trade} for order {order.order_id}.") - self.update_trade_state(trade, order.order_id, send_msg=False) - - def refind_lost_order(self, trade): """ Try refinding a lost trade. Only used when InsufficientFunds appears on sell orders (stoploss or sell). @@ -332,9 +310,6 @@ class FreqtradeBot(LoggingMixin): if not order.ft_is_open: logger.debug(f"Order {order} is no longer open.") continue - if order.ft_order_side == 'buy': - # Skip buy side - this is handled by reupdate_buy_order_fees - continue try: fo = self.exchange.fetch_order_or_stoploss_order(order.order_id, order.ft_pair, order.ft_order_side == 'stoploss') @@ -346,6 +321,9 @@ class FreqtradeBot(LoggingMixin): if fo and fo['status'] == 'open': # Assume this as the open order trade.open_order_id = order.order_id + elif order.ft_order_side == 'buy': + if fo and fo['status'] == 'open': + trade.open_order_id = order.order_id if fo: logger.info(f"Found {order} for trade {trade}.") self.update_trade_state(trade, order.order_id, fo, diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index a84616516..4bbf26362 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -4110,15 +4110,17 @@ def test_reupdate_enter_order_fees(mocker, default_conf_usdt, fee, caplog): freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mock_uts = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.update_trade_state') + mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order', + return_value={'status': 'open'}) create_mock_trades(fee) trades = Trade.get_trades().all() - freqtrade.reupdate_enter_order_fees(trades[0]) - assert log_has_re(r"Trying to reupdate buy fees for .*", caplog) + freqtrade.handle_insufficient_funds(trades[3]) + # assert log_has_re(r"Trying to reupdate buy fees for .*", caplog) assert mock_uts.call_count == 1 - assert mock_uts.call_args_list[0][0][0] == trades[0] - assert mock_uts.call_args_list[0][0][1] == mock_order_1()['id'] - assert log_has_re(r"Updating buy-fee on trade .* for order .*\.", caplog) + assert mock_uts.call_args_list[0][0][0] == trades[3] + assert mock_uts.call_args_list[0][0][1] == mock_order_4()['id'] + assert log_has_re(r"Trying to refind lost order for .*", caplog) mock_uts.reset_mock() caplog.clear() @@ -4136,52 +4138,13 @@ def test_reupdate_enter_order_fees(mocker, default_conf_usdt, fee, caplog): ) Trade.query.session.add(trade) - freqtrade.reupdate_enter_order_fees(trade) - assert log_has_re(r"Trying to reupdate buy fees for .*", caplog) + freqtrade.handle_insufficient_funds(trade) + # assert log_has_re(r"Trying to reupdate buy fees for .*", caplog) assert mock_uts.call_count == 0 - assert not log_has_re(r"Updating buy-fee on trade .* for order .*\.", caplog) @pytest.mark.usefixtures("init_persistence") -def test_handle_insufficient_funds(mocker, default_conf_usdt, fee): - freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) - mock_rlo = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.refind_lost_order') - mock_bof = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.reupdate_enter_order_fees') - create_mock_trades(fee) - trades = Trade.get_trades().all() - - # Trade 0 has only a open buy order, no closed order - freqtrade.handle_insufficient_funds(trades[0]) - assert mock_rlo.call_count == 0 - assert mock_bof.call_count == 1 - - mock_rlo.reset_mock() - mock_bof.reset_mock() - - # Trade 1 has closed buy and sell orders - freqtrade.handle_insufficient_funds(trades[1]) - assert mock_rlo.call_count == 1 - assert mock_bof.call_count == 0 - - mock_rlo.reset_mock() - mock_bof.reset_mock() - - # Trade 2 has closed buy and sell orders - freqtrade.handle_insufficient_funds(trades[2]) - assert mock_rlo.call_count == 1 - assert mock_bof.call_count == 0 - - mock_rlo.reset_mock() - mock_bof.reset_mock() - - # Trade 3 has an opne buy order - freqtrade.handle_insufficient_funds(trades[3]) - assert mock_rlo.call_count == 0 - assert mock_bof.call_count == 1 - - -@pytest.mark.usefixtures("init_persistence") -def test_refind_lost_order(mocker, default_conf_usdt, fee, caplog): +def test_handle_insufficient_funds(mocker, default_conf_usdt, fee, caplog): caplog.set_level(logging.DEBUG) freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) mock_uts = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.update_trade_state') @@ -4204,7 +4167,7 @@ def test_refind_lost_order(mocker, default_conf_usdt, fee, caplog): assert trade.open_order_id is None assert trade.stoploss_order_id is None - freqtrade.refind_lost_order(trade) + freqtrade.handle_insufficient_funds(trade) order = mock_order_1() assert log_has_re(r"Order Order(.*order_id=" + order['id'] + ".*) is no longer open.", caplog) assert mock_fo.call_count == 0 @@ -4222,13 +4185,13 @@ def test_refind_lost_order(mocker, default_conf_usdt, fee, caplog): assert trade.open_order_id is None assert trade.stoploss_order_id is None - freqtrade.refind_lost_order(trade) + freqtrade.handle_insufficient_funds(trade) order = mock_order_4() assert log_has_re(r"Trying to refind Order\(.*", caplog) - assert mock_fo.call_count == 0 - assert mock_uts.call_count == 0 - # No change to orderid - as update_trade_state is mocked - assert trade.open_order_id is None + assert mock_fo.call_count == 1 + assert mock_uts.call_count == 1 + # Found open buy order + assert trade.open_order_id is not None assert trade.stoploss_order_id is None caplog.clear() @@ -4240,11 +4203,11 @@ def test_refind_lost_order(mocker, default_conf_usdt, fee, caplog): assert trade.open_order_id is None assert trade.stoploss_order_id is None - freqtrade.refind_lost_order(trade) + freqtrade.handle_insufficient_funds(trade) order = mock_order_5_stoploss() assert log_has_re(r"Trying to refind Order\(.*", caplog) assert mock_fo.call_count == 1 - assert mock_uts.call_count == 1 + assert mock_uts.call_count == 2 # stoploss_order_id is "refound" and added to the trade assert trade.open_order_id is None assert trade.stoploss_order_id is not None @@ -4259,7 +4222,7 @@ def test_refind_lost_order(mocker, default_conf_usdt, fee, caplog): assert trade.open_order_id is None assert trade.stoploss_order_id is None - freqtrade.refind_lost_order(trade) + freqtrade.handle_insufficient_funds(trade) order = mock_order_6_sell() assert log_has_re(r"Trying to refind Order\(.*", caplog) assert mock_fo.call_count == 1 @@ -4275,7 +4238,7 @@ def test_refind_lost_order(mocker, default_conf_usdt, fee, caplog): side_effect=ExchangeError()) order = mock_order_5_stoploss() - freqtrade.refind_lost_order(trades[4]) + freqtrade.handle_insufficient_funds(trades[4]) assert log_has(f"Error updating {order['id']}.", caplog)