Merge pull request #2118 from freqtrade/config_standalone

Config standalone loading
This commit is contained in:
Matthias 2019-08-12 06:47:52 +02:00 committed by GitHub
commit 615ce6aa69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 22 deletions

View File

@ -56,8 +56,8 @@ freqtrade -c path/far/far/away/config.json
The bot allows you to use multiple configuration files by specifying multiple
`-c/--config` configuration options in the command line. Configuration parameters
defined in the last configuration file override parameters with the same name
defined in the previous configuration file specified in the command line.
defined in latter configuration files override parameters with the same name
defined in the previous configuration files specified in the command line earlier.
For example, you can make a separate configuration file with your key and secrete
for the Exchange you use for trading, specify default configuration file with

View File

@ -31,6 +31,16 @@ df = load_trades_from_db("sqlite:///tradesv3.sqlite")
df.groupby("pair")["sell_reason"].value_counts()
```
### Load multiple configuration files
This option can be usefull to inspect the results of passing in multiple configs in case of problems
``` python
from freqtrade.configuration import Configuration
config = Configuration.from_files(["config1.json", "config2.json"])
print(config)
```
## Strategy debugging example
Debugging a strategy can be time-consuming. FreqTrade offers helper functions to visualize raw data.

View File

@ -4,7 +4,7 @@ This module contains the configuration class
import logging
import warnings
from argparse import Namespace
from typing import Any, Callable, Dict, Optional
from typing import Any, Callable, Dict, List, Optional
from freqtrade import OperationalException, constants
from freqtrade.configuration.check_exchange import check_exchange
@ -39,43 +39,43 @@ class Configuration(object):
return self.config
def _load_config_files(self) -> Dict[str, Any]:
@staticmethod
def from_files(files: List[str]) -> Dict[str, Any]:
"""
Iterate through the config files passed in the args,
loading all of them and merging their contents.
Iterate through the config files passed in, loading all of them
and merging their contents.
Files are loaded in sequence, parameters in later configuration files
override the same parameter from an earlier file (last definition wins).
:param files: List of file paths
:return: configuration dictionary
"""
# Keep this method as staticmethod, so it can be used from interactive environments
config: Dict[str, Any] = {}
# We expect here a list of config filenames
for path in self.args.config:
logger.info('Using config: %s ...', path)
for path in files:
logger.info(f'Using config: {path} ...')
# Merge config options, overwriting old values
config = deep_merge_dicts(load_config_file(path), config)
return config
def _normalize_config(self, config: Dict[str, Any]) -> None:
"""
Make config more canonical -- i.e. for example add missing parts that we expect
to be normally in it...
"""
# Normalize config
if 'internals' not in config:
config['internals'] = {}
# validate configuration before returning
logger.info('Validating configuration ...')
validate_config_schema(config)
return config
def load_config(self) -> Dict[str, Any]:
"""
Extract information for sys.argv and load the bot configuration
:return: Configuration dictionary
"""
# Load all configs
config: Dict[str, Any] = self._load_config_files()
# Make resulting config more canonical
self._normalize_config(config)
logger.info('Validating configuration ...')
validate_config_schema(config)
config: Dict[str, Any] = Configuration.from_files(self.args.config)
self._validate_config_consistency(config)

View File

@ -133,6 +133,35 @@ def test_load_config_combine_dicts(default_conf, mocker, caplog) -> None:
assert log_has('Validating configuration ...', caplog.record_tuples)
def test_from_config(default_conf, mocker, caplog) -> None:
conf1 = deepcopy(default_conf)
conf2 = deepcopy(default_conf)
del conf1['exchange']['key']
del conf1['exchange']['secret']
del conf2['exchange']['name']
conf2['exchange']['pair_whitelist'] += ['NANO/BTC']
conf2['fiat_display_currency'] = "EUR"
config_files = [conf1, conf2]
configsmock = MagicMock(side_effect=config_files)
mocker.patch(
'freqtrade.configuration.configuration.load_config_file',
configsmock
)
validated_conf = Configuration.from_files(['test_conf.json', 'test2_conf.json'])
exchange_conf = default_conf['exchange']
assert validated_conf['exchange']['name'] == exchange_conf['name']
assert validated_conf['exchange']['key'] == exchange_conf['key']
assert validated_conf['exchange']['secret'] == exchange_conf['secret']
assert validated_conf['exchange']['pair_whitelist'] != conf1['exchange']['pair_whitelist']
assert validated_conf['exchange']['pair_whitelist'] == conf2['exchange']['pair_whitelist']
assert validated_conf['fiat_display_currency'] == "EUR"
assert 'internals' in validated_conf
assert log_has('Validating configuration ...', caplog.record_tuples)
def test_load_config_max_open_trades_minus_one(default_conf, mocker, caplog) -> None:
default_conf['max_open_trades'] = -1
patched_configuration_load_config_file(mocker, default_conf)