/delete should Cancel open orders (and stoploss orders)
This commit is contained in:
parent
9163c7f3d3
commit
817f5289db
@ -11,9 +11,9 @@ from typing import Any, Dict, List, Optional, Tuple
|
|||||||
import arrow
|
import arrow
|
||||||
from numpy import NAN, mean
|
from numpy import NAN, mean
|
||||||
|
|
||||||
from freqtrade.exceptions import ExchangeError, PricingError
|
from freqtrade.exceptions import (ExchangeError, InvalidOrderException,
|
||||||
|
PricingError)
|
||||||
from freqtrade.exchange import timeframe_to_msecs, timeframe_to_minutes
|
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs
|
||||||
from freqtrade.misc import shorten_date
|
from freqtrade.misc import shorten_date
|
||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
from freqtrade.rpc.fiat_convert import CryptoToFiatConverter
|
from freqtrade.rpc.fiat_convert import CryptoToFiatConverter
|
||||||
@ -541,24 +541,42 @@ class RPC:
|
|||||||
def _rpc_delete(self, trade_id: str) -> Dict[str, str]:
|
def _rpc_delete(self, trade_id: str) -> Dict[str, str]:
|
||||||
"""
|
"""
|
||||||
Handler for delete <id>.
|
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:
|
with self._freqtrade._sell_lock:
|
||||||
trade = Trade.get_trades(
|
c_count = 0
|
||||||
trade_filter=[Trade.id == trade_id, ]
|
trade = Trade.get_trades(trade_filter=[Trade.id == trade_id]).first()
|
||||||
).first()
|
|
||||||
if not trade:
|
if not trade:
|
||||||
logger.warning('delete: Invalid argument received')
|
logger.warning('delete trade: Invalid argument received')
|
||||||
raise RPCException('invalid argument')
|
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()
|
Trade.session.flush()
|
||||||
self._freqtrade.wallets.update()
|
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]]:
|
def _rpc_performance(self) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
|
@ -8,7 +8,7 @@ import pytest
|
|||||||
from numpy import isnan
|
from numpy import isnan
|
||||||
|
|
||||||
from freqtrade.edge import PairInfo
|
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.persistence import Trade
|
||||||
from freqtrade.rpc import RPC, RPCException
|
from freqtrade.rpc import RPC, RPCException
|
||||||
from freqtrade.rpc.fiat_convert import CryptoToFiatConverter
|
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'
|
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,
|
def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
|
||||||
limit_buy_order, limit_sell_order, mocker) -> None:
|
limit_buy_order, limit_sell_order, mocker) -> None:
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
|
Loading…
Reference in New Issue
Block a user