Merge branch 'develop' into agefilter-max-days-listed
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",
|
||||
}
|
||||
@@ -1761,7 +1762,7 @@ def rpc_balance():
|
||||
'total': 0.1,
|
||||
'free': 0.01,
|
||||
'used': 0.0
|
||||
},
|
||||
},
|
||||
'EUR': {
|
||||
'total': 10.0,
|
||||
'free': 10.0,
|
||||
@@ -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)
|
@@ -105,6 +105,15 @@ def test_api_ui_fallback(botclient):
|
||||
assert rc.status_code == 200
|
||||
|
||||
|
||||
def test_api_ui_version(botclient, mocker):
|
||||
ftbot, client = botclient
|
||||
|
||||
mocker.patch('freqtrade.commands.deploy_commands.read_ui_version', return_value='0.1.2')
|
||||
rc = client_get(client, "/ui_version")
|
||||
assert rc.status_code == 200
|
||||
assert rc.json()['version'] == '0.1.2'
|
||||
|
||||
|
||||
def test_api_auth():
|
||||
with pytest.raises(ValueError):
|
||||
create_token({'identity': {'u': 'Freqtrade'}}, 'secret1234', token_type="NotATokenType")
|
||||
|
@@ -519,12 +519,15 @@ def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance, tick
|
||||
assert msg_mock.call_count == 1
|
||||
assert '*BTC:*' in result
|
||||
assert '*ETH:*' not in result
|
||||
assert '*USDT:*' in result
|
||||
assert '*EUR:*' in result
|
||||
assert '*USDT:*' not in result
|
||||
assert '*EUR:*' not in result
|
||||
assert '*LTC:*' in result
|
||||
assert '*XRP:*' not in result
|
||||
assert 'Balance:' in result
|
||||
assert 'Est. BTC:' in result
|
||||
assert 'BTC: 12.00000000' in result
|
||||
assert '*XRP:* not showing <0.0001 BTC amount' in result
|
||||
assert "*3 Other Currencies (< 0.0001 BTC):*" in result
|
||||
assert 'BTC: 0.00000309' in result
|
||||
|
||||
|
||||
def test_balance_handle_empty_response(default_conf, update, mocker) -> None:
|
||||
|
@@ -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
|
||||
@@ -12,6 +13,7 @@ from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.data.history import load_data
|
||||
from freqtrade.enums import SellType
|
||||
from freqtrade.exceptions import OperationalException, StrategyError
|
||||
from freqtrade.optimize.space import SKDecimal
|
||||
from freqtrade.persistence import PairLocks, Trade
|
||||
from freqtrade.resolvers import StrategyResolver
|
||||
from freqtrade.strategy.hyper import (BaseParameter, CategoricalParameter, DecimalParameter,
|
||||
@@ -657,17 +659,31 @@ def test_hyperopt_parameters():
|
||||
assert list(intpar.range) == [0, 1, 2, 3, 4, 5]
|
||||
|
||||
fltpar = RealParameter(low=0.0, high=5.5, default=1.0, space='buy')
|
||||
assert fltpar.value == 1
|
||||
assert isinstance(fltpar.get_space(''), Real)
|
||||
assert fltpar.value == 1
|
||||
|
||||
fltpar = DecimalParameter(low=0.0, high=5.5, default=1.0004, decimals=3, space='buy')
|
||||
assert isinstance(fltpar.get_space(''), Integer)
|
||||
assert fltpar.value == 1
|
||||
fltpar = DecimalParameter(low=0.0, high=0.5, default=0.14, decimals=1, space='buy')
|
||||
assert fltpar.value == 0.1
|
||||
assert isinstance(fltpar.get_space(''), SKDecimal)
|
||||
assert isinstance(fltpar.range, list)
|
||||
assert len(list(fltpar.range)) == 1
|
||||
# Range contains ONLY the default / value.
|
||||
assert list(fltpar.range) == [fltpar.value]
|
||||
fltpar.in_space = True
|
||||
assert len(list(fltpar.range)) == 6
|
||||
assert list(fltpar.range) == [0.0, 0.1, 0.2, 0.3, 0.4, 0.5]
|
||||
|
||||
catpar = CategoricalParameter(['buy_rsi', 'buy_macd', 'buy_none'],
|
||||
default='buy_macd', space='buy')
|
||||
assert isinstance(catpar.get_space(''), Categorical)
|
||||
assert catpar.value == 'buy_macd'
|
||||
assert isinstance(catpar.get_space(''), Categorical)
|
||||
assert isinstance(catpar.range, list)
|
||||
assert len(list(catpar.range)) == 1
|
||||
# Range contains ONLY the default / value.
|
||||
assert list(catpar.range) == [catpar.value]
|
||||
catpar.in_space = True
|
||||
assert len(list(catpar.range)) == 3
|
||||
assert list(catpar.range) == ['buy_rsi', 'buy_macd', 'buy_none']
|
||||
|
||||
|
||||
def test_auto_hyperopt_interface(default_conf):
|
||||
@@ -692,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