/delete should Cancel open orders (and stoploss orders)

This commit is contained in:
Matthias 2020-08-04 19:43:22 +02:00
parent 9163c7f3d3
commit 817f5289db
2 changed files with 88 additions and 15 deletions

View File

@ -11,9 +11,9 @@ from typing import Any, Dict, List, Optional, Tuple
import arrow
from numpy import NAN, mean
from freqtrade.exceptions import ExchangeError, PricingError
from freqtrade.exchange import timeframe_to_msecs, timeframe_to_minutes
from freqtrade.exceptions import (ExchangeError, InvalidOrderException,
PricingError)
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs
from freqtrade.misc import shorten_date
from freqtrade.persistence import Trade
from freqtrade.rpc.fiat_convert import CryptoToFiatConverter
@ -541,24 +541,42 @@ class RPC:
def _rpc_delete(self, trade_id: str) -> Dict[str, str]:
"""
Handler for delete <id>.
Delete the given trade
Delete the given trade and close eventually existing open orders.
"""
def _exec_delete(trade: Trade) -> None:
Trade.session.delete(trade)
Trade.session.flush()
with self._freqtrade._sell_lock:
trade = Trade.get_trades(
trade_filter=[Trade.id == trade_id, ]
).first()
c_count = 0
trade = Trade.get_trades(trade_filter=[Trade.id == trade_id]).first()
if not trade:
logger.warning('delete: Invalid argument received')
logger.warning('delete trade: Invalid argument received')
raise RPCException('invalid argument')
_exec_delete(trade)
# Try cancelling regular order if that exists
if trade.open_order_id:
try:
self._freqtrade.exchange.cancel_order(trade.open_order_id, trade.pair)
c_count += 1
except (ExchangeError, InvalidOrderException):
pass
# cancel stoploss on exchange ...
if (self._freqtrade.strategy.order_types.get('stoploss_on_exchange')
and trade.stoploss_order_id):
try:
self._freqtrade.exchange.cancel_stoploss_order(trade.stoploss_order_id,
trade.pair)
c_count += 1
except (ExchangeError, InvalidOrderException):
pass
Trade.session.delete(trade)
Trade.session.flush()
self._freqtrade.wallets.update()
return {'result_msg': f'Deleted trade {trade_id}.'}
return {
'result': 'success',
'trade_id': trade_id,
'result_msg': f'Deleted trade {trade_id}. Closed {c_count} open orders.',
'cancel_order_count': c_count,
}
def _rpc_performance(self) -> List[Dict[str, Any]]:
"""

View File

@ -8,7 +8,7 @@ import pytest
from numpy import isnan
from freqtrade.edge import PairInfo
from freqtrade.exceptions import ExchangeError, TemporaryError
from freqtrade.exceptions import ExchangeError, InvalidOrderException, TemporaryError
from freqtrade.persistence import Trade
from freqtrade.rpc import RPC, RPCException
from freqtrade.rpc.fiat_convert import CryptoToFiatConverter
@ -291,6 +291,61 @@ def test_rpc_trade_history(mocker, default_conf, markets, fee):
assert trades['trades'][0]['pair'] == 'XRP/BTC'
def test_rpc_delete_trade(mocker, default_conf, fee, markets, caplog):
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
stoploss_mock = MagicMock()
cancel_mock = MagicMock()
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
markets=PropertyMock(return_value=markets),
cancel_order=cancel_mock,
cancel_stoploss_order=stoploss_mock,
)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
freqtradebot.strategy.order_types['stoploss_on_exchange'] = True
create_mock_trades(fee)
rpc = RPC(freqtradebot)
with pytest.raises(RPCException, match='invalid argument'):
rpc._rpc_delete('200')
create_mock_trades(fee)
trades = Trade.query.all()
trades[1].stoploss_order_id = '1234'
trades[2].stoploss_order_id = '1234'
assert len(trades) > 2
res = rpc._rpc_delete('1')
assert isinstance(res, dict)
assert res['result'] == 'success'
assert res['trade_id'] == '1'
assert res['cancel_order_count'] == 1
assert cancel_mock.call_count == 1
assert stoploss_mock.call_count == 0
cancel_mock.reset_mock()
stoploss_mock.reset_mock()
res = rpc._rpc_delete('2')
assert isinstance(res, dict)
assert cancel_mock.call_count == 1
assert stoploss_mock.call_count == 1
assert res['cancel_order_count'] == 2
stoploss_mock = mocker.patch('freqtrade.exchange.Exchange.cancel_stoploss_order',
side_effect=InvalidOrderException)
res = rpc._rpc_delete('3')
assert stoploss_mock.call_count == 1
stoploss_mock.reset_mock()
cancel_mock = mocker.patch('freqtrade.exchange.Exchange.cancel_order',
side_effect=InvalidOrderException)
res = rpc._rpc_delete('4')
assert cancel_mock.call_count == 1
assert stoploss_mock.call_count == 0
def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
limit_buy_order, limit_sell_order, mocker) -> None:
mocker.patch.multiple(