Merge pull request #2559 from freqtrade/fix/cancelordercrash

Fix 'remaining' bug when handling buy timeout
This commit is contained in:
hroff-1902 2019-11-21 12:09:43 +03:00 committed by GitHub
commit 2acd2542ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 6 deletions

View File

@ -787,7 +787,7 @@ class FreqtradeBot:
continue
# Check if trade is still actually open
if float(order['remaining']) == 0.0:
if float(order.get('remaining', 0.0)) == 0.0:
self.wallets.update()
continue
@ -813,7 +813,8 @@ class FreqtradeBot:
})
def handle_timedout_limit_buy(self, trade: Trade, order: Dict) -> bool:
"""Buy timeout - cancel order
"""
Buy timeout - cancel order
:return: True if order was fully cancelled
"""
reason = "cancelled due to timeout"
@ -824,18 +825,22 @@ class FreqtradeBot:
corder = order
reason = "canceled on Exchange"
if corder['remaining'] == corder['amount']:
if corder.get('remaining', order['remaining']) == order['amount']:
# if trade is not partially completed, just delete the trade
self.handle_buy_order_full_cancel(trade, reason)
return True
# if trade is partially complete, edit the stake details for the trade
# and close the order
trade.amount = corder['amount'] - corder['remaining']
# cancel_order may not contain the full order dict, so we need to fallback
# to the order dict aquired before cancelling.
# we need to fall back to the values from order if corder does not contain these keys.
trade.amount = order['amount'] - corder.get('remaining', order['remaining'])
trade.stake_amount = trade.amount * trade.open_rate
# verify if fees were taken from amount to avoid problems during selling
try:
new_amount = self.get_real_amount(trade, corder, trade.amount)
new_amount = self.get_real_amount(trade, corder if 'fee' in corder else order,
trade.amount)
if not isclose(order['amount'], new_amount, abs_tol=constants.MATH_CLOSE_PREC):
trade.amount = new_amount
# Fee was applied, so set to 0

View File

@ -1804,7 +1804,7 @@ def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order,
def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, open_trade,
fee, mocker) -> None:
rpc_mock = patch_RPCManager(mocker)
cancel_order_mock = MagicMock()
cancel_order_mock = MagicMock(return_value=limit_buy_order_old)
patch_exchange(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
@ -2089,6 +2089,29 @@ def test_handle_timedout_limit_buy(mocker, default_conf, limit_buy_order) -> Non
assert cancel_order_mock.call_count == 1
def test_handle_timedout_limit_buy_corder_empty(mocker, default_conf, limit_buy_order) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
cancel_order_mock = MagicMock(return_value={})
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
cancel_order=cancel_order_mock
)
freqtrade = FreqtradeBot(default_conf)
Trade.session = MagicMock()
trade = MagicMock()
limit_buy_order['remaining'] = limit_buy_order['amount']
assert freqtrade.handle_timedout_limit_buy(trade, limit_buy_order)
assert cancel_order_mock.call_count == 1
cancel_order_mock.reset_mock()
limit_buy_order['amount'] = 2
assert not freqtrade.handle_timedout_limit_buy(trade, limit_buy_order)
assert cancel_order_mock.call_count == 1
def test_handle_timedout_limit_sell(mocker, default_conf) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)