Add specific test for _get_adjust_trade_entry_for_candle

This commit is contained in:
Matthias 2022-05-27 20:34:26 +02:00
parent 88e227d618
commit 05ca4fed06
2 changed files with 93 additions and 1 deletions

View File

@ -495,6 +495,7 @@ class Backtesting:
def _get_adjust_trade_entry_for_candle(self, trade: LocalTrade, row: Tuple def _get_adjust_trade_entry_for_candle(self, trade: LocalTrade, row: Tuple
) -> LocalTrade: ) -> LocalTrade:
current_rate = row[OPEN_IDX] current_rate = row[OPEN_IDX]
current_date = row[DATE_IDX].to_pydatetime()
current_profit = trade.calc_profit_ratio(current_rate) current_profit = trade.calc_profit_ratio(current_rate)
min_stake = self.exchange.get_min_pair_stake_amount(trade.pair, current_rate, -0.1) min_stake = self.exchange.get_min_pair_stake_amount(trade.pair, current_rate, -0.1)
max_stake = self.exchange.get_max_pair_stake_amount(trade.pair, current_rate) max_stake = self.exchange.get_max_pair_stake_amount(trade.pair, current_rate)
@ -502,7 +503,7 @@ class Backtesting:
stake_amount = strategy_safe_wrapper(self.strategy.adjust_trade_position, stake_amount = strategy_safe_wrapper(self.strategy.adjust_trade_position,
default_retval=None)( default_retval=None)(
trade=trade, # type: ignore[arg-type] trade=trade, # type: ignore[arg-type]
current_time=row[DATE_IDX].to_pydatetime(), current_rate=current_rate, current_time=current_date, current_rate=current_rate,
current_profit=current_profit, min_stake=min_stake, current_profit=current_profit, min_stake=min_stake,
max_stake=min(max_stake, stake_available), max_stake=min(max_stake, stake_available),
current_entry_rate=current_rate, current_exit_rate=current_rate, current_entry_rate=current_rate, current_exit_rate=current_rate,
@ -528,6 +529,11 @@ class Backtesting:
return trade return trade
pos_trade = self._exit_trade(trade, row, current_rate, amount) pos_trade = self._exit_trade(trade, row, current_rate, amount)
if pos_trade is not None: if pos_trade is not None:
order = pos_trade.orders[-1]
if self._get_order_filled(order.price, row):
order.close_bt_order(current_date, trade)
trade.process_exit_sub_trade(order)
trade.recalc_trade_from_orders()
self.wallets.update() self.wallets.update()
return pos_trade return pos_trade

View File

@ -1,8 +1,10 @@
# pragma pylint: disable=missing-docstring, W0212, line-too-long, C0103, unused-argument # pragma pylint: disable=missing-docstring, W0212, line-too-long, C0103, unused-argument
from copy import deepcopy from copy import deepcopy
from unittest.mock import MagicMock
import pandas as pd import pandas as pd
import pytest
from arrow import Arrow from arrow import Arrow
from freqtrade.configuration import TimeRange from freqtrade.configuration import TimeRange
@ -82,3 +84,87 @@ def test_backtest_position_adjustment(default_conf, fee, mocker, testdatadir) ->
assert (round(ln.iloc[0]["open"], 6) == round(t["close_rate"], 6) or assert (round(ln.iloc[0]["open"], 6) == round(t["close_rate"], 6) or
round(ln.iloc[0]["low"], 6) < round( round(ln.iloc[0]["low"], 6) < round(
t["close_rate"], 6) < round(ln.iloc[0]["high"], 6)) t["close_rate"], 6) < round(ln.iloc[0]["high"], 6))
def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> 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'))
patch_exchange(mocker)
default_conf.update({
"stake_amount": 100.0,
"dry_run_wallet": 1000.0,
"strategy": "StrategyTestV3"
})
backtesting = Backtesting(default_conf)
backtesting._set_strategy(backtesting.strategylist[0])
pair = 'XRP/USDT'
row = [
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=0),
2.1, # Open
2.2, # High
1.9, # Low
2.1, # Close
1, # enter_long
0, # exit_long
0, # enter_short
0, # exit_short
'', # enter_tag
'', # exit_tag
]
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 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 len(trade.orders) == 1
# Increase position by 100
backtesting.strategy.adjust_trade_position = MagicMock(return_value=100)
trade = backtesting._get_adjust_trade_entry_for_candle(trade, row)
assert trade
assert pytest.approx(trade.stake_amount) == 200.0
assert pytest.approx(trade.amount) == 95.23809524
assert len(trade.orders) == 2
# Reduce by more than amount - no change to trade.
backtesting.strategy.adjust_trade_position = MagicMock(return_value=-500)
trade = backtesting._get_adjust_trade_entry_for_candle(trade, row)
assert trade
assert pytest.approx(trade.stake_amount) == 200.0
assert pytest.approx(trade.amount) == 95.23809524
assert len(trade.orders) == 2
assert trade.nr_of_successful_entries == 2
# Reduce position by 50
backtesting.strategy.adjust_trade_position = MagicMock(return_value=-100)
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 len(trade.orders) == 3
assert trade.nr_of_successful_entries == 2
assert trade.nr_of_successful_exits == 1
# Adjust below minimum
backtesting.strategy.adjust_trade_position = MagicMock(return_value=-99)
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 len(trade.orders) == 3
assert trade.nr_of_successful_entries == 2
assert trade.nr_of_successful_exits == 1