Merge branch 'freqtrade:develop' into partial_sell
This commit is contained in:
commit
1196c00a23
@ -888,11 +888,15 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
stop_price = trade.open_rate * (1 + stoploss)
|
stop_price = trade.open_rate * (1 + stoploss)
|
||||||
|
|
||||||
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.
|
||||||
|
# in which case the trade will be closed - which we must check below.
|
||||||
trade.stoploss_last_update = datetime.utcnow()
|
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
|
||||||
if stoploss_order and stoploss_order['status'] in ('canceled', 'cancelled'):
|
if (trade.is_open
|
||||||
|
and stoploss_order
|
||||||
|
and stoploss_order['status'] in ('canceled', 'cancelled')):
|
||||||
if self.create_stoploss_order(trade=trade, stop_price=trade.stop_loss):
|
if self.create_stoploss_order(trade=trade, stop_price=trade.stop_loss):
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
@ -902,7 +906,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
# Finally we check if stoploss on exchange should be moved up because of trailing.
|
# Finally we check if stoploss on exchange should be moved up because of trailing.
|
||||||
# Triggered Orders are now real orders - so don't replace stoploss anymore
|
# Triggered Orders are now real orders - so don't replace stoploss anymore
|
||||||
if (
|
if (
|
||||||
stoploss_order
|
trade.is_open and stoploss_order
|
||||||
and stoploss_order.get('status_stop') != 'triggered'
|
and stoploss_order.get('status_stop') != 'triggered'
|
||||||
and (self.config.get('trailing_stop', False)
|
and (self.config.get('trailing_stop', False)
|
||||||
or self.config.get('use_custom_stoploss', False))
|
or self.config.get('use_custom_stoploss', False))
|
||||||
|
@ -925,12 +925,10 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog,
|
|||||||
}),
|
}),
|
||||||
create_order=MagicMock(side_effect=[
|
create_order=MagicMock(side_effect=[
|
||||||
{'id': limit_buy_order_usdt['id']},
|
{'id': limit_buy_order_usdt['id']},
|
||||||
{'id': limit_sell_order_usdt['id']},
|
limit_sell_order_usdt,
|
||||||
|
# {'id': limit_sell_order_usdt['id']},
|
||||||
]),
|
]),
|
||||||
get_fee=fee,
|
get_fee=fee,
|
||||||
)
|
|
||||||
mocker.patch.multiple(
|
|
||||||
'freqtrade.exchange.Binance',
|
|
||||||
stoploss=stoploss
|
stoploss=stoploss
|
||||||
)
|
)
|
||||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||||
@ -955,7 +953,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog,
|
|||||||
trade.stoploss_order_id = 100
|
trade.stoploss_order_id = 100
|
||||||
|
|
||||||
hanging_stoploss_order = MagicMock(return_value={'status': 'open'})
|
hanging_stoploss_order = MagicMock(return_value={'status': 'open'})
|
||||||
mocker.patch('freqtrade.exchange.Binance.fetch_stoploss_order', hanging_stoploss_order)
|
mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', hanging_stoploss_order)
|
||||||
|
|
||||||
assert freqtrade.handle_stoploss_on_exchange(trade) is False
|
assert freqtrade.handle_stoploss_on_exchange(trade) is False
|
||||||
assert trade.stoploss_order_id == 100
|
assert trade.stoploss_order_id == 100
|
||||||
@ -968,7 +966,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog,
|
|||||||
trade.stoploss_order_id = 100
|
trade.stoploss_order_id = 100
|
||||||
|
|
||||||
canceled_stoploss_order = MagicMock(return_value={'status': 'canceled'})
|
canceled_stoploss_order = MagicMock(return_value={'status': 'canceled'})
|
||||||
mocker.patch('freqtrade.exchange.Binance.fetch_stoploss_order', canceled_stoploss_order)
|
mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', canceled_stoploss_order)
|
||||||
stoploss.reset_mock()
|
stoploss.reset_mock()
|
||||||
|
|
||||||
assert freqtrade.handle_stoploss_on_exchange(trade) is False
|
assert freqtrade.handle_stoploss_on_exchange(trade) is False
|
||||||
@ -1000,7 +998,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog,
|
|||||||
'average': 2,
|
'average': 2,
|
||||||
'amount': limit_buy_order_usdt['amount'],
|
'amount': limit_buy_order_usdt['amount'],
|
||||||
})
|
})
|
||||||
mocker.patch('freqtrade.exchange.Binance.fetch_stoploss_order', stoploss_order_hit)
|
mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', stoploss_order_hit)
|
||||||
assert freqtrade.handle_stoploss_on_exchange(trade) is True
|
assert freqtrade.handle_stoploss_on_exchange(trade) is True
|
||||||
assert log_has_re(r'STOP_LOSS_LIMIT is hit for Trade\(id=1, .*\)\.', caplog)
|
assert log_has_re(r'STOP_LOSS_LIMIT is hit for Trade\(id=1, .*\)\.', caplog)
|
||||||
assert trade.stoploss_order_id is None
|
assert trade.stoploss_order_id is None
|
||||||
@ -1008,7 +1006,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog,
|
|||||||
caplog.clear()
|
caplog.clear()
|
||||||
|
|
||||||
mocker.patch(
|
mocker.patch(
|
||||||
'freqtrade.exchange.Binance.stoploss',
|
'freqtrade.exchange.Exchange.stoploss',
|
||||||
side_effect=ExchangeError()
|
side_effect=ExchangeError()
|
||||||
)
|
)
|
||||||
trade.is_open = True
|
trade.is_open = True
|
||||||
@ -1020,9 +1018,9 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog,
|
|||||||
# It should try to add stoploss order
|
# It should try to add stoploss order
|
||||||
trade.stoploss_order_id = 100
|
trade.stoploss_order_id = 100
|
||||||
stoploss.reset_mock()
|
stoploss.reset_mock()
|
||||||
mocker.patch('freqtrade.exchange.Binance.fetch_stoploss_order',
|
mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order',
|
||||||
side_effect=InvalidOrderException())
|
side_effect=InvalidOrderException())
|
||||||
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss)
|
mocker.patch('freqtrade.exchange.Exchange.stoploss', stoploss)
|
||||||
freqtrade.handle_stoploss_on_exchange(trade)
|
freqtrade.handle_stoploss_on_exchange(trade)
|
||||||
assert stoploss.call_count == 1
|
assert stoploss.call_count == 1
|
||||||
|
|
||||||
@ -1032,10 +1030,37 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog,
|
|||||||
trade.is_open = False
|
trade.is_open = False
|
||||||
stoploss.reset_mock()
|
stoploss.reset_mock()
|
||||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order')
|
mocker.patch('freqtrade.exchange.Exchange.fetch_order')
|
||||||
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss)
|
mocker.patch('freqtrade.exchange.Exchange.stoploss', stoploss)
|
||||||
assert freqtrade.handle_stoploss_on_exchange(trade) is False
|
assert freqtrade.handle_stoploss_on_exchange(trade) is False
|
||||||
assert stoploss.call_count == 0
|
assert stoploss.call_count == 0
|
||||||
|
|
||||||
|
# Seventh case: emergency exit triggered
|
||||||
|
# Trailing stop should not act anymore
|
||||||
|
stoploss_order_cancelled = MagicMock(side_effect=[{
|
||||||
|
'id': "100",
|
||||||
|
'status': 'canceled',
|
||||||
|
'type': 'stop_loss_limit',
|
||||||
|
'price': 3,
|
||||||
|
'average': 2,
|
||||||
|
'amount': limit_buy_order_usdt['amount'],
|
||||||
|
'info': {'stopPrice': 22},
|
||||||
|
}])
|
||||||
|
trade.stoploss_order_id = 100
|
||||||
|
trade.is_open = True
|
||||||
|
trade.stoploss_last_update = arrow.utcnow().shift(hours=-1).datetime
|
||||||
|
trade.stop_loss = 24
|
||||||
|
freqtrade.config['trailing_stop'] = True
|
||||||
|
stoploss = MagicMock(side_effect=InvalidOrderException())
|
||||||
|
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.cancel_stoploss_order_with_result',
|
||||||
|
side_effect=InvalidOrderException())
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', stoploss_order_cancelled)
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.stoploss', stoploss)
|
||||||
|
assert freqtrade.handle_stoploss_on_exchange(trade) is False
|
||||||
|
assert trade.stoploss_order_id is None
|
||||||
|
assert trade.is_open is False
|
||||||
|
assert trade.sell_reason == str(SellType.EMERGENCY_SELL)
|
||||||
|
|
||||||
|
|
||||||
def test_handle_sle_cancel_cant_recreate(mocker, default_conf_usdt, fee, caplog,
|
def test_handle_sle_cancel_cant_recreate(mocker, default_conf_usdt, fee, caplog,
|
||||||
limit_buy_order_usdt, limit_sell_order_usdt) -> None:
|
limit_buy_order_usdt, limit_sell_order_usdt) -> None:
|
||||||
|
Loading…
Reference in New Issue
Block a user