merge upstream
This commit is contained in:
@@ -2364,7 +2364,7 @@ def test_bot_loop_start_called_once(mocker, default_conf_usdt, caplog):
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
def test_check_handle_timedout_entry_usercustom(
|
||||
def test_manage_open_orders_entry_usercustom(
|
||||
default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade,
|
||||
limit_sell_order_old, fee, mocker, is_short
|
||||
) -> None:
|
||||
@@ -2396,12 +2396,12 @@ def test_check_handle_timedout_entry_usercustom(
|
||||
Trade.query.session.add(open_trade)
|
||||
|
||||
# Ensure default is to return empty (so not mocked yet)
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 0
|
||||
|
||||
# Return false - trade remains open
|
||||
freqtrade.strategy.check_entry_timeout = MagicMock(return_value=False)
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 0
|
||||
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
|
||||
nb_trades = len(trades)
|
||||
@@ -2409,7 +2409,7 @@ def test_check_handle_timedout_entry_usercustom(
|
||||
assert freqtrade.strategy.check_entry_timeout.call_count == 1
|
||||
freqtrade.strategy.check_entry_timeout = MagicMock(side_effect=KeyError)
|
||||
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 0
|
||||
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
|
||||
nb_trades = len(trades)
|
||||
@@ -2418,7 +2418,7 @@ def test_check_handle_timedout_entry_usercustom(
|
||||
freqtrade.strategy.check_entry_timeout = MagicMock(return_value=True)
|
||||
|
||||
# Trade should be closed since the function returns true
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_wr_mock.call_count == 1
|
||||
assert rpc_mock.call_count == 1
|
||||
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
|
||||
@@ -2428,7 +2428,7 @@ def test_check_handle_timedout_entry_usercustom(
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
def test_check_handle_timedout_entry(
|
||||
def test_manage_open_orders_entry(
|
||||
default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade,
|
||||
limit_sell_order_old, fee, mocker, is_short
|
||||
) -> None:
|
||||
@@ -2454,8 +2454,9 @@ def test_check_handle_timedout_entry(
|
||||
Trade.query.session.add(open_trade)
|
||||
|
||||
freqtrade.strategy.check_entry_timeout = MagicMock(return_value=False)
|
||||
freqtrade.strategy.adjust_entry_price = MagicMock(return_value=1234)
|
||||
# check it does cancel buy orders over the time limit
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 1
|
||||
assert rpc_mock.call_count == 1
|
||||
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
|
||||
@@ -2463,6 +2464,99 @@ def test_check_handle_timedout_entry(
|
||||
assert nb_trades == 0
|
||||
# Custom user buy-timeout is never called
|
||||
assert freqtrade.strategy.check_entry_timeout.call_count == 0
|
||||
# Entry adjustment is never called
|
||||
assert freqtrade.strategy.adjust_entry_price.call_count == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
def test_adjust_entry_cancel(
|
||||
default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade,
|
||||
limit_sell_order_old, fee, mocker, caplog, is_short
|
||||
) -> None:
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
|
||||
old_order = limit_sell_order_old if is_short else limit_buy_order_old
|
||||
old_order['id'] = open_trade.open_order_id
|
||||
limit_buy_cancel = deepcopy(old_order)
|
||||
limit_buy_cancel['status'] = 'canceled'
|
||||
cancel_order_mock = MagicMock(return_value=limit_buy_cancel)
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
fetch_ticker=ticker_usdt,
|
||||
fetch_order=MagicMock(return_value=old_order),
|
||||
cancel_order_with_result=cancel_order_mock,
|
||||
get_fee=fee
|
||||
)
|
||||
|
||||
open_trade.is_short = is_short
|
||||
Trade.query.session.add(open_trade)
|
||||
|
||||
# Timeout to not interfere
|
||||
freqtrade.strategy.ft_check_timed_out = MagicMock(return_value=False)
|
||||
|
||||
# check that order is cancelled
|
||||
freqtrade.strategy.adjust_entry_price = MagicMock(return_value=None)
|
||||
freqtrade.manage_open_orders()
|
||||
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
|
||||
assert len(trades) == 0
|
||||
assert len(Order.query.all()) == 0
|
||||
assert log_has_re(
|
||||
f"{'Sell' if is_short else 'Buy'} order user requested order cancel*", caplog)
|
||||
assert log_has_re(
|
||||
f"{'Sell' if is_short else 'Buy'} order fully cancelled.*", caplog)
|
||||
|
||||
# Entry adjustment is called
|
||||
assert freqtrade.strategy.adjust_entry_price.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
def test_adjust_entry_maintain_replace(
|
||||
default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade,
|
||||
limit_sell_order_old, fee, mocker, caplog, is_short
|
||||
) -> None:
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
|
||||
old_order = limit_sell_order_old if is_short else limit_buy_order_old
|
||||
old_order['id'] = open_trade.open_order_id
|
||||
limit_buy_cancel = deepcopy(old_order)
|
||||
limit_buy_cancel['status'] = 'canceled'
|
||||
cancel_order_mock = MagicMock(return_value=limit_buy_cancel)
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
fetch_ticker=ticker_usdt,
|
||||
fetch_order=MagicMock(return_value=old_order),
|
||||
cancel_order_with_result=cancel_order_mock,
|
||||
get_fee=fee
|
||||
)
|
||||
|
||||
open_trade.is_short = is_short
|
||||
Trade.query.session.add(open_trade)
|
||||
|
||||
# Timeout to not interfere
|
||||
freqtrade.strategy.ft_check_timed_out = MagicMock(return_value=False)
|
||||
|
||||
# Check that order is maintained
|
||||
freqtrade.strategy.adjust_entry_price = MagicMock(return_value=old_order['price'])
|
||||
freqtrade.manage_open_orders()
|
||||
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
|
||||
assert len(trades) == 1
|
||||
assert len(Order.get_open_orders()) == 1
|
||||
# Entry adjustment is called
|
||||
assert freqtrade.strategy.adjust_entry_price.call_count == 1
|
||||
|
||||
# Check that order is replaced
|
||||
freqtrade.get_valid_enter_price_and_stake = MagicMock(return_value={100, 10, 1})
|
||||
freqtrade.strategy.adjust_entry_price = MagicMock(return_value=1234)
|
||||
freqtrade.manage_open_orders()
|
||||
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
|
||||
assert len(trades) == 1
|
||||
nb_all_orders = len(Order.query.all())
|
||||
assert nb_all_orders == 2
|
||||
# New order seems to be in closed status?
|
||||
# nb_open_orders = len(Order.get_open_orders())
|
||||
# assert nb_open_orders == 1
|
||||
assert log_has_re(
|
||||
f"{'Sell' if is_short else 'Buy'} order cancelled to be replaced*", caplog)
|
||||
# Entry adjustment is called
|
||||
assert freqtrade.strategy.adjust_entry_price.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
@@ -2488,18 +2582,17 @@ def test_check_handle_cancelled_buy(
|
||||
Trade.query.session.add(open_trade)
|
||||
|
||||
# check it does cancel buy orders over the time limit
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 0
|
||||
assert rpc_mock.call_count == 1
|
||||
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
|
||||
nb_trades = len(trades)
|
||||
assert nb_trades == 0
|
||||
assert len(trades) == 0
|
||||
assert log_has_re(
|
||||
f"{'Sell' if is_short else 'Buy'} order cancelled on exchange for Trade.*", caplog)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
def test_check_handle_timedout_buy_exception(
|
||||
def test_manage_open_orders_buy_exception(
|
||||
default_conf_usdt, ticker_usdt, open_trade, is_short, fee, mocker
|
||||
) -> None:
|
||||
rpc_mock = patch_RPCManager(mocker)
|
||||
@@ -2519,7 +2612,7 @@ def test_check_handle_timedout_buy_exception(
|
||||
Trade.query.session.add(open_trade)
|
||||
|
||||
# check it does cancel buy orders over the time limit
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 0
|
||||
assert rpc_mock.call_count == 0
|
||||
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
|
||||
@@ -2528,7 +2621,7 @@ def test_check_handle_timedout_buy_exception(
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
def test_check_handle_timedout_exit_usercustom(
|
||||
def test_manage_open_orders_exit_usercustom(
|
||||
default_conf_usdt, ticker_usdt, limit_sell_order_old, mocker,
|
||||
is_short, open_trade_usdt, caplog
|
||||
) -> None:
|
||||
@@ -2559,13 +2652,13 @@ def test_check_handle_timedout_exit_usercustom(
|
||||
|
||||
Trade.query.session.add(open_trade_usdt)
|
||||
# Ensure default is false
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 0
|
||||
|
||||
freqtrade.strategy.check_exit_timeout = MagicMock(return_value=False)
|
||||
freqtrade.strategy.check_entry_timeout = MagicMock(return_value=False)
|
||||
# Return false - No impact
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 0
|
||||
assert rpc_mock.call_count == 0
|
||||
assert open_trade_usdt.is_open is False
|
||||
@@ -2575,7 +2668,7 @@ def test_check_handle_timedout_exit_usercustom(
|
||||
freqtrade.strategy.check_exit_timeout = MagicMock(side_effect=KeyError)
|
||||
freqtrade.strategy.check_entry_timeout = MagicMock(side_effect=KeyError)
|
||||
# Return Error - No impact
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 0
|
||||
assert rpc_mock.call_count == 0
|
||||
assert open_trade_usdt.is_open is False
|
||||
@@ -2585,7 +2678,7 @@ def test_check_handle_timedout_exit_usercustom(
|
||||
# Return True - sells!
|
||||
freqtrade.strategy.check_exit_timeout = MagicMock(return_value=True)
|
||||
freqtrade.strategy.check_entry_timeout = MagicMock(return_value=True)
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 1
|
||||
assert rpc_mock.call_count == 1
|
||||
assert open_trade_usdt.is_open is True
|
||||
@@ -2598,7 +2691,7 @@ def test_check_handle_timedout_exit_usercustom(
|
||||
mocker.patch('freqtrade.persistence.Trade.get_exit_order_count', return_value=1)
|
||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.execute_trade_exit',
|
||||
side_effect=DependencyException)
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert log_has_re('Unable to emergency sell .*', caplog)
|
||||
|
||||
et_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.execute_trade_exit')
|
||||
@@ -2608,16 +2701,16 @@ def test_check_handle_timedout_exit_usercustom(
|
||||
|
||||
# If cancelling fails - no emergency sell!
|
||||
with patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_exit', return_value=False):
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert et_mock.call_count == 0
|
||||
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert log_has_re('Emergency exiting trade.*', caplog)
|
||||
assert et_mock.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
def test_check_handle_timedout_exit(
|
||||
def test_manage_open_orders_exit(
|
||||
default_conf_usdt, ticker_usdt, limit_sell_order_old, mocker, is_short, open_trade_usdt
|
||||
) -> None:
|
||||
rpc_mock = patch_RPCManager(mocker)
|
||||
@@ -2644,7 +2737,7 @@ def test_check_handle_timedout_exit(
|
||||
freqtrade.strategy.check_exit_timeout = MagicMock(return_value=False)
|
||||
freqtrade.strategy.check_entry_timeout = MagicMock(return_value=False)
|
||||
# check it does cancel sell orders over the time limit
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 1
|
||||
assert rpc_mock.call_count == 1
|
||||
assert open_trade_usdt.is_open is True
|
||||
@@ -2680,7 +2773,7 @@ def test_check_handle_cancelled_exit(
|
||||
Trade.query.session.add(open_trade_usdt)
|
||||
|
||||
# check it does cancel sell orders over the time limit
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 0
|
||||
assert rpc_mock.call_count == 1
|
||||
assert open_trade_usdt.is_open is True
|
||||
@@ -2690,7 +2783,7 @@ def test_check_handle_cancelled_exit(
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
@pytest.mark.parametrize("leverage", [1, 3, 5, 10])
|
||||
def test_check_handle_timedout_partial(
|
||||
def test_manage_open_orders_partial(
|
||||
default_conf_usdt, ticker_usdt, limit_buy_order_old_partial, is_short, leverage,
|
||||
open_trade, mocker
|
||||
) -> None:
|
||||
@@ -2716,7 +2809,7 @@ def test_check_handle_timedout_partial(
|
||||
|
||||
# check it does cancel buy orders over the time limit
|
||||
# note this is for a partially-complete buy order
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 1
|
||||
assert rpc_mock.call_count == 2
|
||||
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
|
||||
@@ -2727,7 +2820,7 @@ def test_check_handle_timedout_partial(
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
def test_check_handle_timedout_partial_fee(
|
||||
def test_manage_open_orders_partial_fee(
|
||||
default_conf_usdt, ticker_usdt, open_trade, caplog, fee, is_short,
|
||||
limit_buy_order_old_partial, trades_for_order,
|
||||
limit_buy_order_old_partial_canceled, mocker
|
||||
@@ -2759,7 +2852,7 @@ def test_check_handle_timedout_partial_fee(
|
||||
Trade.query.session.add(open_trade)
|
||||
# cancelling a half-filled order should update the amount to the bought amount
|
||||
# and apply fees if necessary.
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
|
||||
assert log_has_re(r"Applying fee on amount for Trade.*", caplog)
|
||||
|
||||
@@ -2776,7 +2869,7 @@ def test_check_handle_timedout_partial_fee(
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
def test_check_handle_timedout_partial_except(
|
||||
def test_manage_open_orders_partial_except(
|
||||
default_conf_usdt, ticker_usdt, open_trade, caplog, fee, is_short,
|
||||
limit_buy_order_old_partial, trades_for_order,
|
||||
limit_buy_order_old_partial_canceled, mocker
|
||||
@@ -2807,7 +2900,7 @@ def test_check_handle_timedout_partial_except(
|
||||
Trade.query.session.add(open_trade)
|
||||
# cancelling a half-filled order should update the amount to the bought amount
|
||||
# and apply fees if necessary.
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
|
||||
assert log_has_re(r"Could not update trade amount: .*", caplog)
|
||||
|
||||
@@ -2823,8 +2916,8 @@ def test_check_handle_timedout_partial_except(
|
||||
assert trades[0].fee_open == fee()
|
||||
|
||||
|
||||
def test_check_handle_timedout_exception(default_conf_usdt, ticker_usdt, open_trade_usdt, mocker,
|
||||
caplog) -> None:
|
||||
def test_manage_open_orders_exception(default_conf_usdt, ticker_usdt, open_trade_usdt, mocker,
|
||||
caplog) -> None:
|
||||
patch_RPCManager(mocker)
|
||||
patch_exchange(mocker)
|
||||
cancel_order_mock = MagicMock()
|
||||
@@ -2845,7 +2938,7 @@ def test_check_handle_timedout_exception(default_conf_usdt, ticker_usdt, open_tr
|
||||
Trade.query.session.add(open_trade_usdt)
|
||||
|
||||
caplog.clear()
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
assert log_has_re(r"Cannot query order for Trade\(id=1, pair=ADA/USDT, amount=30.00000000, "
|
||||
r"is_short=False, leverage=1.0, "
|
||||
r"open_rate=2.00000000, open_since="
|
||||
@@ -3411,7 +3504,7 @@ def test_execute_trade_exit_with_stoploss_on_exchange(
|
||||
assert trade
|
||||
trades = [trade]
|
||||
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
freqtrade.exit_positions(trades)
|
||||
|
||||
# Increase the price and sell it
|
||||
@@ -3463,7 +3556,7 @@ def test_may_execute_trade_exit_after_stoploss_on_exchange_hit(
|
||||
|
||||
# Create some test data
|
||||
freqtrade.enter_positions()
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
trade = Trade.query.first()
|
||||
trades = [trade]
|
||||
assert trade.stoploss_order_id is None
|
||||
@@ -5233,7 +5326,7 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
|
||||
assert trade.stake_amount == 110
|
||||
assert not trade.fee_updated('buy')
|
||||
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
|
||||
trade = Trade.query.first()
|
||||
assert trade
|
||||
@@ -5339,7 +5432,7 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
|
||||
MagicMock(return_value=closed_dca_order_1))
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order',
|
||||
MagicMock(return_value=closed_dca_order_1))
|
||||
freqtrade.check_handle_timedout()
|
||||
freqtrade.manage_open_orders()
|
||||
|
||||
# Assert trade is as expected (averaged dca)
|
||||
trade = Trade.query.first()
|
||||
|
||||
Reference in New Issue
Block a user