Added checks for making sure stop_loss doesn't go below liquidation_price

This commit is contained in:
Sam Germain 2021-07-05 23:53:49 -06:00
parent 0bd71f87d0
commit 811cea288d
4 changed files with 46 additions and 6 deletions

View File

@ -294,8 +294,30 @@ class LocalTrade():
def __init__(self, **kwargs): def __init__(self, **kwargs):
for key in kwargs: for key in kwargs:
setattr(self, key, kwargs[key]) setattr(self, key, kwargs[key])
self.set_liquidation_price(self.liquidation_price)
self.recalc_open_trade_value() self.recalc_open_trade_value()
def set_stop_loss_helper(self, stop_loss: Optional[float], liquidation_price: Optional[float]):
# Stoploss would be better as a computed variable, but that messes up the database so it might not be possible
# TODO-mg: What should be done about initial_stop_loss
if liquidation_price is not None:
if stop_loss is not None:
if self.is_short:
self.stop_loss = min(stop_loss, liquidation_price)
else:
self.stop_loss = max(stop_loss, liquidation_price)
else:
self.stop_loss = liquidation_price
self.liquidation_price = liquidation_price
else:
self.stop_loss = stop_loss
def set_stop_loss(self, stop_loss: float):
self.set_stop_loss_helper(stop_loss=stop_loss, liquidation_price=self.liquidation_price)
def set_liquidation_price(self, liquidation_price: float):
self.set_stop_loss_helper(stop_loss=self.stop_loss, liquidation_price=liquidation_price)
def __repr__(self): def __repr__(self):
open_since = self.open_date.strftime(DATETIME_PRINT_FORMAT) if self.is_open else 'closed' open_since = self.open_date.strftime(DATETIME_PRINT_FORMAT) if self.is_open else 'closed'
@ -390,7 +412,7 @@ class LocalTrade():
def _set_new_stoploss(self, new_loss: float, stoploss: float): def _set_new_stoploss(self, new_loss: float, stoploss: float):
"""Assign new stop value""" """Assign new stop value"""
self.stop_loss = new_loss self.set_stop_loss(new_loss)
if self.is_short: if self.is_short:
self.stop_loss_pct = abs(stoploss) self.stop_loss_pct = abs(stoploss)
else: else:
@ -484,6 +506,9 @@ class LocalTrade():
self.amount = float(safe_value_fallback(order, 'filled', 'amount')) self.amount = float(safe_value_fallback(order, 'filled', 'amount'))
if 'leverage' in order: if 'leverage' in order:
self.leverage = order['leverage'] self.leverage = order['leverage']
if 'liquidation_price' in order:
self.liquidation_price = order['liquidation_price']
self.set_stop_loss(self.stop_loss)
self.recalc_open_trade_value() self.recalc_open_trade_value()
if self.is_open: if self.is_open:
payment = "SELL" if self.is_short else "BUY" payment = "SELL" if self.is_short else "BUY"

View File

@ -2132,7 +2132,8 @@ def limit_short_order_open():
'cost': 0.00106733393, 'cost': 0.00106733393,
'remaining': 90.99181073, 'remaining': 90.99181073,
'status': 'open', 'status': 'open',
'is_short': True 'is_short': True,
'liquidation_price': 0.00001300
} }
@ -2185,7 +2186,8 @@ def market_short_order():
'remaining': 0.0, 'remaining': 0.0,
'status': 'closed', 'status': 'closed',
'is_short': True, 'is_short': True,
'leverage': 3.0 'leverage': 3.0,
'liquidation_price': 0.00004300
} }
@ -2223,7 +2225,8 @@ def limit_leveraged_buy_order_open():
'remaining': 272.97543219, 'remaining': 272.97543219,
'leverage': 3.0, 'leverage': 3.0,
'status': 'open', 'status': 'open',
'exchange': 'binance' 'exchange': 'binance',
'liquidation_price': 0.00001000
} }
@ -2277,7 +2280,8 @@ def market_leveraged_buy_order():
'filled': 275.97543219, 'filled': 275.97543219,
'remaining': 0.0, 'remaining': 0.0,
'status': 'closed', 'status': 'closed',
'exchange': 'kraken' 'exchange': 'kraken',
'liquidation_price': 0.00004000
} }

