Merge pull request #2235 from hroff-1902/eliminate_import_strategy
Allow --strategy for hyperopt
This commit is contained in:
commit
3d028f512e
@ -25,16 +25,6 @@ def setup_configuration(args: Namespace, method: RunMode) -> Dict[str, Any]:
|
|||||||
raise DependencyException('stake amount could not be "%s" for backtesting' %
|
raise DependencyException('stake amount could not be "%s" for backtesting' %
|
||||||
constants.UNLIMITED_STAKE_AMOUNT)
|
constants.UNLIMITED_STAKE_AMOUNT)
|
||||||
|
|
||||||
if method == RunMode.HYPEROPT:
|
|
||||||
# Special cases for Hyperopt
|
|
||||||
if config.get('strategy') and config.get('strategy') != 'DefaultStrategy':
|
|
||||||
logger.error("Please don't use --strategy for hyperopt.")
|
|
||||||
logger.error(
|
|
||||||
"Read the documentation at "
|
|
||||||
"https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md "
|
|
||||||
"to understand how to configure hyperopt.")
|
|
||||||
raise DependencyException("--strategy configured but not supported for hyperopt")
|
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ from typing import Dict, Optional
|
|||||||
|
|
||||||
from freqtrade import constants, OperationalException
|
from freqtrade import constants, OperationalException
|
||||||
from freqtrade.resolvers import IResolver
|
from freqtrade.resolvers import IResolver
|
||||||
from freqtrade.strategy import import_strategy
|
|
||||||
from freqtrade.strategy.interface import IStrategy
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -158,12 +157,7 @@ class StrategyResolver(IResolver):
|
|||||||
strategy._sell_fun_len]]):
|
strategy._sell_fun_len]]):
|
||||||
strategy.INTERFACE_VERSION = 1
|
strategy.INTERFACE_VERSION = 1
|
||||||
|
|
||||||
try:
|
return strategy
|
||||||
return import_strategy(strategy, config=config)
|
|
||||||
except TypeError as e:
|
|
||||||
logger.warning(
|
|
||||||
f"Impossible to load strategy '{strategy_name}'. "
|
|
||||||
f"Error: {e}")
|
|
||||||
|
|
||||||
raise OperationalException(
|
raise OperationalException(
|
||||||
f"Impossible to load Strategy '{strategy_name}'. This class does not exist "
|
f"Impossible to load Strategy '{strategy_name}'. This class does not exist "
|
||||||
|
@ -1,45 +1,3 @@
|
|||||||
import logging
|
from freqtrade.strategy.interface import IStrategy # noqa: F401
|
||||||
import sys
|
|
||||||
from copy import deepcopy
|
|
||||||
|
|
||||||
from freqtrade.strategy.interface import IStrategy
|
|
||||||
# Import Default-Strategy to have hyperopt correctly resolve
|
# Import Default-Strategy to have hyperopt correctly resolve
|
||||||
from freqtrade.strategy.default_strategy import DefaultStrategy # noqa: F401
|
from freqtrade.strategy.default_strategy import DefaultStrategy # noqa: F401
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def import_strategy(strategy: IStrategy, config: dict) -> 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
|
|
||||||
comb = {**strategy.__class__.__dict__, **strategy.__dict__}
|
|
||||||
|
|
||||||
# Delete '_abc_impl' from dict as deepcopy fails on 3.7 with
|
|
||||||
# `TypeError: can't pickle _abc_data objects``
|
|
||||||
# This will only apply to python 3.7
|
|
||||||
if sys.version_info.major == 3 and sys.version_info.minor == 7 and '_abc_impl' in comb:
|
|
||||||
del comb['_abc_impl']
|
|
||||||
|
|
||||||
attr = deepcopy(comb)
|
|
||||||
|
|
||||||
# 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(config)
|
|
||||||
|
@ -9,7 +9,7 @@ from arrow import Arrow
|
|||||||
from filelock import Timeout
|
from filelock import Timeout
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from freqtrade import DependencyException, OperationalException
|
from freqtrade import OperationalException
|
||||||
from freqtrade.data.converter import parse_ticker_dataframe
|
from freqtrade.data.converter import parse_ticker_dataframe
|
||||||
from freqtrade.data.history import load_tickerdata_file
|
from freqtrade.data.history import load_tickerdata_file
|
||||||
from freqtrade.optimize import setup_configuration, start_hyperopt
|
from freqtrade.optimize import setup_configuration, start_hyperopt
|
||||||
@ -246,24 +246,6 @@ def test_start_no_data(mocker, default_conf, caplog) -> None:
|
|||||||
assert log_has('No data found. Terminating.', caplog)
|
assert log_has('No data found. Terminating.', caplog)
|
||||||
|
|
||||||
|
|
||||||
def test_start_failure(mocker, default_conf, caplog) -> None:
|
|
||||||
start_mock = MagicMock()
|
|
||||||
patched_configuration_load_config_file(mocker, default_conf)
|
|
||||||
mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock)
|
|
||||||
patch_exchange(mocker)
|
|
||||||
|
|
||||||
args = [
|
|
||||||
'--config', 'config.json',
|
|
||||||
'--strategy', 'SampleStrategy',
|
|
||||||
'hyperopt',
|
|
||||||
'--epochs', '5'
|
|
||||||
]
|
|
||||||
args = get_args(args)
|
|
||||||
with pytest.raises(DependencyException):
|
|
||||||
start_hyperopt(args)
|
|
||||||
assert log_has("Please don't use --strategy for hyperopt.", caplog)
|
|
||||||
|
|
||||||
|
|
||||||
def test_start_filelock(mocker, default_conf, caplog) -> None:
|
def test_start_filelock(mocker, default_conf, caplog) -> None:
|
||||||
start_mock = MagicMock(side_effect=Timeout(Hyperopt.get_lock_filename(default_conf)))
|
start_mock = MagicMock(side_effect=Timeout(Hyperopt.get_lock_filename(default_conf)))
|
||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
@ -5,40 +5,16 @@ import warnings
|
|||||||
from base64 import urlsafe_b64encode
|
from base64 import urlsafe_b64encode
|
||||||
from os import path
|
from os import path
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import Mock
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
|
|
||||||
from freqtrade import OperationalException
|
from freqtrade import OperationalException
|
||||||
from freqtrade.resolvers import StrategyResolver
|
from freqtrade.resolvers import StrategyResolver
|
||||||
from freqtrade.strategy import import_strategy
|
|
||||||
from freqtrade.strategy.default_strategy import DefaultStrategy
|
|
||||||
from freqtrade.strategy.interface import IStrategy
|
from freqtrade.strategy.interface import IStrategy
|
||||||
from freqtrade.tests.conftest import log_has, log_has_re
|
from freqtrade.tests.conftest import log_has, log_has_re
|
||||||
|
|
||||||
|
|
||||||
def test_import_strategy(caplog):
|
|
||||||
caplog.set_level(logging.DEBUG)
|
|
||||||
default_config = {}
|
|
||||||
|
|
||||||
strategy = DefaultStrategy(default_config)
|
|
||||||
strategy.some_method = lambda *args, **kwargs: 42
|
|
||||||
|
|
||||||
assert strategy.__module__ == 'freqtrade.strategy.default_strategy'
|
|
||||||
assert strategy.some_method() == 42
|
|
||||||
|
|
||||||
imported_strategy = import_strategy(strategy, default_config)
|
|
||||||
|
|
||||||
assert dir(strategy) == dir(imported_strategy)
|
|
||||||
|
|
||||||
assert imported_strategy.__module__ == 'freqtrade.strategy'
|
|
||||||
assert imported_strategy.some_method() == 42
|
|
||||||
|
|
||||||
assert log_has('Imported strategy freqtrade.strategy.default_strategy.DefaultStrategy '
|
|
||||||
'as freqtrade.strategy.DefaultStrategy', caplog)
|
|
||||||
|
|
||||||
|
|
||||||
def test_search_strategy():
|
def test_search_strategy():
|
||||||
default_config = {}
|
default_config = {}
|
||||||
default_location = Path(__file__).parent.parent.parent.joinpath('strategy').resolve()
|
default_location = Path(__file__).parent.parent.parent.joinpath('strategy').resolve()
|
||||||
@ -96,16 +72,6 @@ def test_load_not_found_strategy(default_conf):
|
|||||||
strategy._load_strategy(strategy_name='NotFoundStrategy', config=default_conf)
|
strategy._load_strategy(strategy_name='NotFoundStrategy', config=default_conf)
|
||||||
|
|
||||||
|
|
||||||
def test_load_staticmethod_importerror(mocker, caplog, default_conf):
|
|
||||||
mocker.patch("freqtrade.resolvers.strategy_resolver.import_strategy", Mock(
|
|
||||||
side_effect=TypeError("can't pickle staticmethod objects")))
|
|
||||||
with pytest.raises(OperationalException,
|
|
||||||
match=r"Impossible to load Strategy 'DefaultStrategy'. "
|
|
||||||
r"This class does not exist or contains Python code errors."):
|
|
||||||
StrategyResolver(default_conf)
|
|
||||||
assert log_has_re(r".*Error: can't pickle staticmethod objects", caplog)
|
|
||||||
|
|
||||||
|
|
||||||
def test_strategy(result, default_conf):
|
def test_strategy(result, default_conf):
|
||||||
default_conf.update({'strategy': 'DefaultStrategy'})
|
default_conf.update({'strategy': 'DefaultStrategy'})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user