parent
9f266cbcb2
commit
063511826c
@ -1072,6 +1072,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
order_obj = Order.parse_from_ccxt_object(stoploss_order, trade.pair, 'stoploss')
|
order_obj = Order.parse_from_ccxt_object(stoploss_order, trade.pair, 'stoploss')
|
||||||
trade.orders.append(order_obj)
|
trade.orders.append(order_obj)
|
||||||
trade.stoploss_order_id = str(stoploss_order['id'])
|
trade.stoploss_order_id = str(stoploss_order['id'])
|
||||||
|
trade.stoploss_last_update = datetime.now(timezone.utc)
|
||||||
return True
|
return True
|
||||||
except InsufficientFundsError as e:
|
except InsufficientFundsError as e:
|
||||||
logger.warning(f"Unable to place stoploss order {e}.")
|
logger.warning(f"Unable to place stoploss order {e}.")
|
||||||
@ -1145,10 +1146,9 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
if self.create_stoploss_order(trade=trade, stop_price=stop_price):
|
if self.create_stoploss_order(trade=trade, stop_price=stop_price):
|
||||||
# The above will return False if the placement failed and the trade was force-sold.
|
# The above will return False if the placement failed and the trade was force-sold.
|
||||||
# in which case the trade will be closed - which we must check below.
|
# in which case the trade will be closed - which we must check below.
|
||||||
trade.stoploss_last_update = datetime.utcnow()
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# If stoploss order is canceled for some reason we add it
|
# If stoploss order is canceled for some reason we add it again
|
||||||
if (trade.is_open
|
if (trade.is_open
|
||||||
and stoploss_order
|
and stoploss_order
|
||||||
and stoploss_order['status'] in ('canceled', 'cancelled')):
|
and stoploss_order['status'] in ('canceled', 'cancelled')):
|
||||||
@ -1186,7 +1186,8 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
if self.exchange.stoploss_adjust(stoploss_norm, order, side=trade.exit_side):
|
if self.exchange.stoploss_adjust(stoploss_norm, order, side=trade.exit_side):
|
||||||
# we check if the update is necessary
|
# we check if the update is necessary
|
||||||
update_beat = self.strategy.order_types.get('stoploss_on_exchange_interval', 60)
|
update_beat = self.strategy.order_types.get('stoploss_on_exchange_interval', 60)
|
||||||
if (datetime.utcnow() - trade.stoploss_last_update).total_seconds() >= update_beat:
|
upd_req = datetime.now(timezone.utc) - timedelta(seconds=update_beat)
|
||||||
|
if trade.stoploss_last_update_utc and upd_req >= trade.stoploss_last_update_utc:
|
||||||
# cancelling the current stoploss on exchange first
|
# cancelling the current stoploss on exchange first
|
||||||
logger.info(f"Cancelling current stoploss on exchange for pair {trade.pair} "
|
logger.info(f"Cancelling current stoploss on exchange for pair {trade.pair} "
|
||||||
f"(orderid:{order['id']}) in order to add another one ...")
|
f"(orderid:{order['id']}) in order to add another one ...")
|
||||||
|
@ -376,6 +376,12 @@ class LocalTrade():
|
|||||||
def open_date_utc(self):
|
def open_date_utc(self):
|
||||||
return self.open_date.replace(tzinfo=timezone.utc)
|
return self.open_date.replace(tzinfo=timezone.utc)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stoploss_last_update_utc(self):
|
||||||
|
if self.stoploss_last_update:
|
||||||
|
return self.stoploss_last_update.replace(tzinfo=timezone.utc)
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def close_date_utc(self):
|
def close_date_utc(self):
|
||||||
return self.close_date.replace(tzinfo=timezone.utc)
|
return self.close_date.replace(tzinfo=timezone.utc)
|
||||||
@ -560,7 +566,6 @@ class LocalTrade():
|
|||||||
self.stop_loss = stop_loss_norm
|
self.stop_loss = stop_loss_norm
|
||||||
|
|
||||||
self.stop_loss_pct = -1 * abs(percent)
|
self.stop_loss_pct = -1 * abs(percent)
|
||||||
self.stoploss_last_update = datetime.utcnow()
|
|
||||||
|
|
||||||
def adjust_stop_loss(self, current_price: float, stoploss: float,
|
def adjust_stop_loss(self, current_price: float, stoploss: float,
|
||||||
initial: bool = False, refresh: bool = False) -> None:
|
initial: bool = False, refresh: bool = False) -> None:
|
||||||
|
@ -1427,6 +1427,7 @@ def test_handle_stoploss_on_exchange_trailing(
|
|||||||
trade.is_open = True
|
trade.is_open = True
|
||||||
trade.open_order_id = None
|
trade.open_order_id = None
|
||||||
trade.stoploss_order_id = 100
|
trade.stoploss_order_id = 100
|
||||||
|
trade.stoploss_last_update = arrow.utcnow().shift(minutes=-20).datetime
|
||||||
|
|
||||||
stoploss_order_hanging = MagicMock(return_value={
|
stoploss_order_hanging = MagicMock(return_value={
|
||||||
'id': 100,
|
'id': 100,
|
||||||
@ -1456,7 +1457,7 @@ def test_handle_stoploss_on_exchange_trailing(
|
|||||||
)
|
)
|
||||||
|
|
||||||
cancel_order_mock = MagicMock()
|
cancel_order_mock = MagicMock()
|
||||||
stoploss_order_mock = MagicMock(return_value={'id': 13434334})
|
stoploss_order_mock = MagicMock(return_value={'id': 'so1'})
|
||||||
mocker.patch('freqtrade.exchange.Binance.cancel_stoploss_order', cancel_order_mock)
|
mocker.patch('freqtrade.exchange.Binance.cancel_stoploss_order', cancel_order_mock)
|
||||||
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss_order_mock)
|
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss_order_mock)
|
||||||
|
|
||||||
@ -1569,6 +1570,7 @@ def test_handle_stoploss_on_exchange_trailing_error(
|
|||||||
assert stoploss.call_count == 1
|
assert stoploss.call_count == 1
|
||||||
|
|
||||||
# Fail creating stoploss order
|
# Fail creating stoploss order
|
||||||
|
trade.stoploss_last_update = arrow.utcnow().shift(minutes=-601).datetime
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
cancel_mock = mocker.patch("freqtrade.exchange.Binance.cancel_stoploss_order", MagicMock())
|
cancel_mock = mocker.patch("freqtrade.exchange.Binance.cancel_stoploss_order", MagicMock())
|
||||||
mocker.patch("freqtrade.exchange.Binance.stoploss", side_effect=ExchangeError())
|
mocker.patch("freqtrade.exchange.Binance.stoploss", side_effect=ExchangeError())
|
||||||
@ -1657,6 +1659,7 @@ def test_handle_stoploss_on_exchange_custom_stop(
|
|||||||
trade.is_open = True
|
trade.is_open = True
|
||||||
trade.open_order_id = None
|
trade.open_order_id = None
|
||||||
trade.stoploss_order_id = 100
|
trade.stoploss_order_id = 100
|
||||||
|
trade.stoploss_last_update = arrow.utcnow().shift(minutes=-601).datetime
|
||||||
|
|
||||||
stoploss_order_hanging = MagicMock(return_value={
|
stoploss_order_hanging = MagicMock(return_value={
|
||||||
'id': 100,
|
'id': 100,
|
||||||
@ -1685,7 +1688,7 @@ def test_handle_stoploss_on_exchange_custom_stop(
|
|||||||
)
|
)
|
||||||
|
|
||||||
cancel_order_mock = MagicMock()
|
cancel_order_mock = MagicMock()
|
||||||
stoploss_order_mock = MagicMock(return_value={'id': 13434334})
|
stoploss_order_mock = MagicMock(return_value={'id': 'so1'})
|
||||||
mocker.patch('freqtrade.exchange.Binance.cancel_stoploss_order', cancel_order_mock)
|
mocker.patch('freqtrade.exchange.Binance.cancel_stoploss_order', cancel_order_mock)
|
||||||
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss_order_mock)
|
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss_order_mock)
|
||||||
|
|
||||||
@ -1727,8 +1730,7 @@ def test_handle_stoploss_on_exchange_custom_stop(
|
|||||||
assert freqtrade.handle_trade(trade) is True
|
assert freqtrade.handle_trade(trade) is True
|
||||||
|
|
||||||
|
|
||||||
def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog,
|
def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, limit_order) -> None:
|
||||||
limit_order) -> None:
|
|
||||||
|
|
||||||
enter_order = limit_order['buy']
|
enter_order = limit_order['buy']
|
||||||
exit_order = limit_order['sell']
|
exit_order = limit_order['sell']
|
||||||
@ -1784,6 +1786,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog,
|
|||||||
trade.is_open = True
|
trade.is_open = True
|
||||||
trade.open_order_id = None
|
trade.open_order_id = None
|
||||||
trade.stoploss_order_id = 100
|
trade.stoploss_order_id = 100
|
||||||
|
trade.stoploss_last_update = arrow.utcnow()
|
||||||
|
|
||||||
stoploss_order_hanging = MagicMock(return_value={
|
stoploss_order_hanging = MagicMock(return_value={
|
||||||
'id': 100,
|
'id': 100,
|
||||||
|
Loading…
Reference in New Issue
Block a user