diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index e52581491..7a313a3ac 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -11,7 +11,6 @@ import pickle import signal import sys from argparse import Namespace -from copy import deepcopy from functools import reduce from math import exp from operator import itemgetter @@ -27,25 +26,10 @@ from freqtrade.arguments import Arguments from freqtrade.configuration import Configuration from freqtrade.optimize import load_data from freqtrade.optimize.backtesting import Backtesting -from freqtrade.strategy.interface import IStrategy logger = logging.getLogger(__name__) -HyperoptStrategy = None - - -def wrap_strategy(strategy: IStrategy) -> Optional[HyperoptStrategy]: - """Wraps a given Strategy instance to HyperoptStrategy""" - global HyperoptStrategy - - attr = deepcopy(dict(strategy.__class__.__dict__)) - # Patch module name to make it compatible with pickle - attr['__module__'] = 'freqtrade.optimize.hyperopt' - HyperoptStrategy = type('HyperoptStrategy', (IStrategy,), attr) - return HyperoptStrategy() - - class Hyperopt(Backtesting): """ Hyperopt class, this class contains all the logic to run a hyperopt simulation @@ -72,9 +56,6 @@ class Hyperopt(Backtesting): # check that the reported Σ% values do not exceed this! self.expected_max_profit = 3.0 - # Wrap strategy to make it compatible with pickle - self.analyze.strategy = wrap_strategy(self.analyze.strategy) - # Configuration and data used by hyperopt self.processed: Optional[Dict[str, Any]] = None diff --git a/freqtrade/strategy/__init__.py b/freqtrade/strategy/__init__.py index e69de29bb..e1dc7bb3f 100644 --- a/freqtrade/strategy/__init__.py +++ b/freqtrade/strategy/__init__.py @@ -0,0 +1,32 @@ +import logging +from copy import deepcopy + +from freqtrade.strategy.interface import IStrategy + + +logger = logging.getLogger(__name__) + + +def import_strategy(strategy: IStrategy) -> IStrategy: + """ + Imports given Strategy instance to global scope + of freqtrade.strategy and returns an instance of it + """ + # Copy all attributes from base class and class + attr = deepcopy({**strategy.__class__.__dict__, **strategy.__dict__}) + # Adjust module name + attr['__module__'] = 'freqtrade.strategy' + + name = strategy.__class__.__name__ + clazz = type(name, (IStrategy,), attr) + + logger.debug( + 'Imported strategy %s.%s as %s.%s', + strategy.__module__, strategy.__class__.__name__, + clazz.__module__, strategy.__class__.__name__, + ) + + # Modify global scope to declare class + globals()[name] = clazz + + return clazz() diff --git a/freqtrade/strategy/resolver.py b/freqtrade/strategy/resolver.py index 3fd39bca3..3c7836291 100644 --- a/freqtrade/strategy/resolver.py +++ b/freqtrade/strategy/resolver.py @@ -11,6 +11,7 @@ from collections import OrderedDict from typing import Optional, Dict, Type from freqtrade import constants +from freqtrade.strategy import import_strategy from freqtrade.strategy.interface import IStrategy @@ -83,7 +84,7 @@ class StrategyResolver(object): strategy = self._search_strategy(path, strategy_name) if strategy: logger.info('Using resolved strategy %s from \'%s\'', strategy_name, path) - return strategy + return import_strategy(strategy) raise ImportError( "Impossible to load Strategy '{}'. This class does not exist" @@ -100,7 +101,7 @@ class StrategyResolver(object): """ # Generate spec based on absolute path - spec = importlib.util.spec_from_file_location('user_data.strategies', module_path) + spec = importlib.util.spec_from_file_location('unknown', module_path) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) # type: ignore # importlib does not use typehints