Repository: freqtrade/freqtrade

Issue:
How to close a half position
<!-- 
Have you searched for similar issues before posting it?
Did you have a VERY good look at the [documentation](https://www.freqtrade.io/en/latest/) and are sure that the question is not explained there

Please do not use the question template to report bugs or to request new features.
-->

## Describe your environment
Operating system: centos7
Python Version: Python 3.10.5___ (python -V)
CCXT version: _ccxt==1.93.66 (pip freeze | grep ccxt)
Freqtrade Version: freqtrade 2022.9.dev-873eb5f__ (freqtrade -V or docker-compose run --rm freqtrade -V for Freqtrade running in docker)
  
## Your question

If leverage is used, half of the closing position here is actually only half of the initial value



    def adjust_trade_position(self, trade: Trade, current_time: datetime,
                              current_rate: float, current_profit: float,
                              min_stake: Optional[float], max_stake: float,
                              current_entry_rate: float, current_exit_rate: float,
                              current_entry_profit: float, current_exit_profit: float,
                              **kwargs) -> Optional[float]:

        filled_entries = trade.select_filled_orders(trade.entry_side)
        count_of_entries = trade.nr_of_successful_entries

        if current_profit > 0.05 and trade.nr_of_successful_exits == 0:
            # Take half of the profit at +5%
            return -(trade.stake_amount / 2)



Orders generated from partial back testing：

          "profit_abs": 421.4452752,
          "exit_reason": "roi",
          "initial_stop_loss_abs": 1388.71,
          "initial_stop_loss_ratio": -0.198,
          "stop_loss_abs": 1368.52,
          "stop_loss_ratio": -0.198,
          "min_rate": 1315,
          "max_rate": 1340.69,
          "is_open": false,
          "enter_tag": "down >= 0.8",
          "is_short": true,
          "open_timestamp": 1663710300000,
          "close_timestamp": 1663711200000,
          "orders": [
            {
              "amount": 31.3,
              "safe_price": 1335.81,
              "ft_order_side": "sell",
              "order_filled_timestamp": 1663710300000,
              "ft_is_entry": true
            },
            {
              "amount": 3.1,
              "safe_price": 1316.39,
              "ft_order_side": "buy",
              "order_filled_timestamp": 1663711200000,
              "ft_is_entry": false
            },
            {
              "amount": 28.2,
              "safe_price": 1322.41,
              "ft_order_side": "buy",
              "order_filled_timestamp": 1663711200000,
              "ft_is_entry": false
            }
          ]
        },





*Ask the question you have not been able to find an answer in the [Documentation](https://www.freqtrade.io/en/latest/)*



Discussion:

Resolving patch:
diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py
--- a/freqtrade/freqtradebot.py
+++ b/freqtrade/freqtradebot.py
@@ -597,7 +597,7 @@ def check_and_call_adjust_trade_position(self, trade: Trade):
             # We should decrease our position
             amount = self.exchange.amount_to_contract_precision(
                 trade.pair,
-                abs(float(FtPrecise(stake_amount) / FtPrecise(current_exit_rate))))
+                abs(float(FtPrecise(stake_amount * trade.leverage) / FtPrecise(current_exit_rate))))
             if amount > trade.amount:
                 # This is currently ineffective as remaining would become < min tradable
                 # Fixing this would require checking for 0.0 there -
diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py
--- a/freqtrade/optimize/backtesting.py
+++ b/freqtrade/optimize/backtesting.py
@@ -540,7 +540,7 @@ def _get_adjust_trade_entry_for_candle(self, trade: LocalTrade, row: Tuple
 
         if stake_amount is not None and stake_amount < 0.0:
             amount = amount_to_contract_precision(
-                abs(stake_amount) / current_rate, trade.amount_precision,
+                abs(stake_amount * trade.leverage) / current_rate, trade.amount_precision,
                 self.precision_mode, trade.contract_size)
             if amount == 0.0:
                 return trade


Test patch:
diff --git a/tests/optimize/test_backtesting_adjust_position.py b/tests/optimize/test_backtesting_adjust_position.py
--- a/tests/optimize/test_backtesting_adjust_position.py
+++ b/tests/optimize/test_backtesting_adjust_position.py
@@ -93,11 +93,16 @@ def test_backtest_position_adjustment(default_conf, fee, mocker, testdatadir) ->
                 t["close_rate"], 6) < round(ln.iloc[0]["high"], 6))
 
 
-def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> None:
+@pytest.mark.parametrize('leverage', [
+    1, 2
+])
+def test_backtest_position_adjustment_detailed(default_conf, fee, mocker, leverage) -> None:
     default_conf['use_exit_signal'] = False
     mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
     mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=10)
     mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=float('inf'))
+    mocker.patch("freqtrade.exchange.Exchange.get_max_leverage", return_value=10)
+
     patch_exchange(mocker)
     default_conf.update({
         "stake_amount": 100.0,
@@ -105,6 +110,7 @@ def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> Non
         "strategy": "StrategyTestV3"
     })
     backtesting = Backtesting(default_conf)
+    backtesting._can_short = True
     backtesting._set_strategy(backtesting.strategylist[0])
     pair = 'XRP/USDT'
     row = [
@@ -120,18 +126,19 @@ def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> Non
             '',  # enter_tag
             '',  # exit_tag
             ]
