config validation moved to configuration file
This commit is contained in:
parent
3c99e3b7c7
commit
29305dd070
@ -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
|
||||||
|
@ -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))
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user