Merge pull request #5219 from freqtrade/hyperopt_paramfile
automatic Hyperopt paramfile
This commit is contained in:
@@ -1168,6 +1168,7 @@ def test_hyperopt_show(mocker, capsys, saved_hyperopt_results):
|
||||
'freqtrade.optimize.hyperopt_tools.HyperoptTools.load_previous_results',
|
||||
MagicMock(return_value=saved_hyperopt_results)
|
||||
)
|
||||
mocker.patch('freqtrade.commands.hyperopt_commands.show_backtest_result')
|
||||
|
||||
args = [
|
||||
"hyperopt-show",
|
||||
|
@@ -324,6 +324,7 @@ def get_default_conf(testdatadir):
|
||||
"verbosity": 3,
|
||||
"strategy_path": str(Path(__file__).parent / "strategy" / "strats"),
|
||||
"strategy": "DefaultStrategy",
|
||||
"disableparamexport": True,
|
||||
"internals": {},
|
||||
"export": "none",
|
||||
}
|
||||
@@ -1953,12 +1954,13 @@ def saved_hyperopt_results():
|
||||
'params_dict': {
|
||||
'mfi-value': 15, 'fastd-value': 20, 'adx-value': 25, 'rsi-value': 28, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'macd_cross_signal', 'sell-mfi-value': 88, 'sell-fastd-value': 97, 'sell-adx-value': 51, 'sell-rsi-value': 67, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper', 'roi_t1': 1190, 'roi_t2': 541, 'roi_t3': 408, 'roi_p1': 0.026035863879169705, 'roi_p2': 0.12508730043628782, 'roi_p3': 0.27766427921605896, 'stoploss': -0.2562930402099556}, # noqa: E501
|
||||
'params_details': {'buy': {'mfi-value': 15, 'fastd-value': 20, 'adx-value': 25, 'rsi-value': 28, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'macd_cross_signal'}, 'sell': {'sell-mfi-value': 88, 'sell-fastd-value': 97, 'sell-adx-value': 51, 'sell-rsi-value': 67, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper'}, 'roi': {0: 0.4287874435315165, 408: 0.15112316431545753, 949: 0.026035863879169705, 2139: 0}, 'stoploss': {'stoploss': -0.2562930402099556}}, # noqa: E501
|
||||
'results_metrics': {'total_trades': 2, 'wins': 0, 'draws': 0, 'losses': 2, 'profit_mean': -0.01254995, 'profit_median': -0.012222, 'profit_total': -0.00125625, 'profit_total_abs': -2.50999, 'holding_avg': timedelta(minutes=3930.0)}, # noqa: E501
|
||||
'results_metrics': {'total_trades': 2, 'wins': 0, 'draws': 0, 'losses': 2, 'profit_mean': -0.01254995, 'profit_median': -0.012222, 'profit_total': -0.00125625, 'profit_total_abs': -2.50999, 'holding_avg': timedelta(minutes=3930.0), 'stake_currency': 'BTC', 'strategy_name': 'SampleStrategy'}, # noqa: E501
|
||||
'results_explanation': ' 2 trades. Avg profit -1.25%. Total profit -0.00125625 BTC ( -2.51Σ%). Avg duration 3930.0 min.', # noqa: E501
|
||||
'total_profit': -0.00125625,
|
||||
'current_epoch': 1,
|
||||
'is_initial_point': True,
|
||||
'is_best': True
|
||||
'is_best': True,
|
||||
|
||||
}, {
|
||||
'loss': 20.0,
|
||||
'params_dict': {
|
||||
|
@@ -1,9 +1,6 @@
|
||||
# pragma pylint: disable=missing-docstring,W0212,C0103
|
||||
import logging
|
||||
import re
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
from unittest.mock import ANY, MagicMock
|
||||
|
||||
import pandas as pd
|
||||
@@ -28,12 +25,6 @@ from tests.conftest import (get_args, log_has, log_has_re, patch_exchange,
|
||||
from .hyperopts.default_hyperopt import DefaultHyperOpt
|
||||
|
||||
|
||||
# Functions for recurrent object patching
|
||||
def create_results() -> List[Dict]:
|
||||
|
||||
return [{'loss': 1, 'result': 'foo', 'params': {}, 'is_best': True}]
|
||||
|
||||
|
||||
def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, caplog) -> None:
|
||||
patched_configuration_load_config_file(mocker, default_conf)
|
||||
|
||||
@@ -303,52 +294,6 @@ def test_no_log_if_loss_does_not_improve(hyperopt, caplog) -> None:
|
||||
assert caplog.record_tuples == []
|
||||
|
||||
|
||||
def test_save_results_saves_epochs(mocker, hyperopt, tmpdir, caplog) -> None:
|
||||
# Test writing to temp dir and reading again
|
||||
epochs = create_results()
|
||||
hyperopt.results_file = Path(tmpdir / 'ut_results.fthypt')
|
||||
|
||||
caplog.set_level(logging.DEBUG)
|
||||
|
||||
for epoch in epochs:
|
||||
hyperopt._save_result(epoch)
|
||||
assert log_has(f"1 epoch saved to '{hyperopt.results_file}'.", caplog)
|
||||
|
||||
hyperopt._save_result(epochs[0])
|
||||
assert log_has(f"2 epochs saved to '{hyperopt.results_file}'.", caplog)
|
||||
|
||||
hyperopt_epochs = HyperoptTools.load_previous_results(hyperopt.results_file)
|
||||
assert len(hyperopt_epochs) == 2
|
||||
|
||||
|
||||
def test_load_previous_results(testdatadir, caplog) -> None:
|
||||
|
||||
results_file = testdatadir / 'hyperopt_results_SampleStrategy.pickle'
|
||||
|
||||
hyperopt_epochs = HyperoptTools.load_previous_results(results_file)
|
||||
|
||||
assert len(hyperopt_epochs) == 5
|
||||
assert log_has_re(r"Reading pickled epochs from .*", caplog)
|
||||
|
||||
caplog.clear()
|
||||
|
||||
# Modern version
|
||||
results_file = testdatadir / 'strategy_SampleStrategy.fthypt'
|
||||
|
||||
hyperopt_epochs = HyperoptTools.load_previous_results(results_file)
|
||||
|
||||
assert len(hyperopt_epochs) == 5
|
||||
assert log_has_re(r"Reading epochs from .*", caplog)
|
||||
|
||||
|
||||
def test_load_previous_results2(mocker, testdatadir, caplog) -> None:
|
||||
mocker.patch('freqtrade.optimize.hyperopt_tools.HyperoptTools._read_results_pickle',
|
||||
return_value=[{'asdf': '222'}])
|
||||
results_file = testdatadir / 'hyperopt_results_SampleStrategy.pickle'
|
||||
with pytest.raises(OperationalException, match=r"The file .* incompatible.*"):
|
||||
HyperoptTools.load_previous_results(results_file)
|
||||
|
||||
|
||||
def test_roi_table_generation(hyperopt) -> None:
|
||||
params = {
|
||||
'roi_t1': 5,
|
||||
@@ -362,6 +307,18 @@ def test_roi_table_generation(hyperopt) -> None:
|
||||
assert hyperopt.custom_hyperopt.generate_roi_table(params) == {0: 6, 15: 3, 25: 1, 30: 0}
|
||||
|
||||
|
||||
def test_params_no_optimize_details(hyperopt) -> None:
|
||||
hyperopt.config['spaces'] = ['buy']
|
||||
res = hyperopt._get_no_optimize_details()
|
||||
assert isinstance(res, dict)
|
||||
assert "trailing" in res
|
||||
assert res["trailing"]['trailing_stop'] is False
|
||||
assert "roi" in res
|
||||
assert res['roi']['0'] == 0.04
|
||||
assert "stoploss" in res
|
||||
assert res['stoploss']['stoploss'] == -0.1
|
||||
|
||||
|
||||
def test_start_calls_optimizer(mocker, hyperopt_conf, capsys) -> None:
|
||||
dumper = mocker.patch('freqtrade.optimize.hyperopt.dump')
|
||||
dumper2 = mocker.patch('freqtrade.optimize.hyperopt.Hyperopt._save_result')
|
||||
@@ -467,40 +424,6 @@ def test_hyperopt_format_results(hyperopt):
|
||||
assert '0:50:00 min' in result
|
||||
|
||||
|
||||
@pytest.mark.parametrize("spaces, expected_results", [
|
||||
(['buy'],
|
||||
{'buy': True, 'sell': False, 'roi': False, 'stoploss': False, 'trailing': False}),
|
||||
(['sell'],
|
||||
{'buy': False, 'sell': True, 'roi': False, 'stoploss': False, 'trailing': False}),
|
||||
(['roi'],
|
||||
{'buy': False, 'sell': False, 'roi': True, 'stoploss': False, 'trailing': False}),
|
||||
(['stoploss'],
|
||||
{'buy': False, 'sell': False, 'roi': False, 'stoploss': True, 'trailing': False}),
|
||||
(['trailing'],
|
||||
{'buy': False, 'sell': False, 'roi': False, 'stoploss': False, 'trailing': True}),
|
||||
(['buy', 'sell', 'roi', 'stoploss'],
|
||||
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False}),
|
||||
(['buy', 'sell', 'roi', 'stoploss', 'trailing'],
|
||||
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}),
|
||||
(['buy', 'roi'],
|
||||
{'buy': True, 'sell': False, 'roi': True, 'stoploss': False, 'trailing': False}),
|
||||
(['all'],
|
||||
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}),
|
||||
(['default'],
|
||||
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False}),
|
||||
(['default', 'trailing'],
|
||||
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}),
|
||||
(['all', 'buy'],
|
||||
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}),
|
||||
(['default', 'buy'],
|
||||
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False}),
|
||||
])
|
||||
def test_has_space(hyperopt_conf, spaces, expected_results):
|
||||
for s in ['buy', 'sell', 'roi', 'stoploss', 'trailing']:
|
||||
hyperopt_conf.update({'spaces': spaces})
|
||||
assert HyperoptTools.has_space(hyperopt_conf, s) == expected_results[s]
|
||||
|
||||
|
||||
def test_populate_indicators(hyperopt, testdatadir) -> None:
|
||||
data = load_data(testdatadir, '1m', ['UNITTEST/BTC'], fill_up_missing=True)
|
||||
dataframes = hyperopt.backtesting.strategy.ohlcvdata_to_dataframe(data)
|
||||
@@ -686,6 +609,8 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None:
|
||||
def test_clean_hyperopt(mocker, hyperopt_conf, caplog):
|
||||
patch_exchange(mocker)
|
||||
|
||||
mocker.patch("freqtrade.strategy.hyper.HyperStrategyMixin.load_params_from_file",
|
||||
MagicMock(return_value={}))
|
||||
mocker.patch("freqtrade.optimize.hyperopt.Path.is_file", MagicMock(return_value=True))
|
||||
unlinkmock = mocker.patch("freqtrade.optimize.hyperopt.Path.unlink", MagicMock())
|
||||
h = Hyperopt(hyperopt_conf)
|
||||
@@ -1068,42 +993,6 @@ def test_simplified_interface_failed(mocker, hyperopt_conf, method, space) -> No
|
||||
hyperopt.start()
|
||||
|
||||
|
||||
def test_show_epoch_details(capsys):
|
||||
test_result = {
|
||||
'params_details': {
|
||||
'trailing': {
|
||||
'trailing_stop': True,
|
||||
'trailing_stop_positive': 0.02,
|
||||
'trailing_stop_positive_offset': 0.04,
|
||||
'trailing_only_offset_is_reached': True
|
||||
},
|
||||
'roi': {
|
||||
0: 0.18,
|
||||
90: 0.14,
|
||||
225: 0.05,
|
||||
430: 0},
|
||||
},
|
||||
'results_explanation': 'foo result',
|
||||
'is_initial_point': False,
|
||||
'total_profit': 0,
|
||||
'current_epoch': 2, # This starts from 1 (in a human-friendly manner)
|
||||
'is_best': True
|
||||
}
|
||||
|
||||
HyperoptTools.show_epoch_details(test_result, 5, False, no_header=True)
|
||||
captured = capsys.readouterr()
|
||||
assert '# Trailing stop:' in captured.out
|
||||
# re.match(r"Pairs for .*", captured.out)
|
||||
assert re.search(r'^\s+trailing_stop = True$', captured.out, re.MULTILINE)
|
||||
assert re.search(r'^\s+trailing_stop_positive = 0.02$', captured.out, re.MULTILINE)
|
||||
assert re.search(r'^\s+trailing_stop_positive_offset = 0.04$', captured.out, re.MULTILINE)
|
||||
assert re.search(r'^\s+trailing_only_offset_is_reached = True$', captured.out, re.MULTILINE)
|
||||
|
||||
assert '# ROI table:' in captured.out
|
||||
assert re.search(r'^\s+minimal_roi = \{$', captured.out, re.MULTILINE)
|
||||
assert re.search(r'^\s+\"90\"\:\s0.14,\s*$', captured.out, re.MULTILINE)
|
||||
|
||||
|
||||
def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None:
|
||||
patch_exchange(mocker)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
||||
@@ -1143,17 +1032,3 @@ 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___pprint():
|
||||
params = {'buy_std': 1.2, 'buy_rsi': 31, 'buy_enable': True, 'buy_what': 'asdf'}
|
||||
non_params = {'buy_notoptimied': 55}
|
||||
|
||||
x = HyperoptTools._pprint(params, non_params)
|
||||
assert x == """{
|
||||
"buy_std": 1.2,
|
||||
"buy_rsi": 31,
|
||||
"buy_enable": True,
|
||||
"buy_what": "asdf",
|
||||
"buy_notoptimied": 55, # value loaded from strategy
|
||||
}"""
|
||||
|
317
tests/optimize/test_hyperopt_tools.py
Normal file
317
tests/optimize/test_hyperopt_tools.py
Normal file
@@ -0,0 +1,317 @@
|
||||
import logging
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
import rapidjson
|
||||
|
||||
from freqtrade.constants import FTHYPT_FILEVERSION
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.optimize.hyperopt_tools import HyperoptTools, hyperopt_serializer
|
||||
from tests.conftest import log_has, log_has_re
|
||||
|
||||
|
||||
# Functions for recurrent object patching
|
||||
def create_results() -> List[Dict]:
|
||||
|
||||
return [{'loss': 1, 'result': 'foo', 'params': {}, 'is_best': True}]
|
||||
|
||||
|
||||
def test_save_results_saves_epochs(hyperopt, tmpdir, caplog) -> None:
|
||||
# Test writing to temp dir and reading again
|
||||
epochs = create_results()
|
||||
hyperopt.results_file = Path(tmpdir / 'ut_results.fthypt')
|
||||
|
||||
caplog.set_level(logging.DEBUG)
|
||||
|
||||
for epoch in epochs:
|
||||
hyperopt._save_result(epoch)
|
||||
assert log_has(f"1 epoch saved to '{hyperopt.results_file}'.", caplog)
|
||||
|
||||
hyperopt._save_result(epochs[0])
|
||||
assert log_has(f"2 epochs saved to '{hyperopt.results_file}'.", caplog)
|
||||
|
||||
hyperopt_epochs = HyperoptTools.load_previous_results(hyperopt.results_file)
|
||||
assert len(hyperopt_epochs) == 2
|
||||
|
||||
|
||||
def test_load_previous_results(testdatadir, caplog) -> None:
|
||||
|
||||
results_file = testdatadir / 'hyperopt_results_SampleStrategy.pickle'
|
||||
|
||||
hyperopt_epochs = HyperoptTools.load_previous_results(results_file)
|
||||
|
||||
assert len(hyperopt_epochs) == 5
|
||||
assert log_has_re(r"Reading pickled epochs from .*", caplog)
|
||||
|
||||
caplog.clear()
|
||||
|
||||
# Modern version
|
||||
results_file = testdatadir / 'strategy_SampleStrategy.fthypt'
|
||||
|
||||
hyperopt_epochs = HyperoptTools.load_previous_results(results_file)
|
||||
|
||||
assert len(hyperopt_epochs) == 5
|
||||
assert log_has_re(r"Reading epochs from .*", caplog)
|
||||
|
||||
|
||||
def test_load_previous_results2(mocker, testdatadir, caplog) -> None:
|
||||
mocker.patch('freqtrade.optimize.hyperopt_tools.HyperoptTools._read_results_pickle',
|
||||
return_value=[{'asdf': '222'}])
|
||||
results_file = testdatadir / 'hyperopt_results_SampleStrategy.pickle'
|
||||
with pytest.raises(OperationalException, match=r"The file .* incompatible.*"):
|
||||
HyperoptTools.load_previous_results(results_file)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("spaces, expected_results", [
|
||||
(['buy'],
|
||||
{'buy': True, 'sell': False, 'roi': False, 'stoploss': False, 'trailing': False}),
|
||||
(['sell'],
|
||||
{'buy': False, 'sell': True, 'roi': False, 'stoploss': False, 'trailing': False}),
|
||||
(['roi'],
|
||||
{'buy': False, 'sell': False, 'roi': True, 'stoploss': False, 'trailing': False}),
|
||||
(['stoploss'],
|
||||
{'buy': False, 'sell': False, 'roi': False, 'stoploss': True, 'trailing': False}),
|
||||
(['trailing'],
|
||||
{'buy': False, 'sell': False, 'roi': False, 'stoploss': False, 'trailing': True}),
|
||||
(['buy', 'sell', 'roi', 'stoploss'],
|
||||
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False}),
|
||||
(['buy', 'sell', 'roi', 'stoploss', 'trailing'],
|
||||
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}),
|
||||
(['buy', 'roi'],
|
||||
{'buy': True, 'sell': False, 'roi': True, 'stoploss': False, 'trailing': False}),
|
||||
(['all'],
|
||||
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}),
|
||||
(['default'],
|
||||
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False}),
|
||||
(['default', 'trailing'],
|
||||
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}),
|
||||
(['all', 'buy'],
|
||||
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True}),
|
||||
(['default', 'buy'],
|
||||
{'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False}),
|
||||
])
|
||||
def test_has_space(hyperopt_conf, spaces, expected_results):
|
||||
for s in ['buy', 'sell', 'roi', 'stoploss', 'trailing']:
|
||||
hyperopt_conf.update({'spaces': spaces})
|
||||
assert HyperoptTools.has_space(hyperopt_conf, s) == expected_results[s]
|
||||
|
||||
|
||||
def test_show_epoch_details(capsys):
|
||||
test_result = {
|
||||
'params_details': {
|
||||
'trailing': {
|
||||
'trailing_stop': True,
|
||||
'trailing_stop_positive': 0.02,
|
||||
'trailing_stop_positive_offset': 0.04,
|
||||
'trailing_only_offset_is_reached': True
|
||||
},
|
||||
'roi': {
|
||||
0: 0.18,
|
||||
90: 0.14,
|
||||
225: 0.05,
|
||||
430: 0},
|
||||
},
|
||||
'results_explanation': 'foo result',
|
||||
'is_initial_point': False,
|
||||
'total_profit': 0,
|
||||
'current_epoch': 2, # This starts from 1 (in a human-friendly manner)
|
||||
'is_best': True
|
||||
}
|
||||
|
||||
HyperoptTools.show_epoch_details(test_result, 5, False, no_header=True)
|
||||
captured = capsys.readouterr()
|
||||
assert '# Trailing stop:' in captured.out
|
||||
# re.match(r"Pairs for .*", captured.out)
|
||||
assert re.search(r'^\s+trailing_stop = True$', captured.out, re.MULTILINE)
|
||||
assert re.search(r'^\s+trailing_stop_positive = 0.02$', captured.out, re.MULTILINE)
|
||||
assert re.search(r'^\s+trailing_stop_positive_offset = 0.04$', captured.out, re.MULTILINE)
|
||||
assert re.search(r'^\s+trailing_only_offset_is_reached = True$', captured.out, re.MULTILINE)
|
||||
|
||||
assert '# ROI table:' in captured.out
|
||||
assert re.search(r'^\s+minimal_roi = \{$', captured.out, re.MULTILINE)
|
||||
assert re.search(r'^\s+\"90\"\:\s0.14,\s*$', captured.out, re.MULTILINE)
|
||||
|
||||
|
||||
def test__pprint_dict():
|
||||
params = {'buy_std': 1.2, 'buy_rsi': 31, 'buy_enable': True, 'buy_what': 'asdf'}
|
||||
non_params = {'buy_notoptimied': 55}
|
||||
|
||||
x = HyperoptTools._pprint_dict(params, non_params)
|
||||
assert x == """{
|
||||
"buy_std": 1.2,
|
||||
"buy_rsi": 31,
|
||||
"buy_enable": True,
|
||||
"buy_what": "asdf",
|
||||
"buy_notoptimied": 55, # value loaded from strategy
|
||||
}"""
|
||||
|
||||
|
||||
def test_get_strategy_filename(default_conf):
|
||||
|
||||
x = HyperoptTools.get_strategy_filename(default_conf, 'DefaultStrategy')
|
||||
assert isinstance(x, Path)
|
||||
assert x == Path(__file__).parents[1] / 'strategy/strats/default_strategy.py'
|
||||
|
||||
x = HyperoptTools.get_strategy_filename(default_conf, 'NonExistingStrategy')
|
||||
assert x is None
|
||||
|
||||
|
||||
def test_export_params(tmpdir):
|
||||
|
||||
filename = Path(tmpdir) / "DefaultStrategy.json"
|
||||
assert not filename.is_file()
|
||||
params = {
|
||||
"params_details": {
|
||||
"buy": {
|
||||
"buy_rsi": 30
|
||||
},
|
||||
"sell": {
|
||||
"sell_rsi": 70
|
||||
},
|
||||
"roi": {
|
||||
"0": 0.528,
|
||||
"346": 0.08499,
|
||||
"507": 0.049,
|
||||
"1595": 0
|
||||
}
|
||||
},
|
||||
"params_not_optimized": {
|
||||
"stoploss": -0.05,
|
||||
"trailing": {
|
||||
"trailing_stop": False,
|
||||
"trailing_stop_positive": 0.05,
|
||||
"trailing_stop_positive_offset": 0.1,
|
||||
"trailing_only_offset_is_reached": True
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
HyperoptTools.export_params(params, "DefaultStrategy", filename)
|
||||
|
||||
assert filename.is_file()
|
||||
|
||||
content = rapidjson.load(filename.open('r'))
|
||||
assert content['strategy_name'] == 'DefaultStrategy'
|
||||
assert 'params' in content
|
||||
assert "buy" in content["params"]
|
||||
assert "sell" in content["params"]
|
||||
assert "roi" in content["params"]
|
||||
assert "stoploss" in content["params"]
|
||||
assert "trailing" in content["params"]
|
||||
|
||||
|
||||
def test_try_export_params(default_conf, tmpdir, caplog, mocker):
|
||||
default_conf['disableparamexport'] = False
|
||||
export_mock = mocker.patch("freqtrade.optimize.hyperopt_tools.HyperoptTools.export_params")
|
||||
|
||||
filename = Path(tmpdir) / "DefaultStrategy.json"
|
||||
assert not filename.is_file()
|
||||
params = {
|
||||
"params_details": {
|
||||
"buy": {
|
||||
"buy_rsi": 30
|
||||
},
|
||||
"sell": {
|
||||
"sell_rsi": 70
|
||||
},
|
||||
"roi": {
|
||||
"0": 0.528,
|
||||
"346": 0.08499,
|
||||
"507": 0.049,
|
||||
"1595": 0
|
||||
}
|
||||
},
|
||||
"params_not_optimized": {
|
||||
"stoploss": -0.05,
|
||||
"trailing": {
|
||||
"trailing_stop": False,
|
||||
"trailing_stop_positive": 0.05,
|
||||
"trailing_stop_positive_offset": 0.1,
|
||||
"trailing_only_offset_is_reached": True
|
||||
},
|
||||
},
|
||||
FTHYPT_FILEVERSION: 2,
|
||||
|
||||
}
|
||||
HyperoptTools.try_export_params(default_conf, "DefaultStrategy22", params)
|
||||
|
||||
assert log_has("Strategy not found, not exporting parameter file.", caplog)
|
||||
assert export_mock.call_count == 0
|
||||
caplog.clear()
|
||||
|
||||
HyperoptTools.try_export_params(default_conf, "DefaultStrategy", params)
|
||||
|
||||
assert export_mock.call_count == 1
|
||||
assert export_mock.call_args_list[0][0][1] == 'DefaultStrategy'
|
||||
assert export_mock.call_args_list[0][0][2].name == 'default_strategy.json'
|
||||
|
||||
|
||||
def test_params_print(capsys):
|
||||
|
||||
params = {
|
||||
"buy": {
|
||||
"buy_rsi": 30
|
||||
},
|
||||
"sell": {
|
||||
"sell_rsi": 70
|
||||
},
|
||||
}
|
||||
non_optimized = {
|
||||
"buy": {
|
||||
"buy_adx": 44
|
||||
},
|
||||
"sell": {
|
||||
"sell_adx": 65
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -0.05,
|
||||
},
|
||||
"roi": {
|
||||
"0": 0.05,
|
||||
"20": 0.01,
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": False,
|
||||
"trailing_stop_positive": 0.05,
|
||||
"trailing_stop_positive_offset": 0.1,
|
||||
"trailing_only_offset_is_reached": True
|
||||
},
|
||||
|
||||
}
|
||||
HyperoptTools._params_pretty_print(params, 'buy', 'No header', non_optimized)
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert re.search("# No header", captured.out)
|
||||
assert re.search('"buy_rsi": 30,\n', captured.out)
|
||||
assert re.search('"buy_adx": 44, # value loaded.*\n', captured.out)
|
||||
assert not re.search("sell", captured.out)
|
||||
|
||||
HyperoptTools._params_pretty_print(params, 'sell', 'Sell Header', non_optimized)
|
||||
captured = capsys.readouterr()
|
||||
assert re.search("# Sell Header", captured.out)
|
||||
assert re.search('"sell_rsi": 70,\n', captured.out)
|
||||
assert re.search('"sell_adx": 65, # value loaded.*\n', captured.out)
|
||||
|
||||
HyperoptTools._params_pretty_print(params, 'roi', 'ROI Table:', non_optimized)
|
||||
captured = capsys.readouterr()
|
||||
assert re.search("# ROI Table: # value loaded.*\n", captured.out)
|
||||
assert re.search('minimal_roi = {\n', captured.out)
|
||||
assert re.search('"20": 0.01\n', captured.out)
|
||||
|
||||
HyperoptTools._params_pretty_print(params, 'trailing', 'Trailing stop:', non_optimized)
|
||||
captured = capsys.readouterr()
|
||||
assert re.search("# Trailing stop:", captured.out)
|
||||
assert re.search('trailing_stop = False # value loaded.*\n', captured.out)
|
||||
assert re.search('trailing_stop_positive = 0.05 # value loaded.*\n', captured.out)
|
||||
assert re.search('trailing_stop_positive_offset = 0.1 # value loaded.*\n', captured.out)
|
||||
assert re.search('trailing_only_offset_is_reached = True # value loaded.*\n', captured.out)
|
||||
|
||||
|
||||
def test_hyperopt_serializer():
|
||||
|
||||
assert isinstance(hyperopt_serializer(np.int_(5)), int)
|
||||
assert isinstance(hyperopt_serializer(np.bool_(True)), bool)
|
||||
assert isinstance(hyperopt_serializer(np.bool_(False)), bool)
|
@@ -1,6 +1,7 @@
|
||||
# pragma pylint: disable=missing-docstring, C0103
|
||||
import logging
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import arrow
|
||||
@@ -707,3 +708,50 @@ def test_auto_hyperopt_interface(default_conf):
|
||||
|
||||
with pytest.raises(OperationalException, match=r"Inconclusive parameter.*"):
|
||||
[x for x in strategy.detect_parameters('sell')]
|
||||
|
||||
|
||||
def test_auto_hyperopt_interface_loadparams(default_conf, mocker, caplog):
|
||||
default_conf.update({'strategy': 'HyperoptableStrategy'})
|
||||
del default_conf['stoploss']
|
||||
del default_conf['minimal_roi']
|
||||
mocker.patch.object(Path, 'is_file', MagicMock(return_value=True))
|
||||
mocker.patch.object(Path, 'open')
|
||||
expected_result = {
|
||||
"strategy_name": "HyperoptableStrategy",
|
||||
"params": {
|
||||
"stoploss": {
|
||||
"stoploss": -0.05,
|
||||
},
|
||||
"roi": {
|
||||
"0": 0.2,
|
||||
"1200": 0.01
|
||||
}
|
||||
}
|
||||
}
|
||||
mocker.patch('freqtrade.strategy.hyper.json_load', return_value=expected_result)
|
||||
PairLocks.timeframe = default_conf['timeframe']
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
assert strategy.stoploss == -0.05
|
||||
assert strategy.minimal_roi == {0: 0.2, 1200: 0.01}
|
||||
|
||||
expected_result = {
|
||||
"strategy_name": "HyperoptableStrategy_No",
|
||||
"params": {
|
||||
"stoploss": {
|
||||
"stoploss": -0.05,
|
||||
},
|
||||
"roi": {
|
||||
"0": 0.2,
|
||||
"1200": 0.01
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mocker.patch('freqtrade.strategy.hyper.json_load', return_value=expected_result)
|
||||
with pytest.raises(OperationalException, match="Invalid parameter file provided."):
|
||||
StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
mocker.patch('freqtrade.strategy.hyper.json_load', MagicMock(side_effect=ValueError()))
|
||||
|
||||
StrategyResolver.load_strategy(default_conf)
|
||||
assert log_has("Invalid parameter file format.", caplog)
|
||||
|
Reference in New Issue
Block a user