+    backtesting.strategy.leverage = MagicMock(return_value=leverage)
     trade = backtesting._enter_trade(pair, row=row, direction='long')
     trade.orders[0].close_bt_order(row[0], trade)
     assert trade
     assert pytest.approx(trade.stake_amount) == 100.0
-    assert pytest.approx(trade.amount) == 47.61904762
+    assert pytest.approx(trade.amount) == 47.61904762 * leverage
     assert len(trade.orders) == 1
     backtesting.strategy.adjust_trade_position = MagicMock(return_value=None)
 
     trade = backtesting._get_adjust_trade_entry_for_candle(trade, row)
     assert trade
     assert pytest.approx(trade.stake_amount) == 100.0
-    assert pytest.approx(trade.amount) == 47.61904762
+    assert pytest.approx(trade.amount) == 47.61904762 * leverage
     assert len(trade.orders) == 1
     # Increase position by 100
     backtesting.strategy.adjust_trade_position = MagicMock(return_value=100)
@@ -140,7 +147,7 @@ def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> Non
 
     assert trade
     assert pytest.approx(trade.stake_amount) == 200.0
-    assert pytest.approx(trade.amount) == 95.23809524
+    assert pytest.approx(trade.amount) == 95.23809524 * leverage
     assert len(trade.orders) == 2
 
     # Reduce by more than amount - no change to trade.
@@ -150,7 +157,7 @@ def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> Non
 
     assert trade
     assert pytest.approx(trade.stake_amount) == 200.0
-    assert pytest.approx(trade.amount) == 95.23809524
+    assert pytest.approx(trade.amount) == 95.23809524 * leverage
     assert len(trade.orders) == 2
     assert trade.nr_of_successful_entries == 2
 
@@ -160,7 +167,7 @@ def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> Non
 
     assert trade
     assert pytest.approx(trade.stake_amount) == 100.0
-    assert pytest.approx(trade.amount) == 47.61904762
+    assert pytest.approx(trade.amount) == 47.61904762 * leverage
     assert len(trade.orders) == 3
     assert trade.nr_of_successful_entries == 2
     assert trade.nr_of_successful_exits == 1
@@ -171,7 +178,7 @@ def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> Non
 
     assert trade
     assert pytest.approx(trade.stake_amount) == 100.0
-    assert pytest.approx(trade.amount) == 47.61904762
+    assert pytest.approx(trade.amount) == 47.61904762 * leverage
     assert len(trade.orders) == 3
     assert trade.nr_of_successful_entries == 2
     assert trade.nr_of_successful_exits == 1
diff --git a/tests/test_integration.py b/tests/test_integration.py
--- a/tests/test_integration.py
+++ b/tests/test_integration.py
@@ -2,7 +2,7 @@
 
 import pytest
 
-from freqtrade.enums import ExitCheckTuple, ExitType
+from freqtrade.enums import ExitCheckTuple, ExitType, TradingMode
 from freqtrade.persistence import Trade
 from freqtrade.persistence.models import Order
 from freqtrade.rpc.rpc import RPC
@@ -455,10 +455,12 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
     assert pytest.approx(trade.orders[-1].amount) == 61.538461232
 
 
-def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog) -> None:
+@pytest.mark.parametrize('leverage', [1, 2])
+def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog, leverage) -> None:
     default_conf_usdt['position_adjustment_enable'] = True
 
     freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
+    freqtrade.trading_mode = TradingMode.FUTURES
     mocker.patch.multiple(
         'freqtrade.exchange.Exchange',
         fetch_ticker=ticker_usdt,
@@ -467,15 +469,17 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog) -> Non
         price_to_precision=lambda s, x, y: y,
         get_min_pair_stake_amount=MagicMock(return_value=10),
     )
+    mocker.patch("freqtrade.exchange.Exchange.get_max_leverage", return_value=10)
 
     patch_get_signal(freqtrade)
+    freqtrade.strategy.leverage = MagicMock(return_value=leverage)
     freqtrade.enter_positions()
 
     assert len(Trade.get_trades().all()) == 1
     trade = Trade.get_trades().first()
     assert len(trade.orders) == 1
     assert pytest.approx(trade.stake_amount) == 60
-    assert pytest.approx(trade.amount) == 30.0
+    assert pytest.approx(trade.amount) == 30.0 * leverage
     assert trade.open_rate == 2.0
 
     # Too small size
@@ -484,8 +488,9 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog) -> Non
     trade = Trade.get_trades().first()
     assert len(trade.orders) == 1
     assert pytest.approx(trade.stake_amount) == 60
-    assert pytest.approx(trade.amount) == 30.0
-    assert log_has_re("Remaining amount of 1.6.* would be smaller than the minimum of 10.", caplog)
+    assert pytest.approx(trade.amount) == 30.0 * leverage
+    assert log_has_re(
+        r"Remaining amount of \d\.\d+.* would be smaller than the minimum of 10.", caplog)
 
     freqtrade.strategy.adjust_trade_position = MagicMock(return_value=-20)
 
@@ -494,7 +499,7 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog) -> Non
     assert len(trade.orders) == 2
     assert trade.orders[-1].ft_order_side == 'sell'
     assert pytest.approx(trade.stake_amount) == 40.198
-    assert pytest.approx(trade.amount) == 20.099
+    assert pytest.approx(trade.amount) == 20.099 * leverage
     assert trade.open_rate == 2.0
     assert trade.is_open
     caplog.clear()