Merge branch 'feat/short' into pr/samgermain/5378
This commit is contained in:
@@ -16,7 +16,7 @@ def hyperopt_conf(default_conf):
|
||||
hyperconf.update({
|
||||
'datadir': Path(default_conf['datadir']),
|
||||
'runmode': RunMode.HYPEROPT,
|
||||
'hyperopt': 'HyperoptTestSepFile',
|
||||
'strategy': 'HyperoptableStrategy',
|
||||
'hyperopt_loss': 'ShortTradeDurHyperOptLoss',
|
||||
'hyperopt_path': str(Path(__file__).parent / 'hyperopts'),
|
||||
'epochs': 1,
|
||||
|
@@ -1,207 +0,0 @@
|
||||
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
|
||||
from functools import reduce
|
||||
from typing import Any, Callable, Dict, List
|
||||
|
||||
import talib.abstract as ta
|
||||
from pandas import DataFrame
|
||||
from skopt.space import Categorical, Dimension, Integer
|
||||
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||
|
||||
|
||||
class HyperoptTestSepFile(IHyperOpt):
|
||||
"""
|
||||
Default hyperopt provided by the Freqtrade bot.
|
||||
You can override it with your own Hyperopt
|
||||
"""
|
||||
@staticmethod
|
||||
def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Add several indicators needed for buy and sell strategies defined below.
|
||||
"""
|
||||
# ADX
|
||||
dataframe['adx'] = ta.ADX(dataframe)
|
||||
# MACD
|
||||
macd = ta.MACD(dataframe)
|
||||
dataframe['macd'] = macd['macd']
|
||||
dataframe['macdsignal'] = macd['macdsignal']
|
||||
# MFI
|
||||
dataframe['mfi'] = ta.MFI(dataframe)
|
||||
# RSI
|
||||
dataframe['rsi'] = ta.RSI(dataframe)
|
||||
# Stochastic Fast
|
||||
stoch_fast = ta.STOCHF(dataframe)
|
||||
dataframe['fastd'] = stoch_fast['fastd']
|
||||
# Minus-DI
|
||||
dataframe['minus_di'] = ta.MINUS_DI(dataframe)
|
||||
# Bollinger bands
|
||||
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||
dataframe['bb_lowerband'] = bollinger['lower']
|
||||
dataframe['bb_upperband'] = bollinger['upper']
|
||||
# SAR
|
||||
dataframe['sar'] = ta.SAR(dataframe)
|
||||
|
||||
return dataframe
|
||||
|
||||
@staticmethod
|
||||
def buy_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||
"""
|
||||
Define the buy strategy parameters to be used by Hyperopt.
|
||||
"""
|
||||
def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Buy strategy Hyperopt will build and use.
|
||||
"""
|
||||
conditions = []
|
||||
|
||||
# GUARDS AND TRENDS
|
||||
if 'mfi-enabled' in params and params['mfi-enabled']:
|
||||
conditions.append(dataframe['mfi'] < params['mfi-value'])
|
||||
if 'fastd-enabled' in params and params['fastd-enabled']:
|
||||
conditions.append(dataframe['fastd'] < params['fastd-value'])
|
||||
if 'adx-enabled' in params and params['adx-enabled']:
|
||||
conditions.append(dataframe['adx'] > params['adx-value'])
|
||||
if 'rsi-enabled' in params and params['rsi-enabled']:
|
||||
conditions.append(dataframe['rsi'] < params['rsi-value'])
|
||||
|
||||
# TRIGGERS
|
||||
if 'trigger' in params:
|
||||
if params['trigger'] == 'boll':
|
||||
conditions.append(dataframe['close'] < dataframe['bb_lowerband'])
|
||||
if params['trigger'] == 'macd_cross_signal':
|
||||
conditions.append(qtpylib.crossed_above(
|
||||
dataframe['macd'],
|
||||
dataframe['macdsignal']
|
||||
))
|
||||
if params['trigger'] == 'sar_reversal':
|
||||
conditions.append(qtpylib.crossed_above(
|
||||
dataframe['close'],
|
||||
dataframe['sar']
|
||||
))
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'buy'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
return populate_buy_trend
|
||||
|
||||
@staticmethod
|
||||
def indicator_space() -> List[Dimension]:
|
||||
"""
|
||||
Define your Hyperopt space for searching buy strategy parameters.
|
||||
"""
|
||||
return [
|
||||
Integer(10, 25, name='mfi-value'),
|
||||
Integer(15, 45, name='fastd-value'),
|
||||
Integer(20, 50, name='adx-value'),
|
||||
Integer(20, 40, name='rsi-value'),
|
||||
Categorical([True, False], name='mfi-enabled'),
|
||||
Categorical([True, False], name='fastd-enabled'),
|
||||
Categorical([True, False], name='adx-enabled'),
|
||||
Categorical([True, False], name='rsi-enabled'),
|
||||
Categorical(['boll', 'macd_cross_signal', 'sar_reversal'], name='trigger')
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def sell_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||
"""
|
||||
Define the sell strategy parameters to be used by Hyperopt.
|
||||
"""
|
||||
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Sell strategy Hyperopt will build and use.
|
||||
"""
|
||||
conditions = []
|
||||
|
||||
# GUARDS AND TRENDS
|
||||
if 'sell-mfi-enabled' in params and params['sell-mfi-enabled']:
|
||||
conditions.append(dataframe['mfi'] > params['sell-mfi-value'])
|
||||
if 'sell-fastd-enabled' in params and params['sell-fastd-enabled']:
|
||||
conditions.append(dataframe['fastd'] > params['sell-fastd-value'])
|
||||
if 'sell-adx-enabled' in params and params['sell-adx-enabled']:
|
||||
conditions.append(dataframe['adx'] < params['sell-adx-value'])
|
||||
if 'sell-rsi-enabled' in params and params['sell-rsi-enabled']:
|
||||
conditions.append(dataframe['rsi'] > params['sell-rsi-value'])
|
||||
|
||||
# TRIGGERS
|
||||
if 'sell-trigger' in params:
|
||||
if params['sell-trigger'] == 'sell-boll':
|
||||
conditions.append(dataframe['close'] > dataframe['bb_upperband'])
|
||||
if params['sell-trigger'] == 'sell-macd_cross_signal':
|
||||
conditions.append(qtpylib.crossed_above(
|
||||
dataframe['macdsignal'],
|
||||
dataframe['macd']
|
||||
))
|
||||
if params['sell-trigger'] == 'sell-sar_reversal':
|
||||
conditions.append(qtpylib.crossed_above(
|
||||
dataframe['sar'],
|
||||
dataframe['close']
|
||||
))
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'sell'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
return populate_sell_trend
|
||||
|
||||
@staticmethod
|
||||
def sell_indicator_space() -> List[Dimension]:
|
||||
"""
|
||||
Define your Hyperopt space for searching sell strategy parameters.
|
||||
"""
|
||||
return [
|
||||
Integer(75, 100, name='sell-mfi-value'),
|
||||
Integer(50, 100, name='sell-fastd-value'),
|
||||
Integer(50, 100, name='sell-adx-value'),
|
||||
Integer(60, 100, name='sell-rsi-value'),
|
||||
Categorical([True, False], name='sell-mfi-enabled'),
|
||||
Categorical([True, False], name='sell-fastd-enabled'),
|
||||
Categorical([True, False], name='sell-adx-enabled'),
|
||||
Categorical([True, False], name='sell-rsi-enabled'),
|
||||
Categorical(['sell-boll',
|
||||
'sell-macd_cross_signal',
|
||||
'sell-sar_reversal'],
|
||||
name='sell-trigger')
|
||||
]
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators. Should be a copy of same method from strategy.
|
||||
Must align to populate_indicators in this file.
|
||||
Only used when --spaces does not include buy space.
|
||||
"""
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['close'] < dataframe['bb_lowerband']) &
|
||||
(dataframe['mfi'] < 16) &
|
||||
(dataframe['adx'] > 25) &
|
||||
(dataframe['rsi'] < 21)
|
||||
),
|
||||
'buy'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators. Should be a copy of same method from strategy.
|
||||
Must align to populate_indicators in this file.
|
||||
Only used when --spaces does not include sell space.
|
||||
"""
|
||||
dataframe.loc[
|
||||
(
|
||||
(qtpylib.crossed_above(
|
||||
dataframe['macdsignal'], dataframe['macd']
|
||||
)) &
|
||||
(dataframe['fastd'] > 54)
|
||||
),
|
||||
'sell'] = 1
|
||||
|
||||
return dataframe
|
@@ -1,271 +0,0 @@
|
||||
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
|
||||
from functools import reduce
|
||||
from typing import Any, Callable, Dict, List
|
||||
|
||||
import talib.abstract as ta
|
||||
from pandas import DataFrame
|
||||
from skopt.space import Categorical, Dimension, Integer
|
||||
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||
|
||||
|
||||
class DefaultHyperOpt(IHyperOpt):
|
||||
"""
|
||||
Default hyperopt provided by the Freqtrade bot.
|
||||
You can override it with your own Hyperopt
|
||||
"""
|
||||
@staticmethod
|
||||
def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Add several indicators needed for buy and sell strategies defined below.
|
||||
"""
|
||||
# ADX
|
||||
dataframe['adx'] = ta.ADX(dataframe)
|
||||
# MACD
|
||||
macd = ta.MACD(dataframe)
|
||||
dataframe['macd'] = macd['macd']
|
||||
dataframe['macdsignal'] = macd['macdsignal']
|
||||
# MFI
|
||||
dataframe['mfi'] = ta.MFI(dataframe)
|
||||
# RSI
|
||||
dataframe['rsi'] = ta.RSI(dataframe)
|
||||
# Stochastic Fast
|
||||
stoch_fast = ta.STOCHF(dataframe)
|
||||
dataframe['fastd'] = stoch_fast['fastd']
|
||||
# Minus-DI
|
||||
dataframe['minus_di'] = ta.MINUS_DI(dataframe)
|
||||
# Bollinger bands
|
||||
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||
dataframe['bb_lowerband'] = bollinger['lower']
|
||||
dataframe['bb_upperband'] = bollinger['upper']
|
||||
# SAR
|
||||
dataframe['sar'] = ta.SAR(dataframe)
|
||||
|
||||
return dataframe
|
||||
|
||||
@staticmethod
|
||||
def buy_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||
"""
|
||||
Define the buy strategy parameters to be used by Hyperopt.
|
||||
"""
|
||||
def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Buy strategy Hyperopt will build and use.
|
||||
"""
|
||||
long_conditions = []
|
||||
short_conditions = []
|
||||
|
||||
# GUARDS AND TRENDS
|
||||
if 'mfi-enabled' in params and params['mfi-enabled']:
|
||||
long_conditions.append(dataframe['mfi'] < params['mfi-value'])
|
||||
short_conditions.append(dataframe['mfi'] > params['short-mfi-value'])
|
||||
if 'fastd-enabled' in params and params['fastd-enabled']:
|
||||
long_conditions.append(dataframe['fastd'] < params['fastd-value'])
|
||||
short_conditions.append(dataframe['fastd'] > params['short-fastd-value'])
|
||||
if 'adx-enabled' in params and params['adx-enabled']:
|
||||
long_conditions.append(dataframe['adx'] > params['adx-value'])
|
||||
short_conditions.append(dataframe['adx'] < params['short-adx-value'])
|
||||
if 'rsi-enabled' in params and params['rsi-enabled']:
|
||||
long_conditions.append(dataframe['rsi'] < params['rsi-value'])
|
||||
short_conditions.append(dataframe['rsi'] > params['short-rsi-value'])
|
||||
|
||||
# TRIGGERS
|
||||
if 'trigger' in params:
|
||||
if params['trigger'] == 'boll':
|
||||
long_conditions.append(dataframe['close'] < dataframe['bb_lowerband'])
|
||||
short_conditions.append(dataframe['close'] > dataframe['bb_upperband'])
|
||||
if params['trigger'] == 'macd_cross_signal':
|
||||
long_conditions.append(qtpylib.crossed_above(
|
||||
dataframe['macd'],
|
||||
dataframe['macdsignal']
|
||||
))
|
||||
short_conditions.append(qtpylib.crossed_below(
|
||||
dataframe['macd'],
|
||||
dataframe['macdsignal']
|
||||
))
|
||||
if params['trigger'] == 'sar_reversal':
|
||||
long_conditions.append(qtpylib.crossed_above(
|
||||
dataframe['close'],
|
||||
dataframe['sar']
|
||||
))
|
||||
short_conditions.append(qtpylib.crossed_below(
|
||||
dataframe['close'],
|
||||
dataframe['sar']
|
||||
))
|
||||
|
||||
if long_conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, long_conditions),
|
||||
'buy'] = 1
|
||||
|
||||
if short_conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, short_conditions),
|
||||
'enter_short'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
return populate_buy_trend
|
||||
|
||||
@staticmethod
|
||||
def indicator_space() -> List[Dimension]:
|
||||
"""
|
||||
Define your Hyperopt space for searching buy strategy parameters.
|
||||
"""
|
||||
return [
|
||||
Integer(10, 25, name='mfi-value'),
|
||||
Integer(15, 45, name='fastd-value'),
|
||||
Integer(20, 50, name='adx-value'),
|
||||
Integer(20, 40, name='rsi-value'),
|
||||
Integer(75, 90, name='short-mfi-value'),
|
||||
Integer(55, 85, name='short-fastd-value'),
|
||||
Integer(50, 80, name='short-adx-value'),
|
||||
Integer(60, 80, name='short-rsi-value'),
|
||||
Categorical([True, False], name='mfi-enabled'),
|
||||
Categorical([True, False], name='fastd-enabled'),
|
||||
Categorical([True, False], name='adx-enabled'),
|
||||
Categorical([True, False], name='rsi-enabled'),
|
||||
Categorical(['boll', 'macd_cross_signal', 'sar_reversal'], name='trigger')
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def sell_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||
"""
|
||||
Define the sell strategy parameters to be used by Hyperopt.
|
||||
"""
|
||||
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Sell strategy Hyperopt will build and use.
|
||||
"""
|
||||
exit_long_conditions = []
|
||||
exit_short_conditions = []
|
||||
|
||||
# GUARDS AND TRENDS
|
||||
if 'sell-mfi-enabled' in params and params['sell-mfi-enabled']:
|
||||
exit_long_conditions.append(dataframe['mfi'] > params['sell-mfi-value'])
|
||||
exit_short_conditions.append(dataframe['mfi'] < params['exit-short-mfi-value'])
|
||||
if 'sell-fastd-enabled' in params and params['sell-fastd-enabled']:
|
||||
exit_long_conditions.append(dataframe['fastd'] > params['sell-fastd-value'])
|
||||
exit_short_conditions.append(dataframe['fastd'] < params['exit-short-fastd-value'])
|
||||
if 'sell-adx-enabled' in params and params['sell-adx-enabled']:
|
||||
exit_long_conditions.append(dataframe['adx'] < params['sell-adx-value'])
|
||||
exit_short_conditions.append(dataframe['adx'] > params['exit-short-adx-value'])
|
||||
if 'sell-rsi-enabled' in params and params['sell-rsi-enabled']:
|
||||
exit_long_conditions.append(dataframe['rsi'] > params['sell-rsi-value'])
|
||||
exit_short_conditions.append(dataframe['rsi'] < params['exit-short-rsi-value'])
|
||||
|
||||
# TRIGGERS
|
||||
if 'sell-trigger' in params:
|
||||
if params['sell-trigger'] == 'sell-boll':
|
||||
exit_long_conditions.append(dataframe['close'] > dataframe['bb_upperband'])
|
||||
exit_short_conditions.append(dataframe['close'] < dataframe['bb_lowerband'])
|
||||
if params['sell-trigger'] == 'sell-macd_cross_signal':
|
||||
exit_long_conditions.append(qtpylib.crossed_above(
|
||||
dataframe['macdsignal'],
|
||||
dataframe['macd']
|
||||
))
|
||||
exit_short_conditions.append(qtpylib.crossed_below(
|
||||
dataframe['macdsignal'],
|
||||
dataframe['macd']
|
||||
))
|
||||
if params['sell-trigger'] == 'sell-sar_reversal':
|
||||
exit_long_conditions.append(qtpylib.crossed_above(
|
||||
dataframe['sar'],
|
||||
dataframe['close']
|
||||
))
|
||||
exit_short_conditions.append(qtpylib.crossed_below(
|
||||
dataframe['sar'],
|
||||
dataframe['close']
|
||||
))
|
||||
|
||||
if exit_long_conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, exit_long_conditions),
|
||||
'sell'] = 1
|
||||
|
||||
if exit_short_conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, exit_short_conditions),
|
||||
'exit-short'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
return populate_sell_trend
|
||||
|
||||
@staticmethod
|
||||
def sell_indicator_space() -> List[Dimension]:
|
||||
"""
|
||||
Define your Hyperopt space for searching sell strategy parameters.
|
||||
"""
|
||||
return [
|
||||
Integer(75, 100, name='sell-mfi-value'),
|
||||
Integer(50, 100, name='sell-fastd-value'),
|
||||
Integer(50, 100, name='sell-adx-value'),
|
||||
Integer(60, 100, name='sell-rsi-value'),
|
||||
Integer(1, 25, name='exit-short-mfi-value'),
|
||||
Integer(1, 50, name='exit-short-fastd-value'),
|
||||
Integer(1, 50, name='exit-short-adx-value'),
|
||||
Integer(1, 40, name='exit-short-rsi-value'),
|
||||
Categorical([True, False], name='sell-mfi-enabled'),
|
||||
Categorical([True, False], name='sell-fastd-enabled'),
|
||||
Categorical([True, False], name='sell-adx-enabled'),
|
||||
Categorical([True, False], name='sell-rsi-enabled'),
|
||||
Categorical(['sell-boll',
|
||||
'sell-macd_cross_signal',
|
||||
'sell-sar_reversal'],
|
||||
name='sell-trigger')
|
||||
]
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators. Should be a copy of same method from strategy.
|
||||
Must align to populate_indicators in this file.
|
||||
Only used when --spaces does not include buy space.
|
||||
"""
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['close'] < dataframe['bb_lowerband']) &
|
||||
(dataframe['mfi'] < 16) &
|
||||
(dataframe['adx'] > 25) &
|
||||
(dataframe['rsi'] < 21)
|
||||
),
|
||||
'buy'] = 1
|
||||
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['close'] > dataframe['bb_upperband']) &
|
||||
(dataframe['mfi'] < 84) &
|
||||
(dataframe['adx'] > 75) &
|
||||
(dataframe['rsi'] < 79)
|
||||
),
|
||||
'enter_short'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators. Should be a copy of same method from strategy.
|
||||
Must align to populate_indicators in this file.
|
||||
Only used when --spaces does not include sell space.
|
||||
"""
|
||||
dataframe.loc[
|
||||
(
|
||||
(qtpylib.crossed_above(
|
||||
dataframe['macdsignal'], dataframe['macd']
|
||||
)) &
|
||||
(dataframe['fastd'] > 54)
|
||||
),
|
||||
'sell'] = 1
|
||||
|
||||
dataframe.loc[
|
||||
(
|
||||
(qtpylib.crossed_below(
|
||||
dataframe['macdsignal'], dataframe['macd']
|
||||
)) &
|
||||
(dataframe['fastd'] < 46)
|
||||
),
|
||||
'exit_short'] = 1
|
||||
|
||||
return dataframe
|
@@ -17,13 +17,10 @@ from freqtrade.optimize.hyperopt_auto import HyperOptAuto
|
||||
from freqtrade.optimize.hyperopt_tools import HyperoptTools
|
||||
from freqtrade.optimize.optimize_reports import generate_strategy_stats
|
||||
from freqtrade.optimize.space import SKDecimal
|
||||
from freqtrade.resolvers.hyperopt_resolver import HyperOptResolver
|
||||
from freqtrade.strategy.hyper import IntParameter
|
||||
from tests.conftest import (get_args, log_has, log_has_re, patch_exchange,
|
||||
patched_configuration_load_config_file)
|
||||
|
||||
from .hyperopts.hyperopt_test_sep_file import HyperoptTestSepFile
|
||||
|
||||
|
||||
# TODO-lev: This file
|
||||
|
||||
@@ -34,7 +31,7 @@ def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, ca
|
||||
args = [
|
||||
'hyperopt',
|
||||
'--config', 'config.json',
|
||||
'--hyperopt', 'HyperoptTestSepFile',
|
||||
'--strategy', 'HyperoptableStrategy',
|
||||
]
|
||||
|
||||
config = setup_optimize_configuration(get_args(args), RunMode.HYPEROPT)
|
||||
@@ -66,7 +63,7 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo
|
||||
args = [
|
||||
'hyperopt',
|
||||
'--config', 'config.json',
|
||||
'--hyperopt', 'HyperoptTestSepFile',
|
||||
'--strategy', 'HyperoptableStrategy',
|
||||
'--datadir', '/foo/bar',
|
||||
'--timeframe', '1m',
|
||||
'--timerange', ':100',
|
||||
@@ -118,7 +115,7 @@ def test_setup_hyperopt_configuration_stake_amount(mocker, default_conf) -> None
|
||||
args = [
|
||||
'hyperopt',
|
||||
'--config', 'config.json',
|
||||
'--hyperopt', 'HyperoptTestSepFile',
|
||||
'--strategy', 'HyperoptableStrategy',
|
||||
'--stake-amount', '1',
|
||||
'--starting-balance', '2'
|
||||
]
|
||||
@@ -136,47 +133,6 @@ def test_setup_hyperopt_configuration_stake_amount(mocker, default_conf) -> None
|
||||
setup_optimize_configuration(get_args(args), RunMode.HYPEROPT)
|
||||
|
||||
|
||||
def test_hyperoptresolver(mocker, default_conf, caplog) -> None:
|
||||
patched_configuration_load_config_file(mocker, default_conf)
|
||||
|
||||
hyperopt = HyperoptTestSepFile
|
||||
delattr(hyperopt, 'populate_indicators')
|
||||
delattr(hyperopt, 'populate_buy_trend')
|
||||
delattr(hyperopt, 'populate_sell_trend')
|
||||
mocker.patch(
|
||||
'freqtrade.resolvers.hyperopt_resolver.HyperOptResolver.load_object',
|
||||
MagicMock(return_value=hyperopt(default_conf))
|
||||
)
|
||||
default_conf.update({'hyperopt': 'HyperoptTestSepFile'})
|
||||
x = HyperOptResolver.load_hyperopt(default_conf)
|
||||
assert not hasattr(x, 'populate_indicators')
|
||||
assert not hasattr(x, 'populate_buy_trend')
|
||||
assert not hasattr(x, 'populate_sell_trend')
|
||||
assert log_has("Hyperopt class does not provide populate_indicators() method. "
|
||||
"Using populate_indicators from the strategy.", caplog)
|
||||
assert log_has("Hyperopt class does not provide populate_sell_trend() method. "
|
||||
"Using populate_sell_trend from the strategy.", caplog)
|
||||
assert log_has("Hyperopt class does not provide populate_buy_trend() method. "
|
||||
"Using populate_buy_trend from the strategy.", caplog)
|
||||
assert hasattr(x, "ticker_interval") # DEPRECATED
|
||||
assert hasattr(x, "timeframe")
|
||||
|
||||
|
||||
def test_hyperoptresolver_wrongname(default_conf) -> None:
|
||||
default_conf.update({'hyperopt': "NonExistingHyperoptClass"})
|
||||
|
||||
with pytest.raises(OperationalException, match=r'Impossible to load Hyperopt.*'):
|
||||
HyperOptResolver.load_hyperopt(default_conf)
|
||||
|
||||
|
||||
def test_hyperoptresolver_noname(default_conf):
|
||||
default_conf['hyperopt'] = ''
|
||||
with pytest.raises(OperationalException,
|
||||
match="No Hyperopt set. Please use `--hyperopt` to specify "
|
||||
"the Hyperopt class to use."):
|
||||
HyperOptResolver.load_hyperopt(default_conf)
|
||||
|
||||
|
||||
def test_start_not_installed(mocker, default_conf, import_fails) -> None:
|
||||
start_mock = MagicMock()
|
||||
patched_configuration_load_config_file(mocker, default_conf)
|
||||
@@ -187,9 +143,7 @@ def test_start_not_installed(mocker, default_conf, import_fails) -> None:
|
||||
args = [
|
||||
'hyperopt',
|
||||
'--config', 'config.json',
|
||||
'--hyperopt', 'HyperoptTestSepFile',
|
||||
'--hyperopt-path',
|
||||
str(Path(__file__).parent / "hyperopts"),
|
||||
'--strategy', 'HyperoptableStrategy',
|
||||
'--epochs', '5',
|
||||
'--hyperopt-loss', 'SharpeHyperOptLossDaily',
|
||||
]
|
||||
@@ -199,7 +153,7 @@ def test_start_not_installed(mocker, default_conf, import_fails) -> None:
|
||||
start_hyperopt(pargs)
|
||||
|
||||
|
||||
def test_start(mocker, hyperopt_conf, caplog) -> None:
|
||||
def test_start_no_hyperopt_allowed(mocker, hyperopt_conf, caplog) -> None:
|
||||
start_mock = MagicMock()
|
||||
patched_configuration_load_config_file(mocker, hyperopt_conf)
|
||||
mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock)
|
||||
@@ -213,10 +167,8 @@ def test_start(mocker, hyperopt_conf, caplog) -> None:
|
||||
'--epochs', '5'
|
||||
]
|
||||
pargs = get_args(args)
|
||||
start_hyperopt(pargs)
|
||||
|
||||
assert log_has('Starting freqtrade in Hyperopt mode', caplog)
|
||||
assert start_mock.call_count == 1
|
||||
with pytest.raises(OperationalException, match=r"Using separate Hyperopt files has been.*"):
|
||||
start_hyperopt(pargs)
|
||||
|
||||
|
||||
def test_start_no_data(mocker, hyperopt_conf) -> None:
|
||||
@@ -228,11 +180,11 @@ def test_start_no_data(mocker, hyperopt_conf) -> None:
|
||||
)
|
||||
|
||||
patch_exchange(mocker)
|
||||
|
||||
# TODO: migrate to strategy-based hyperopt
|
||||
args = [
|
||||
'hyperopt',
|
||||
'--config', 'config.json',
|
||||
'--hyperopt', 'HyperoptTestSepFile',
|
||||
'--strategy', 'HyperoptableStrategy',
|
||||
'--hyperopt-loss', 'SharpeHyperOptLossDaily',
|
||||
'--epochs', '5'
|
||||
]
|
||||
@@ -250,7 +202,7 @@ def test_start_filelock(mocker, hyperopt_conf, caplog) -> None:
|
||||
args = [
|
||||
'hyperopt',
|
||||
'--config', 'config.json',
|
||||
'--hyperopt', 'HyperoptTestSepFile',
|
||||
'--strategy', 'HyperoptableStrategy',
|
||||
'--hyperopt-loss', 'SharpeHyperOptLossDaily',
|
||||
'--epochs', '5'
|
||||
]
|
||||
@@ -430,74 +382,14 @@ def test_hyperopt_format_results(hyperopt):
|
||||
def test_populate_indicators(hyperopt, testdatadir) -> None:
|
||||
data = load_data(testdatadir, '1m', ['UNITTEST/BTC'], fill_up_missing=True)
|
||||
dataframes = hyperopt.backtesting.strategy.advise_all_indicators(data)
|
||||
dataframe = hyperopt.custom_hyperopt.populate_indicators(dataframes['UNITTEST/BTC'],
|
||||
{'pair': 'UNITTEST/BTC'})
|
||||
dataframe = dataframes['UNITTEST/BTC']
|
||||
|
||||
# Check if some indicators are generated. We will not test all of them
|
||||
assert 'adx' in dataframe
|
||||
assert 'mfi' in dataframe
|
||||
assert 'macd' in dataframe
|
||||
assert 'rsi' in dataframe
|
||||
|
||||
|
||||
def test_buy_strategy_generator(hyperopt, testdatadir) -> None:
|
||||
data = load_data(testdatadir, '1m', ['UNITTEST/BTC'], fill_up_missing=True)
|
||||
dataframes = hyperopt.backtesting.strategy.advise_all_indicators(data)
|
||||
dataframe = hyperopt.custom_hyperopt.populate_indicators(dataframes['UNITTEST/BTC'],
|
||||
{'pair': 'UNITTEST/BTC'})
|
||||
|
||||
populate_buy_trend = hyperopt.custom_hyperopt.buy_strategy_generator(
|
||||
{
|
||||
'adx-value': 20,
|
||||
'fastd-value': 20,
|
||||
'mfi-value': 20,
|
||||
'rsi-value': 20,
|
||||
'short-adx-value': 80,
|
||||
'short-fastd-value': 80,
|
||||
'short-mfi-value': 80,
|
||||
'short-rsi-value': 80,
|
||||
'adx-enabled': True,
|
||||
'fastd-enabled': True,
|
||||
'mfi-enabled': True,
|
||||
'rsi-enabled': True,
|
||||
'trigger': 'bb_lower'
|
||||
}
|
||||
)
|
||||
result = populate_buy_trend(dataframe, {'pair': 'UNITTEST/BTC'})
|
||||
# Check if some indicators are generated. We will not test all of them
|
||||
assert 'buy' in result
|
||||
assert 1 in result['buy']
|
||||
|
||||
|
||||
def test_sell_strategy_generator(hyperopt, testdatadir) -> None:
|
||||
data = load_data(testdatadir, '1m', ['UNITTEST/BTC'], fill_up_missing=True)
|
||||
dataframes = hyperopt.backtesting.strategy.advise_all_indicators(data)
|
||||
dataframe = hyperopt.custom_hyperopt.populate_indicators(dataframes['UNITTEST/BTC'],
|
||||
{'pair': 'UNITTEST/BTC'})
|
||||
|
||||
populate_sell_trend = hyperopt.custom_hyperopt.sell_strategy_generator(
|
||||
{
|
||||
'sell-adx-value': 20,
|
||||
'sell-fastd-value': 75,
|
||||
'sell-mfi-value': 80,
|
||||
'sell-rsi-value': 20,
|
||||
'exit-short-adx-value': 80,
|
||||
'exit-short-fastd-value': 25,
|
||||
'exit-short-mfi-value': 20,
|
||||
'exit-short-rsi-value': 80,
|
||||
'sell-adx-enabled': True,
|
||||
'sell-fastd-enabled': True,
|
||||
'sell-mfi-enabled': True,
|
||||
'sell-rsi-enabled': True,
|
||||
'sell-trigger': 'sell-bb_upper'
|
||||
}
|
||||
)
|
||||
result = populate_sell_trend(dataframe, {'pair': 'UNITTEST/BTC'})
|
||||
# Check if some indicators are generated. We will not test all of them
|
||||
print(result)
|
||||
assert 'sell' in result
|
||||
assert 1 in result['sell']
|
||||
|
||||
|
||||
def test_generate_optimizer(mocker, hyperopt_conf) -> None:
|
||||
hyperopt_conf.update({'spaces': 'all',
|
||||
'hyperopt_min_trades': 1,
|
||||
@@ -538,24 +430,12 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None:
|
||||
mocker.patch('freqtrade.optimize.hyperopt.load', return_value={'XRP/BTC': None})
|
||||
|
||||
optimizer_param = {
|
||||
'adx-value': 0,
|
||||
'fastd-value': 35,
|
||||
'mfi-value': 0,
|
||||
'rsi-value': 0,
|
||||
'adx-enabled': False,
|
||||
'fastd-enabled': True,
|
||||
'mfi-enabled': False,
|
||||
'rsi-enabled': False,
|
||||
'trigger': 'macd_cross_signal',
|
||||
'sell-adx-value': 0,
|
||||
'sell-fastd-value': 75,
|
||||
'sell-mfi-value': 0,
|
||||
'sell-rsi-value': 0,
|
||||
'sell-adx-enabled': False,
|
||||
'sell-fastd-enabled': True,
|
||||
'sell-mfi-enabled': False,
|
||||
'sell-rsi-enabled': False,
|
||||
'sell-trigger': 'macd_cross_signal',
|
||||
'buy_plusdi': 0.02,
|
||||
'buy_rsi': 35,
|
||||
'sell_minusdi': 0.02,
|
||||
'sell_rsi': 75,
|
||||
'protection_cooldown_lookback': 20,
|
||||
'protection_enabled': True,
|
||||
'roi_t1': 60.0,
|
||||
'roi_t2': 30.0,
|
||||
'roi_t3': 20.0,
|
||||
@@ -575,29 +455,19 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None:
|
||||
'0.00003100 BTC ( 0.00%). '
|
||||
'Avg duration 0:50:00 min.'
|
||||
),
|
||||
'params_details': {'buy': {'adx-enabled': False,
|
||||
'adx-value': 0,
|
||||
'fastd-enabled': True,
|
||||
'fastd-value': 35,
|
||||
'mfi-enabled': False,
|
||||
'mfi-value': 0,
|
||||
'rsi-enabled': False,
|
||||
'rsi-value': 0,
|
||||
'trigger': 'macd_cross_signal'},
|
||||
'params_details': {'buy': {'buy_plusdi': 0.02,
|
||||
'buy_rsi': 35,
|
||||
},
|
||||
'roi': {"0": 0.12000000000000001,
|
||||
"20.0": 0.02,
|
||||
"50.0": 0.01,
|
||||
"110.0": 0},
|
||||
'protection': {},
|
||||
'sell': {'sell-adx-enabled': False,
|
||||
'sell-adx-value': 0,
|
||||
'sell-fastd-enabled': True,
|
||||
'sell-fastd-value': 75,
|
||||
'sell-mfi-enabled': False,
|
||||
'sell-mfi-value': 0,
|
||||
'sell-rsi-enabled': False,
|
||||
'sell-rsi-value': 0,
|
||||
'sell-trigger': 'macd_cross_signal'},
|
||||
'protection': {'protection_cooldown_lookback': 20,
|
||||
'protection_enabled': True,
|
||||
},
|
||||
'sell': {'sell_minusdi': 0.02,
|
||||
'sell_rsi': 75,
|
||||
},
|
||||
'stoploss': {'stoploss': -0.4},
|
||||
'trailing': {'trailing_only_offset_is_reached': False,
|
||||
'trailing_stop': True,
|
||||
@@ -819,11 +689,6 @@ def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> Non
|
||||
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
|
||||
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
|
||||
|
||||
del hyperopt.custom_hyperopt.__class__.buy_strategy_generator
|
||||
del hyperopt.custom_hyperopt.__class__.sell_strategy_generator
|
||||
del hyperopt.custom_hyperopt.__class__.indicator_space
|
||||
del hyperopt.custom_hyperopt.__class__.sell_indicator_space
|
||||
|
||||
hyperopt.start()
|
||||
|
||||
parallel.assert_called_once()
|
||||
@@ -854,16 +719,14 @@ def test_simplified_interface_all_failed(mocker, hyperopt_conf) -> None:
|
||||
|
||||
hyperopt_conf.update({'spaces': 'all', })
|
||||
|
||||
mocker.patch('freqtrade.optimize.hyperopt_auto.HyperOptAuto._generate_indicator_space',
|
||||
return_value=[])
|
||||
|
||||
hyperopt = Hyperopt(hyperopt_conf)
|
||||
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
|
||||
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
|
||||
|
||||
del hyperopt.custom_hyperopt.__class__.buy_strategy_generator
|
||||
del hyperopt.custom_hyperopt.__class__.sell_strategy_generator
|
||||
del hyperopt.custom_hyperopt.__class__.indicator_space
|
||||
del hyperopt.custom_hyperopt.__class__.sell_indicator_space
|
||||
|
||||
with pytest.raises(OperationalException, match=r"The 'buy' space is included into *"):
|
||||
with pytest.raises(OperationalException, match=r"The 'protection' space is included into *"):
|
||||
hyperopt.start()
|
||||
|
||||
|
||||
@@ -900,11 +763,6 @@ def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None:
|
||||
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
|
||||
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
|
||||
|
||||
# TODO: sell_strategy_generator() is actually not called because
|
||||
# run_optimizer_parallel() is mocked
|
||||
del hyperopt.custom_hyperopt.__class__.sell_strategy_generator
|
||||
del hyperopt.custom_hyperopt.__class__.sell_indicator_space
|
||||
|
||||
hyperopt.start()
|
||||
|
||||
parallel.assert_called_once()
|
||||
@@ -954,11 +812,6 @@ def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None:
|
||||
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
|
||||
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
|
||||
|
||||
# TODO: buy_strategy_generator() is actually not called because
|
||||
# run_optimizer_parallel() is mocked
|
||||
del hyperopt.custom_hyperopt.__class__.buy_strategy_generator
|
||||
del hyperopt.custom_hyperopt.__class__.indicator_space
|
||||
|
||||
hyperopt.start()
|
||||
|
||||
parallel.assert_called_once()
|
||||
@@ -975,13 +828,12 @@ def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None:
|
||||
assert hasattr(hyperopt, "position_stacking")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("method,space", [
|
||||
('buy_strategy_generator', 'buy'),
|
||||
('indicator_space', 'buy'),
|
||||
('sell_strategy_generator', 'sell'),
|
||||
('sell_indicator_space', 'sell'),
|
||||
@pytest.mark.parametrize("space", [
|
||||
('buy'),
|
||||
('sell'),
|
||||
('protection'),
|
||||
])
|
||||
def test_simplified_interface_failed(mocker, hyperopt_conf, method, space) -> None:
|
||||
def test_simplified_interface_failed(mocker, hyperopt_conf, space) -> None:
|
||||
mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock())
|
||||
mocker.patch('freqtrade.optimize.hyperopt.file_dump_json')
|
||||
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
|
||||
@@ -990,6 +842,8 @@ def test_simplified_interface_failed(mocker, hyperopt_conf, method, space) -> No
|
||||
'freqtrade.optimize.hyperopt.get_timerange',
|
||||
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
|
||||
)
|
||||
mocker.patch('freqtrade.optimize.hyperopt_auto.HyperOptAuto._generate_indicator_space',
|
||||
return_value=[])
|
||||
|
||||
patch_exchange(mocker)
|
||||
|
||||
@@ -999,8 +853,6 @@ def test_simplified_interface_failed(mocker, hyperopt_conf, method, space) -> No
|
||||
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
|
||||
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
|
||||
|
||||
delattr(hyperopt.custom_hyperopt.__class__, method)
|
||||
|
||||
with pytest.raises(OperationalException, match=f"The '{space}' space is included into *"):
|
||||
hyperopt.start()
|
||||
|
||||
@@ -1010,7 +862,6 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None:
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
||||
(Path(tmpdir) / 'hyperopt_results').mkdir(parents=True)
|
||||
# No hyperopt needed
|
||||
del hyperopt_conf['hyperopt']
|
||||
hyperopt_conf.update({
|
||||
'strategy': 'HyperoptableStrategy',
|
||||
'user_data_dir': Path(tmpdir),
|
||||
@@ -1036,6 +887,10 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None:
|
||||
assert hyperopt.backtesting.strategy.buy_rsi.value != 35
|
||||
assert hyperopt.backtesting.strategy.sell_rsi.value != 74
|
||||
|
||||
hyperopt.custom_hyperopt.generate_estimator = lambda *args, **kwargs: 'ET1'
|
||||
with pytest.raises(OperationalException, match="Estimator ET1 not supported."):
|
||||
hyperopt.get_optimizer([], 2)
|
||||
|
||||
|
||||
def test_SKDecimal():
|
||||
space = SKDecimal(1, 2, decimals=2)
|
||||
|
Reference in New Issue
Block a user