diff --git a/freqtrade/configuration/__init__.py b/freqtrade/configuration/__init__.py new file mode 100644 index 000000000..548b508a7 --- /dev/null +++ b/freqtrade/configuration/__init__.py @@ -0,0 +1,2 @@ +from freqtrade.configuration.arguments import Arguments, TimeRange # noqa: F401 +from freqtrade.configuration.configuration import Configuration # noqa: F401 diff --git a/freqtrade/arguments.py b/freqtrade/configuration/arguments.py similarity index 99% rename from freqtrade/arguments.py rename to freqtrade/configuration/arguments.py index cb45bcdf5..3e940ae2a 100644 --- a/freqtrade/arguments.py +++ b/freqtrade/configuration/arguments.py @@ -5,6 +5,7 @@ import argparse import os import re from typing import List, NamedTuple, Optional + import arrow from freqtrade import __version__, constants diff --git a/freqtrade/configuration/check_exchange.py b/freqtrade/configuration/check_exchange.py new file mode 100644 index 000000000..8dae06f7a --- /dev/null +++ b/freqtrade/configuration/check_exchange.py @@ -0,0 +1,48 @@ +import logging +from typing import Any, Dict + +from freqtrade import OperationalException +from freqtrade.exchange import (is_exchange_bad, is_exchange_available, + is_exchange_officially_supported, available_exchanges) + + +logger = logging.getLogger(__name__) + + +def check_exchange(config: Dict[str, Any], check_for_bad: bool = True) -> bool: + """ + Check if the exchange name in the config file is supported by Freqtrade + :param check_for_bad: if True, check the exchange against the list of known 'bad' + exchanges + :return: False if exchange is 'bad', i.e. is known to work with the bot with + critical issues or does not work at all, crashes, etc. True otherwise. + raises an exception if the exchange if not supported by ccxt + and thus is not known for the Freqtrade at all. + """ + logger.info("Checking exchange...") + + exchange = config.get('exchange', {}).get('name').lower() + if not is_exchange_available(exchange): + raise OperationalException( + f'Exchange "{exchange}" is not supported by ccxt ' + f'and therefore not available for the bot.\n' + f'The following exchanges are supported by ccxt: ' + f'{", ".join(available_exchanges())}' + ) + + if check_for_bad and is_exchange_bad(exchange): + logger.warning(f'Exchange "{exchange}" is known to not work with the bot yet. ' + f'Use it only for development and testing purposes.') + return False + + if is_exchange_officially_supported(exchange): + logger.info(f'Exchange "{exchange}" is officially supported ' + f'by the Freqtrade development team.') + else: + logger.warning(f'Exchange "{exchange}" is supported by ccxt ' + f'and therefore available for the bot but not officially supported ' + f'by the Freqtrade development team. ' + f'It may work flawlessly (please report back) or have serious issues. ' + f'Use it at your own discretion.') + + return True diff --git a/freqtrade/configuration.py b/freqtrade/configuration/configuration.py similarity index 75% rename from freqtrade/configuration.py rename to freqtrade/configuration/configuration.py index 8ad0fffe9..4959c2adc 100644 --- a/freqtrade/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -3,17 +3,14 @@ This module contains the configuration class """ import json import logging -import os import sys from argparse import Namespace from typing import Any, Callable, Dict, Optional -from jsonschema import Draft4Validator, validators -from jsonschema.exceptions import ValidationError, best_match - from freqtrade import OperationalException, constants -from freqtrade.exchange import (is_exchange_bad, is_exchange_available, - is_exchange_officially_supported, available_exchanges) +from freqtrade.configuration.check_exchange import check_exchange +from freqtrade.configuration.create_datadir import create_datadir +from freqtrade.configuration.json_schema import validate_config_schema from freqtrade.loggers import setup_logging from freqtrade.misc import deep_merge_dicts from freqtrade.state import RunMode @@ -22,31 +19,6 @@ from freqtrade.state import RunMode logger = logging.getLogger(__name__) -def _extend_validator(validator_class): - """ - Extended validator for the Freqtrade configuration JSON Schema. - Currently it only handles defaults for subschemas. - """ - validate_properties = validator_class.VALIDATORS['properties'] - - def set_defaults(validator, properties, instance, schema): - for prop, subschema in properties.items(): - if 'default' in subschema: - instance.setdefault(prop, subschema['default']) - - for error in validate_properties( - validator, properties, instance, schema, - ): - yield error - - return validators.extend( - validator_class, {'properties': set_defaults} - ) - - -FreqtradeValidator = _extend_validator(Draft4Validator) - - class Configuration(object): """ Class to read and init the bot configuration @@ -58,6 +30,16 @@ class Configuration(object): self.config: Optional[Dict[str, Any]] = None self.runmode = runmode + def get_config(self) -> Dict[str, Any]: + """ + Return the config. Use this method to get the bot config + :return: Dict: Bot config + """ + if self.config is None: + self.config = self.load_config() + + return self.config + def load_config(self) -> Dict[str, Any]: """ Extract information for sys.argv and load the bot configuration @@ -75,7 +57,7 @@ class Configuration(object): config['internals'] = {} logger.info('Validating configuration ...') - self._validate_config_schema(config) + validate_config_schema(config) self._validate_config_consistency(config) # Set strategy if not specified in config and or if it's non default @@ -185,21 +167,10 @@ class Configuration(object): logger.info(f'Using DB: "{config["db_url"]}"') # Check if the exchange set by the user is supported - self.check_exchange(config) + check_exchange(config) return config - def _create_datadir(self, config: Dict[str, Any], datadir: Optional[str] = None) -> str: - if not datadir: - # set datadir - exchange_name = config.get('exchange', {}).get('name').lower() - datadir = os.path.join('user_data', 'data', exchange_name) - - if not os.path.isdir(datadir): - os.makedirs(datadir) - logger.info(f'Created data directory: {datadir}') - return datadir - def _args_to_config(self, config: Dict[str, Any], argname: str, logstring: str, logfun: Optional[Callable] = None) -> None: """ @@ -225,9 +196,9 @@ class Configuration(object): the --datadir option """ if 'datadir' in self.args and self.args.datadir: - config.update({'datadir': self._create_datadir(config, self.args.datadir)}) + config.update({'datadir': create_datadir(config, self.args.datadir)}) else: - config.update({'datadir': self._create_datadir(config, None)}) + config.update({'datadir': create_datadir(config, None)}) logger.info('Using data directory: %s ...', config.get('datadir')) def _load_optimize_config(self, config: Dict[str, Any]) -> Dict[str, Any]: @@ -337,24 +308,6 @@ class Configuration(object): logstring='Using trades from: {}') return config - def _validate_config_schema(self, conf: Dict[str, Any]) -> Dict[str, Any]: - """ - Validate the configuration follow the Config Schema - :param conf: Config in JSON format - :return: Returns the config if valid, otherwise throw an exception - """ - try: - FreqtradeValidator(constants.CONF_SCHEMA).validate(conf) - return conf - except ValidationError as exception: - logger.critical( - 'Invalid configuration. See config.json.example. Reason: %s', - exception - ) - raise ValidationError( - best_match(Draft4Validator(constants.CONF_SCHEMA).iter_errors(conf)).message - ) - def _validate_config_consistency(self, conf: Dict[str, Any]) -> None: """ Validate the configuration consistency @@ -383,51 +336,3 @@ class Configuration(object): raise OperationalException( f'The config trailing_stop_positive_offset needs ' 'to be greater than trailing_stop_positive_offset in your config.') - - def get_config(self) -> Dict[str, Any]: - """ - Return the config. Use this method to get the bot config - :return: Dict: Bot config - """ - if self.config is None: - self.config = self.load_config() - - return self.config - - def check_exchange(self, config: Dict[str, Any], check_for_bad: bool = True) -> bool: - """ - Check if the exchange name in the config file is supported by Freqtrade - :param check_for_bad: if True, check the exchange against the list of known 'bad' - exchanges - :return: False if exchange is 'bad', i.e. is known to work with the bot with - critical issues or does not work at all, crashes, etc. True otherwise. - raises an exception if the exchange if not supported by ccxt - and thus is not known for the Freqtrade at all. - """ - logger.info("Checking exchange...") - - exchange = config.get('exchange', {}).get('name').lower() - if not is_exchange_available(exchange): - raise OperationalException( - f'Exchange "{exchange}" is not supported by ccxt ' - f'and therefore not available for the bot.\n' - f'The following exchanges are supported by ccxt: ' - f'{", ".join(available_exchanges())}' - ) - - if check_for_bad and is_exchange_bad(exchange): - logger.warning(f'Exchange "{exchange}" is known to not work with the bot yet. ' - f'Use it only for development and testing purposes.') - return False - - if is_exchange_officially_supported(exchange): - logger.info(f'Exchange "{exchange}" is officially supported ' - f'by the Freqtrade development team.') - else: - logger.warning(f'Exchange "{exchange}" is supported by ccxt ' - f'and therefore available for the bot but not officially supported ' - f'by the Freqtrade development team. ' - f'It may work flawlessly (please report back) or have serious issues. ' - f'Use it at your own discretion.') - - return True diff --git a/freqtrade/configuration/create_datadir.py b/freqtrade/configuration/create_datadir.py new file mode 100644 index 000000000..ecb59bc84 --- /dev/null +++ b/freqtrade/configuration/create_datadir.py @@ -0,0 +1,18 @@ +import logging +import os +from typing import Any, Dict, Optional + + +logger = logging.getLogger(__name__) + + +def create_datadir(config: Dict[str, Any], datadir: Optional[str] = None) -> str: + if not datadir: + # set datadir + exchange_name = config.get('exchange', {}).get('name').lower() + datadir = os.path.join('user_data', 'data', exchange_name) + + if not os.path.isdir(datadir): + os.makedirs(datadir) + logger.info(f'Created data directory: {datadir}') + return datadir diff --git a/freqtrade/configuration/json_schema.py b/freqtrade/configuration/json_schema.py new file mode 100644 index 000000000..4c6f4a4a0 --- /dev/null +++ b/freqtrade/configuration/json_schema.py @@ -0,0 +1,53 @@ +import logging +from typing import Any, Dict + +from jsonschema import Draft4Validator, validators +from jsonschema.exceptions import ValidationError, best_match + +from freqtrade import constants + + +logger = logging.getLogger(__name__) + + +def _extend_validator(validator_class): + """ + Extended validator for the Freqtrade configuration JSON Schema. + Currently it only handles defaults for subschemas. + """ + validate_properties = validator_class.VALIDATORS['properties'] + + def set_defaults(validator, properties, instance, schema): + for prop, subschema in properties.items(): + if 'default' in subschema: + instance.setdefault(prop, subschema['default']) + + for error in validate_properties( + validator, properties, instance, schema, + ): + yield error + + return validators.extend( + validator_class, {'properties': set_defaults} + ) + + +FreqtradeValidator = _extend_validator(Draft4Validator) + + +def validate_config_schema(conf: Dict[str, Any]) -> Dict[str, Any]: + """ + Validate the configuration follow the Config Schema + :param conf: Config in JSON format + :return: Returns the config if valid, otherwise throw an exception + """ + try: + FreqtradeValidator(constants.CONF_SCHEMA).validate(conf) + return conf + except ValidationError as e: + logger.critical( + f"Invalid configuration. See config.json.example. Reason: {e}" + ) + raise ValidationError( + best_match(Draft4Validator(constants.CONF_SCHEMA).iter_errors(conf)).message + ) diff --git a/freqtrade/data/history.py b/freqtrade/data/history.py index 2a0d9b15e..f600615df 100644 --- a/freqtrade/data/history.py +++ b/freqtrade/data/history.py @@ -16,7 +16,7 @@ import arrow from pandas import DataFrame from freqtrade import OperationalException, misc -from freqtrade.arguments import TimeRange +from freqtrade.configuration import TimeRange from freqtrade.data.converter import parse_ticker_dataframe from freqtrade.exchange import Exchange, timeframe_to_minutes diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index 4bc8bb493..7085663d6 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -10,8 +10,7 @@ import utils_find_1st as utf1st from pandas import DataFrame from freqtrade import constants, OperationalException -from freqtrade.arguments import Arguments -from freqtrade.arguments import TimeRange +from freqtrade.configuration import Arguments, TimeRange from freqtrade.data import history from freqtrade.strategy.interface import SellType diff --git a/freqtrade/main.py b/freqtrade/main.py index f02159a0e..a96fd43c5 100755 --- a/freqtrade/main.py +++ b/freqtrade/main.py @@ -15,7 +15,7 @@ from argparse import Namespace from typing import Any, List from freqtrade import OperationalException -from freqtrade.arguments import Arguments +from freqtrade.configuration import Arguments from freqtrade.worker import Worker diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 9abc68fec..429633f31 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -12,7 +12,7 @@ from typing import Any, Dict, List, NamedTuple, Optional from pandas import DataFrame from tabulate import tabulate -from freqtrade.arguments import Arguments +from freqtrade.configuration import Arguments from freqtrade.data import history from freqtrade.data.dataprovider import DataProvider from freqtrade.exchange import timeframe_to_minutes diff --git a/freqtrade/optimize/edge_cli.py b/freqtrade/optimize/edge_cli.py index 231493e4d..8d1fa381b 100644 --- a/freqtrade/optimize/edge_cli.py +++ b/freqtrade/optimize/edge_cli.py @@ -9,7 +9,7 @@ from tabulate import tabulate from freqtrade import constants from freqtrade.edge import Edge -from freqtrade.arguments import Arguments +from freqtrade.configuration import Arguments from freqtrade.exchange import Exchange from freqtrade.resolvers import StrategyResolver diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 4167dc619..e3683a66c 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -18,7 +18,7 @@ from pandas import DataFrame from skopt import Optimizer from skopt.space import Dimension -from freqtrade.arguments import Arguments +from freqtrade.configuration import Arguments from freqtrade.data.history import load_data, get_timeframe from freqtrade.optimize.backtesting import Backtesting from freqtrade.resolvers.hyperopt_resolver import HyperOptResolver diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index 7904d42c9..dde6f78f0 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -4,7 +4,7 @@ from typing import Dict, List, Optional import pandas as pd -from freqtrade.arguments import Arguments +from freqtrade.configuration import Arguments from freqtrade.data import history from freqtrade.data.btanalysis import (combine_tickers_with_mean, create_cum_profit, load_trades) diff --git a/freqtrade/tests/conftest.py b/freqtrade/tests/conftest.py index 888135fa1..5862a2e89 100644 --- a/freqtrade/tests/conftest.py +++ b/freqtrade/tests/conftest.py @@ -6,7 +6,6 @@ from copy import deepcopy from datetime import datetime from functools import reduce from pathlib import Path -from typing import List from unittest.mock import MagicMock, PropertyMock import arrow @@ -14,7 +13,7 @@ import pytest from telegram import Chat, Message, Update from freqtrade import constants, persistence -from freqtrade.arguments import Arguments +from freqtrade.configuration import Arguments from freqtrade.data.converter import parse_ticker_dataframe from freqtrade.edge import Edge, PairInfo from freqtrade.exchange import Exchange @@ -22,6 +21,7 @@ from freqtrade.freqtradebot import FreqtradeBot from freqtrade.resolvers import ExchangeResolver from freqtrade.worker import Worker + logging.getLogger('').setLevel(logging.INFO) @@ -39,10 +39,17 @@ def log_has_re(line, logs): False) -def get_args(args) -> List[str]: +def get_args(args): return Arguments(args, '').get_parsed_arg() +def patched_configuration_load_config_file(mocker, config) -> None: + mocker.patch( + 'freqtrade.configuration.configuration.Configuration._load_config_file', + lambda *args, **kwargs: config + ) + + def patch_exchange(mocker, api_mock=None, id='bittrex') -> None: mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={})) mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock()) diff --git a/freqtrade/tests/data/test_btanalysis.py b/freqtrade/tests/data/test_btanalysis.py index e8872f9a4..e80840009 100644 --- a/freqtrade/tests/data/test_btanalysis.py +++ b/freqtrade/tests/data/test_btanalysis.py @@ -4,7 +4,7 @@ import pytest from arrow import Arrow from pandas import DataFrame, to_datetime -from freqtrade.arguments import Arguments, TimeRange +from freqtrade.configuration import Arguments, TimeRange from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, combine_tickers_with_mean, create_cum_profit, diff --git a/freqtrade/tests/data/test_history.py b/freqtrade/tests/data/test_history.py index 46bcf06c4..424333e99 100644 --- a/freqtrade/tests/data/test_history.py +++ b/freqtrade/tests/data/test_history.py @@ -12,7 +12,7 @@ import pytest from pandas import DataFrame from freqtrade import OperationalException -from freqtrade.arguments import TimeRange +from freqtrade.configuration import TimeRange from freqtrade.data import history from freqtrade.data.history import (download_pair_history, load_cached_data_for_updating, diff --git a/freqtrade/tests/optimize/test_backtesting.py b/freqtrade/tests/optimize/test_backtesting.py index 498a04db5..9304871a8 100644 --- a/freqtrade/tests/optimize/test_backtesting.py +++ b/freqtrade/tests/optimize/test_backtesting.py @@ -1,6 +1,5 @@ # pragma pylint: disable=missing-docstring, W0212, line-too-long, C0103, unused-argument -import json import math import random from unittest.mock import MagicMock @@ -11,7 +10,7 @@ import pytest from arrow import Arrow from freqtrade import DependencyException, constants -from freqtrade.arguments import TimeRange +from freqtrade.configuration import TimeRange from freqtrade.data import history from freqtrade.data.btanalysis import evaluate_result_multi from freqtrade.data.converter import parse_ticker_dataframe @@ -22,7 +21,8 @@ from freqtrade.optimize.backtesting import Backtesting from freqtrade.state import RunMode from freqtrade.strategy.default_strategy import DefaultStrategy from freqtrade.strategy.interface import SellType -from freqtrade.tests.conftest import get_args, log_has, log_has_re, patch_exchange +from freqtrade.tests.conftest import (get_args, log_has, log_has_re, patch_exchange, + patched_configuration_load_config_file) def trim_dictlist(dict_list, num): @@ -165,9 +165,7 @@ def _trend_alternate(dataframe=None, metadata=None): # Unit tests def test_setup_configuration_without_arguments(mocker, default_conf, caplog) -> None: - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) args = [ '--config', 'config.json', @@ -205,10 +203,11 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) -> def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) -> None: - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) - mocker.patch('freqtrade.configuration.Configuration._create_datadir', lambda s, c, x: x) + patched_configuration_load_config_file(mocker, default_conf) + mocker.patch( + 'freqtrade.configuration.configuration.create_datadir', + lambda c, x: x + ) args = [ '--config', 'config.json', @@ -276,9 +275,7 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) -> def test_setup_configuration_unlimited_stake_amount(mocker, default_conf, caplog) -> None: default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) args = [ '--config', 'config.json', @@ -295,9 +292,8 @@ def test_start(mocker, fee, default_conf, caplog) -> None: mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) patch_exchange(mocker) mocker.patch('freqtrade.optimize.backtesting.Backtesting.start', start_mock) - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) + args = [ '--config', 'config.json', '--strategy', 'DefaultStrategy', @@ -828,9 +824,7 @@ def test_backtest_start_live(default_conf, mocker, caplog): patch_exchange(mocker, api_mock) mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting._generate_text_table', MagicMock()) - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) args = [ '--config', 'config.json', @@ -880,9 +874,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog): gen_strattable_mock = MagicMock() mocker.patch('freqtrade.optimize.backtesting.Backtesting._generate_text_table_strategy', gen_strattable_mock) - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) args = [ '--config', 'config.json', diff --git a/freqtrade/tests/optimize/test_edge_cli.py b/freqtrade/tests/optimize/test_edge_cli.py index 7cc41b095..badaa5c45 100644 --- a/freqtrade/tests/optimize/test_edge_cli.py +++ b/freqtrade/tests/optimize/test_edge_cli.py @@ -1,20 +1,18 @@ # pragma pylint: disable=missing-docstring, C0103, C0330 # pragma pylint: disable=protected-access, too-many-lines, invalid-name, too-many-arguments -import json from unittest.mock import MagicMock from freqtrade.edge import PairInfo from freqtrade.optimize import setup_configuration, start_edge from freqtrade.optimize.edge_cli import EdgeCli from freqtrade.state import RunMode -from freqtrade.tests.conftest import get_args, log_has, log_has_re, patch_exchange +from freqtrade.tests.conftest import (get_args, log_has, log_has_re, patch_exchange, + patched_configuration_load_config_file) def test_setup_configuration_without_arguments(mocker, default_conf, caplog) -> None: - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) args = [ '--config', 'config.json', @@ -46,10 +44,11 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) -> def test_setup_edge_configuration_with_arguments(mocker, edge_conf, caplog) -> None: - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(edge_conf) - )) - mocker.patch('freqtrade.configuration.Configuration._create_datadir', lambda s, c, x: x) + patched_configuration_load_config_file(mocker, edge_conf) + mocker.patch( + 'freqtrade.configuration.configuration.create_datadir', + lambda c, x: x + ) args = [ '--config', 'config.json', @@ -92,9 +91,8 @@ def test_start(mocker, fee, edge_conf, caplog) -> None: mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) patch_exchange(mocker) mocker.patch('freqtrade.optimize.edge_cli.EdgeCli.start', start_mock) - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(edge_conf) - )) + patched_configuration_load_config_file(mocker, edge_conf) + args = [ '--config', 'config.json', '--strategy', 'DefaultStrategy', diff --git a/freqtrade/tests/optimize/test_hyperopt.py b/freqtrade/tests/optimize/test_hyperopt.py index e5f87b022..e8b4aa78d 100644 --- a/freqtrade/tests/optimize/test_hyperopt.py +++ b/freqtrade/tests/optimize/test_hyperopt.py @@ -1,5 +1,4 @@ # pragma pylint: disable=missing-docstring,W0212,C0103 -import json import os from datetime import datetime from unittest.mock import MagicMock @@ -16,7 +15,8 @@ from freqtrade.optimize.hyperopt import Hyperopt, HYPEROPT_LOCKFILE from freqtrade.optimize import setup_configuration, start_hyperopt from freqtrade.resolvers.hyperopt_resolver import HyperOptResolver from freqtrade.state import RunMode -from freqtrade.tests.conftest import get_args, log_has, log_has_re, patch_exchange +from freqtrade.tests.conftest import (get_args, log_has, log_has_re, patch_exchange, + patched_configuration_load_config_file) @pytest.fixture(scope='function') @@ -44,9 +44,7 @@ def create_trials(mocker, hyperopt) -> None: def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, caplog) -> None: - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) args = [ '--config', 'config.json', @@ -82,10 +80,11 @@ def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, ca def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplog) -> None: - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) - mocker.patch('freqtrade.configuration.Configuration._create_datadir', lambda s, c, x: x) + patched_configuration_load_config_file(mocker, default_conf) + mocker.patch( + 'freqtrade.configuration.configuration.create_datadir', + lambda c, x: x + ) args = [ '--config', 'config.json', @@ -148,11 +147,8 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo def test_hyperoptresolver(mocker, default_conf, caplog) -> None: + patched_configuration_load_config_file(mocker, default_conf) - mocker.patch( - 'freqtrade.configuration.Configuration._load_config_file', - lambda *args, **kwargs: default_conf - ) hyperopts = DefaultHyperOpts delattr(hyperopts, 'populate_buy_trend') delattr(hyperopts, 'populate_sell_trend') @@ -172,10 +168,7 @@ def test_hyperoptresolver(mocker, default_conf, caplog) -> None: def test_start(mocker, default_conf, caplog) -> None: start_mock = MagicMock() - mocker.patch( - 'freqtrade.configuration.Configuration._load_config_file', - lambda *args, **kwargs: default_conf - ) + patched_configuration_load_config_file(mocker, default_conf) mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock) patch_exchange(mocker) @@ -198,10 +191,7 @@ def test_start(mocker, default_conf, caplog) -> None: def test_start_no_data(mocker, default_conf, caplog) -> None: - mocker.patch( - 'freqtrade.configuration.Configuration._load_config_file', - lambda *args, **kwargs: default_conf - ) + patched_configuration_load_config_file(mocker, default_conf) mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock(return_value={})) mocker.patch( 'freqtrade.optimize.hyperopt.get_timeframe', @@ -226,10 +216,7 @@ def test_start_no_data(mocker, default_conf, caplog) -> None: def test_start_failure(mocker, default_conf, caplog) -> None: start_mock = MagicMock() - mocker.patch( - 'freqtrade.configuration.Configuration._load_config_file', - lambda *args, **kwargs: default_conf - ) + patched_configuration_load_config_file(mocker, default_conf) mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock) patch_exchange(mocker) @@ -250,10 +237,7 @@ def test_start_failure(mocker, default_conf, caplog) -> None: def test_start_filelock(mocker, default_conf, caplog) -> None: start_mock = MagicMock(side_effect=Timeout(HYPEROPT_LOCKFILE)) - mocker.patch( - 'freqtrade.configuration.Configuration._load_config_file', - lambda *args, **kwargs: default_conf - ) + patched_configuration_load_config_file(mocker, default_conf) mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock) patch_exchange(mocker) diff --git a/freqtrade/tests/strategy/test_interface.py b/freqtrade/tests/strategy/test_interface.py index e92cb7b1c..ee8c8ddd4 100644 --- a/freqtrade/tests/strategy/test_interface.py +++ b/freqtrade/tests/strategy/test_interface.py @@ -6,7 +6,7 @@ from unittest.mock import MagicMock import arrow from pandas import DataFrame -from freqtrade.arguments import TimeRange +from freqtrade.configuration import TimeRange from freqtrade.data.converter import parse_ticker_dataframe from freqtrade.data.history import load_tickerdata_file from freqtrade.persistence import Trade diff --git a/freqtrade/tests/test_arguments.py b/freqtrade/tests/test_arguments.py index 8186892aa..9de960da3 100644 --- a/freqtrade/tests/test_arguments.py +++ b/freqtrade/tests/test_arguments.py @@ -3,8 +3,9 @@ import argparse import pytest -from freqtrade.arguments import (ARGS_DOWNLOADER, ARGS_PLOT_DATAFRAME, - Arguments, TimeRange, check_int_positive) +from freqtrade.configuration import Arguments, TimeRange +from freqtrade.configuration.arguments import ARGS_DOWNLOADER, ARGS_PLOT_DATAFRAME +from freqtrade.configuration.arguments import check_int_positive # Parse common command-line-arguments. Used for all tools diff --git a/freqtrade/tests/test_configuration.py b/freqtrade/tests/test_configuration.py index c5e60be7f..4f3f4934d 100644 --- a/freqtrade/tests/test_configuration.py +++ b/freqtrade/tests/test_configuration.py @@ -1,5 +1,4 @@ # pragma pylint: disable=missing-docstring, protected-access, invalid-name - import json import logging from argparse import Namespace @@ -11,12 +10,15 @@ import pytest from jsonschema import Draft4Validator, ValidationError, validate from freqtrade import OperationalException, constants -from freqtrade.arguments import Arguments -from freqtrade.configuration import Configuration +from freqtrade.configuration import Arguments, Configuration +from freqtrade.configuration.check_exchange import check_exchange +from freqtrade.configuration.create_datadir import create_datadir +from freqtrade.configuration.json_schema import validate_config_schema from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL from freqtrade.loggers import _set_loggers from freqtrade.state import RunMode -from freqtrade.tests.conftest import log_has, log_has_re +from freqtrade.tests.conftest import (log_has, log_has_re, + patched_configuration_load_config_file) @pytest.fixture(scope="function") @@ -32,28 +34,25 @@ def test_load_config_invalid_pair(default_conf) -> None: default_conf['exchange']['pair_whitelist'].append('ETH-BTC') with pytest.raises(ValidationError, match=r'.*does not match.*'): - configuration = Configuration(Namespace()) - configuration._validate_config_schema(default_conf) + validate_config_schema(default_conf) def test_load_config_missing_attributes(default_conf) -> None: default_conf.pop('exchange') with pytest.raises(ValidationError, match=r'.*\'exchange\' is a required property.*'): - configuration = Configuration(Namespace()) - configuration._validate_config_schema(default_conf) + validate_config_schema(default_conf) def test_load_config_incorrect_stake_amount(default_conf) -> None: default_conf['stake_amount'] = 'fake' with pytest.raises(ValidationError, match=r'.*\'fake\' does not match \'unlimited\'.*'): - configuration = Configuration(Namespace()) - configuration._validate_config_schema(default_conf) + validate_config_schema(default_conf) def test_load_config_file(default_conf, mocker, caplog) -> None: - file_mock = mocker.patch('freqtrade.configuration.open', mocker.mock_open( + file_mock = mocker.patch('freqtrade.configuration.configuration.open', mocker.mock_open( read_data=json.dumps(default_conf) )) @@ -65,9 +64,7 @@ def test_load_config_file(default_conf, mocker, caplog) -> None: def test_load_config_max_open_trades_zero(default_conf, mocker, caplog) -> None: default_conf['max_open_trades'] = 0 - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) args = Arguments([], '').get_parsed_arg() configuration = Configuration(args) @@ -89,7 +86,10 @@ def test_load_config_combine_dicts(default_conf, mocker, caplog) -> None: config_files = [conf1, conf2] configsmock = MagicMock(side_effect=config_files) - mocker.patch('freqtrade.configuration.Configuration._load_config_file', configsmock) + mocker.patch( + 'freqtrade.configuration.configuration.Configuration._load_config_file', + configsmock + ) arg_list = ['-c', 'test_conf.json', '--config', 'test2_conf.json', ] args = Arguments(arg_list, '').get_parsed_arg() @@ -109,9 +109,7 @@ def test_load_config_combine_dicts(default_conf, mocker, caplog) -> None: def test_load_config_max_open_trades_minus_one(default_conf, mocker, caplog) -> None: default_conf['max_open_trades'] = -1 - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) args = Arguments([], '').get_parsed_arg() configuration = Configuration(args) @@ -126,7 +124,7 @@ def test_load_config_max_open_trades_minus_one(default_conf, mocker, caplog) -> def test_load_config_file_exception(mocker) -> None: mocker.patch( - 'freqtrade.configuration.open', + 'freqtrade.configuration.configuration.open', MagicMock(side_effect=FileNotFoundError('File not found')) ) configuration = Configuration(Namespace()) @@ -136,9 +134,7 @@ def test_load_config_file_exception(mocker) -> None: def test_load_config(default_conf, mocker) -> None: - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) args = Arguments([], '').get_parsed_arg() configuration = Configuration(args) @@ -150,9 +146,8 @@ def test_load_config(default_conf, mocker) -> None: def test_load_config_with_params(default_conf, mocker) -> None: - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) + arglist = [ '--dynamic-whitelist', '10', '--strategy', 'TestStrategy', @@ -173,9 +168,7 @@ def test_load_config_with_params(default_conf, mocker) -> None: conf = default_conf.copy() conf["dry_run"] = False conf["db_url"] = "sqlite:///path/to/db.sqlite" - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(conf) - )) + patched_configuration_load_config_file(mocker, conf) arglist = [ '--strategy', 'TestStrategy', @@ -191,9 +184,7 @@ def test_load_config_with_params(default_conf, mocker) -> None: conf = default_conf.copy() conf["dry_run"] = True conf["db_url"] = "sqlite:///path/to/db.sqlite" - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(conf) - )) + patched_configuration_load_config_file(mocker, conf) arglist = [ '--strategy', 'TestStrategy', @@ -209,9 +200,7 @@ def test_load_config_with_params(default_conf, mocker) -> None: conf = default_conf.copy() conf["dry_run"] = False del conf["db_url"] - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(conf) - )) + patched_configuration_load_config_file(mocker, conf) arglist = [ '--strategy', 'TestStrategy', @@ -229,9 +218,7 @@ def test_load_config_with_params(default_conf, mocker) -> None: conf = default_conf.copy() conf["dry_run"] = True conf["db_url"] = DEFAULT_DB_PROD_URL - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(conf) - )) + patched_configuration_load_config_file(mocker, conf) arglist = [ '--strategy', 'TestStrategy', @@ -249,9 +236,7 @@ def test_load_custom_strategy(default_conf, mocker) -> None: 'strategy': 'CustomStrategy', 'strategy_path': '/tmp/strategies', }) - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) args = Arguments([], '').get_parsed_arg() configuration = Configuration(args) @@ -262,9 +247,8 @@ def test_load_custom_strategy(default_conf, mocker) -> None: def test_show_info(default_conf, mocker, caplog) -> None: - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) + arglist = [ '--dynamic-whitelist', '10', '--strategy', 'TestStrategy', @@ -287,9 +271,8 @@ def test_show_info(default_conf, mocker, caplog) -> None: def test_setup_configuration_without_arguments(mocker, default_conf, caplog) -> None: - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) + arglist = [ '--config', 'config.json', '--strategy', 'DefaultStrategy', @@ -327,10 +310,11 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) -> def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> None: - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) - mocker.patch('freqtrade.configuration.Configuration._create_datadir', lambda s, c, x: x) + patched_configuration_load_config_file(mocker, default_conf) + mocker.patch( + 'freqtrade.configuration.configuration.create_datadir', + lambda c, x: x + ) arglist = [ '--config', 'config.json', @@ -393,9 +377,7 @@ def test_setup_configuration_with_stratlist(mocker, default_conf, caplog) -> Non """ Test setup_configuration() function """ - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) arglist = [ '--config', 'config.json', @@ -443,9 +425,8 @@ def test_setup_configuration_with_stratlist(mocker, default_conf, caplog) -> Non def test_hyperopt_with_arguments(mocker, default_conf, caplog) -> None: - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) + arglist = [ 'hyperopt', '--epochs', '10', @@ -469,25 +450,23 @@ def test_hyperopt_with_arguments(mocker, default_conf, caplog) -> None: def test_check_exchange(default_conf, caplog) -> None: - configuration = Configuration(Namespace()) - # Test an officially supported by Freqtrade team exchange default_conf.get('exchange').update({'name': 'BITTREX'}) - assert configuration.check_exchange(default_conf) + assert check_exchange(default_conf) assert log_has_re(r"Exchange .* is officially supported by the Freqtrade development team\.", caplog.record_tuples) caplog.clear() # Test an officially supported by Freqtrade team exchange default_conf.get('exchange').update({'name': 'binance'}) - assert configuration.check_exchange(default_conf) + assert check_exchange(default_conf) assert log_has_re(r"Exchange .* is officially supported by the Freqtrade development team\.", caplog.record_tuples) caplog.clear() # Test an available exchange, supported by ccxt default_conf.get('exchange').update({'name': 'kraken'}) - assert configuration.check_exchange(default_conf) + assert check_exchange(default_conf) assert log_has_re(r"Exchange .* is supported by ccxt and .* not officially supported " r"by the Freqtrade development team\. .*", caplog.record_tuples) @@ -495,7 +474,7 @@ def test_check_exchange(default_conf, caplog) -> None: # Test a 'bad' exchange, which known to have serious problems default_conf.get('exchange').update({'name': 'bitmex'}) - assert not configuration.check_exchange(default_conf) + assert not check_exchange(default_conf) assert log_has_re(r"Exchange .* is known to not work with the bot yet\. " r"Use it only for development and testing purposes\.", caplog.record_tuples) @@ -503,7 +482,7 @@ def test_check_exchange(default_conf, caplog) -> None: # Test a 'bad' exchange with check_for_bad=False default_conf.get('exchange').update({'name': 'bitmex'}) - assert configuration.check_exchange(default_conf, False) + assert check_exchange(default_conf, False) assert log_has_re(r"Exchange .* is supported by ccxt and .* not officially supported " r"by the Freqtrade development team\. .*", caplog.record_tuples) @@ -511,19 +490,18 @@ def test_check_exchange(default_conf, caplog) -> None: # Test an invalid exchange default_conf.get('exchange').update({'name': 'unknown_exchange'}) - configuration.config = default_conf with pytest.raises( OperationalException, match=r'.*Exchange "unknown_exchange" is not supported by ccxt ' r'and therefore not available for the bot.*' ): - configuration.check_exchange(default_conf) + check_exchange(default_conf) def test_cli_verbose_with_params(default_conf, mocker, caplog) -> None: - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf))) + patched_configuration_load_config_file(mocker, default_conf) + # Prevent setting loggers mocker.patch('freqtrade.loggers._set_loggers', MagicMock) arglist = ['-vvv'] @@ -575,8 +553,7 @@ def test_set_loggers() -> None: def test_set_logfile(default_conf, mocker): - mocker.patch('freqtrade.configuration.open', - mocker.mock_open(read_data=json.dumps(default_conf))) + patched_configuration_load_config_file(mocker, default_conf) arglist = [ '--logfile', 'test_file.log', @@ -593,9 +570,7 @@ def test_set_logfile(default_conf, mocker): def test_load_config_warn_forcebuy(default_conf, mocker, caplog) -> None: default_conf['forcebuy_enable'] = True - mocker.patch('freqtrade.configuration.open', mocker.mock_open( - read_data=json.dumps(default_conf) - )) + patched_configuration_load_config_file(mocker, default_conf) args = Arguments([], '').get_parsed_arg() configuration = Configuration(args) @@ -609,12 +584,11 @@ def test_validate_default_conf(default_conf) -> None: validate(default_conf, constants.CONF_SCHEMA, Draft4Validator) -def test__create_datadir(mocker, default_conf, caplog) -> None: +def test_create_datadir(mocker, default_conf, caplog) -> None: mocker.patch('os.path.isdir', MagicMock(return_value=False)) md = MagicMock() mocker.patch('os.makedirs', md) - cfg = Configuration(Namespace()) - cfg._create_datadir(default_conf, '/foo/bar') + create_datadir(default_conf, '/foo/bar') assert md.call_args[0][0] == "/foo/bar" assert log_has('Created data directory: /foo/bar', caplog.record_tuples) @@ -656,8 +630,7 @@ def test_load_config_default_exchange(all_conf) -> None: with pytest.raises(ValidationError, match=r'\'exchange\' is a required property'): - configuration = Configuration(Namespace()) - configuration._validate_config_schema(all_conf) + validate_config_schema(all_conf) def test_load_config_default_exchange_name(all_conf) -> None: @@ -671,8 +644,7 @@ def test_load_config_default_exchange_name(all_conf) -> None: with pytest.raises(ValidationError, match=r'\'name\' is a required property'): - configuration = Configuration(Namespace()) - configuration._validate_config_schema(all_conf) + validate_config_schema(all_conf) @pytest.mark.parametrize("keys", [("exchange", "sandbox", False), @@ -695,7 +667,6 @@ def test_load_config_default_subkeys(all_conf, keys) -> None: assert subkey not in all_conf[key] - configuration = Configuration(Namespace()) - configuration._validate_config_schema(all_conf) + validate_config_schema(all_conf) assert subkey in all_conf[key] assert all_conf[key][subkey] == keys[2] diff --git a/freqtrade/tests/test_main.py b/freqtrade/tests/test_main.py index 9c578099d..bcaad4d7d 100644 --- a/freqtrade/tests/test_main.py +++ b/freqtrade/tests/test_main.py @@ -6,11 +6,12 @@ from unittest.mock import MagicMock import pytest from freqtrade import OperationalException -from freqtrade.arguments import Arguments +from freqtrade.configuration import Arguments from freqtrade.freqtradebot import FreqtradeBot from freqtrade.main import main from freqtrade.state import State -from freqtrade.tests.conftest import log_has, patch_exchange +from freqtrade.tests.conftest import (log_has, patch_exchange, + patched_configuration_load_config_file) from freqtrade.worker import Worker @@ -50,10 +51,7 @@ def test_main_fatal_exception(mocker, default_conf, caplog) -> None: patch_exchange(mocker) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.cleanup', MagicMock()) mocker.patch('freqtrade.worker.Worker._worker', MagicMock(side_effect=Exception)) - mocker.patch( - 'freqtrade.configuration.Configuration._load_config_file', - lambda *args, **kwargs: default_conf - ) + patched_configuration_load_config_file(mocker, default_conf) mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock()) @@ -70,10 +68,7 @@ def test_main_keyboard_interrupt(mocker, default_conf, caplog) -> None: patch_exchange(mocker) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.cleanup', MagicMock()) mocker.patch('freqtrade.worker.Worker._worker', MagicMock(side_effect=KeyboardInterrupt)) - mocker.patch( - 'freqtrade.configuration.Configuration._load_config_file', - lambda *args, **kwargs: default_conf - ) + patched_configuration_load_config_file(mocker, default_conf) mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock()) @@ -93,10 +88,7 @@ def test_main_operational_exception(mocker, default_conf, caplog) -> None: 'freqtrade.worker.Worker._worker', MagicMock(side_effect=OperationalException('Oh snap!')) ) - mocker.patch( - 'freqtrade.configuration.Configuration._load_config_file', - lambda *args, **kwargs: default_conf - ) + patched_configuration_load_config_file(mocker, default_conf) mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock()) @@ -118,10 +110,7 @@ def test_main_reload_conf(mocker, default_conf, caplog) -> None: State.RUNNING, OperationalException("Oh snap!")]) mocker.patch('freqtrade.worker.Worker._worker', worker_mock) - mocker.patch( - 'freqtrade.configuration.Configuration._load_config_file', - lambda *args, **kwargs: default_conf - ) + patched_configuration_load_config_file(mocker, default_conf) reconfigure_mock = mocker.patch('freqtrade.main.Worker._reconfigure', MagicMock()) mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) @@ -145,10 +134,7 @@ def test_reconfigure(mocker, default_conf) -> None: 'freqtrade.worker.Worker._worker', MagicMock(side_effect=OperationalException('Oh snap!')) ) - mocker.patch( - 'freqtrade.configuration.Configuration._load_config_file', - lambda *args, **kwargs: default_conf - ) + patched_configuration_load_config_file(mocker, default_conf) mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock()) @@ -159,10 +145,7 @@ def test_reconfigure(mocker, default_conf) -> None: # Renew mock to return modified data conf = deepcopy(default_conf) conf['stake_amount'] += 1 - mocker.patch( - 'freqtrade.configuration.Configuration._load_config_file', - lambda *args, **kwargs: conf - ) + patched_configuration_load_config_file(mocker, conf) worker._config = conf # reconfigure should return a new instance diff --git a/freqtrade/tests/test_plotting.py b/freqtrade/tests/test_plotting.py index 565659d25..0ebadf720 100644 --- a/freqtrade/tests/test_plotting.py +++ b/freqtrade/tests/test_plotting.py @@ -5,7 +5,7 @@ from unittest.mock import MagicMock import plotly.graph_objs as go from plotly import tools -from freqtrade.arguments import Arguments, TimeRange +from freqtrade.configuration import Arguments, TimeRange from freqtrade.data import history from freqtrade.data.btanalysis import create_cum_profit, load_backtest_data from freqtrade.plot.plotting import (add_indicators, add_profit, diff --git a/scripts/download_backtest_data.py b/scripts/download_backtest_data.py index 472b3ef4e..9bf05941f 100755 --- a/scripts/download_backtest_data.py +++ b/scripts/download_backtest_data.py @@ -8,8 +8,10 @@ import sys from pathlib import Path from typing import Any, Dict, List -from freqtrade.arguments import Arguments, TimeRange, ARGS_DOWNLOADER +from freqtrade.configuration import Arguments, TimeRange from freqtrade.configuration import Configuration +from freqtrade.configuration.arguments import ARGS_DOWNLOADER +from freqtrade.configuration.check_exchange import check_exchange from freqtrade.data.history import download_pair_history from freqtrade.exchange import Exchange from freqtrade.misc import deep_merge_dicts @@ -79,7 +81,7 @@ if args.config and args.exchange: "using exchange settings from the configuration file.") # Check if the exchange set by the user is supported -configuration.check_exchange(config) +check_exchange(config) configuration._load_datadir_config(config) diff --git a/scripts/plot_dataframe.py b/scripts/plot_dataframe.py index 1e2d9f248..fc7e30173 100755 --- a/scripts/plot_dataframe.py +++ b/scripts/plot_dataframe.py @@ -18,7 +18,8 @@ from typing import Any, Dict, List import pandas as pd -from freqtrade.arguments import ARGS_PLOT_DATAFRAME, Arguments +from freqtrade.configuration import Arguments +from freqtrade.configuration.arguments import ARGS_PLOT_DATAFRAME from freqtrade.data.btanalysis import extract_trades_of_period from freqtrade.optimize import setup_configuration from freqtrade.plot.plotting import (init_plotscript, generate_candlestick_graph, diff --git a/scripts/plot_profit.py b/scripts/plot_profit.py index 7442ef155..96536e1e5 100755 --- a/scripts/plot_profit.py +++ b/scripts/plot_profit.py @@ -8,7 +8,8 @@ import logging import sys from typing import Any, Dict, List -from freqtrade.arguments import ARGS_PLOT_PROFIT, Arguments +from freqtrade.configuration import Arguments +from freqtrade.configuration.arguments import ARGS_PLOT_PROFIT from freqtrade.optimize import setup_configuration from freqtrade.plot.plotting import init_plotscript, generate_profit_graph, store_plot_file from freqtrade.state import RunMode