mirror of
https://github.com/freqtrade/freqtrade.git
synced 2024-11-10 10:21:59 +00:00
Improve handling of order cancelation failures with force_exit
closes #8708
This commit is contained in:
parent
430cd24bbc
commit
5fc8426b9b
|
@ -755,7 +755,7 @@ class RPC:
|
|||
return {'status': 'Reloaded from orders from exchange'}
|
||||
|
||||
def __exec_force_exit(self, trade: Trade, ordertype: Optional[str],
|
||||
amount: Optional[float] = None) -> None:
|
||||
amount: Optional[float] = None) -> bool:
|
||||
# Check if there is there is an open order
|
||||
fully_canceled = False
|
||||
if trade.open_order_id:
|
||||
|
@ -770,6 +770,9 @@ class RPC:
|
|||
self._freqtrade.handle_cancel_exit(trade, order, CANCEL_REASON['FORCE_EXIT'])
|
||||
|
||||
if not fully_canceled:
|
||||
if trade.open_order_id is not None:
|
||||
# Order cancellation failed, so we can't exit.
|
||||
return False
|
||||
# Get current rate and execute sell
|
||||
current_rate = self._freqtrade.exchange.get_rate(
|
||||
trade.pair, side='exit', is_short=trade.is_short, refresh=True)
|
||||
|
@ -790,6 +793,9 @@ class RPC:
|
|||
trade, current_rate, exit_check, ordertype=order_type,
|
||||
sub_trade_amt=sub_amount)
|
||||
|
||||
return True
|
||||
return False
|
||||
|
||||
def _rpc_force_exit(self, trade_id: str, ordertype: Optional[str] = None, *,
|
||||
amount: Optional[float] = None) -> Dict[str, str]:
|
||||
"""
|
||||
|
@ -817,9 +823,11 @@ class RPC:
|
|||
logger.warning('force_exit: Invalid argument received')
|
||||
raise RPCException('invalid argument')
|
||||
|
||||
self.__exec_force_exit(trade, ordertype, amount)
|
||||
result = self.__exec_force_exit(trade, ordertype, amount)
|
||||
Trade.commit()
|
||||
self._freqtrade.wallets.update()
|
||||
if not result:
|
||||
raise RPCException('Failed to exit trade.')
|
||||
return {'result': f'Created exit order for trade {trade_id}.'}
|
||||
|
||||
def _force_entry_validations(self, pair: str, order_side: SignalDirection):
|
||||
|
|
|
@ -765,7 +765,7 @@ def test_rpc_force_exit(default_conf, ticker, fee, mocker) -> None:
|
|||
cancel_order_mock.reset_mock()
|
||||
trade = Trade.session.scalars(select(Trade).filter(Trade.id == '3')).first()
|
||||
amount = trade.amount
|
||||
# make an limit-sell open trade
|
||||
# make an limit-sell open order trade
|
||||
mocker.patch(
|
||||
f'{EXMS}.fetch_order',
|
||||
return_value={
|
||||
|
@ -778,12 +778,24 @@ def test_rpc_force_exit(default_conf, ticker, fee, mocker) -> None:
|
|||
'id': trade.orders[0].order_id,
|
||||
}
|
||||
)
|
||||
cancel_order_3 = mocker.patch(
|
||||
f'{EXMS}.cancel_order_with_result',
|
||||
return_value={
|
||||
'status': 'canceled',
|
||||
'type': 'limit',
|
||||
'side': 'sell',
|
||||
'amount': amount,
|
||||
'remaining': amount,
|
||||
'filled': 0.0,
|
||||
'id': trade.orders[0].order_id,
|
||||
}
|
||||
)
|
||||
msg = rpc._rpc_force_exit('3')
|
||||
assert msg == {'result': 'Created exit order for trade 3.'}
|
||||
# status quo, no exchange calls
|
||||
assert cancel_order_mock.call_count == 1
|
||||
assert cancel_order_3.call_count == 1
|
||||
assert cancel_order_mock.call_count == 0
|
||||
|
||||
cancel_order_mock.reset_mock()
|
||||
trade = Trade.session.scalars(select(Trade).filter(Trade.id == '2')).first()
|
||||
amount = trade.amount
|
||||
# make an limit-buy open trade, if there is no 'filled', don't sell it
|
||||
|
@ -796,10 +808,23 @@ def test_rpc_force_exit(default_conf, ticker, fee, mocker) -> None:
|
|||
'filled': None
|
||||
}
|
||||
)
|
||||
cancel_order_4 = mocker.patch(
|
||||
f'{EXMS}.cancel_order_with_result',
|
||||
return_value={
|
||||
'status': 'canceled',
|
||||
'type': 'limit',
|
||||
'side': 'sell',
|
||||
'amount': amount,
|
||||
'remaining': 0.0,
|
||||
'filled': amount,
|
||||
'id': trade.orders[0].order_id,
|
||||
}
|
||||
)
|
||||
# check that the trade is called, which is done by ensuring exchange.cancel_order is called
|
||||
msg = rpc._rpc_force_exit('4')
|
||||
assert msg == {'result': 'Created exit order for trade 4.'}
|
||||
assert cancel_order_mock.call_count == 1
|
||||
assert cancel_order_4.call_count == 1
|
||||
assert cancel_order_mock.call_count == 0
|
||||
assert trade.amount == amount
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user