Fixed max_open_trades update from hyperopt

Fixed max_open_trades update from hyperopt + removed max_open_trades as a param to backtesting + refactoring
This commit is contained in:
Antonio Della Fortuna
2023-01-08 12:39:39 +01:00
parent 8c3ac56bc5
commit 464cb4761c
7 changed files with 132 additions and 52 deletions

View File

@@ -1,5 +1,6 @@
# pragma pylint: disable=missing-docstring,W0212,C0103
from datetime import datetime, timedelta
from functools import wraps
from pathlib import Path
from unittest.mock import ANY, MagicMock, PropertyMock
@@ -336,8 +337,7 @@ def test_start_calls_optimizer(mocker, hyperopt_conf, capsys) -> None:
assert dumper2.call_count == 1
assert hasattr(hyperopt.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.backtesting.strategy, "advise_entry")
assert hasattr(hyperopt, "max_open_trades")
assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades']
assert hyperopt.backtesting.strategy.max_open_trades == hyperopt_conf['max_open_trades']
assert hasattr(hyperopt.backtesting, "_position_stacking")
@@ -708,8 +708,7 @@ def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> Non
assert hasattr(hyperopt.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.backtesting.strategy, "advise_entry")
assert hasattr(hyperopt, "max_open_trades")
assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades']
assert hyperopt.backtesting.strategy.max_open_trades == hyperopt_conf['max_open_trades']
assert hasattr(hyperopt.backtesting, "_position_stacking")
@@ -782,8 +781,7 @@ def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None:
assert dumper2.call_count == 1
assert hasattr(hyperopt.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.backtesting.strategy, "advise_entry")
assert hasattr(hyperopt, "max_open_trades")
assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades']
assert hyperopt.backtesting.strategy.max_open_trades == hyperopt_conf['max_open_trades']
assert hasattr(hyperopt.backtesting, "_position_stacking")
@@ -825,8 +823,7 @@ def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None:
assert dumper2.call_count == 1
assert hasattr(hyperopt.backtesting.strategy, "advise_exit")
assert hasattr(hyperopt.backtesting.strategy, "advise_entry")
assert hasattr(hyperopt, "max_open_trades")
assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades']
assert hyperopt.backtesting.strategy.max_open_trades == hyperopt_conf['max_open_trades']
assert hasattr(hyperopt.backtesting, "_position_stacking")
@@ -880,7 +877,7 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None:
assert hyperopt.backtesting.strategy.buy_rsi.value == 35
assert hyperopt.backtesting.strategy.sell_rsi.value == 74
assert hyperopt.backtesting.strategy.protection_cooldown_lookback.value == 30
assert hyperopt.max_open_trades == 1
assert hyperopt.backtesting.strategy.max_open_trades == 1
buy_rsi_range = hyperopt.backtesting.strategy.buy_rsi.range
assert isinstance(buy_rsi_range, range)
# Range from 0 - 50 (inclusive)
@@ -891,7 +888,7 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None:
assert hyperopt.backtesting.strategy.protection_cooldown_lookback.value != 30
assert hyperopt.backtesting.strategy.buy_rsi.value != 35
assert hyperopt.backtesting.strategy.sell_rsi.value != 74
assert hyperopt.max_open_trades != 1
assert hyperopt.backtesting.strategy.max_open_trades != 1
hyperopt.custom_hyperopt.generate_estimator = lambda *args, **kwargs: 'ET1'
with pytest.raises(OperationalException, match="Estimator ET1 not supported."):
@@ -992,3 +989,75 @@ def test_SKDecimal():
assert space.transform([2.0]) == [200]
assert space.transform([1.0]) == [100]
assert space.transform([1.5, 1.6]) == [150, 160]
def test_stake_amount_unlimited_max_open_trades(mocker, hyperopt_conf, tmpdir, fee) -> None:
# This test is to ensure that unlimited max_open_trades are ignored for the backtesting
# if we have an unlimited stake amount
patch_exchange(mocker)
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
(Path(tmpdir) / 'hyperopt_results').mkdir(parents=True)
hyperopt_conf.update({
'strategy': 'HyperoptableStrategy',
'user_data_dir': Path(tmpdir),
'hyperopt_random_state': 42,
'spaces': ['trades'],
'stake_amount': 'unlimited'
})
hyperopt = Hyperopt(hyperopt_conf)
mocker.patch('freqtrade.optimize.hyperopt.Hyperopt._get_params_dict',
return_value={
'max_open_trades': -1
})
assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
assert hyperopt.backtesting.strategy.max_open_trades == 1
hyperopt.start()
assert hyperopt.backtesting.strategy.max_open_trades == 1
def test_max_open_trades_consistency(mocker, hyperopt_conf, tmpdir, fee) -> None:
# This test is to ensure that max_open_trades is the same across all functions needing it
# after it has been changed from the hyperopt
patch_exchange(mocker)
mocker.patch('freqtrade.exchange.Exchange.get_fee', return_value=0)
(Path(tmpdir) / 'hyperopt_results').mkdir(parents=True)
hyperopt_conf.update({
'strategy': 'HyperoptableStrategy',
'user_data_dir': Path(tmpdir),
'hyperopt_random_state': 42,
'spaces': ['trades'],
'stake_amount': 'unlimited',
'dry_run_wallet': 8,
'available_capital': 8,
'dry_run': True,
'epochs': 1
})
hyperopt = Hyperopt(hyperopt_conf)
assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
first_time_evaluated = False
def stake_amount_interceptor(func):
@wraps(func)
def wrapper(*args, **kwargs):
nonlocal first_time_evaluated
stake_amount = func(*args, **kwargs)
if first_time_evaluated is False:
assert stake_amount == 1
first_time_evaluated = True
return stake_amount
return wrapper
hyperopt.backtesting.wallets._calculate_unlimited_stake_amount = stake_amount_interceptor(
hyperopt.backtesting.wallets._calculate_unlimited_stake_amount)
hyperopt.start()
assert hyperopt.backtesting.strategy.max_open_trades == 8
assert hyperopt.config['max_open_trades'] == 8