have Arguments return a dict instead of Namespace

This commit is contained in:
Matthias 2019-09-12 20:16:39 +02:00
parent 52b186eabe
commit e6ccc1427c
6 changed files with 56 additions and 60 deletions

View File

@ -3,7 +3,6 @@ This module contains the configuration class
""" """
import logging import logging
import warnings import warnings
from argparse import Namespace
from copy import deepcopy from copy import deepcopy
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Dict, List, Optional from typing import Any, Callable, Dict, List, Optional
@ -28,7 +27,7 @@ class Configuration:
Reuse this class for the bot, backtesting, hyperopt and every script that required configuration Reuse this class for the bot, backtesting, hyperopt and every script that required configuration
""" """
def __init__(self, args: Namespace, runmode: RunMode = None) -> None: def __init__(self, args: Dict[str, Any], runmode: RunMode = None) -> None:
self.args = args self.args = args
self.config: Optional[Dict[str, Any]] = None self.config: Optional[Dict[str, Any]] = None
self.runmode = runmode self.runmode = runmode
@ -82,7 +81,7 @@ class Configuration:
:return: Configuration dictionary :return: Configuration dictionary
""" """
# Load all configs # Load all configs
config: Dict[str, Any] = Configuration.from_files(self.args.config) config: Dict[str, Any] = Configuration.from_files(self.args["config"])
self._process_common_options(config) self._process_common_options(config)
@ -107,13 +106,13 @@ class Configuration:
the -v/--verbose, --logfile options the -v/--verbose, --logfile options
""" """
# Log level # Log level
if 'verbosity' in self.args and self.args.verbosity: if 'verbosity' in self.args and self.args["verbosity"]:
config.update({'verbosity': self.args.verbosity}) config.update({'verbosity': self.args["verbosity"]})
else: else:
config.update({'verbosity': 0}) config.update({'verbosity': 0})
if 'logfile' in self.args and self.args.logfile: if 'logfile' in self.args and self.args["logfile"]:
config.update({'logfile': self.args.logfile}) config.update({'logfile': self.args["logfile"]})
setup_logging(config) setup_logging(config)
@ -122,15 +121,15 @@ class Configuration:
self._process_logging_options(config) self._process_logging_options(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
if self.args.strategy != constants.DEFAULT_STRATEGY or not config.get('strategy'): if self.args["strategy"] != constants.DEFAULT_STRATEGY or not config.get('strategy'):
config.update({'strategy': self.args.strategy}) config.update({'strategy': self.args["strategy"]})
self._args_to_config(config, argname='strategy_path', self._args_to_config(config, argname='strategy_path',
logstring='Using additional Strategy lookup path: {}') logstring='Using additional Strategy lookup path: {}')
if ('db_url' in self.args and self.args.db_url and if ('db_url' in self.args and self.args["db_url"] and
self.args.db_url != constants.DEFAULT_DB_PROD_URL): self.args["db_url"] != constants.DEFAULT_DB_PROD_URL):
config.update({'db_url': self.args.db_url}) config.update({'db_url': self.args["db_url"]})
logger.info('Parameter --db-url detected ...') logger.info('Parameter --db-url detected ...')
if config.get('dry_run', False): if config.get('dry_run', False):
@ -153,7 +152,7 @@ class Configuration:
config['max_open_trades'] = float('inf') config['max_open_trades'] = float('inf')
# Support for sd_notify # Support for sd_notify
if 'sd_notify' in self.args and self.args.sd_notify: if 'sd_notify' in self.args and self.args["sd_notify"]:
config['internals'].update({'sd_notify': True}) config['internals'].update({'sd_notify': True})
def _process_datadir_options(self, config: Dict[str, Any]) -> None: def _process_datadir_options(self, config: Dict[str, Any]) -> None:
@ -162,12 +161,12 @@ class Configuration:
--user-data, --datadir --user-data, --datadir
""" """
# Check exchange parameter here - otherwise `datadir` might be wrong. # Check exchange parameter here - otherwise `datadir` might be wrong.
if "exchange" in self.args and self.args.exchange: if "exchange" in self.args and self.args["exchange"]:
config['exchange']['name'] = self.args.exchange config['exchange']['name'] = self.args["exchange"]
logger.info(f"Using exchange {config['exchange']['name']}") logger.info(f"Using exchange {config['exchange']['name']}")
if 'user_data_dir' in self.args and self.args.user_data_dir: if 'user_data_dir' in self.args and self.args["user_data_dir"]:
config.update({'user_data_dir': self.args.user_data_dir}) config.update({'user_data_dir': self.args["user_data_dir"]})
elif 'user_data_dir' not in config: elif 'user_data_dir' not in config:
# Default to cwd/user_data (legacy option ...) # Default to cwd/user_data (legacy option ...)
config.update({'user_data_dir': str(Path.cwd() / "user_data")}) config.update({'user_data_dir': str(Path.cwd() / "user_data")})
@ -176,8 +175,8 @@ class Configuration:
config['user_data_dir'] = create_userdata_dir(config['user_data_dir'], create_dir=False) config['user_data_dir'] = create_userdata_dir(config['user_data_dir'], create_dir=False)
logger.info('Using user-data directory: %s ...', config['user_data_dir']) logger.info('Using user-data directory: %s ...', config['user_data_dir'])
if 'datadir' in self.args and self.args.datadir: if 'datadir' in self.args and self.args["datadir"]:
config.update({'datadir': create_datadir(config, self.args.datadir)}) config.update({'datadir': create_datadir(config, self.args["datadir"])})
else: else:
config.update({'datadir': create_datadir(config, None)}) config.update({'datadir': create_datadir(config, None)})
logger.info('Using data directory: %s ...', config.get('datadir')) logger.info('Using data directory: %s ...', config.get('datadir'))
@ -192,12 +191,12 @@ class Configuration:
self._args_to_config(config, argname='position_stacking', self._args_to_config(config, argname='position_stacking',
logstring='Parameter --enable-position-stacking detected ...') logstring='Parameter --enable-position-stacking detected ...')
if 'use_max_market_positions' in self.args and not self.args.use_max_market_positions: if 'use_max_market_positions' in self.args and not self.args["use_max_market_positions"]:
config.update({'use_max_market_positions': False}) config.update({'use_max_market_positions': False})
logger.info('Parameter --disable-max-market-positions detected ...') logger.info('Parameter --disable-max-market-positions detected ...')
logger.info('max_open_trades set to unlimited ...') logger.info('max_open_trades set to unlimited ...')
elif 'max_open_trades' in self.args and self.args.max_open_trades: elif 'max_open_trades' in self.args and self.args["max_open_trades"]:
config.update({'max_open_trades': self.args.max_open_trades}) config.update({'max_open_trades': self.args["max_open_trades"]})
logger.info('Parameter --max_open_trades detected, ' logger.info('Parameter --max_open_trades detected, '
'overriding max_open_trades to: %s ...', config.get('max_open_trades')) 'overriding max_open_trades to: %s ...', config.get('max_open_trades'))
else: else:
@ -229,12 +228,12 @@ class Configuration:
logstring='Storing backtest results to {} ...') logstring='Storing backtest results to {} ...')
# Edge section: # Edge section:
if 'stoploss_range' in self.args and self.args.stoploss_range: if 'stoploss_range' in self.args and self.args["stoploss_range"]:
txt_range = eval(self.args.stoploss_range) txt_range = eval(self.args["stoploss_range"])
config['edge'].update({'stoploss_range_min': txt_range[0]}) config['edge'].update({'stoploss_range_min': txt_range[0]})
config['edge'].update({'stoploss_range_max': txt_range[1]}) config['edge'].update({'stoploss_range_max': txt_range[1]})
config['edge'].update({'stoploss_range_step': txt_range[2]}) config['edge'].update({'stoploss_range_step': txt_range[2]})
logger.info('Parameter --stoplosses detected: %s ...', self.args.stoploss_range) logger.info('Parameter --stoplosses detected: %s ...', self.args["stoploss_range"])
# Hyperopt section # Hyperopt section
self._args_to_config(config, argname='hyperopt', self._args_to_config(config, argname='hyperopt',
@ -254,7 +253,7 @@ class Configuration:
self._args_to_config(config, argname='print_all', self._args_to_config(config, argname='print_all',
logstring='Parameter --print-all detected ...') logstring='Parameter --print-all detected ...')
if 'print_colorized' in self.args and not self.args.print_colorized: if 'print_colorized' in self.args and not self.args["print_colorized"]:
logger.info('Parameter --no-color detected ...') logger.info('Parameter --no-color detected ...')
config.update({'print_colorized': False}) config.update({'print_colorized': False})
else: else:
@ -324,9 +323,9 @@ class Configuration:
sample: logfun=len (prints the length of the found sample: logfun=len (prints the length of the found
configuration instead of the content) configuration instead of the content)
""" """
if argname in self.args and getattr(self.args, argname): if argname in self.args and self.args[argname]:
config.update({argname: getattr(self.args, argname)}) config.update({argname: self.args[argname]})
if logfun: if logfun:
logger.info(logstring.format(logfun(config[argname]))) logger.info(logstring.format(logfun(config[argname])))
else: else:
@ -346,8 +345,8 @@ class Configuration:
if "pairs" in config: if "pairs" in config:
return return
if "pairs_file" in self.args and self.args.pairs_file: if "pairs_file" in self.args and self.args["pairs_file"]:
pairs_file = Path(self.args.pairs_file) pairs_file = Path(self.args["pairs_file"])
logger.info(f'Reading pairs file "{pairs_file}".') logger.info(f'Reading pairs file "{pairs_file}".')
# Download pairs from the pairs file if no config is specified # Download pairs from the pairs file if no config is specified
# or if pairs file is specified explicitely # or if pairs file is specified explicitely
@ -358,7 +357,7 @@ class Configuration:
config['pairs'].sort() config['pairs'].sort()
return return
if "config" in self.args and self.args.config: if "config" in self.args and self.args["config"]:
logger.info("Using pairlist from configuration.") logger.info("Using pairlist from configuration.")
config['pairs'] = config.get('exchange', {}).get('pair_whitelist') config['pairs'] = config.get('exchange', {}).get('pair_whitelist')
else: else:

View File

@ -32,12 +32,12 @@ def main(sysargv: List[str] = None) -> None:
worker = None worker = None
try: try:
arguments = Arguments(sysargv) arguments = Arguments(sysargv)
args: Namespace = arguments.get_parsed_arg() args = arguments.get_parsed_arg()
# A subcommand has been issued. # A subcommand has been issued.
# Means if Backtesting or Hyperopt have been called we exit the bot # Means if Backtesting or Hyperopt have been called we exit the bot
if hasattr(args, 'func'): if 'func' in args:
args.func(args) args['func'](args)
# TODO: fetch return_code as returned by the command function here # TODO: fetch return_code as returned by the command function here
return_code = 0 return_code = 0
else: else:

View File

@ -1,5 +1,4 @@
import logging import logging
from argparse import Namespace
from typing import Any, Dict from typing import Any, Dict
from filelock import FileLock, Timeout from filelock import FileLock, Timeout
@ -12,7 +11,7 @@ from freqtrade.utils import setup_utils_configuration
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def setup_configuration(args: Namespace, method: RunMode) -> Dict[str, Any]: def setup_configuration(args: Dict[str, Any], method: RunMode) -> Dict[str, Any]:
""" """
Prepare the configuration for the Hyperopt module Prepare the configuration for the Hyperopt module
:param args: Cli args from Arguments() :param args: Cli args from Arguments()
@ -28,7 +27,7 @@ def setup_configuration(args: Namespace, method: RunMode) -> Dict[str, Any]:
return config return config
def start_backtesting(args: Namespace) -> None: def start_backtesting(args: Dict[str, Any]) -> None:
""" """
Start Backtesting script Start Backtesting script
:param args: Cli args from Arguments() :param args: Cli args from Arguments()
@ -47,7 +46,7 @@ def start_backtesting(args: Namespace) -> None:
backtesting.start() backtesting.start()
def start_hyperopt(args: Namespace) -> None: def start_hyperopt(args: Dict[str, Any]) -> None:
""" """
Start hyperopt script Start hyperopt script
:param args: Cli args from Arguments() :param args: Cli args from Arguments()
@ -85,7 +84,7 @@ def start_hyperopt(args: Namespace) -> None:
# Same in Edge and Backtesting start() functions. # Same in Edge and Backtesting start() functions.
def start_edge(args: Namespace) -> None: def start_edge(args: Dict[str, Any]) -> None:
""" """
Start Edge script Start Edge script
:param args: Cli args from Arguments() :param args: Cli args from Arguments()

View File

@ -1,18 +1,18 @@
from argparse import Namespace from typing import Any, Dict
from freqtrade import OperationalException from freqtrade import OperationalException
from freqtrade.state import RunMode from freqtrade.state import RunMode
from freqtrade.utils import setup_utils_configuration from freqtrade.utils import setup_utils_configuration
def validate_plot_args(args: Namespace): def validate_plot_args(args: Dict[str, Any]):
args_tmp = vars(args) if not args.get('datadir') and not args.get('config'):
if not args_tmp.get('datadir') and not args_tmp.get('config'):
raise OperationalException( raise OperationalException(
"You need to specify either `--datadir` or `--config` " "You need to specify either `--datadir` or `--config` "
"for plot-profit and plot-dataframe.") "for plot-profit and plot-dataframe.")
def start_plot_dataframe(args: Namespace) -> None: def start_plot_dataframe(args: Dict[str, Any]) -> None:
""" """
Entrypoint for dataframe plotting Entrypoint for dataframe plotting
""" """
@ -24,7 +24,7 @@ def start_plot_dataframe(args: Namespace) -> None:
load_and_plot_trades(config) load_and_plot_trades(config)
def start_plot_profit(args: Namespace) -> None: def start_plot_profit(args: Dict[str, Any]) -> None:
""" """
Entrypoint for plot_profit Entrypoint for plot_profit
""" """

View File

@ -1,6 +1,5 @@
import logging import logging
import sys import sys
from argparse import Namespace
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List from typing import Any, Dict, List
@ -16,7 +15,7 @@ from freqtrade.state import RunMode
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def setup_utils_configuration(args: Namespace, method: RunMode) -> Dict[str, Any]: def setup_utils_configuration(args: Dict[str, Any], method: RunMode) -> Dict[str, Any]:
""" """
Prepare the configuration for utils subcommands Prepare the configuration for utils subcommands
:param args: Cli args from Arguments() :param args: Cli args from Arguments()
@ -33,34 +32,34 @@ def setup_utils_configuration(args: Namespace, method: RunMode) -> Dict[str, Any
return config return config
def start_list_exchanges(args: Namespace) -> None: def start_list_exchanges(args: Dict[str, Any]) -> None:
""" """
Print available exchanges Print available exchanges
:param args: Cli args from Arguments() :param args: Cli args from Arguments()
:return: None :return: None
""" """
if args.print_one_column: if args['print_one_column']:
print('\n'.join(available_exchanges())) print('\n'.join(available_exchanges()))
else: else:
print(f"Exchanges supported by ccxt and available for Freqtrade: " print(f"Exchanges supported by ccxt and available for Freqtrade: "
f"{', '.join(available_exchanges())}") f"{', '.join(available_exchanges())}")
def start_create_userdir(args: Namespace) -> None: def start_create_userdir(args: Dict[str, Any]) -> None:
""" """
Create "user_data" directory to contain user data strategies, hyperopts, ...) Create "user_data" directory to contain user data strategies, hyperopts, ...)
:param args: Cli args from Arguments() :param args: Cli args from Arguments()
:return: None :return: None
""" """
if "user_data_dir" in args and args.user_data_dir: if "user_data_dir" in args and args["user_data_dir"]:
create_userdata_dir(args.user_data_dir, create_dir=True) create_userdata_dir(args["user_data_dir"], create_dir=True)
else: else:
logger.warning("`create-userdir` requires --userdir to be set.") logger.warning("`create-userdir` requires --userdir to be set.")
sys.exit(1) sys.exit(1)
def start_download_data(args: Namespace) -> None: def start_download_data(args: Dict[str, Any]) -> None:
""" """
Download data (former download_backtest_data.py script) Download data (former download_backtest_data.py script)
""" """

View File

@ -4,17 +4,16 @@ Main Freqtrade worker class.
import logging import logging
import time import time
import traceback import traceback
from argparse import Namespace from typing import Any, Callable, Dict, Optional
from typing import Any, Callable, Optional
import sdnotify import sdnotify
from freqtrade import (constants, OperationalException, TemporaryError, from freqtrade import (OperationalException, TemporaryError, __version__,
__version__) constants)
from freqtrade.configuration import Configuration from freqtrade.configuration import Configuration
from freqtrade.freqtradebot import FreqtradeBot from freqtrade.freqtradebot import FreqtradeBot
from freqtrade.state import State
from freqtrade.rpc import RPCMessageType from freqtrade.rpc import RPCMessageType
from freqtrade.state import State
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -24,7 +23,7 @@ class Worker:
Freqtradebot worker class Freqtradebot worker class
""" """
def __init__(self, args: Namespace, config=None) -> None: def __init__(self, args: Dict[str, Any], config=None) -> None:
""" """
Init all variables and objects the bot needs to work Init all variables and objects the bot needs to work
""" """