Merge pull request #7146 from freqtrade/fix/liquidation

Update liquidation price handling
This commit is contained in:
Matthias 2022-07-31 08:09:54 +02:00 committed by GitHub
commit 369c6da5d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 142 additions and 106 deletions

View File

@ -623,6 +623,7 @@ class AwesomeStrategy(IStrategy):
!!! Warning
`confirm_trade_exit()` can prevent stoploss exits, causing significant losses as this would ignore stoploss exits.
`confirm_trade_exit()` will not be called for Liquidations - as liquidations are forced by the exchange, and therefore cannot be rejected.
## Adjust trade position

View File

@ -9,6 +9,7 @@ class ExitType(Enum):
STOP_LOSS = "stop_loss"
STOPLOSS_ON_EXCHANGE = "stoploss_on_exchange"
TRAILING_STOP_LOSS = "trailing_stop_loss"
LIQUIDATION = "liquidation"
EXIT_SIGNAL = "exit_signal"
FORCE_EXIT = "force_exit"
EMERGENCY_EXIT = "emergency_exit"

View File

@ -1016,7 +1016,7 @@ class FreqtradeBot(LoggingMixin):
trade.stoploss_order_id = None
logger.error(f'Unable to place a stoploss order on exchange. {e}')
logger.warning('Exiting the trade forcefully')
self.execute_trade_exit(trade, trade.stop_loss, exit_check=ExitCheckTuple(
self.execute_trade_exit(trade, stop_price, exit_check=ExitCheckTuple(
exit_type=ExitType.EMERGENCY_EXIT))
except ExchangeError:
@ -1086,7 +1086,7 @@ class FreqtradeBot(LoggingMixin):
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.stoploss_or_liquidation):
return False
else:
trade.stoploss_order_id = None
@ -1115,7 +1115,7 @@ class FreqtradeBot(LoggingMixin):
:param order: Current on exchange stoploss order
:return: None
"""
stoploss_norm = self.exchange.price_to_precision(trade.pair, trade.stop_loss)
stoploss_norm = self.exchange.price_to_precision(trade.pair, trade.stoploss_or_liquidation)
if self.exchange.stoploss_adjust(stoploss_norm, order, side=trade.exit_side):
# we check if the update is necessary
@ -1133,7 +1133,7 @@ class FreqtradeBot(LoggingMixin):
f"for pair {trade.pair}")
# Create new stoploss order
if not self.create_stoploss_order(trade=trade, stop_price=trade.stop_loss):
if not self.create_stoploss_order(trade=trade, stop_price=stoploss_norm):
logger.warning(f"Could not create trailing stoploss order "
f"for pair {trade.pair}.")
@ -1432,14 +1432,15 @@ class FreqtradeBot(LoggingMixin):
)
exit_type = 'exit'
exit_reason = exit_tag or exit_check.exit_reason
if exit_check.exit_type in (ExitType.STOP_LOSS, ExitType.TRAILING_STOP_LOSS):
if exit_check.exit_type in (
ExitType.STOP_LOSS, ExitType.TRAILING_STOP_LOSS, ExitType.LIQUIDATION):
exit_type = 'stoploss'
# if stoploss is on exchange and we are on dry_run mode,
# we consider the sell price stop price
if (self.config['dry_run'] and exit_type == 'stoploss'
and self.strategy.order_types['stoploss_on_exchange']):
limit = trade.stop_loss
limit = trade.stoploss_or_liquidation
# set custom_exit_price if available
proposed_limit_rate = limit
@ -1464,11 +1465,12 @@ class FreqtradeBot(LoggingMixin):
amount = self._safe_exit_amount(trade.pair, trade.amount)
time_in_force = self.strategy.order_time_in_force['exit']
if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)(
if (exit_check.exit_type != ExitType.LIQUIDATION and not strategy_safe_wrapper(
self.strategy.confirm_trade_exit, default_retval=True)(
pair=trade.pair, trade=trade, order_type=order_type, amount=amount, rate=limit,
time_in_force=time_in_force, exit_reason=exit_reason,
sell_reason=exit_reason, # sellreason -> compatibility
current_time=datetime.now(timezone.utc)):
current_time=datetime.now(timezone.utc))):
logger.info(f"User denied exit for {trade.pair}.")
return False
@ -1661,7 +1663,7 @@ class FreqtradeBot(LoggingMixin):
trade = self.cancel_stoploss_on_exchange(trade)
# TODO: Margin will need to use interest_rate as well.
# interest_rate = self.exchange.get_interest_rate()
trade.set_isolated_liq(self.exchange.get_liquidation_price(
trade.set_liquidation_price(self.exchange.get_liquidation_price(
leverage=trade.leverage,
pair=trade.pair,
amount=trade.amount,

View File

@ -381,7 +381,8 @@ class Backtesting:
Get close rate for backtesting result
"""
# Special handling if high or low hit STOP_LOSS or ROI
if exit.exit_type in (ExitType.STOP_LOSS, ExitType.TRAILING_STOP_LOSS):
if exit.exit_type in (
ExitType.STOP_LOSS, ExitType.TRAILING_STOP_LOSS, ExitType.LIQUIDATION):
return self._get_close_rate_for_stoploss(row, trade, exit, trade_dur)
elif exit.exit_type == (ExitType.ROI):
return self._get_close_rate_for_roi(row, trade, exit, trade_dur)
@ -396,11 +397,16 @@ class Backtesting:
is_short = trade.is_short or False
leverage = trade.leverage or 1.0
side_1 = -1 if is_short else 1
if exit.exit_type == ExitType.LIQUIDATION and trade.liquidation_price:
stoploss_value = trade.liquidation_price
else:
stoploss_value = trade.stop_loss
if is_short:
if trade.stop_loss < row[LOW_IDX]:
if stoploss_value < row[LOW_IDX]:
return row[OPEN_IDX]
else:
if trade.stop_loss > row[HIGH_IDX]:
if stoploss_value > row[HIGH_IDX]:
return row[OPEN_IDX]
# Special case: trailing triggers within same candle as trade opened. Assume most
@ -433,7 +439,7 @@ class Backtesting:
return max(row[LOW_IDX], stop_rate)
# Set close_rate to stoploss
return trade.stop_loss
return stoploss_value
def _get_close_rate_for_roi(self, row: Tuple, trade: LocalTrade, exit: ExitCheckTuple,
trade_dur: int) -> float:
@ -592,7 +598,8 @@ class Backtesting:
# Confirm trade exit:
time_in_force = self.strategy.order_time_in_force['exit']
if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)(
if (exit_.exit_type != ExitType.LIQUIDATION and not strategy_safe_wrapper(
self.strategy.confirm_trade_exit, default_retval=True)(
pair=trade.pair,
trade=trade, # type: ignore[arg-type]
order_type='limit',
@ -601,7 +608,7 @@ class Backtesting:
time_in_force=time_in_force,
sell_reason=exit_reason, # deprecated
exit_reason=exit_reason,
current_time=exit_candle_time):
current_time=exit_candle_time)):
return None
trade.exit_reason = exit_reason
@ -807,7 +814,7 @@ class Backtesting:
trade.adjust_stop_loss(trade.open_rate, self.strategy.stoploss, initial=True)
trade.set_isolated_liq(self.exchange.get_liquidation_price(
trade.set_liquidation_price(self.exchange.get_liquidation_price(
pair=pair,
open_rate=propose_rate,
amount=amount,

View File

@ -302,6 +302,16 @@ class LocalTrade():
# Futures properties
funding_fees: Optional[float] = None
@property
def stoploss_or_liquidation(self) -> float:
if self.liquidation_price:
if self.is_short:
return min(self.stop_loss, self.liquidation_price)
else:
return max(self.stop_loss, self.liquidation_price)
return self.stop_loss
@property
def buy_tag(self) -> Optional[str]:
"""
@ -497,7 +507,7 @@ class LocalTrade():
self.max_rate = max(current_price, self.max_rate or self.open_rate)
self.min_rate = min(current_price_low, self.min_rate or self.open_rate)
def set_isolated_liq(self, liquidation_price: Optional[float]):
def set_liquidation_price(self, liquidation_price: Optional[float]):
"""
Method you should use to set self.liquidation price.
Assures stop_loss is not passed the liquidation price
@ -506,22 +516,13 @@ class LocalTrade():
return
self.liquidation_price = liquidation_price
def _set_stop_loss(self, stop_loss: float, percent: float):
def __set_stop_loss(self, stop_loss: float, percent: float):
"""
Method you should use to set self.stop_loss.
Assures stop_loss is not passed the liquidation price
Method used internally to set self.stop_loss.
"""
if self.liquidation_price is not None:
if self.is_short:
sl = min(stop_loss, self.liquidation_price)
else:
sl = max(stop_loss, self.liquidation_price)
else:
sl = stop_loss
if not self.stop_loss:
self.initial_stop_loss = sl
self.stop_loss = sl
self.initial_stop_loss = stop_loss
self.stop_loss = stop_loss
self.stop_loss_pct = -1 * abs(percent)
self.stoploss_last_update = datetime.utcnow()
@ -543,18 +544,12 @@ class LocalTrade():
leverage = self.leverage or 1.0
if self.is_short:
new_loss = float(current_price * (1 + abs(stoploss / leverage)))
# If trading with leverage, don't set the stoploss below the liquidation price
if self.liquidation_price:
new_loss = min(self.liquidation_price, new_loss)
else:
new_loss = float(current_price * (1 - abs(stoploss / leverage)))
# If trading with leverage, don't set the stoploss below the liquidation price
if self.liquidation_price:
new_loss = max(self.liquidation_price, new_loss)
# no stop loss assigned yet
if self.initial_stop_loss_pct is None or refresh:
self._set_stop_loss(new_loss, stoploss)
self.__set_stop_loss(new_loss, stoploss)
self.initial_stop_loss = new_loss
self.initial_stop_loss_pct = -1 * abs(stoploss)
@ -569,7 +564,7 @@ class LocalTrade():
# ? decreasing the minimum stoploss
if (higher_stop and not self.is_short) or (lower_stop and self.is_short):
logger.debug(f"{self.pair} - Adjusting stoploss...")
self._set_stop_loss(new_loss, stoploss)
self.__set_stop_loss(new_loss, stoploss)
else:
logger.debug(f"{self.pair} - Keeping current stoploss...")

View File

@ -49,7 +49,7 @@ class StoplossGuard(IProtection):
trades1 = Trade.get_trades_proxy(pair=pair, is_open=False, close_date=look_back_until)
trades = [trade for trade in trades1 if (str(trade.exit_reason) in (
ExitType.TRAILING_STOP_LOSS.value, ExitType.STOP_LOSS.value,
ExitType.STOPLOSS_ON_EXCHANGE.value)
ExitType.STOPLOSS_ON_EXCHANGE.value, ExitType.LIQUIDATION.value)
and trade.close_profit and trade.close_profit < self._profit_limit)]
if self._only_per_side:

View File

@ -963,7 +963,7 @@ class IStrategy(ABC, HyperStrategyMixin):
# ROI
# Trailing stoploss
if stoplossflag.exit_type == ExitType.STOP_LOSS:
if stoplossflag.exit_type in (ExitType.STOP_LOSS, ExitType.LIQUIDATION):
logger.debug(f"{trade.pair} - Stoploss hit. exit_type={stoplossflag.exit_type}")
exits.append(stoplossflag)
@ -1035,6 +1035,17 @@ class IStrategy(ABC, HyperStrategyMixin):
sl_higher_long = (trade.stop_loss >= (low or current_rate) and not trade.is_short)
sl_lower_short = (trade.stop_loss <= (high or current_rate) and trade.is_short)
liq_higher_long = (trade.liquidation_price
and trade.liquidation_price >= (low or current_rate)
and not trade.is_short)
liq_lower_short = (trade.liquidation_price
and trade.liquidation_price <= (high or current_rate)
and trade.is_short)
if (liq_higher_long or liq_lower_short):
logger.debug(f"{trade.pair} - Liquidation price hit. exit_type=ExitType.LIQUIDATION")
return ExitCheckTuple(exit_type=ExitType.LIQUIDATION)
# evaluate if the stoploss was hit if stoploss is not on exchange
# in Dry-Run, this handles stoploss logic as well, as the logic will not be different to
# regular stoploss handling.
@ -1052,13 +1063,6 @@ class IStrategy(ABC, HyperStrategyMixin):
f"stoploss is {trade.stop_loss:.6f}, "
f"initial stoploss was at {trade.initial_stop_loss:.6f}, "
f"trade opened at {trade.open_rate:.6f}")
new_stoploss = (
trade.stop_loss + trade.initial_stop_loss
if trade.is_short else
trade.stop_loss - trade.initial_stop_loss
)
logger.debug(f"{trade.pair} - Trailing stop saved "
f"{new_stoploss:.6f}")
return ExitCheckTuple(exit_type=exit_type)

View File

@ -408,28 +408,31 @@ def test_min_roi_reached3(default_conf, fee) -> None:
@pytest.mark.parametrize(
'profit,adjusted,expected,trailing,custom,profit2,adjusted2,expected2,custom_stop', [
'profit,adjusted,expected,liq,trailing,custom,profit2,adjusted2,expected2,custom_stop', [
# Profit, adjusted stoploss(absolute), profit for 2nd call, enable trailing,
# enable custom stoploss, expected after 1st call, expected after 2nd call
(0.2, 0.9, ExitType.NONE, False, False, 0.3, 0.9, ExitType.NONE, None),
(0.2, 0.9, ExitType.NONE, False, False, -0.2, 0.9, ExitType.STOP_LOSS, None),
(0.2, 1.14, ExitType.NONE, True, False, 0.05, 1.14, ExitType.TRAILING_STOP_LOSS, None),
(0.01, 0.96, ExitType.NONE, True, False, 0.05, 1, ExitType.NONE, None),
(0.05, 1, ExitType.NONE, True, False, -0.01, 1, ExitType.TRAILING_STOP_LOSS, None),
(0.2, 0.9, ExitType.NONE, None, False, False, 0.3, 0.9, ExitType.NONE, None),
(0.2, 0.9, ExitType.NONE, None, False, False, -0.2, 0.9, ExitType.STOP_LOSS, None),
(0.2, 0.9, ExitType.NONE, 0.8, False, False, -0.2, 0.9, ExitType.LIQUIDATION, None),
(0.2, 1.14, ExitType.NONE, None, True, False, 0.05, 1.14, ExitType.TRAILING_STOP_LOSS,
None),
(0.01, 0.96, ExitType.NONE, None, True, False, 0.05, 1, ExitType.NONE, None),
(0.05, 1, ExitType.NONE, None, True, False, -0.01, 1, ExitType.TRAILING_STOP_LOSS, None),
# Default custom case - trails with 10%
(0.05, 0.95, ExitType.NONE, False, True, -0.02, 0.95, ExitType.NONE, None),
(0.05, 0.95, ExitType.NONE, False, True, -0.06, 0.95, ExitType.TRAILING_STOP_LOSS, None),
(0.05, 1, ExitType.NONE, False, True, -0.06, 1, ExitType.TRAILING_STOP_LOSS,
(0.05, 0.95, ExitType.NONE, None, False, True, -0.02, 0.95, ExitType.NONE, None),
(0.05, 0.95, ExitType.NONE, None, False, True, -0.06, 0.95, ExitType.TRAILING_STOP_LOSS,
None),
(0.05, 1, ExitType.NONE, None, False, True, -0.06, 1, ExitType.TRAILING_STOP_LOSS,
lambda **kwargs: -0.05),
(0.05, 1, ExitType.NONE, False, True, 0.09, 1.04, ExitType.NONE,
(0.05, 1, ExitType.NONE, None, False, True, 0.09, 1.04, ExitType.NONE,
lambda **kwargs: -0.05),
(0.05, 0.95, ExitType.NONE, False, True, 0.09, 0.98, ExitType.NONE,
(0.05, 0.95, ExitType.NONE, None, False, True, 0.09, 0.98, ExitType.NONE,
lambda current_profit, **kwargs: -0.1 if current_profit < 0.6 else -(current_profit * 2)),
# Error case - static stoploss in place
(0.05, 0.9, ExitType.NONE, False, True, 0.09, 0.9, ExitType.NONE,
(0.05, 0.9, ExitType.NONE, None, False, True, 0.09, 0.9, ExitType.NONE,
lambda **kwargs: None),
])
def test_stop_loss_reached(default_conf, fee, profit, adjusted, expected, trailing, custom,
def test_stop_loss_reached(default_conf, fee, profit, adjusted, expected, liq, trailing, custom,
profit2, adjusted2, expected2, custom_stop) -> None:
strategy = StrategyResolver.load_strategy(default_conf)
@ -442,6 +445,7 @@ def test_stop_loss_reached(default_conf, fee, profit, adjusted, expected, traili
fee_close=fee.return_value,
exchange='binance',
open_rate=1,
liquidation_price=liq,
)
trade.adjust_min_max_rates(trade.open_rate, trade.open_rate)
strategy.trailing_stop = trailing

View File

@ -99,7 +99,7 @@ def test_enter_exit_side(fee, is_short):
@pytest.mark.usefixtures("init_persistence")
def test_set_stop_loss_isolated_liq(fee):
def test_set_stop_loss_liquidation(fee):
trade = Trade(
id=2,
pair='ADA/USDT',
@ -115,73 +115,94 @@ def test_set_stop_loss_isolated_liq(fee):
leverage=2.0,
trading_mode=margin
)
trade.set_isolated_liq(0.09)
trade.set_liquidation_price(0.09)
assert trade.liquidation_price == 0.09
assert trade.stop_loss is None
assert trade.initial_stop_loss is None
trade._set_stop_loss(0.1, (1.0 / 9.0))
trade.adjust_stop_loss(2.0, 0.2, True)
assert trade.liquidation_price == 0.09
assert trade.stop_loss == 0.1
assert trade.initial_stop_loss == 0.1
assert trade.stop_loss == 1.8
assert trade.initial_stop_loss == 1.8
trade.set_isolated_liq(0.08)
trade.set_liquidation_price(0.08)
assert trade.liquidation_price == 0.08
assert trade.stop_loss == 0.1
assert trade.initial_stop_loss == 0.1
assert trade.stop_loss == 1.8
assert trade.initial_stop_loss == 1.8
trade.set_isolated_liq(0.11)
trade._set_stop_loss(0.1, 0)
trade.set_liquidation_price(0.11)
trade.adjust_stop_loss(2.0, 0.2)
assert trade.liquidation_price == 0.11
assert trade.stop_loss == 0.11
assert trade.initial_stop_loss == 0.1
# Stoploss does not change from liquidation price
assert trade.stop_loss == 1.8
assert trade.initial_stop_loss == 1.8
# lower stop doesn't move stoploss
trade._set_stop_loss(0.1, 0)
trade.adjust_stop_loss(1.8, 0.2)
assert trade.liquidation_price == 0.11
assert trade.stop_loss == 0.11
assert trade.initial_stop_loss == 0.1
assert trade.stop_loss == 1.8
assert trade.initial_stop_loss == 1.8
# higher stop does move stoploss
trade.adjust_stop_loss(2.1, 0.1)
assert trade.liquidation_price == 0.11
assert pytest.approx(trade.stop_loss) == 1.994999
assert trade.initial_stop_loss == 1.8
assert trade.stoploss_or_liquidation == trade.stop_loss
trade.stop_loss = None
trade.liquidation_price = None
trade.initial_stop_loss = None
trade.initial_stop_loss_pct = None
trade._set_stop_loss(0.07, 0)
trade.adjust_stop_loss(2.0, 0.1, True)
assert trade.liquidation_price is None
assert trade.stop_loss == 0.07
assert trade.initial_stop_loss == 0.07
assert trade.stop_loss == 1.9
assert trade.initial_stop_loss == 1.9
assert trade.stoploss_or_liquidation == 1.9
trade.is_short = True
trade.recalc_open_trade_value()
trade.stop_loss = None
trade.initial_stop_loss = None
trade.initial_stop_loss_pct = None
trade.set_isolated_liq(0.09)
assert trade.liquidation_price == 0.09
trade.set_liquidation_price(3.09)
assert trade.liquidation_price == 3.09
assert trade.stop_loss is None
assert trade.initial_stop_loss is None
trade._set_stop_loss(0.08, (1.0 / 9.0))
assert trade.liquidation_price == 0.09
assert trade.stop_loss == 0.08
assert trade.initial_stop_loss == 0.08
trade.adjust_stop_loss(2.0, 0.2)
assert trade.liquidation_price == 3.09
assert trade.stop_loss == 2.2
assert trade.initial_stop_loss == 2.2
assert trade.stoploss_or_liquidation == 2.2
trade.set_isolated_liq(0.1)
assert trade.liquidation_price == 0.1
assert trade.stop_loss == 0.08
assert trade.initial_stop_loss == 0.08
trade.set_liquidation_price(3.1)
assert trade.liquidation_price == 3.1
assert trade.stop_loss == 2.2
assert trade.initial_stop_loss == 2.2
assert trade.stoploss_or_liquidation == 2.2
trade.set_isolated_liq(0.07)
trade._set_stop_loss(0.1, (1.0 / 8.0))
assert trade.liquidation_price == 0.07
assert trade.stop_loss == 0.07
assert trade.initial_stop_loss == 0.08
trade.set_liquidation_price(3.8)
assert trade.liquidation_price == 3.8
# Stoploss does not change from liquidation price
assert trade.stop_loss == 2.2
assert trade.initial_stop_loss == 2.2
# Stop doesn't move stop higher
trade._set_stop_loss(0.1, (1.0 / 9.0))
assert trade.liquidation_price == 0.07
assert trade.stop_loss == 0.07
assert trade.initial_stop_loss == 0.08
trade.adjust_stop_loss(2.0, 0.3)
assert trade.liquidation_price == 3.8
assert trade.stop_loss == 2.2
assert trade.initial_stop_loss == 2.2
# Stoploss does move lower
trade.set_liquidation_price(1.5)
trade.adjust_stop_loss(1.8, 0.1)
assert trade.liquidation_price == 1.5
assert pytest.approx(trade.stop_loss) == 1.89
assert trade.initial_stop_loss == 2.2
assert trade.stoploss_or_liquidation == 1.5
@pytest.mark.parametrize('exchange,is_short,lev,minutes,rate,interest,trading_mode', [
@ -1537,26 +1558,26 @@ def test_adjust_stop_loss(fee):
# Get percent of profit with a custom rate (Higher than open rate)
trade.adjust_stop_loss(1.3, -0.1)
assert round(trade.stop_loss, 8) == 1.17
assert pytest.approx(trade.stop_loss) == 1.17
assert trade.stop_loss_pct == -0.1
assert trade.initial_stop_loss == 0.95
assert trade.initial_stop_loss_pct == -0.05
# current rate lower again ... should not change
trade.adjust_stop_loss(1.2, 0.1)
assert round(trade.stop_loss, 8) == 1.17
assert pytest.approx(trade.stop_loss) == 1.17
assert trade.initial_stop_loss == 0.95
assert trade.initial_stop_loss_pct == -0.05
# current rate higher... should raise stoploss
trade.adjust_stop_loss(1.4, 0.1)
assert round(trade.stop_loss, 8) == 1.26
assert pytest.approx(trade.stop_loss) == 1.26
assert trade.initial_stop_loss == 0.95
assert trade.initial_stop_loss_pct == -0.05
# Initial is true but stop_loss set - so doesn't do anything
trade.adjust_stop_loss(1.7, 0.1, True)
assert round(trade.stop_loss, 8) == 1.26
assert pytest.approx(trade.stop_loss) == 1.26
assert trade.initial_stop_loss == 0.95
assert trade.initial_stop_loss_pct == -0.05
assert trade.stop_loss_pct == -0.1
@ -1609,9 +1630,10 @@ def test_adjust_stop_loss_short(fee):
assert trade.initial_stop_loss == 1.05
assert trade.initial_stop_loss_pct == -0.05
assert trade.stop_loss_pct == -0.1
trade.set_isolated_liq(0.63)
# Liquidation price is lower than stoploss - so liquidation would trigger first.
trade.set_liquidation_price(0.63)
trade.adjust_stop_loss(0.59, -0.1)
assert trade.stop_loss == 0.63
assert trade.stop_loss == 0.649
assert trade.liquidation_price == 0.63
@ -2009,10 +2031,10 @@ def test_stoploss_reinitialization_short(default_conf, fee):
assert trade_adj.initial_stop_loss == 1.01
assert trade_adj.initial_stop_loss_pct == -0.05
# Stoploss can't go above liquidation price
trade_adj.set_isolated_liq(0.985)
trade_adj.set_liquidation_price(0.985)
trade.adjust_stop_loss(0.9799, -0.05)
assert trade_adj.stop_loss == 0.985
assert trade_adj.stop_loss == 0.985
assert trade_adj.stop_loss == 0.989699
assert trade_adj.liquidation_price == 0.985
def test_update_fee(fee):