config validation moved to configuration file

This commit is contained in:
misagh 2019-03-14 09:01:03 +01:00
parent 3c99e3b7c7
commit 29305dd070
3 changed files with 62 additions and 31 deletions

View File

@ -58,6 +58,7 @@ class Configuration(object):
config['internals'] = {} config['internals'] = {}
logger.info('Validating configuration ...') logger.info('Validating configuration ...')
self._validate_config_schema(config)
self._validate_config(config) self._validate_config(config)
# Set strategy if not specified in config and or if it's non default # Set strategy if not specified in config and or if it's non default
@ -291,7 +292,7 @@ class Configuration(object):
return config return config
def _validate_config(self, conf: Dict[str, Any]) -> Dict[str, Any]: def _validate_config_schema(self, conf: Dict[str, Any]) -> Dict[str, Any]:
""" """
Validate the configuration follow the Config Schema Validate the configuration follow the Config Schema
:param conf: Config in JSON format :param conf: Config in JSON format
@ -309,6 +310,35 @@ class Configuration(object):
best_match(Draft4Validator(constants.CONF_SCHEMA).iter_errors(conf)).message best_match(Draft4Validator(constants.CONF_SCHEMA).iter_errors(conf)).message
) )
def _validate_config(self, conf: Dict[str, Any]) -> None:
"""
Validate the configuration consistency
:param conf: Config in JSON format
:return: Returns None if everything is ok, otherwise throw an exception
"""
# validating trailing stoploss
self._validate_trailing_stoploss(conf)
def _validate_trailing_stoploss(self, conf: Dict[str, Any]) -> None:
# Skip if trailing stoploss is not activated
if not conf.get('trailing_stop', False):
return
tsl_positive = float(conf.get('trailing_stop_positive', 0))
tsl_offset = float(conf.get('trailing_stop_positive_offset', 0))
tsl_only_offset = conf.get('trailing_only_offset_is_reached', False)
if tsl_only_offset:
if tsl_positive == 0.0:
raise OperationalException(
f'The config trailing_only_offset_is_reached need '
'trailing_stop_positive_offset to be more than 0 in your config.')
if tsl_positive > 0 and 0 < tsl_offset <= tsl_positive:
raise OperationalException(
f'The config trailing_stop_positive_offset need '
'to be greater than trailing_stop_positive_offset in your config.')
def get_config(self) -> Dict[str, Any]: def get_config(self) -> Dict[str, Any]:
""" """
Return the config. Use this method to get the bot config Return the config. Use this method to get the bot config

View File

@ -449,33 +449,6 @@ def test_validate_order_types(default_conf, mocker):
Exchange(default_conf) Exchange(default_conf)
def test_validate_tsl(default_conf, mocker):
api_mock = MagicMock()
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.name', 'Bittrex')
default_conf['trailing_stop'] = True
default_conf['trailing_stop_positive'] = 0
default_conf['trailing_stop_positive_offset'] = 0
default_conf['trailing_only_offset_is_reached'] = False
Exchange(default_conf)
default_conf['trailing_only_offset_is_reached'] = True
with pytest.raises(OperationalException,
match=r'The config trailing_only_offset_is_reached need '
'trailing_stop_positive_offset to be more than 0 in your config.'):
Exchange(default_conf)
default_conf['trailing_stop_positive_offset'] = 0.01
default_conf['trailing_stop_positive'] = 0.015
with pytest.raises(OperationalException,
match=r'The config trailing_stop_positive_offset need '
'to be greater than trailing_stop_positive_offset in your config.'):
Exchange(default_conf)
def test_validate_order_types_not_in_config(default_conf, mocker): def test_validate_order_types_not_in_config(default_conf, mocker):
api_mock = MagicMock() api_mock = MagicMock()
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))

View File

@ -13,6 +13,7 @@ from freqtrade import OperationalException, constants
from freqtrade.arguments import Arguments from freqtrade.arguments import Arguments
from freqtrade.configuration import Configuration, set_loggers from freqtrade.configuration import Configuration, set_loggers
from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL
from freqtrade.exchange import Exchange
from freqtrade.state import RunMode from freqtrade.state import RunMode
from freqtrade.tests.conftest import log_has from freqtrade.tests.conftest import log_has
@ -22,7 +23,7 @@ def test_load_config_invalid_pair(default_conf) -> None:
with pytest.raises(ValidationError, match=r'.*does not match.*'): with pytest.raises(ValidationError, match=r'.*does not match.*'):
configuration = Configuration(Namespace()) configuration = Configuration(Namespace())
configuration._validate_config(default_conf) configuration._validate_config_schema(default_conf)
def test_load_config_missing_attributes(default_conf) -> None: def test_load_config_missing_attributes(default_conf) -> None:
@ -30,7 +31,7 @@ def test_load_config_missing_attributes(default_conf) -> None:
with pytest.raises(ValidationError, match=r'.*\'exchange\' is a required property.*'): with pytest.raises(ValidationError, match=r'.*\'exchange\' is a required property.*'):
configuration = Configuration(Namespace()) configuration = Configuration(Namespace())
configuration._validate_config(default_conf) configuration._validate_config_schema(default_conf)
def test_load_config_incorrect_stake_amount(default_conf) -> None: def test_load_config_incorrect_stake_amount(default_conf) -> None:
@ -38,7 +39,7 @@ def test_load_config_incorrect_stake_amount(default_conf) -> None:
with pytest.raises(ValidationError, match=r'.*\'fake\' does not match \'unlimited\'.*'): with pytest.raises(ValidationError, match=r'.*\'fake\' does not match \'unlimited\'.*'):
configuration = Configuration(Namespace()) configuration = Configuration(Namespace())
configuration._validate_config(default_conf) configuration._validate_config_schema(default_conf)
def test_load_config_file(default_conf, mocker, caplog) -> None: def test_load_config_file(default_conf, mocker, caplog) -> None:
@ -573,3 +574,30 @@ def test__create_datadir(mocker, default_conf, caplog) -> None:
cfg._create_datadir(default_conf, '/foo/bar') cfg._create_datadir(default_conf, '/foo/bar')
assert md.call_args[0][0] == "/foo/bar" assert md.call_args[0][0] == "/foo/bar"
assert log_has('Created data directory: /foo/bar', caplog.record_tuples) assert log_has('Created data directory: /foo/bar', caplog.record_tuples)
def test_validate_tsl(default_conf, mocker):
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.validate_ordertypes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.name', 'Bittrex')
default_conf['trailing_stop'] = True
default_conf['trailing_stop_positive'] = 0
default_conf['trailing_stop_positive_offset'] = 0
default_conf['trailing_only_offset_is_reached'] = False
Exchange(default_conf)
default_conf['trailing_only_offset_is_reached'] = True
with pytest.raises(OperationalException,
match=r'The config trailing_only_offset_is_reached need '
'trailing_stop_positive_offset to be more than 0 in your config.'):
Exchange(default_conf)
default_conf['trailing_stop_positive_offset'] = 0.01
default_conf['trailing_stop_positive'] = 0.015
with pytest.raises(OperationalException,
match=r'The config trailing_stop_positive_offset need '
'to be greater than trailing_stop_positive_offset in your config.'):
Exchange(default_conf)