mirror of
https://github.com/freqtrade/freqtrade.git
synced 2025-12-02 01:53:05 +00:00
Merge branch 'develop' into align_userdata
This commit is contained in:
@@ -9,12 +9,13 @@ from typing import Any, Callable, Dict, List, Optional
|
||||
|
||||
from freqtrade import OperationalException, constants
|
||||
from freqtrade.configuration.check_exchange import check_exchange
|
||||
from freqtrade.configuration.config_validation import (
|
||||
validate_config_consistency, validate_config_schema)
|
||||
from freqtrade.configuration.directory_operations import (create_datadir,
|
||||
create_userdata_dir)
|
||||
from freqtrade.configuration.json_schema import validate_config_schema
|
||||
from freqtrade.configuration.load_config import load_config_file
|
||||
from freqtrade.loggers import setup_logging
|
||||
from freqtrade.misc import deep_merge_dicts
|
||||
from freqtrade.misc import deep_merge_dicts, json_load
|
||||
from freqtrade.state import RunMode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -54,6 +55,9 @@ class Configuration(object):
|
||||
# Keep this method as staticmethod, so it can be used from interactive environments
|
||||
config: Dict[str, Any] = {}
|
||||
|
||||
if not files:
|
||||
return constants.MINIMAL_CONFIG.copy()
|
||||
|
||||
# We expect here a list of config filenames
|
||||
for path in files:
|
||||
logger.info(f'Using config: {path} ...')
|
||||
@@ -79,8 +83,6 @@ class Configuration(object):
|
||||
# Load all configs
|
||||
config: Dict[str, Any] = Configuration.from_files(self.args.config)
|
||||
|
||||
self._validate_config_consistency(config)
|
||||
|
||||
self._process_common_options(config)
|
||||
|
||||
self._process_optimize_options(config)
|
||||
@@ -89,6 +91,13 @@ class Configuration(object):
|
||||
|
||||
self._process_runmode(config)
|
||||
|
||||
# Check if the exchange set by the user is supported
|
||||
check_exchange(config, config.get('experimental', {}).get('block_bad_exchanges', True))
|
||||
|
||||
self._resolve_pairs_list(config)
|
||||
|
||||
validate_config_consistency(config)
|
||||
|
||||
return config
|
||||
|
||||
def _process_logging_options(self, config: Dict[str, Any]) -> None:
|
||||
@@ -146,9 +155,6 @@ class Configuration(object):
|
||||
if 'sd_notify' in self.args and self.args.sd_notify:
|
||||
config['internals'].update({'sd_notify': True})
|
||||
|
||||
# Check if the exchange set by the user is supported
|
||||
check_exchange(config, config.get('experimental', {}).get('block_bad_exchanges', True))
|
||||
|
||||
def _process_datadir_options(self, config: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Extract information for sys.argv and load directory configurations
|
||||
@@ -285,6 +291,19 @@ class Configuration(object):
|
||||
self._args_to_config(config, argname='trade_source',
|
||||
logstring='Using trades from: {}')
|
||||
|
||||
self._args_to_config(config, argname='erase',
|
||||
logstring='Erase detected. Deleting existing data.')
|
||||
|
||||
self._args_to_config(config, argname='timeframes',
|
||||
logstring='timeframes --timeframes: {}')
|
||||
|
||||
self._args_to_config(config, argname='days',
|
||||
logstring='Detected --days: {}')
|
||||
|
||||
if "exchange" in self.args and self.args.exchange:
|
||||
config['exchange']['name'] = self.args.exchange
|
||||
logger.info(f"Using exchange {config['exchange']['name']}")
|
||||
|
||||
def _process_runmode(self, config: Dict[str, Any]) -> None:
|
||||
|
||||
if not self.runmode:
|
||||
@@ -294,35 +313,6 @@ class Configuration(object):
|
||||
|
||||
config.update({'runmode': self.runmode})
|
||||
|
||||
def _validate_config_consistency(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 OperationalException
|
||||
"""
|
||||
# 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 needs '
|
||||
'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 needs '
|
||||
'to be greater than trailing_stop_positive_offset in your config.')
|
||||
|
||||
def _args_to_config(self, config: Dict[str, Any], argname: str,
|
||||
logstring: str, logfun: Optional[Callable] = None,
|
||||
deprecated_msg: Optional[str] = None) -> None:
|
||||
@@ -344,3 +334,39 @@ class Configuration(object):
|
||||
logger.info(logstring.format(config[argname]))
|
||||
if deprecated_msg:
|
||||
warnings.warn(f"DEPRECATED: {deprecated_msg}", DeprecationWarning)
|
||||
|
||||
def _resolve_pairs_list(self, config: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Helper for download script.
|
||||
Takes first found:
|
||||
* -p (pairs argument)
|
||||
* --pairs-file
|
||||
* whitelist from config
|
||||
"""
|
||||
|
||||
if "pairs" in config:
|
||||
return
|
||||
|
||||
if "pairs_file" in self.args and self.args.pairs_file:
|
||||
pairs_file = Path(self.args.pairs_file)
|
||||
logger.info(f'Reading pairs file "{pairs_file}".')
|
||||
# Download pairs from the pairs file if no config is specified
|
||||
# or if pairs file is specified explicitely
|
||||
if not pairs_file.exists():
|
||||
raise OperationalException(f'No pairs file found with path "{pairs_file}".')
|
||||
with pairs_file.open('r') as f:
|
||||
config['pairs'] = json_load(f)
|
||||
config['pairs'].sort()
|
||||
return
|
||||
|
||||
if "config" in self.args and self.args.config:
|
||||
logger.info("Using pairlist from configuration.")
|
||||
config['pairs'] = config.get('exchange', {}).get('pair_whitelist')
|
||||
else:
|
||||
# Fall back to /dl_path/pairs.json
|
||||
pairs_file = Path(config['datadir']) / config['exchange']['name'].lower() / "pairs.json"
|
||||
if pairs_file.exists():
|
||||
with pairs_file.open('r') as f:
|
||||
config['pairs'] = json_load(f)
|
||||
if 'pairs' in config:
|
||||
config['pairs'].sort()
|
||||
|
||||
Reference in New Issue
Block a user