use update_trade_state also for closed stoploss orders

This commit is contained in:
Matthias 2020-05-13 20:25:32 +02:00
parent 0c3bdd66ac
commit 60f26ba501
3 changed files with 36 additions and 30 deletions

View File

@ -752,7 +752,7 @@ class FreqtradeBot:
# We check if stoploss order is fulfilled # We check if stoploss order is fulfilled
if stoploss_order and stoploss_order['status'] == 'closed': if stoploss_order and stoploss_order['status'] == 'closed':
trade.sell_reason = SellType.STOPLOSS_ON_EXCHANGE.value trade.sell_reason = SellType.STOPLOSS_ON_EXCHANGE.value
trade.update(stoploss_order) self.update_trade_state(trade, stoploss_order, sl_order=True)
# Lock pair for one candle to prevent immediate rebuys # Lock pair for one candle to prevent immediate rebuys
self.strategy.lock_pair(trade.pair, self.strategy.lock_pair(trade.pair,
timeframe_to_next_date(self.config['ticker_interval'])) timeframe_to_next_date(self.config['ticker_interval']))
@ -1123,7 +1123,7 @@ class FreqtradeBot:
# #
def update_trade_state(self, trade: Trade, action_order: dict = None, def update_trade_state(self, trade: Trade, action_order: dict = None,
order_amount: float = None) -> bool: order_amount: float = None, sl_order: bool = False) -> bool:
""" """
Checks trades with open orders and updates the amount if necessary Checks trades with open orders and updates the amount if necessary
Handles closing both buy and sell orders. Handles closing both buy and sell orders.
@ -1131,34 +1131,37 @@ class FreqtradeBot:
""" """
# Get order details for actual price per unit # Get order details for actual price per unit
if trade.open_order_id: if trade.open_order_id:
# Update trade with order values order_id = trade.open_order_id
logger.info('Found open order for %s', trade) elif trade.stoploss_order_id and sl_order:
try: order_id = trade.stoploss_order_id
order = action_order or self.exchange.get_order(trade.open_order_id, trade.pair) else:
except InvalidOrderException as exception: return False
logger.warning('Unable to fetch order %s: %s', trade.open_order_id, exception) # Update trade with order values
return False logger.info('Found open order for %s', trade)
# Try update amount (binance-fix) try:
try: order = action_order or self.exchange.get_order(order_id, trade.pair)
new_amount = self.get_real_amount(trade, order, order_amount) except InvalidOrderException as exception:
if not isclose(order['amount'], new_amount, abs_tol=constants.MATH_CLOSE_PREC): logger.warning('Unable to fetch order %s: %s', order_id, exception)
order['amount'] = new_amount return False
order.pop('filled', None) # Try update amount (binance-fix)
trade.recalc_open_trade_price() try:
except DependencyException as exception: new_amount = self.get_real_amount(trade, order, order_amount)
logger.warning("Could not update trade amount: %s", exception) if not isclose(order['amount'], new_amount, abs_tol=constants.MATH_CLOSE_PREC):
order['amount'] = new_amount
order.pop('filled', None)
trade.recalc_open_trade_price()
except DependencyException as exception:
logger.warning("Could not update trade amount: %s", exception)
if self.exchange.check_order_canceled_empty(order): if self.exchange.check_order_canceled_empty(order):
# Trade has been cancelled on exchange # Trade has been cancelled on exchange
# Handling of this will happen in check_handle_timeout. # Handling of this will happen in check_handle_timeout.
return True return True
trade.update(order) trade.update(order)
# Updating wallets when order is closed # Updating wallets when order is closed
if not trade.is_open: if not trade.is_open:
self.wallets.update() self.wallets.update()
return False
def apply_fee_conditional(self, trade: Trade, trade_base_currency: str, def apply_fee_conditional(self, trade: Trade, trade_base_currency: str,
amount: float, fee_abs: float) -> float: amount: float, fee_abs: float) -> float:

View File

@ -1140,7 +1140,8 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog,
'status': 'closed', 'status': 'closed',
'type': 'stop_loss_limit', 'type': 'stop_loss_limit',
'price': 3, 'price': 3,
'average': 2 'average': 2,
'amount': limit_buy_order['amount'],
}) })
mocker.patch('freqtrade.exchange.Exchange.get_order', stoploss_order_hit) mocker.patch('freqtrade.exchange.Exchange.get_order', stoploss_order_hit)
assert freqtrade.handle_stoploss_on_exchange(trade) is True assert freqtrade.handle_stoploss_on_exchange(trade) is True

View File

@ -44,6 +44,8 @@ def test_may_execute_sell_stoploss_on_exchange_multi(default_conf, ticker, fee,
} }
stoploss_order_closed = stoploss_order_open.copy() stoploss_order_closed = stoploss_order_open.copy()
stoploss_order_closed['status'] = 'closed' stoploss_order_closed['status'] = 'closed'
stoploss_order_closed['filled'] = stoploss_order_closed['amount']
# Sell first trade based on stoploss, keep 2nd and 3rd trade open # Sell first trade based on stoploss, keep 2nd and 3rd trade open
stoploss_order_mock = MagicMock( stoploss_order_mock = MagicMock(
side_effect=[stoploss_order_closed, stoploss_order_open, stoploss_order_open]) side_effect=[stoploss_order_closed, stoploss_order_open, stoploss_order_open])
@ -98,7 +100,7 @@ def test_may_execute_sell_stoploss_on_exchange_multi(default_conf, ticker, fee,
assert cancel_order_mock.call_count == 1 assert cancel_order_mock.call_count == 1
# Wallets must be updated between stoploss cancellation and selling, and will be updated again # Wallets must be updated between stoploss cancellation and selling, and will be updated again
# during update_trade_state # during update_trade_state
assert wallets_mock.call_count == 3 assert wallets_mock.call_count == 4
trade = trades[0] trade = trades[0]
assert trade.sell_reason == SellType.STOPLOSS_ON_EXCHANGE.value assert trade.sell_reason == SellType.STOPLOSS_ON_EXCHANGE.value