Use get_stoploss_order and cancel_stoploss_order
This allows exchanges to use stoploss which don't have the same endpoints
This commit is contained in:
parent
d90d6ed5d0
commit
f83c1c5abf
@ -79,7 +79,7 @@ class Exchange:
|
||||
|
||||
if config['dry_run']:
|
||||
logger.info('Instance is running with dry_run enabled')
|
||||
|
||||
logger.info(f"Using CCXT {ccxt.__version__}")
|
||||
exchange_config = config['exchange']
|
||||
|
||||
# Deep merge ft_has with default ft_has options
|
||||
@ -952,6 +952,9 @@ class Exchange:
|
||||
except ccxt.BaseError as e:
|
||||
raise OperationalException(e) from e
|
||||
|
||||
# Assign method to get_stoploss_order to allow easy overriding in other classes
|
||||
cancel_stoploss_order = cancel_order
|
||||
|
||||
def is_cancel_order_result_suitable(self, corder) -> bool:
|
||||
if not isinstance(corder, dict):
|
||||
return False
|
||||
@ -1004,6 +1007,9 @@ class Exchange:
|
||||
except ccxt.BaseError as e:
|
||||
raise OperationalException(e) from e
|
||||
|
||||
# Assign method to get_stoploss_order to allow easy overriding in other classes
|
||||
get_stoploss_order = get_order
|
||||
|
||||
@retrier
|
||||
def fetch_l2_order_book(self, pair: str, limit: int = 100) -> dict:
|
||||
"""
|
||||
|
@ -7,6 +7,7 @@ import ccxt
|
||||
from freqtrade.exceptions import (DependencyException, InvalidOrderException,
|
||||
OperationalException, TemporaryError)
|
||||
from freqtrade.exchange import Exchange
|
||||
from freqtrade.exchange.common import retrier
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -66,3 +67,46 @@ class Ftx(Exchange):
|
||||
f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e
|
||||
except ccxt.BaseError as e:
|
||||
raise OperationalException(e) from e
|
||||
|
||||
@retrier
|
||||
def get_stoploss_order(self, order_id: str, pair: str) -> Dict:
|
||||
if self._config['dry_run']:
|
||||
try:
|
||||
order = self._dry_run_open_orders[order_id]
|
||||
return order
|
||||
except KeyError as e:
|
||||
# Gracefully handle errors with dry-run orders.
|
||||
raise InvalidOrderException(
|
||||
f'Tried to get an invalid dry-run-order (id: {order_id}). Message: {e}') from e
|
||||
try:
|
||||
orders = self._api.fetch_orders('BNB/USD', None, params={'type': 'stop'})
|
||||
|
||||
order = [order for order in orders if order['id'] == order_id]
|
||||
if len(order) == 1:
|
||||
return order[0]
|
||||
else:
|
||||
raise InvalidOrderException(f"Could not get Stoploss Order for id {order_id}")
|
||||
|
||||
except ccxt.InvalidOrder as e:
|
||||
raise InvalidOrderException(
|
||||
f'Tried to get an invalid order (id: {order_id}). Message: {e}') from e
|
||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||
raise TemporaryError(
|
||||
f'Could not get order due to {e.__class__.__name__}. Message: {e}') from e
|
||||
except ccxt.BaseError as e:
|
||||
raise OperationalException(e) from e
|
||||
|
||||
@retrier
|
||||
def cancel_stoploss_order(self, order_id: str, pair: str) -> None:
|
||||
if self._config['dry_run']:
|
||||
return
|
||||
try:
|
||||
return self._api.cancel_order(order_id, pair, params={'type': 'stop'})
|
||||
except ccxt.InvalidOrder as e:
|
||||
raise InvalidOrderException(
|
||||
f'Could not cancel order. Message: {e}') from e
|
||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||
raise TemporaryError(
|
||||
f'Could not cancel order due to {e.__class__.__name__}. Message: {e}') from e
|
||||
except ccxt.BaseError as e:
|
||||
raise OperationalException(e) from e
|
||||
|
@ -774,13 +774,13 @@ class FreqtradeBot:
|
||||
|
||||
try:
|
||||
# First we check if there is already a stoploss on exchange
|
||||
stoploss_order = self.exchange.get_order(trade.stoploss_order_id, trade.pair) \
|
||||
stoploss_order = self.exchange.get_stoploss_order(trade.stoploss_order_id, trade.pair) \
|
||||
if trade.stoploss_order_id else None
|
||||
except InvalidOrderException as exception:
|
||||
logger.warning('Unable to fetch stoploss order: %s', exception)
|
||||
|
||||
# We check if stoploss order is fulfilled
|
||||
if stoploss_order and stoploss_order['status'] == 'closed':
|
||||
if stoploss_order and stoploss_order['status'] in ('closed', 'triggered'):
|
||||
trade.sell_reason = SellType.STOPLOSS_ON_EXCHANGE.value
|
||||
self.update_trade_state(trade, stoploss_order, sl_order=True)
|
||||
# Lock pair for one candle to prevent immediate rebuys
|
||||
@ -807,7 +807,7 @@ class FreqtradeBot:
|
||||
return False
|
||||
|
||||
# If stoploss order is canceled for some reason we add it
|
||||
if stoploss_order and stoploss_order['status'] == 'canceled':
|
||||
if stoploss_order and stoploss_order['status'] in ('canceled', 'cancelled'):
|
||||
if self.create_stoploss_order(trade=trade, stop_price=trade.stop_loss,
|
||||
rate=trade.stop_loss):
|
||||
return False
|
||||
@ -840,7 +840,7 @@ class FreqtradeBot:
|
||||
logger.info('Trailing stoploss: cancelling current stoploss on exchange (id:{%s}) '
|
||||
'in order to add another one ...', order['id'])
|
||||
try:
|
||||
self.exchange.cancel_order(order['id'], trade.pair)
|
||||
self.exchange.cancel_stoploss_order(order['id'], trade.pair)
|
||||
except InvalidOrderException:
|
||||
logger.exception(f"Could not cancel stoploss order {order['id']} "
|
||||
f"for pair {trade.pair}")
|
||||
@ -1068,7 +1068,7 @@ class FreqtradeBot:
|
||||
# First cancelling stoploss on exchange ...
|
||||
if self.strategy.order_types.get('stoploss_on_exchange') and trade.stoploss_order_id:
|
||||
try:
|
||||
self.exchange.cancel_order(trade.stoploss_order_id, trade.pair)
|
||||
self.exchange.cancel_stoploss_order(trade.stoploss_order_id, trade.pair)
|
||||
except InvalidOrderException:
|
||||
logger.exception(f"Could not cancel stoploss order {trade.stoploss_order_id}")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user