Merge pull request #808 from xmatthias/mypy_typecheck
add mypy typechecking
This commit is contained in:
commit
fff7ec1dab
1
.gitignore
vendored
1
.gitignore
vendored
@ -90,3 +90,4 @@ target/
|
||||
.vscode
|
||||
|
||||
.pytest_cache/
|
||||
.mypy_cache/
|
||||
|
@ -13,7 +13,7 @@ addons:
|
||||
install:
|
||||
- ./install_ta-lib.sh
|
||||
- export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
|
||||
- pip install --upgrade flake8 coveralls pytest-random-order
|
||||
- pip install --upgrade flake8 coveralls pytest-random-order mypy
|
||||
- pip install -r requirements.txt
|
||||
- pip install -e .
|
||||
jobs:
|
||||
@ -26,6 +26,7 @@ jobs:
|
||||
- cp config.json.example config.json
|
||||
- python freqtrade/main.py hyperopt -e 5
|
||||
- script: flake8 freqtrade
|
||||
- script: mypy freqtrade
|
||||
after_success:
|
||||
- coveralls
|
||||
notifications:
|
||||
|
@ -12,7 +12,7 @@ from pandas import DataFrame, to_datetime
|
||||
from freqtrade import constants
|
||||
from freqtrade.exchange import get_ticker_history
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.strategy.resolver import StrategyResolver
|
||||
from freqtrade.strategy.resolver import StrategyResolver, IStrategy
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -37,7 +37,7 @@ class Analyze(object):
|
||||
:param config: Bot configuration (use the one from Configuration())
|
||||
"""
|
||||
self.config = config
|
||||
self.strategy = StrategyResolver(self.config).strategy
|
||||
self.strategy: IStrategy = StrategyResolver(self.config).strategy
|
||||
|
||||
@staticmethod
|
||||
def parse_ticker_dataframe(ticker: list) -> DataFrame:
|
||||
|
@ -17,9 +17,9 @@ class Arguments(object):
|
||||
Arguments Class. Manage the arguments received by the cli
|
||||
"""
|
||||
|
||||
def __init__(self, args: List[str], description: str):
|
||||
def __init__(self, args: List[str], description: str) -> None:
|
||||
self.args = args
|
||||
self.parsed_arg = None
|
||||
self.parsed_arg: Optional[argparse.Namespace] = None
|
||||
self.parser = argparse.ArgumentParser(description=description)
|
||||
|
||||
def _load_args(self) -> None:
|
||||
@ -211,7 +211,8 @@ class Arguments(object):
|
||||
self.hyperopt_options(hyperopt_cmd)
|
||||
|
||||
@staticmethod
|
||||
def parse_timerange(text: str) -> Optional[Tuple[List, int, int]]:
|
||||
def parse_timerange(text: Optional[str]) -> Optional[Tuple[Tuple,
|
||||
Optional[int], Optional[int]]]:
|
||||
"""
|
||||
Parse the value of the argument --timerange to determine what is the range desired
|
||||
:param text: value from --timerange
|
||||
@ -234,23 +235,23 @@ class Arguments(object):
|
||||
if match: # Regex has matched
|
||||
rvals = match.groups()
|
||||
index = 0
|
||||
start = None
|
||||
stop = None
|
||||
start: Optional[int] = None
|
||||
stop: Optional[int] = None
|
||||
if stype[0]:
|
||||
start = rvals[index]
|
||||
starts = rvals[index]
|
||||
if stype[0] == 'date':
|
||||
start = int(start) if len(start) == 10 \
|
||||
else arrow.get(start, 'YYYYMMDD').timestamp
|
||||
start = int(starts) if len(starts) == 10 \
|
||||
else arrow.get(starts, 'YYYYMMDD').timestamp
|
||||
else:
|
||||
start = int(start)
|
||||
start = int(starts)
|
||||
index += 1
|
||||
if stype[1]:
|
||||
stop = rvals[index]
|
||||
stops = rvals[index]
|
||||
if stype[1] == 'date':
|
||||
stop = int(stop) if len(stop) == 10 \
|
||||
else arrow.get(stop, 'YYYYMMDD').timestamp
|
||||
stop = int(stops) if len(stops) == 10 \
|
||||
else arrow.get(stops, 'YYYYMMDD').timestamp
|
||||
else:
|
||||
stop = int(stop)
|
||||
stop = int(stops)
|
||||
return stype, start, stop
|
||||
raise Exception('Incorrect syntax for timerange "%s"' % text)
|
||||
|
||||
|
@ -5,7 +5,7 @@ This module contains the configuration class
|
||||
import json
|
||||
import logging
|
||||
from argparse import Namespace
|
||||
from typing import Dict, Any
|
||||
from typing import Optional, Dict, Any
|
||||
from jsonschema import Draft4Validator, validate
|
||||
from jsonschema.exceptions import ValidationError, best_match
|
||||
import ccxt
|
||||
@ -23,7 +23,7 @@ class Configuration(object):
|
||||
"""
|
||||
def __init__(self, args: Namespace) -> None:
|
||||
self.args = args
|
||||
self.config = None
|
||||
self.config: Optional[Dict[str, Any]] = None
|
||||
|
||||
def load_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
@ -192,7 +192,7 @@ class Configuration(object):
|
||||
validate(conf, constants.CONF_SCHEMA)
|
||||
return conf
|
||||
except ValidationError as exception:
|
||||
logger.fatal(
|
||||
logger.critical(
|
||||
'Invalid configuration. See config.json.example. Reason: %s',
|
||||
exception
|
||||
)
|
||||
|
@ -290,7 +290,7 @@ def get_ticker_history(pair: str, tick_interval: str, since_ms: Optional[int] =
|
||||
# chached data was already downloaded
|
||||
till_time_ms = min(till_time_ms, arrow.utcnow().shift(minutes=-10).timestamp * 1000)
|
||||
|
||||
data = []
|
||||
data: List[Dict[Any, Any]] = []
|
||||
while not since_ms or since_ms < till_time_ms:
|
||||
data_part = _API.fetch_ohlcv(pair, timeframe=tick_interval, since=since_ms)
|
||||
|
||||
|
@ -5,7 +5,7 @@ e.g BTC to USD
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Dict
|
||||
from typing import Dict, List
|
||||
|
||||
from coinmarketcap import Market
|
||||
from requests.exceptions import RequestException
|
||||
@ -34,7 +34,7 @@ class CryptoFiat(object):
|
||||
self.price = 0.0
|
||||
|
||||
# Private attributes
|
||||
self._expiration = 0
|
||||
self._expiration = 0.0
|
||||
|
||||
self.crypto_symbol = crypto_symbol.upper()
|
||||
self.fiat_symbol = fiat_symbol.upper()
|
||||
@ -65,7 +65,7 @@ class CryptoToFiatConverter(object):
|
||||
This object is also a Singleton
|
||||
"""
|
||||
__instance = None
|
||||
_coinmarketcap = None
|
||||
_coinmarketcap: Market = None
|
||||
|
||||
# Constants
|
||||
SUPPORTED_FIAT = [
|
||||
@ -87,7 +87,7 @@ class CryptoToFiatConverter(object):
|
||||
return CryptoToFiatConverter.__instance
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._pairs = []
|
||||
self._pairs: List[CryptoFiat] = []
|
||||
self._load_cryptomap()
|
||||
|
||||
def _load_cryptomap(self) -> None:
|
||||
|
@ -33,7 +33,7 @@ class FreqtradeBot(object):
|
||||
This is from here the bot start its logic.
|
||||
"""
|
||||
|
||||
def __init__(self, config: Dict[str, Any], db_url: Optional[str] = None):
|
||||
def __init__(self, config: Dict[str, Any], db_url: Optional[str] = None)-> None:
|
||||
"""
|
||||
Init all variables and object the bot need to work
|
||||
:param config: configuration dict, you can use the Configuration.get_config()
|
||||
@ -51,9 +51,9 @@ class FreqtradeBot(object):
|
||||
|
||||
# Init objects
|
||||
self.config = config
|
||||
self.analyze = None
|
||||
self.fiat_converter = None
|
||||
self.rpc = None
|
||||
self.analyze = Analyze(self.config)
|
||||
self.fiat_converter = CryptoToFiatConverter()
|
||||
self.rpc: RPCManager = RPCManager(self)
|
||||
self.persistence = None
|
||||
self.exchange = None
|
||||
|
||||
@ -66,9 +66,6 @@ class FreqtradeBot(object):
|
||||
:return: None
|
||||
"""
|
||||
# Initialize all modules
|
||||
self.analyze = Analyze(self.config)
|
||||
self.fiat_converter = CryptoToFiatConverter()
|
||||
self.rpc = RPCManager(self)
|
||||
|
||||
persistence.init(self.config, db_url)
|
||||
exchange.init(self.config)
|
||||
@ -93,7 +90,7 @@ class FreqtradeBot(object):
|
||||
persistence.cleanup()
|
||||
return True
|
||||
|
||||
def worker(self, old_state: None) -> State:
|
||||
def worker(self, old_state: State = None) -> State:
|
||||
"""
|
||||
Trading routine that must be run at each loop
|
||||
:param old_state: the previous service state from the previous call
|
||||
|
@ -13,7 +13,7 @@ def went_down(series: Series) -> bool:
|
||||
return series < series.shift(1)
|
||||
|
||||
|
||||
def ehlers_super_smoother(series: Series, smoothing: float = 6) -> type(Series):
|
||||
def ehlers_super_smoother(series: Series, smoothing: float = 6) -> Series:
|
||||
magic = pi * sqrt(2) / smoothing
|
||||
a1 = exp(-magic)
|
||||
coeff2 = 2 * a1 * cos(magic)
|
||||
|
@ -83,7 +83,7 @@ def file_dump_json(filename, data, is_zip=False) -> None:
|
||||
json.dump(data, fp, default=str)
|
||||
|
||||
|
||||
def format_ms_time(date: str) -> str:
|
||||
def format_ms_time(date: int) -> str:
|
||||
"""
|
||||
convert MS date to readable format.
|
||||
: epoch-string in ms
|
||||
|
@ -4,8 +4,8 @@ import gzip
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from typing import Optional, List, Dict, Tuple, Any
|
||||
import arrow
|
||||
from typing import Optional, List, Dict, Tuple
|
||||
|
||||
from freqtrade import misc, constants
|
||||
from freqtrade.exchange import get_ticker_history
|
||||
@ -144,7 +144,9 @@ def download_pairs(datadir, pairs: List[str],
|
||||
|
||||
def load_cached_data_for_updating(filename: str,
|
||||
tick_interval: str,
|
||||
timerange: Optional[Tuple[Tuple, int, int]]) -> Tuple[list, int]:
|
||||
timerange: Optional[Tuple[Tuple, int, int]]) -> Tuple[
|
||||
List[Any],
|
||||
Optional[int]]:
|
||||
"""
|
||||
Load cached data and choose what part of the data should be updated
|
||||
"""
|
||||
|
@ -33,18 +33,6 @@ class Backtesting(object):
|
||||
"""
|
||||
def __init__(self, config: Dict[str, Any]) -> None:
|
||||
self.config = config
|
||||
self.analyze = None
|
||||
self.ticker_interval = None
|
||||
self.tickerdata_to_dataframe = None
|
||||
self.populate_buy_trend = None
|
||||
self.populate_sell_trend = None
|
||||
self._init()
|
||||
|
||||
def _init(self) -> None:
|
||||
"""
|
||||
Init objects required for backtesting
|
||||
:return: None
|
||||
"""
|
||||
self.analyze = Analyze(self.config)
|
||||
self.ticker_interval = self.analyze.strategy.ticker_interval
|
||||
self.tickerdata_to_dataframe = self.analyze.tickerdata_to_dataframe
|
||||
@ -78,7 +66,7 @@ class Backtesting(object):
|
||||
Generates and returns a text table for the given backtest data and the results dataframe
|
||||
:return: pretty printed table with tabulate as str
|
||||
"""
|
||||
stake_currency = self.config.get('stake_currency')
|
||||
stake_currency = str(self.config.get('stake_currency'))
|
||||
|
||||
floatfmt = ('s', 'd', '.2f', '.8f', '.1f')
|
||||
tabular_data = []
|
||||
@ -168,7 +156,7 @@ class Backtesting(object):
|
||||
record = args.get('record', None)
|
||||
records = []
|
||||
trades = []
|
||||
trade_count_lock = {}
|
||||
trade_count_lock: Dict = {}
|
||||
for pair, pair_data in processed.items():
|
||||
pair_data['buy'], pair_data['sell'] = 0, 0 # cleanup from previous run
|
||||
|
||||
@ -230,8 +218,9 @@ class Backtesting(object):
|
||||
else:
|
||||
logger.info('Using local backtesting data (using whitelist in given config) ...')
|
||||
|
||||
timerange = Arguments.parse_timerange(self.config.get('timerange'))
|
||||
data = optimize.load_data(
|
||||
timerange = Arguments.parse_timerange(None if self.config.get(
|
||||
'timerange') is None else str(self.config.get('timerange')))
|
||||
data = optimize.load_data( # type: ignore # timerange will be refactored
|
||||
self.config['datadir'],
|
||||
pairs=pairs,
|
||||
ticker_interval=self.ticker_interval,
|
||||
|
@ -14,7 +14,7 @@ from argparse import Namespace
|
||||
from functools import reduce
|
||||
from math import exp
|
||||
from operator import itemgetter
|
||||
from typing import Dict, Any, Callable
|
||||
from typing import Dict, Any, Callable, Optional
|
||||
|
||||
import numpy
|
||||
import talib.abstract as ta
|
||||
@ -60,7 +60,7 @@ class Hyperopt(Backtesting):
|
||||
self.expected_max_profit = 3.0
|
||||
|
||||
# Configuration and data used by hyperopt
|
||||
self.processed = None
|
||||
self.processed: Optional[Dict[str, Any]] = None
|
||||
|
||||
# Hyperopt Trials
|
||||
self.trials_file = os.path.join('user_data', 'hyperopt_trials.pickle')
|
||||
@ -344,7 +344,7 @@ class Hyperopt(Backtesting):
|
||||
"""
|
||||
Return the space to use during Hyperopt
|
||||
"""
|
||||
spaces = {}
|
||||
spaces: Dict = {}
|
||||
if self.has_space('buy'):
|
||||
spaces = {**spaces, **Hyperopt.indicator_space()}
|
||||
if self.has_space('roi'):
|
||||
@ -495,16 +495,17 @@ class Hyperopt(Backtesting):
|
||||
)
|
||||
|
||||
def start(self) -> None:
|
||||
timerange = Arguments.parse_timerange(self.config.get('timerange'))
|
||||
data = load_data(
|
||||
datadir=self.config.get('datadir'),
|
||||
timerange = Arguments.parse_timerange(None if self.config.get(
|
||||
'timerange') is None else str(self.config.get('timerange')))
|
||||
data = load_data( # type: ignore # timerange will be refactored
|
||||
datadir=str(self.config.get('datadir')),
|
||||
pairs=self.config['exchange']['pair_whitelist'],
|
||||
ticker_interval=self.ticker_interval,
|
||||
timerange=timerange
|
||||
)
|
||||
|
||||
if self.has_space('buy'):
|
||||
self.analyze.populate_indicators = Hyperopt.populate_indicators
|
||||
self.analyze.populate_indicators = Hyperopt.populate_indicators # type: ignore
|
||||
self.processed = self.tickerdata_to_dataframe(data)
|
||||
|
||||
if self.config.get('mongodb'):
|
||||
|
@ -5,7 +5,7 @@ This module contains the class to persist trades into SQLite
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from decimal import Decimal, getcontext
|
||||
from typing import Dict, Optional
|
||||
from typing import Dict, Optional, Any
|
||||
|
||||
import arrow
|
||||
from sqlalchemy import (Boolean, Column, DateTime, Float, Integer, String,
|
||||
@ -21,7 +21,7 @@ from sqlalchemy import inspect
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_CONF = {}
|
||||
_DECL_BASE = declarative_base()
|
||||
_DECL_BASE: Any = declarative_base()
|
||||
|
||||
|
||||
def init(config: dict, engine: Optional[Engine] = None) -> None:
|
||||
|
@ -2,9 +2,9 @@
|
||||
This module contains class to define a RPC communications
|
||||
"""
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, date
|
||||
from decimal import Decimal
|
||||
from typing import Tuple, Any
|
||||
from typing import Dict, Tuple, Any
|
||||
|
||||
import arrow
|
||||
import sqlalchemy as sql
|
||||
@ -114,7 +114,7 @@ class RPC(object):
|
||||
self, timescale: int,
|
||||
stake_currency: str, fiat_display_currency: str) -> Tuple[bool, Any]:
|
||||
today = datetime.utcnow().date()
|
||||
profit_days = {}
|
||||
profit_days: Dict[date, Dict] = {}
|
||||
|
||||
if not (isinstance(timescale, int) and timescale > 0):
|
||||
return True, '*Daily [n]:* `must be an integer greater than 0`'
|
||||
@ -172,7 +172,7 @@ class RPC(object):
|
||||
durations = []
|
||||
|
||||
for trade in trades:
|
||||
current_rate = None
|
||||
current_rate: float = 0.0
|
||||
|
||||
if not trade.open_rate:
|
||||
continue
|
||||
@ -278,7 +278,7 @@ class RPC(object):
|
||||
value = fiat.convert_amount(total, 'BTC', symbol)
|
||||
return False, (output, total, symbol, value)
|
||||
|
||||
def rpc_start(self) -> (bool, str):
|
||||
def rpc_start(self) -> Tuple[bool, str]:
|
||||
"""
|
||||
Handler for start.
|
||||
"""
|
||||
@ -288,7 +288,7 @@ class RPC(object):
|
||||
self.freqtrade.state = State.RUNNING
|
||||
return False, '`Starting trader ...`'
|
||||
|
||||
def rpc_stop(self) -> (bool, str):
|
||||
def rpc_stop(self) -> Tuple[bool, str]:
|
||||
"""
|
||||
Handler for stop.
|
||||
"""
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""
|
||||
This module contains class to manage RPC communications (Telegram, Slack, ...)
|
||||
"""
|
||||
from typing import Any, List
|
||||
import logging
|
||||
|
||||
from freqtrade.rpc.telegram import Telegram
|
||||
@ -21,8 +22,8 @@ class RPCManager(object):
|
||||
"""
|
||||
self.freqtrade = freqtrade
|
||||
|
||||
self.registered_modules = []
|
||||
self.telegram = None
|
||||
self.registered_modules: List[str] = []
|
||||
self.telegram: Any = None
|
||||
self._init()
|
||||
|
||||
def _init(self) -> None:
|
||||
|
@ -18,7 +18,7 @@ from freqtrade.rpc.rpc import RPC
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def authorized_only(command_handler: Callable[[Bot, Update], None]) -> Callable[..., Any]:
|
||||
def authorized_only(command_handler: Callable[[Any, Bot, Update], None]) -> Callable[..., Any]:
|
||||
"""
|
||||
Decorator to check if the message comes from the correct chat_id
|
||||
:param command_handler: Telegram CommandHandler
|
||||
@ -65,7 +65,7 @@ class Telegram(RPC):
|
||||
"""
|
||||
super().__init__(freqtrade)
|
||||
|
||||
self._updater = None
|
||||
self._updater: Updater = None
|
||||
self._config = freqtrade.config
|
||||
self._init()
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
IStrategy interface
|
||||
This module defines the interface to apply for strategies
|
||||
"""
|
||||
|
||||
from typing import Dict
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from pandas import DataFrame
|
||||
@ -16,9 +16,13 @@ class IStrategy(ABC):
|
||||
Attributes you can use:
|
||||
minimal_roi -> Dict: Minimal ROI designed for the strategy
|
||||
stoploss -> float: optimal stoploss designed for the strategy
|
||||
ticker_interval -> int: value of the ticker interval to use for the strategy
|
||||
ticker_interval -> str: value of the ticker interval to use for the strategy
|
||||
"""
|
||||
|
||||
minimal_roi: Dict
|
||||
stoploss: float
|
||||
ticker_interval: str
|
||||
|
||||
@abstractmethod
|
||||
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
|
||||
"""
|
||||
|
@ -33,7 +33,8 @@ class StrategyResolver(object):
|
||||
|
||||
# Verify the strategy is in the configuration, otherwise fallback to the default strategy
|
||||
strategy_name = config.get('strategy') or constants.DEFAULT_STRATEGY
|
||||
self.strategy = self._load_strategy(strategy_name, extra_dir=config.get('strategy_path'))
|
||||
self.strategy: IStrategy = self._load_strategy(strategy_name,
|
||||
extra_dir=config.get('strategy_path'))
|
||||
|
||||
# Set attributes
|
||||
# Check if we need to override configuration
|
||||
@ -61,7 +62,7 @@ class StrategyResolver(object):
|
||||
self.strategy.stoploss = float(self.strategy.stoploss)
|
||||
|
||||
def _load_strategy(
|
||||
self, strategy_name: str, extra_dir: Optional[str] = None) -> Optional[IStrategy]:
|
||||
self, strategy_name: str, extra_dir: Optional[str] = None) -> IStrategy:
|
||||
"""
|
||||
Search and loads the specified strategy.
|
||||
:param strategy_name: name of the module to import
|
||||
@ -101,7 +102,7 @@ class StrategyResolver(object):
|
||||
# Generate spec based on absolute path
|
||||
spec = importlib.util.spec_from_file_location('user_data.strategies', module_path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
spec.loader.exec_module(module) # type: ignore # importlib does not use typehints
|
||||
|
||||
valid_strategies_gen = (
|
||||
obj for name, obj in inspect.getmembers(module, inspect.isclass)
|
||||
|
@ -286,23 +286,6 @@ def test_start(mocker, fee, default_conf, caplog) -> None:
|
||||
assert start_mock.call_count == 1
|
||||
|
||||
|
||||
def test_backtesting__init__(mocker, default_conf) -> None:
|
||||
"""
|
||||
Test Backtesting.__init__() method
|
||||
"""
|
||||
init_mock = MagicMock()
|
||||
mocker.patch('freqtrade.optimize.backtesting.Backtesting._init', init_mock)
|
||||
|
||||
backtesting = Backtesting(default_conf)
|
||||
assert backtesting.config == default_conf
|
||||
assert backtesting.analyze is None
|
||||
assert backtesting.ticker_interval is None
|
||||
assert backtesting.tickerdata_to_dataframe is None
|
||||
assert backtesting.populate_buy_trend is None
|
||||
assert backtesting.populate_sell_trend is None
|
||||
assert init_mock.call_count == 1
|
||||
|
||||
|
||||
def test_backtesting_init(mocker, default_conf) -> None:
|
||||
"""
|
||||
Test Backtesting._init() method
|
||||
|
@ -6,6 +6,7 @@ Unit test file for configuration.py
|
||||
import json
|
||||
from copy import deepcopy
|
||||
from unittest.mock import MagicMock
|
||||
from argparse import Namespace
|
||||
|
||||
import pytest
|
||||
from jsonschema import ValidationError
|
||||
@ -37,7 +38,7 @@ def test_load_config_invalid_pair(default_conf) -> None:
|
||||
conf['exchange']['pair_whitelist'].append('ETH-BTC')
|
||||
|
||||
with pytest.raises(ValidationError, match=r'.*does not match.*'):
|
||||
configuration = Configuration([])
|
||||
configuration = Configuration(Namespace())
|
||||
configuration._validate_config(conf)
|
||||
|
||||
|
||||
@ -49,7 +50,7 @@ def test_load_config_missing_attributes(default_conf) -> None:
|
||||
conf.pop('exchange')
|
||||
|
||||
with pytest.raises(ValidationError, match=r'.*\'exchange\' is a required property.*'):
|
||||
configuration = Configuration([])
|
||||
configuration = Configuration(Namespace())
|
||||
configuration._validate_config(conf)
|
||||
|
||||
|
||||
@ -61,7 +62,7 @@ def test_load_config_file(default_conf, mocker, caplog) -> None:
|
||||
read_data=json.dumps(default_conf)
|
||||
))
|
||||
|
||||
configuration = Configuration([])
|
||||
configuration = Configuration(Namespace())
|
||||
validated_conf = configuration._load_config_file('somefile')
|
||||
assert file_mock.call_count == 1
|
||||
assert validated_conf.items() >= default_conf.items()
|
||||
@ -79,7 +80,7 @@ def test_load_config_max_open_trades_zero(default_conf, mocker, caplog) -> None:
|
||||
read_data=json.dumps(conf)
|
||||
))
|
||||
|
||||
Configuration([])._load_config_file('somefile')
|
||||
Configuration(Namespace())._load_config_file('somefile')
|
||||
assert file_mock.call_count == 1
|
||||
assert log_has('Validating configuration ...', caplog.record_tuples)
|
||||
|
||||
@ -92,7 +93,7 @@ def test_load_config_file_exception(mocker, caplog) -> None:
|
||||
'freqtrade.configuration.open',
|
||||
MagicMock(side_effect=FileNotFoundError('File not found'))
|
||||
)
|
||||
configuration = Configuration([])
|
||||
configuration = Configuration(Namespace())
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
configuration._load_config_file('somefile')
|
||||
@ -128,13 +129,13 @@ def test_load_config_with_params(default_conf, mocker) -> None:
|
||||
read_data=json.dumps(default_conf)
|
||||
))
|
||||
|
||||
args = [
|
||||
arglist = [
|
||||
'--dynamic-whitelist', '10',
|
||||
'--strategy', 'TestStrategy',
|
||||
'--strategy-path', '/some/path',
|
||||
'--dry-run-db',
|
||||
]
|
||||
args = Arguments(args, '').get_parsed_arg()
|
||||
args = Arguments(arglist, '').get_parsed_arg()
|
||||
|
||||
configuration = Configuration(args)
|
||||
validated_conf = configuration.load_config()
|
||||
@ -174,12 +175,12 @@ def test_show_info(default_conf, mocker, caplog) -> None:
|
||||
read_data=json.dumps(default_conf)
|
||||
))
|
||||
|
||||
args = [
|
||||
arglist = [
|
||||
'--dynamic-whitelist', '10',
|
||||
'--strategy', 'TestStrategy',
|
||||
'--dry-run-db'
|
||||
]
|
||||
args = Arguments(args, '').get_parsed_arg()
|
||||
args = Arguments(arglist, '').get_parsed_arg()
|
||||
|
||||
configuration = Configuration(args)
|
||||
configuration.get_config()
|
||||
@ -202,8 +203,8 @@ def test_show_info(default_conf, mocker, caplog) -> None:
|
||||
)
|
||||
|
||||
# Test the Dry run condition
|
||||
configuration.config.update({'dry_run': False})
|
||||
configuration._load_common_config(configuration.config)
|
||||
configuration.config.update({'dry_run': False}) # type: ignore
|
||||
configuration._load_common_config(configuration.config) # type: ignore
|
||||
assert log_has(
|
||||
'Dry run is disabled. (--dry_run_db ignored)',
|
||||
caplog.record_tuples
|
||||
@ -218,13 +219,13 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
|
||||
read_data=json.dumps(default_conf)
|
||||
))
|
||||
|
||||
args = [
|
||||
arglist = [
|
||||
'--config', 'config.json',
|
||||
'--strategy', 'DefaultStrategy',
|
||||
'backtesting'
|
||||
]
|
||||
|
||||
args = Arguments(args, '').get_parsed_arg()
|
||||
args = Arguments(arglist, '').get_parsed_arg()
|
||||
|
||||
configuration = Configuration(args)
|
||||
config = configuration.get_config()
|
||||
@ -262,7 +263,7 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
|
||||
read_data=json.dumps(default_conf)
|
||||
))
|
||||
|
||||
args = [
|
||||
arglist = [
|
||||
'--config', 'config.json',
|
||||
'--strategy', 'DefaultStrategy',
|
||||
'--datadir', '/foo/bar',
|
||||
@ -275,7 +276,7 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
|
||||
'--export', '/bar/foo'
|
||||
]
|
||||
|
||||
args = Arguments(args, '').get_parsed_arg()
|
||||
args = Arguments(arglist, '').get_parsed_arg()
|
||||
|
||||
configuration = Configuration(args)
|
||||
config = configuration.get_config()
|
||||
@ -326,14 +327,14 @@ def test_hyperopt_with_arguments(mocker, default_conf, caplog) -> None:
|
||||
read_data=json.dumps(default_conf)
|
||||
))
|
||||
|
||||
args = [
|
||||
arglist = [
|
||||
'hyperopt',
|
||||
'--epochs', '10',
|
||||
'--use-mongodb',
|
||||
'--spaces', 'all',
|
||||
]
|
||||
|
||||
args = Arguments(args, '').get_parsed_arg()
|
||||
args = Arguments(arglist, '').get_parsed_arg()
|
||||
|
||||
configuration = Configuration(args)
|
||||
config = configuration.get_config()
|
||||
@ -357,7 +358,7 @@ def test_check_exchange(default_conf) -> None:
|
||||
Test the configuration validator with a missing attribute
|
||||
"""
|
||||
conf = deepcopy(default_conf)
|
||||
configuration = Configuration([])
|
||||
configuration = Configuration(Namespace())
|
||||
|
||||
# Test a valid exchange
|
||||
conf.get('exchange').update({'name': 'BITTREX'})
|
||||
|
Loading…
Reference in New Issue
Block a user