Avoid double notifications in case of partially filled buy orders

This commit is contained in:
Matthias 2020-08-26 22:17:43 +02:00
parent 5e75caa917
commit 9c0a3fffd7
5 changed files with 18 additions and 15 deletions

View File

@ -338,7 +338,9 @@ SCHEMA_MINIMAL_REQUIRED = [
CANCEL_REASON = {
"TIMEOUT": "cancelled due to timeout",
"PARTIALLY_FILLED": "partially filled - keeping order open",
"PARTIALLY_FILLED_KEEP_OPEN": "partially filled - keeping order open",
"PARTIALLY_FILLED": "partially filled",
"FULLY_CANCELLED": "fully cancelled",
"ALL_CANCELLED": "cancelled (all unfilled and partially filled open orders cancelled)",
"CANCELLED_ON_EXCHANGE": "cancelled on exchange",
"FORCE_SELL": "forcesold",

View File

@ -618,7 +618,7 @@ class FreqtradeBot:
# Send the message
self.rpc.send_msg(msg)
def _notify_buy_cancel(self, trade: Trade, order_type: str) -> None:
def _notify_buy_cancel(self, trade: Trade, order_type: str, reason: str) -> None:
"""
Sends rpc notification when a buy cancel occured.
"""
@ -637,6 +637,7 @@ class FreqtradeBot:
'amount': trade.amount,
'open_date': trade.open_date,
'current_rate': current_rate,
'reason': reason,
}
# Send the message
@ -993,13 +994,13 @@ class FreqtradeBot:
# Using filled to determine the filled amount
filled_amount = safe_value_fallback2(corder, order, 'filled', 'filled')
if isclose(filled_amount, 0.0, abs_tol=constants.MATH_CLOSE_PREC):
logger.info('Buy order fully cancelled. Removing %s from database.', trade)
# if trade is not partially completed, just delete the trade
Trade.session.delete(trade)
Trade.session.flush()
was_trade_fully_canceled = True
reason += f", {constants.CANCEL_REASON['FULLY_CANCELLED']}"
else:
# if trade is partially complete, edit the stake details for the trade
# and close the order
@ -1012,13 +1013,11 @@ class FreqtradeBot:
trade.open_order_id = None
logger.info('Partial buy order timeout for %s.', trade)
self.rpc.send_msg({
'type': RPCMessageType.STATUS_NOTIFICATION,
'status': f'Remaining buy order for {trade.pair} cancelled due to timeout'
})
reason += f", {constants.CANCEL_REASON['PARTIALLY_FILLED']}"
self.wallets.update()
self._notify_buy_cancel(trade, order_type=self.strategy.order_types['buy'])
self._notify_buy_cancel(trade, order_type=self.strategy.order_types['buy'],
reason=reason)
return was_trade_fully_canceled
def handle_cancel_sell(self, trade: Trade, order: Dict, reason: str) -> str:
@ -1049,7 +1048,7 @@ class FreqtradeBot:
trade.open_order_id = None
else:
# TODO: figure out how to handle partially complete sell orders
reason = constants.CANCEL_REASON['PARTIALLY_FILLED']
reason = constants.CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN']
self.wallets.update()
self._notify_sell_cancel(

View File

@ -149,7 +149,7 @@ class Telegram(RPC):
elif msg['type'] == RPCMessageType.BUY_CANCEL_NOTIFICATION:
message = ("\N{WARNING SIGN} *{exchange}:* "
"Cancelling Open Buy Order for {pair}".format(**msg))
"Cancelling open buy Order for {pair}. Reason: {reason}.".format(**msg))
elif msg['type'] == RPCMessageType.SELL_NOTIFICATION:
msg['amount'] = round(msg['amount'], 8)

View File

@ -14,6 +14,7 @@ from telegram import Chat, Message, Update
from telegram.error import NetworkError
from freqtrade import __version__
from freqtrade.constants import CANCEL_REASON
from freqtrade.edge import PairInfo
from freqtrade.freqtradebot import FreqtradeBot
from freqtrade.persistence import Trade
@ -1310,9 +1311,10 @@ def test_send_msg_buy_cancel_notification(default_conf, mocker) -> None:
'type': RPCMessageType.BUY_CANCEL_NOTIFICATION,
'exchange': 'Bittrex',
'pair': 'ETH/BTC',
'reason': CANCEL_REASON['TIMEOUT']
})
assert msg_mock.call_args[0][0] \
== ('\N{WARNING SIGN} *Bittrex:* Cancelling Open Buy Order for ETH/BTC')
assert (msg_mock.call_args[0][0] == '\N{WARNING SIGN} *Bittrex:* '
'Cancelling open buy Order for ETH/BTC. Reason: cancelled due to timeout.')
def test_send_msg_sell_notification(default_conf, mocker) -> None:

View File

@ -2527,13 +2527,13 @@ def test_handle_cancel_sell_limit(mocker, default_conf, fee) -> None:
send_msg_mock.reset_mock()
order['amount'] = 2
assert freqtrade.handle_cancel_sell(trade, order, reason) == CANCEL_REASON['PARTIALLY_FILLED']
assert freqtrade.handle_cancel_sell(trade, order, reason) == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN']
# Assert cancel_order was not called (callcount remains unchanged)
assert cancel_order_mock.call_count == 1
assert send_msg_mock.call_count == 1
assert freqtrade.handle_cancel_sell(trade, order, reason) == CANCEL_REASON['PARTIALLY_FILLED']
assert freqtrade.handle_cancel_sell(trade, order, reason) == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN']
# Message should not be iterated again
assert trade.sell_order_status == CANCEL_REASON['PARTIALLY_FILLED']
assert trade.sell_order_status == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN']
assert send_msg_mock.call_count == 1