View File

@ -428,6 +428,8 @@ def test_update_limit_order_lev(limit_leveraged_buy_order, limit_leveraged_sell_
assert trade.close_profit is None assert trade.close_profit is None
assert trade.close_date is None assert trade.close_date is None
assert trade.borrowed == 0.0019999999998453998 assert trade.borrowed == 0.0019999999998453998
assert trade.stop_loss == 0.00001000
assert trade.liquidation_price == 0.00001000
assert log_has_re(r"LIMIT_BUY has been fulfilled for Trade\(id=2, " assert log_has_re(r"LIMIT_BUY has been fulfilled for Trade\(id=2, "
r"pair=ETH/BTC, amount=272.97543219, open_rate=0.00001099, open_since=.*\).", r"pair=ETH/BTC, amount=272.97543219, open_rate=0.00001099, open_since=.*\).",
caplog) caplog)
@ -494,6 +496,8 @@ def test_update_market_order_lev(market_leveraged_buy_order, market_leveraged_se
assert trade.close_profit is None assert trade.close_profit is None
assert trade.close_date is None assert trade.close_date is None
assert trade.interest_rate == 0.0005 assert trade.interest_rate == 0.0005
assert trade.stop_loss == 0.00004000
assert trade.liquidation_price == 0.00004000
# TODO: Uncomment the next assert and make it work. # TODO: Uncomment the next assert and make it work.
# The logger also has the exact same but there's some spacing in there # The logger also has the exact same but there's some spacing in there
assert log_has_re(r"MARKET_BUY has been fulfilled for Trade\(id=1, " assert log_has_re(r"MARKET_BUY has been fulfilled for Trade\(id=1, "

View File

@ -433,6 +433,8 @@ def test_update_with_binance_short(limit_short_order, limit_exit_short_order, fe
assert trade.close_date is None assert trade.close_date is None
assert trade.borrowed == 90.99181073 assert trade.borrowed == 90.99181073
assert trade.is_short is True assert trade.is_short is True
assert trade.stop_loss == 0.00001300
assert trade.liquidation_price == 0.00001300
assert log_has_re(r"LIMIT_SELL has been fulfilled for Trade\(id=2, " assert log_has_re(r"LIMIT_SELL has been fulfilled for Trade\(id=2, "
r"pair=ETH/BTC, amount=90.99181073, open_rate=0.00001173, open_since=.*\).", r"pair=ETH/BTC, amount=90.99181073, open_rate=0.00001173, open_since=.*\).",
caplog) caplog)
@ -506,6 +508,8 @@ def test_update_market_order_short(
assert trade.close_profit is None assert trade.close_profit is None
assert trade.close_date is None assert trade.close_date is None
assert trade.interest_rate == 0.0005 assert trade.interest_rate == 0.0005
assert trade.stop_loss == 0.00004300
assert trade.liquidation_price == 0.00004300
# The logger also has the exact same but there's some spacing in there # The logger also has the exact same but there's some spacing in there
assert log_has_re(r"MARKET_SELL has been fulfilled for Trade\(id=1, " assert log_has_re(r"MARKET_SELL has been fulfilled for Trade\(id=1, "
r"pair=ETH/BTC, amount=275.97543219, open_rate=0.00004173, open_since=.*\).", r"pair=ETH/BTC, amount=275.97543219, open_rate=0.00004173, open_since=.*\).",
@ -670,7 +674,10 @@ def test_adjust_stop_loss_short(fee):
assert trade.initial_stop_loss == 1.05 assert trade.initial_stop_loss == 1.05
assert trade.initial_stop_loss_pct == 0.05 assert trade.initial_stop_loss_pct == 0.05
assert trade.stop_loss_pct == 0.1 assert trade.stop_loss_pct == 0.1
trade.liquidation_price == 1.03 trade.set_liquidation_price(0.63)
trade.adjust_stop_loss(0.59, -0.1)
assert trade.stop_loss == 0.63
assert trade.liquidation_price == 0.63
# TODO-mg: Do a test with a trade that has a liquidation price # TODO-mg: Do a test with a trade that has a liquidation price