diff --git a/freqtrade/analyze.py b/freqtrade/analyze.py index e6eb01e93..ccdbb139e 100644 --- a/freqtrade/analyze.py +++ b/freqtrade/analyze.py @@ -36,7 +36,7 @@ class Analyze(object): :param config: Bot configuration (use the one from Configuration()) """ self.config = config - self.strategy = StrategyResolver(self.config) + self.strategy = StrategyResolver(self.config).strategy @staticmethod def parse_ticker_dataframe(ticker: list) -> DataFrame: diff --git a/freqtrade/strategy/resolver.py b/freqtrade/strategy/resolver.py index 826a50513..5709d15a7 100644 --- a/freqtrade/strategy/resolver.py +++ b/freqtrade/strategy/resolver.py @@ -10,8 +10,6 @@ import os from collections import OrderedDict from typing import Optional, Dict, Type -from pandas import DataFrame - from freqtrade.constants import Constants from freqtrade.strategy.interface import IStrategy @@ -38,42 +36,37 @@ class StrategyResolver(object): strategy = Constants.DEFAULT_STRATEGY # Try to load the strategy - self._load_strategy(strategy) + self.strategy = self._load_strategy(strategy) # Set attributes # Check if we need to override configuration if 'minimal_roi' in config: - self.custom_strategy.minimal_roi = config['minimal_roi'] + self.strategy.minimal_roi = config['minimal_roi'] logger.info("Override strategy \'minimal_roi\' with value in config file.") if 'stoploss' in config: - self.custom_strategy.stoploss = config['stoploss'] + self.strategy.stoploss = float(config['stoploss']) logger.info( "Override strategy \'stoploss\' with value in config file: %s.", config['stoploss'] ) if 'ticker_interval' in config: - self.custom_strategy.ticker_interval = config['ticker_interval'] + self.strategy.ticker_interval = int(config['ticker_interval']) logger.info( "Override strategy \'ticker_interval\' with value in config file: %s.", config['ticker_interval'] ) # Minimal ROI designed for the strategy - self.minimal_roi = OrderedDict(sorted( - {int(key): value for (key, value) in self.custom_strategy.minimal_roi.items()}.items(), + self.strategy.minimal_roi = OrderedDict(sorted( + {int(key): value for (key, value) in self.strategy.minimal_roi.items()}.items(), key=lambda t: t[0])) # sort after converting to number - # Optimal stoploss designed for the strategy - self.stoploss = float(self.custom_strategy.stoploss) - - self.ticker_interval = int(self.custom_strategy.ticker_interval) - - def _load_strategy(self, strategy_name: str) -> None: + def _load_strategy(self, strategy_name: str) -> Optional[IStrategy]: """ Search and loads the specified strategy. :param strategy_name: name of the module to import - :return: None + :return: Strategy instance or None """ try: current_path = os.path.dirname(os.path.realpath(__file__)) @@ -82,10 +75,10 @@ class StrategyResolver(object): current_path, ] for path in abs_paths: - self.custom_strategy = self._search_strategy(path, strategy_name) - if self.custom_strategy: + strategy = self._search_strategy(path, strategy_name) + if strategy: logger.info('Using resolved strategy %s from \'%s\'', strategy_name, path) - return None + return strategy raise ImportError('not found') # Fallback to the default strategy @@ -99,6 +92,7 @@ class StrategyResolver(object): "The error is:\n%s.", error ) + return None @staticmethod def _get_valid_strategies(module_path: str, strategy_name: str) -> Optional[Type[IStrategy]]: @@ -139,28 +133,3 @@ class StrategyResolver(object): if strategy: return strategy() return None - - def populate_indicators(self, dataframe: DataFrame) -> DataFrame: - """ - Populate indicators that will be used in the Buy and Sell strategy - :param dataframe: Raw data from the exchange and parsed by parse_ticker_dataframe() - :return: a Dataframe with all mandatory indicators for the strategies - """ - return self.custom_strategy.populate_indicators(dataframe) - - def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame: - """ - Based on TA indicators, populates the buy signal for the given dataframe - :param dataframe: DataFrame - :return: DataFrame with buy column - :return: - """ - return self.custom_strategy.populate_buy_trend(dataframe) - - def populate_sell_trend(self, dataframe: DataFrame) -> DataFrame: - """ - Based on TA indicators, populates the sell signal for the given dataframe - :param dataframe: DataFrame - :return: DataFrame with buy column - """ - return self.custom_strategy.populate_sell_trend(dataframe) diff --git a/freqtrade/tests/strategy/test_strategy.py b/freqtrade/tests/strategy/test_strategy.py index 075efd6ab..6e69e2b09 100644 --- a/freqtrade/tests/strategy/test_strategy.py +++ b/freqtrade/tests/strategy/test_strategy.py @@ -19,15 +19,15 @@ def test_search_strategy(): def test_load_strategy(result): - strategy = StrategyResolver() + resolver = StrategyResolver() assert not hasattr(StrategyResolver, 'custom_strategy') - strategy._load_strategy('TestStrategy') + resolver._load_strategy('TestStrategy') assert not hasattr(StrategyResolver, 'custom_strategy') - assert hasattr(strategy.custom_strategy, 'populate_indicators') - assert 'adx' in strategy.populate_indicators(result) + assert hasattr(resolver.strategy, 'populate_indicators') + assert 'adx' in resolver.strategy.populate_indicators(result) def test_load_not_found_strategy(caplog): @@ -42,23 +42,23 @@ def test_load_not_found_strategy(caplog): def test_strategy(result): - strategy = StrategyResolver({'strategy': 'DefaultStrategy'}) + resolver = StrategyResolver({'strategy': 'DefaultStrategy'}) - assert hasattr(strategy.custom_strategy, 'minimal_roi') - assert strategy.minimal_roi[0] == 0.04 + assert hasattr(resolver.strategy, 'minimal_roi') + assert resolver.strategy.minimal_roi[0] == 0.04 - assert hasattr(strategy.custom_strategy, 'stoploss') - assert strategy.stoploss == -0.10 + assert hasattr(resolver.strategy, 'stoploss') + assert resolver.strategy.stoploss == -0.10 - assert hasattr(strategy.custom_strategy, 'populate_indicators') - assert 'adx' in strategy.populate_indicators(result) + assert hasattr(resolver.strategy, 'populate_indicators') + assert 'adx' in resolver.strategy.populate_indicators(result) - assert hasattr(strategy.custom_strategy, 'populate_buy_trend') - dataframe = strategy.populate_buy_trend(strategy.populate_indicators(result)) + assert hasattr(resolver.strategy, 'populate_buy_trend') + dataframe = resolver.strategy.populate_buy_trend(resolver.strategy.populate_indicators(result)) assert 'buy' in dataframe.columns - assert hasattr(strategy.custom_strategy, 'populate_sell_trend') - dataframe = strategy.populate_sell_trend(strategy.populate_indicators(result)) + assert hasattr(resolver.strategy, 'populate_sell_trend') + dataframe = resolver.strategy.populate_sell_trend(resolver.strategy.populate_indicators(result)) assert 'sell' in dataframe.columns @@ -70,10 +70,10 @@ def test_strategy_override_minimal_roi(caplog): "0": 0.5 } } - strategy = StrategyResolver(config) + resolver = StrategyResolver(config) - assert hasattr(strategy.custom_strategy, 'minimal_roi') - assert strategy.minimal_roi[0] == 0.5 + assert hasattr(resolver.strategy, 'minimal_roi') + assert resolver.strategy.minimal_roi[0] == 0.5 assert ('freqtrade.strategy.resolver', logging.INFO, 'Override strategy \'minimal_roi\' with value in config file.' @@ -86,10 +86,10 @@ def test_strategy_override_stoploss(caplog): 'strategy': 'DefaultStrategy', 'stoploss': -0.5 } - strategy = StrategyResolver(config) + resolver = StrategyResolver(config) - assert hasattr(strategy.custom_strategy, 'stoploss') - assert strategy.stoploss == -0.5 + assert hasattr(resolver.strategy, 'stoploss') + assert resolver.strategy.stoploss == -0.5 assert ('freqtrade.strategy.resolver', logging.INFO, 'Override strategy \'stoploss\' with value in config file: -0.5.' @@ -103,10 +103,10 @@ def test_strategy_override_ticker_interval(caplog): 'strategy': 'DefaultStrategy', 'ticker_interval': 60 } - strategy = StrategyResolver(config) + resolver = StrategyResolver(config) - assert hasattr(strategy.custom_strategy, 'ticker_interval') - assert strategy.ticker_interval == 60 + assert hasattr(resolver.strategy, 'ticker_interval') + assert resolver.strategy.ticker_interval == 60 assert ('freqtrade.strategy.resolver', logging.INFO, 'Override strategy \'ticker_interval\' with value in config file: 60.' @@ -120,14 +120,3 @@ def test_strategy_fallback_default_strategy(): assert not hasattr(StrategyResolver, 'custom_strategy') strategy._load_strategy('../../super_duper') assert not hasattr(StrategyResolver, 'custom_strategy') - - -def test_strategy_singleton(): - strategy1 = StrategyResolver({'strategy': 'DefaultStrategy'}) - - assert hasattr(strategy1.custom_strategy, 'minimal_roi') - assert strategy1.minimal_roi[0] == 0.04 - - strategy2 = StrategyResolver() - assert hasattr(strategy2.custom_strategy, 'minimal_roi') - assert strategy2.minimal_roi[0] == 0.04