Add specific test for _get_adjust_trade_entry_for_candle
This commit is contained in:
parent
88e227d618
commit
05ca4fed06
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user