From ac433eebfe8a9931810c3240812715021a3bf669 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Fri, 18 Feb 2022 05:43:16 -0600 Subject: [PATCH 1/5] stoploss in freqtradebot leverage adjustment --- freqtrade/freqtradebot.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index abd38859b..4d0316bb8 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1065,7 +1065,11 @@ class FreqtradeBot(LoggingMixin): # If enter order is fulfilled but there is no stoploss, we add a stoploss on exchange if not stoploss_order: - stoploss = self.edge.stoploss(pair=trade.pair) if self.edge else self.strategy.stoploss + stoploss = ( + self.edge.stoploss(pair=trade.pair) + if self.edge else + self.strategy.stoploss / trade.leverage + ) if trade.is_short: stop_price = trade.open_rate * (1 - stoploss) else: From 78194559f4cc2319e8407688fda93b0d35237474 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sat, 26 Feb 2022 08:07:01 -0600 Subject: [PATCH 2/5] persistence.adjust_stop_loss accounts for leverage --- freqtrade/persistence/models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 18491d687..ae4265374 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -566,13 +566,14 @@ class LocalTrade(): # Don't modify if called with initial and nothing to do return + leverage = self.leverage or 1.0 if self.is_short: - new_loss = float(current_price * (1 + abs(stoploss))) + new_loss = float(current_price * (1 + abs(stoploss / leverage))) # If trading with leverage, don't set the stoploss below the liquidation price if self.isolated_liq: new_loss = min(self.isolated_liq, new_loss) else: - new_loss = float(current_price * (1 - abs(stoploss))) + new_loss = float(current_price * (1 - abs(stoploss / leverage))) # If trading with leverage, don't set the stoploss below the liquidation price if self.isolated_liq: new_loss = max(self.isolated_liq, new_loss) From 499e21517bb4e7fbddfc0e4a605420fb204fbe65 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sat, 26 Feb 2022 08:33:57 -0600 Subject: [PATCH 3/5] test_persistence tests for stoploss with leverage adjustements --- tests/optimize/test_backtest_detail.py | 2 +- tests/test_persistence.py | 117 +++++++++++++++++++------ 2 files changed, 90 insertions(+), 29 deletions(-) diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index 0d3cdbf9f..ea95a500f 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -634,7 +634,7 @@ tc39 = BTContainer(data=[ [3, 5010, 5010, 4986, 5010, 6172, 0, 1], [4, 5010, 5010, 4855, 4995, 6172, 0, 0], # Triggers stoploss + sellsignal acted on [5, 4995, 4995, 4950, 4950, 6172, 0, 0]], - stop_loss=-0.01, roi={"0": 1}, profit_perc=0.002 * 5.0, use_sell_signal=True, + stop_loss=-0.05, roi={"0": 1}, profit_perc=0.002 * 5.0, use_sell_signal=True, leverage=5.0, trades=[BTrade(sell_reason=SellType.SELL_SIGNAL, open_tick=1, close_tick=4)] ) diff --git a/tests/test_persistence.py b/tests/test_persistence.py index f7273950a..efba25550 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -1749,6 +1749,67 @@ def test_stoploss_reinitialization(default_conf, fee): assert trade_adj.initial_stop_loss_pct == -0.04 +def test_stoploss_reinitialization_leverage(default_conf, fee): + init_db(default_conf['db_url']) + trade = Trade( + pair='ADA/USDT', + stake_amount=30.0, + fee_open=fee.return_value, + open_date=arrow.utcnow().shift(hours=-2).datetime, + amount=30.0, + fee_close=fee.return_value, + exchange='binance', + open_rate=1, + max_rate=1, + leverage=5.0, + ) + + trade.adjust_stop_loss(trade.open_rate, 0.1, True) + assert trade.stop_loss == 0.98 + assert trade.stop_loss_pct == -0.1 + assert trade.initial_stop_loss == 0.98 + assert trade.initial_stop_loss_pct == -0.1 + Trade.query.session.add(trade) + + # Lower stoploss + Trade.stoploss_reinitialization(0.15) + + trades = Trade.get_open_trades() + assert len(trades) == 1 + trade_adj = trades[0] + assert trade_adj.stop_loss == 0.97 + assert trade_adj.stop_loss_pct == -0.15 + assert trade_adj.initial_stop_loss == 0.97 + assert trade_adj.initial_stop_loss_pct == -0.15 + + # Raise stoploss + Trade.stoploss_reinitialization(0.05) + + trades = Trade.get_open_trades() + assert len(trades) == 1 + trade_adj = trades[0] + assert trade_adj.stop_loss == 0.99 + assert trade_adj.stop_loss_pct == -0.05 + assert trade_adj.initial_stop_loss == 0.99 + assert trade_adj.initial_stop_loss_pct == -0.05 + + # Trailing stoploss (move stoplos up a bit) + trade.adjust_stop_loss(1.02, 0.05) + assert trade_adj.stop_loss == 1.0098 + assert trade_adj.initial_stop_loss == 0.99 + + Trade.stoploss_reinitialization(0.05) + + trades = Trade.get_open_trades() + assert len(trades) == 1 + trade_adj = trades[0] + # Stoploss should not change in this case. + assert trade_adj.stop_loss == 1.0098 + assert trade_adj.stop_loss_pct == -0.05 + assert trade_adj.initial_stop_loss == 0.99 + assert trade_adj.initial_stop_loss_pct == -0.05 + + def test_stoploss_reinitialization_short(default_conf, fee): init_db(default_conf['db_url']) trade = Trade( @@ -1762,50 +1823,50 @@ def test_stoploss_reinitialization_short(default_conf, fee): open_rate=1, max_rate=1, is_short=True, - leverage=3.0, + leverage=5.0, ) - trade.adjust_stop_loss(trade.open_rate, -0.05, True) - assert trade.stop_loss == 1.05 - assert trade.stop_loss_pct == 0.05 - assert trade.initial_stop_loss == 1.05 - assert trade.initial_stop_loss_pct == 0.05 + trade.adjust_stop_loss(trade.open_rate, -0.1, True) + assert trade.stop_loss == 1.02 + assert trade.stop_loss_pct == 0.1 + assert trade.initial_stop_loss == 1.02 + assert trade.initial_stop_loss_pct == 0.1 Trade.query.session.add(trade) # Lower stoploss - Trade.stoploss_reinitialization(-0.06) + Trade.stoploss_reinitialization(-0.15) trades = Trade.get_open_trades() assert len(trades) == 1 trade_adj = trades[0] - assert trade_adj.stop_loss == 1.06 - assert trade_adj.stop_loss_pct == 0.06 - assert trade_adj.initial_stop_loss == 1.06 - assert trade_adj.initial_stop_loss_pct == 0.06 + assert trade_adj.stop_loss == 1.03 + assert trade_adj.stop_loss_pct == 0.15 + assert trade_adj.initial_stop_loss == 1.03 + assert trade_adj.initial_stop_loss_pct == 0.15 # Raise stoploss - Trade.stoploss_reinitialization(-0.04) + Trade.stoploss_reinitialization(-0.05) trades = Trade.get_open_trades() assert len(trades) == 1 trade_adj = trades[0] - assert trade_adj.stop_loss == 1.04 - assert trade_adj.stop_loss_pct == 0.04 - assert trade_adj.initial_stop_loss == 1.04 - assert trade_adj.initial_stop_loss_pct == 0.04 + assert trade_adj.stop_loss == 1.01 + assert trade_adj.stop_loss_pct == 0.05 + assert trade_adj.initial_stop_loss == 1.01 + assert trade_adj.initial_stop_loss_pct == 0.05 # Trailing stoploss - trade.adjust_stop_loss(0.98, -0.04) - assert trade_adj.stop_loss == 1.0192 - assert trade_adj.initial_stop_loss == 1.04 - Trade.stoploss_reinitialization(-0.04) + trade.adjust_stop_loss(0.98, -0.05) + assert trade_adj.stop_loss == 0.9898 + assert trade_adj.initial_stop_loss == 1.01 + Trade.stoploss_reinitialization(-0.05) trades = Trade.get_open_trades() assert len(trades) == 1 trade_adj = trades[0] # Stoploss should not change in this case. - assert trade_adj.stop_loss == 1.0192 - assert trade_adj.stop_loss_pct == 0.04 - assert trade_adj.initial_stop_loss == 1.04 - assert trade_adj.initial_stop_loss_pct == 0.04 + assert trade_adj.stop_loss == 0.9898 + assert trade_adj.stop_loss_pct == 0.05 + 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(1.0) - trade.adjust_stop_loss(0.97, -0.04) - assert trade_adj.stop_loss == 1.0 - assert trade_adj.stop_loss == 1.0 + trade_adj.set_isolated_liq(0.985) + trade.adjust_stop_loss(0.9799, -0.05) + assert trade_adj.stop_loss == 0.985 + assert trade_adj.stop_loss == 0.985 def test_update_fee(fee): From b363940baf1a6e15ed10dd13fceef428724be331 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sat, 26 Feb 2022 08:42:18 -0600 Subject: [PATCH 4/5] Add TODO-lev comment in test_handle_stoploss_on_exchange --- tests/test_freqtradebot.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index d6930bc24..7b77375b6 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1128,6 +1128,9 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ assert trade.is_open is False caplog.clear() + # TODO-lev: Test 2 identical orders but one with leverage, 1 without, and test that the + # leveraged trade is hit, but the other trade is not + mocker.patch( 'freqtrade.exchange.Binance.stoploss', side_effect=ExchangeError() From 7b9880035b9aaf452c626c1700746baf09f31138 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 27 Feb 2022 15:11:09 +0100 Subject: [PATCH 5/5] Remove wrong TODO-lev comment --- tests/test_freqtradebot.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 7b77375b6..d6930bc24 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1128,9 +1128,6 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ assert trade.is_open is False caplog.clear() - # TODO-lev: Test 2 identical orders but one with leverage, 1 without, and test that the - # leveraged trade is hit, but the other trade is not - mocker.patch( 'freqtrade.exchange.Binance.stoploss', side_effect=ExchangeError()