Merge pull request #7396 from freqtrade/hyperopt_per_epoch
Hyperopt per epoch
This commit is contained in:
commit
fac8f19554
@ -196,7 +196,9 @@ class DataProvider:
|
|||||||
Clear pair dataframe cache.
|
Clear pair dataframe cache.
|
||||||
"""
|
"""
|
||||||
self.__cached_pairs = {}
|
self.__cached_pairs = {}
|
||||||
self.__cached_pairs_backtesting = {}
|
# Don't reset backtesting pairs -
|
||||||
|
# otherwise they're reloaded each time during hyperopt due to with analyze_per_epoch
|
||||||
|
# self.__cached_pairs_backtesting = {}
|
||||||
self.__slice_index = 0
|
self.__slice_index = 0
|
||||||
|
|
||||||
# Exchange functions
|
# Exchange functions
|
||||||
|
@ -580,11 +580,23 @@ class Hyperopt:
|
|||||||
max_value=self.total_epochs, redirect_stdout=False, redirect_stderr=False,
|
max_value=self.total_epochs, redirect_stdout=False, redirect_stderr=False,
|
||||||
widgets=widgets
|
widgets=widgets
|
||||||
) as pbar:
|
) as pbar:
|
||||||
EVALS = ceil(self.total_epochs / jobs)
|
start = 0
|
||||||
for i in range(EVALS):
|
|
||||||
|
if self.analyze_per_epoch:
|
||||||
|
# First analysis not in parallel mode when using --analyze-per-epoch.
|
||||||
|
# This allows dataprovider to load it's informative cache.
|
||||||
|
asked, is_random = self.get_asked_points(n_points=1)
|
||||||
|
f_val0 = self.generate_optimizer(asked[0])
|
||||||
|
self.opt.tell(asked, [f_val0['loss']])
|
||||||
|
self.evaluate_result(f_val0, 1, is_random[0])
|
||||||
|
pbar.update(1)
|
||||||
|
start += 1
|
||||||
|
|
||||||
|
evals = ceil((self.total_epochs - start) / jobs)
|
||||||
|
for i in range(evals):
|
||||||
# Correct the number of epochs to be processed for the last
|
# Correct the number of epochs to be processed for the last
|
||||||
# iteration (should not exceed self.total_epochs in total)
|
# iteration (should not exceed self.total_epochs in total)
|
||||||
n_rest = (i + 1) * jobs - self.total_epochs
|
n_rest = (i + 1) * jobs - (self.total_epochs - start)
|
||||||
current_jobs = jobs - n_rest if n_rest > 0 else jobs
|
current_jobs = jobs - n_rest if n_rest > 0 else jobs
|
||||||
|
|
||||||
asked, is_random = self.get_asked_points(n_points=current_jobs)
|
asked, is_random = self.get_asked_points(n_points=current_jobs)
|
||||||
@ -594,7 +606,7 @@ class Hyperopt:
|
|||||||
# Calculate progressbar outputs
|
# Calculate progressbar outputs
|
||||||
for j, val in enumerate(f_val):
|
for j, val in enumerate(f_val):
|
||||||
# Use human-friendly indexes here (starting from 1)
|
# Use human-friendly indexes here (starting from 1)
|
||||||
current = i * jobs + j + 1
|
current = i * jobs + j + 1 + start
|
||||||
|
|
||||||
self.evaluate_result(val, current, is_random[j])
|
self.evaluate_result(val, current, is_random[j])
|
||||||
|
|
||||||
|
@ -922,6 +922,45 @@ def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmpdir,
|
|||||||
hyperopt.start()
|
hyperopt.start()
|
||||||
|
|
||||||
|
|
||||||
|
def test_in_strategy_auto_hyperopt_per_epoch(mocker, hyperopt_conf, tmpdir, fee) -> None:
|
||||||
|
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': ['all'],
|
||||||
|
'epochs': 3,
|
||||||
|
'analyze_per_epoch': True,
|
||||||
|
})
|
||||||
|
go = mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.generate_optimizer',
|
||||||
|
return_value={
|
||||||
|
'loss': 0.05,
|
||||||
|
'results_explanation': 'foo result', 'params': {},
|
||||||
|
'results_metrics': generate_result_metrics(),
|
||||||
|
})
|
||||||
|
hyperopt = Hyperopt(hyperopt_conf)
|
||||||
|
hyperopt.backtesting.exchange.get_max_leverage = MagicMock(return_value=1.0)
|
||||||
|
assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
|
||||||
|
assert isinstance(hyperopt.backtesting.strategy.buy_rsi, IntParameter)
|
||||||
|
assert hyperopt.backtesting.strategy.bot_loop_started is True
|
||||||
|
|
||||||
|
assert hyperopt.backtesting.strategy.buy_rsi.in_space is True
|
||||||
|
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
|
||||||
|
buy_rsi_range = hyperopt.backtesting.strategy.buy_rsi.range
|
||||||
|
assert isinstance(buy_rsi_range, range)
|
||||||
|
# Range from 0 - 50 (inclusive)
|
||||||
|
assert len(list(buy_rsi_range)) == 51
|
||||||
|
|
||||||
|
hyperopt.start()
|
||||||
|
# backtesting should be called 3 times (once per epoch)
|
||||||
|
assert go.call_count == 3
|
||||||
|
|
||||||
|
|
||||||
def test_SKDecimal():
|
def test_SKDecimal():
|
||||||
space = SKDecimal(1, 2, decimals=2)
|
space = SKDecimal(1, 2, decimals=2)
|
||||||
assert 1.5 in space
|
assert 1.5 in space
|
||||||
|
Loading…
Reference in New Issue
Block a user