Merge pull request #2538 from freqtrade/strategy_template
new-strategy / new-hyperopt - from templates
This commit is contained in:
@@ -869,6 +869,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
|
||||
'backtesting',
|
||||
'--config', 'config.json',
|
||||
'--datadir', str(testdatadir),
|
||||
'--strategy-path', str(Path(__file__).parents[2] / 'freqtrade/templates'),
|
||||
'--ticker-interval', '1m',
|
||||
'--timerange', '1510694220-1510700340',
|
||||
'--enable-position-stacking',
|
||||
|
@@ -36,13 +36,15 @@ def test_search_strategy():
|
||||
|
||||
|
||||
def test_load_strategy(default_conf, result):
|
||||
default_conf.update({'strategy': 'SampleStrategy'})
|
||||
default_conf.update({'strategy': 'SampleStrategy',
|
||||
'strategy_path': str(Path(__file__).parents[2] / 'freqtrade/templates')
|
||||
})
|
||||
resolver = StrategyResolver(default_conf)
|
||||
assert 'rsi' in resolver.strategy.advise_indicators(result, {'pair': 'ETH/BTC'})
|
||||
|
||||
|
||||
def test_load_strategy_base64(result, caplog, default_conf):
|
||||
with open("user_data/strategies/sample_strategy.py", "rb") as file:
|
||||
with (Path(__file__).parents[2] / 'freqtrade/templates/sample_strategy.py').open("rb") as file:
|
||||
encoded_string = urlsafe_b64encode(file.read()).decode("utf-8")
|
||||
default_conf.update({'strategy': 'SampleStrategy:{}'.format(encoded_string)})
|
||||
|
||||
@@ -54,10 +56,10 @@ def test_load_strategy_base64(result, caplog, default_conf):
|
||||
|
||||
|
||||
def test_load_strategy_invalid_directory(result, caplog, default_conf):
|
||||
default_conf['strategy'] = 'SampleStrategy'
|
||||
default_conf['strategy'] = 'DefaultStrategy'
|
||||
resolver = StrategyResolver(default_conf)
|
||||
extra_dir = Path.cwd() / 'some/path'
|
||||
resolver._load_strategy('SampleStrategy', config=default_conf, extra_dir=extra_dir)
|
||||
resolver._load_strategy('DefaultStrategy', config=default_conf, extra_dir=extra_dir)
|
||||
|
||||
assert log_has_re(r'Path .*' + r'some.*path.*' + r'.* does not exist', caplog)
|
||||
|
||||
|
@@ -17,8 +17,6 @@ from freqtrade.configuration.config_validation import validate_config_schema
|
||||
from freqtrade.configuration.deprecated_settings import (
|
||||
check_conflicting_settings, process_deprecated_setting,
|
||||
process_temporary_deprecated_settings)
|
||||
from freqtrade.configuration.directory_operations import (create_datadir,
|
||||
create_userdata_dir)
|
||||
from freqtrade.configuration.load_config import load_config_file
|
||||
from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL
|
||||
from freqtrade.loggers import _set_loggers
|
||||
@@ -670,45 +668,6 @@ def test_validate_default_conf(default_conf) -> None:
|
||||
validate(default_conf, constants.CONF_SCHEMA, Draft4Validator)
|
||||
|
||||
|
||||
def test_create_datadir(mocker, default_conf, caplog) -> None:
|
||||
mocker.patch.object(Path, "is_dir", MagicMock(return_value=False))
|
||||
md = mocker.patch.object(Path, 'mkdir', MagicMock())
|
||||
|
||||
create_datadir(default_conf, '/foo/bar')
|
||||
assert md.call_args[1]['parents'] is True
|
||||
assert log_has('Created data directory: /foo/bar', caplog)
|
||||
|
||||
|
||||
def test_create_userdata_dir(mocker, default_conf, caplog) -> None:
|
||||
mocker.patch.object(Path, "is_dir", MagicMock(return_value=False))
|
||||
md = mocker.patch.object(Path, 'mkdir', MagicMock())
|
||||
|
||||
x = create_userdata_dir('/tmp/bar', create_dir=True)
|
||||
assert md.call_count == 7
|
||||
assert md.call_args[1]['parents'] is False
|
||||
assert log_has(f'Created user-data directory: {Path("/tmp/bar")}', caplog)
|
||||
assert isinstance(x, Path)
|
||||
assert str(x) == str(Path("/tmp/bar"))
|
||||
|
||||
|
||||
def test_create_userdata_dir_exists(mocker, default_conf, caplog) -> None:
|
||||
mocker.patch.object(Path, "is_dir", MagicMock(return_value=True))
|
||||
md = mocker.patch.object(Path, 'mkdir', MagicMock())
|
||||
|
||||
create_userdata_dir('/tmp/bar')
|
||||
assert md.call_count == 0
|
||||
|
||||
|
||||
def test_create_userdata_dir_exists_exception(mocker, default_conf, caplog) -> None:
|
||||
mocker.patch.object(Path, "is_dir", MagicMock(return_value=False))
|
||||
md = mocker.patch.object(Path, 'mkdir', MagicMock())
|
||||
|
||||
with pytest.raises(OperationalException,
|
||||
match=r'Directory `.{1,2}tmp.{1,2}bar` does not exist.*'):
|
||||
create_userdata_dir('/tmp/bar', create_dir=False)
|
||||
assert md.call_count == 0
|
||||
|
||||
|
||||
def test_validate_tsl(default_conf):
|
||||
default_conf['stoploss'] = 0.0
|
||||
with pytest.raises(OperationalException, match='The config stoploss needs to be different '
|
||||
|
91
tests/test_directory_operations.py
Normal file
91
tests/test_directory_operations.py
Normal file
@@ -0,0 +1,91 @@
|
||||
# pragma pylint: disable=missing-docstring, protected-access, invalid-name
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from freqtrade import OperationalException
|
||||
from freqtrade.configuration.directory_operations import (copy_sample_files,
|
||||
create_datadir,
|
||||
create_userdata_dir)
|
||||
from tests.conftest import log_has, log_has_re
|
||||
|
||||
|
||||
def test_create_datadir(mocker, default_conf, caplog) -> None:
|
||||
mocker.patch.object(Path, "is_dir", MagicMock(return_value=False))
|
||||
md = mocker.patch.object(Path, 'mkdir', MagicMock())
|
||||
|
||||
create_datadir(default_conf, '/foo/bar')
|
||||
assert md.call_args[1]['parents'] is True
|
||||
assert log_has('Created data directory: /foo/bar', caplog)
|
||||
|
||||
|
||||
def test_create_userdata_dir(mocker, default_conf, caplog) -> None:
|
||||
mocker.patch.object(Path, "is_dir", MagicMock(return_value=False))
|
||||
md = mocker.patch.object(Path, 'mkdir', MagicMock())
|
||||
|
||||
x = create_userdata_dir('/tmp/bar', create_dir=True)
|
||||
assert md.call_count == 8
|
||||
assert md.call_args[1]['parents'] is False
|
||||
assert log_has(f'Created user-data directory: {Path("/tmp/bar")}', caplog)
|
||||
assert isinstance(x, Path)
|
||||
assert str(x) == str(Path("/tmp/bar"))
|
||||
|
||||
|
||||
def test_create_userdata_dir_exists(mocker, default_conf, caplog) -> None:
|
||||
mocker.patch.object(Path, "is_dir", MagicMock(return_value=True))
|
||||
md = mocker.patch.object(Path, 'mkdir', MagicMock())
|
||||
|
||||
create_userdata_dir('/tmp/bar')
|
||||
assert md.call_count == 0
|
||||
|
||||
|
||||
def test_create_userdata_dir_exists_exception(mocker, default_conf, caplog) -> None:
|
||||
mocker.patch.object(Path, "is_dir", MagicMock(return_value=False))
|
||||
md = mocker.patch.object(Path, 'mkdir', MagicMock())
|
||||
|
||||
with pytest.raises(OperationalException,
|
||||
match=r'Directory `.{1,2}tmp.{1,2}bar` does not exist.*'):
|
||||
create_userdata_dir('/tmp/bar', create_dir=False)
|
||||
assert md.call_count == 0
|
||||
|
||||
|
||||
def test_copy_sample_files(mocker, default_conf, caplog) -> None:
|
||||
mocker.patch.object(Path, "is_dir", MagicMock(return_value=True))
|
||||
mocker.patch.object(Path, "exists", MagicMock(return_value=False))
|
||||
copymock = mocker.patch('shutil.copy', MagicMock())
|
||||
|
||||
copy_sample_files(Path('/tmp/bar'))
|
||||
assert copymock.call_count == 5
|
||||
assert copymock.call_args_list[0][0][1] == str(
|
||||
Path('/tmp/bar') / 'strategies/sample_strategy.py')
|
||||
assert copymock.call_args_list[1][0][1] == str(
|
||||
Path('/tmp/bar') / 'hyperopts/sample_hyperopt_advanced.py')
|
||||
assert copymock.call_args_list[2][0][1] == str(
|
||||
Path('/tmp/bar') / 'hyperopts/sample_hyperopt_loss.py')
|
||||
assert copymock.call_args_list[3][0][1] == str(
|
||||
Path('/tmp/bar') / 'hyperopts/sample_hyperopt.py')
|
||||
assert copymock.call_args_list[4][0][1] == str(
|
||||
Path('/tmp/bar') / 'notebooks/strategy_analysis_example.ipynb')
|
||||
|
||||
|
||||
def test_copy_sample_files_errors(mocker, default_conf, caplog) -> None:
|
||||
mocker.patch.object(Path, "is_dir", MagicMock(return_value=False))
|
||||
mocker.patch.object(Path, "exists", MagicMock(return_value=False))
|
||||
mocker.patch('shutil.copy', MagicMock())
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"Directory `.{1,2}tmp.{1,2}bar` does not exist\."):
|
||||
copy_sample_files(Path('/tmp/bar'))
|
||||
|
||||
mocker.patch.object(Path, "is_dir", MagicMock(side_effect=[True, False]))
|
||||
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"Directory `.{1,2}tmp.{1,2}bar.{1,2}strategies` does not exist\."):
|
||||
copy_sample_files(Path('/tmp/bar'))
|
||||
mocker.patch.object(Path, "is_dir", MagicMock(return_value=True))
|
||||
mocker.patch.object(Path, "exists", MagicMock(return_value=True))
|
||||
copy_sample_files(Path('/tmp/bar'))
|
||||
assert log_has_re(r"File `.*` exists already, not deploying sample file\.", caplog)
|
||||
caplog.clear()
|
||||
copy_sample_files(Path('/tmp/bar'), overwrite=True)
|
||||
assert log_has_re(r"File `.*` exists already, overwriting\.", caplog)
|
@@ -9,8 +9,9 @@ from freqtrade.state import RunMode
|
||||
from freqtrade.utils import (setup_utils_configuration, start_create_userdir,
|
||||
start_download_data, start_list_exchanges,
|
||||
start_list_markets, start_list_timeframes,
|
||||
start_new_hyperopt, start_new_strategy,
|
||||
start_trading)
|
||||
from tests.conftest import get_args, log_has, patch_exchange
|
||||
from tests.conftest import get_args, log_has, log_has_re, patch_exchange
|
||||
|
||||
|
||||
def test_setup_utils_configuration():
|
||||
@@ -442,6 +443,7 @@ def test_create_datadir_failed(caplog):
|
||||
|
||||
def test_create_datadir(caplog, mocker):
|
||||
cud = mocker.patch("freqtrade.utils.create_userdata_dir", MagicMock())
|
||||
csf = mocker.patch("freqtrade.utils.copy_sample_files", MagicMock())
|
||||
args = [
|
||||
"create-userdir",
|
||||
"--userdir",
|
||||
@@ -450,9 +452,82 @@ def test_create_datadir(caplog, mocker):
|
||||
start_create_userdir(get_args(args))
|
||||
|
||||
assert cud.call_count == 1
|
||||
assert csf.call_count == 1
|
||||
assert len(caplog.record_tuples) == 0
|
||||
|
||||
|
||||
def test_start_new_strategy(mocker, caplog):
|
||||
wt_mock = mocker.patch.object(Path, "write_text", MagicMock())
|
||||
mocker.patch.object(Path, "exists", MagicMock(return_value=False))
|
||||
|
||||
args = [
|
||||
"new-strategy",
|
||||
"--strategy",
|
||||
"CoolNewStrategy"
|
||||
]
|
||||
start_new_strategy(get_args(args))
|
||||
|
||||
assert wt_mock.call_count == 1
|
||||
assert "CoolNewStrategy" in wt_mock.call_args_list[0][0][0]
|
||||
assert log_has_re("Writing strategy to .*", caplog)
|
||||
|
||||
|
||||
def test_start_new_strategy_DefaultStrat(mocker, caplog):
|
||||
args = [
|
||||
"new-strategy",
|
||||
"--strategy",
|
||||
"DefaultStrategy"
|
||||
]
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"DefaultStrategy is not allowed as name\."):
|
||||
start_new_strategy(get_args(args))
|
||||
|
||||
|
||||
def test_start_new_strategy_no_arg(mocker, caplog):
|
||||
args = [
|
||||
"new-strategy",
|
||||
]
|
||||
with pytest.raises(OperationalException,
|
||||
match="`new-strategy` requires --strategy to be set."):
|
||||
start_new_strategy(get_args(args))
|
||||
|
||||
|
||||
def test_start_new_hyperopt(mocker, caplog):
|
||||
wt_mock = mocker.patch.object(Path, "write_text", MagicMock())
|
||||
mocker.patch.object(Path, "exists", MagicMock(return_value=False))
|
||||
|
||||
args = [
|
||||
"new-hyperopt",
|
||||
"--hyperopt",
|
||||
"CoolNewhyperopt"
|
||||
]
|
||||
start_new_hyperopt(get_args(args))
|
||||
|
||||
assert wt_mock.call_count == 1
|
||||
assert "CoolNewhyperopt" in wt_mock.call_args_list[0][0][0]
|
||||
assert log_has_re("Writing hyperopt to .*", caplog)
|
||||
|
||||
|
||||
def test_start_new_hyperopt_DefaultHyperopt(mocker, caplog):
|
||||
args = [
|
||||
"new-hyperopt",
|
||||
"--hyperopt",
|
||||
"DefaultHyperopt"
|
||||
]
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"DefaultHyperopt is not allowed as name\."):
|
||||
start_new_hyperopt(get_args(args))
|
||||
|
||||
|
||||
def test_start_new_hyperopt_no_arg(mocker, caplog):
|
||||
args = [
|
||||
"new-hyperopt",
|
||||
]
|
||||
with pytest.raises(OperationalException,
|
||||
match="`new-hyperopt` requires --hyperopt to be set."):
|
||||
start_new_hyperopt(get_args(args))
|
||||
|
||||
|
||||
def test_download_data_keyboardInterrupt(mocker, caplog, markets):
|
||||
dl_mock = mocker.patch('freqtrade.utils.refresh_backtest_ohlcv_data',
|
||||
MagicMock(side_effect=KeyboardInterrupt))
|
||||
|
Reference in New Issue
Block a user