Merge pull request #5566 from freqtrade/remove_hyperopt
Remove legacy hyperopt
This commit is contained in:
@@ -11,11 +11,11 @@ from freqtrade.commands.build_config_commands import start_new_config
|
||||
from freqtrade.commands.data_commands import (start_convert_data, start_download_data,
|
||||
start_list_data)
|
||||
from freqtrade.commands.deploy_commands import (start_create_userdir, start_install_ui,
|
||||
start_new_hyperopt, start_new_strategy)
|
||||
start_new_strategy)
|
||||
from freqtrade.commands.hyperopt_commands import start_hyperopt_list, start_hyperopt_show
|
||||
from freqtrade.commands.list_commands import (start_list_exchanges, start_list_hyperopts,
|
||||
start_list_markets, start_list_strategies,
|
||||
start_list_timeframes, start_show_trades)
|
||||
from freqtrade.commands.list_commands import (start_list_exchanges, start_list_markets,
|
||||
start_list_strategies, start_list_timeframes,
|
||||
start_show_trades)
|
||||
from freqtrade.commands.optimize_commands import start_backtesting, start_edge, start_hyperopt
|
||||
from freqtrade.commands.pairlist_commands import start_test_pairlist
|
||||
from freqtrade.commands.plot_commands import start_plot_dataframe, start_plot_profit
|
||||
|
@@ -55,8 +55,6 @@ ARGS_BUILD_CONFIG = ["config"]
|
||||
|
||||
ARGS_BUILD_STRATEGY = ["user_data_dir", "strategy", "template"]
|
||||
|
||||
ARGS_BUILD_HYPEROPT = ["user_data_dir", "hyperopt", "template"]
|
||||
|
||||
ARGS_CONVERT_DATA = ["pairs", "format_from", "format_to", "erase"]
|
||||
ARGS_CONVERT_DATA_OHLCV = ARGS_CONVERT_DATA + ["timeframes"]
|
||||
|
||||
@@ -92,10 +90,10 @@ ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperop
|
||||
|
||||
NO_CONF_REQURIED = ["convert-data", "convert-trade-data", "download-data", "list-timeframes",
|
||||
"list-markets", "list-pairs", "list-strategies", "list-data",
|
||||
"list-hyperopts", "hyperopt-list", "hyperopt-show",
|
||||
"hyperopt-list", "hyperopt-show",
|
||||
"plot-dataframe", "plot-profit", "show-trades"]
|
||||
|
||||
NO_CONF_ALLOWED = ["create-userdir", "list-exchanges", "new-hyperopt", "new-strategy"]
|
||||
NO_CONF_ALLOWED = ["create-userdir", "list-exchanges", "new-strategy"]
|
||||
|
||||
|
||||
class Arguments:
|
||||
@@ -174,12 +172,11 @@ class Arguments:
|
||||
from freqtrade.commands import (start_backtesting, start_convert_data, start_create_userdir,
|
||||
start_download_data, start_edge, start_hyperopt,
|
||||
start_hyperopt_list, start_hyperopt_show, start_install_ui,
|
||||
start_list_data, start_list_exchanges, start_list_hyperopts,
|
||||
start_list_markets, start_list_strategies,
|
||||
start_list_timeframes, start_new_config, start_new_hyperopt,
|
||||
start_new_strategy, start_plot_dataframe, start_plot_profit,
|
||||
start_show_trades, start_test_pairlist, start_trading,
|
||||
start_webserver)
|
||||
start_list_data, start_list_exchanges, start_list_markets,
|
||||
start_list_strategies, start_list_timeframes,
|
||||
start_new_config, start_new_strategy, start_plot_dataframe,
|
||||
start_plot_profit, start_show_trades, start_test_pairlist,
|
||||
start_trading, start_webserver)
|
||||
|
||||
subparsers = self.parser.add_subparsers(dest='command',
|
||||
# Use custom message when no subhandler is added
|
||||
@@ -206,12 +203,6 @@ class Arguments:
|
||||
build_config_cmd.set_defaults(func=start_new_config)
|
||||
self._build_args(optionlist=ARGS_BUILD_CONFIG, parser=build_config_cmd)
|
||||
|
||||
# add new-hyperopt subcommand
|
||||
build_hyperopt_cmd = subparsers.add_parser('new-hyperopt',
|
||||
help="Create new hyperopt")
|
||||
build_hyperopt_cmd.set_defaults(func=start_new_hyperopt)
|
||||
self._build_args(optionlist=ARGS_BUILD_HYPEROPT, parser=build_hyperopt_cmd)
|
||||
|
||||
# add new-strategy subcommand
|
||||
build_strategy_cmd = subparsers.add_parser('new-strategy',
|
||||
help="Create new strategy")
|
||||
@@ -300,15 +291,6 @@ class Arguments:
|
||||
list_exchanges_cmd.set_defaults(func=start_list_exchanges)
|
||||
self._build_args(optionlist=ARGS_LIST_EXCHANGES, parser=list_exchanges_cmd)
|
||||
|
||||
# Add list-hyperopts subcommand
|
||||
list_hyperopts_cmd = subparsers.add_parser(
|
||||
'list-hyperopts',
|
||||
help='Print available hyperopt classes.',
|
||||
parents=[_common_parser],
|
||||
)
|
||||
list_hyperopts_cmd.set_defaults(func=start_list_hyperopts)
|
||||
self._build_args(optionlist=ARGS_LIST_HYPEROPTS, parser=list_hyperopts_cmd)
|
||||
|
||||
# Add list-markets subcommand
|
||||
list_markets_cmd = subparsers.add_parser(
|
||||
'list-markets',
|
||||
|
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
Definition of cli arguments used in arguments.py
|
||||
"""
|
||||
from argparse import ArgumentTypeError
|
||||
from argparse import SUPPRESS, ArgumentTypeError
|
||||
|
||||
from freqtrade import __version__, constants
|
||||
from freqtrade.constants import HYPEROPT_LOSS_BUILTIN
|
||||
@@ -203,13 +203,13 @@ AVAILABLE_CLI_OPTIONS = {
|
||||
# Hyperopt
|
||||
"hyperopt": Arg(
|
||||
'--hyperopt',
|
||||
help='Specify hyperopt class name which will be used by the bot.',
|
||||
help=SUPPRESS,
|
||||
metavar='NAME',
|
||||
required=False,
|
||||
),
|
||||
"hyperopt_path": Arg(
|
||||
'--hyperopt-path',
|
||||
help='Specify additional lookup path for Hyperopt and Hyperopt Loss functions.',
|
||||
help='Specify additional lookup path for Hyperopt Loss functions.',
|
||||
metavar='PATH',
|
||||
),
|
||||
"epochs": Arg(
|
||||
|
@@ -7,7 +7,7 @@ import requests
|
||||
|
||||
from freqtrade.configuration import setup_utils_configuration
|
||||
from freqtrade.configuration.directory_operations import copy_sample_files, create_userdata_dir
|
||||
from freqtrade.constants import USERPATH_HYPEROPTS, USERPATH_STRATEGIES
|
||||
from freqtrade.constants import USERPATH_STRATEGIES
|
||||
from freqtrade.enums import RunMode
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.misc import render_template, render_template_with_fallback
|
||||
@@ -87,56 +87,6 @@ def start_new_strategy(args: Dict[str, Any]) -> None:
|
||||
raise OperationalException("`new-strategy` requires --strategy to be set.")
|
||||
|
||||
|
||||
def deploy_new_hyperopt(hyperopt_name: str, hyperopt_path: Path, subtemplate: str) -> None:
|
||||
"""
|
||||
Deploys a new hyperopt template to hyperopt_path
|
||||
"""
|
||||
fallback = 'full'
|
||||
buy_guards = render_template_with_fallback(
|
||||
templatefile=f"subtemplates/hyperopt_buy_guards_{subtemplate}.j2",
|
||||
templatefallbackfile=f"subtemplates/hyperopt_buy_guards_{fallback}.j2",
|
||||
)
|
||||
sell_guards = render_template_with_fallback(
|
||||
templatefile=f"subtemplates/hyperopt_sell_guards_{subtemplate}.j2",
|
||||
templatefallbackfile=f"subtemplates/hyperopt_sell_guards_{fallback}.j2",
|
||||
)
|
||||
buy_space = render_template_with_fallback(
|
||||
templatefile=f"subtemplates/hyperopt_buy_space_{subtemplate}.j2",
|
||||
templatefallbackfile=f"subtemplates/hyperopt_buy_space_{fallback}.j2",
|
||||
)
|
||||
sell_space = render_template_with_fallback(
|
||||
templatefile=f"subtemplates/hyperopt_sell_space_{subtemplate}.j2",
|
||||
templatefallbackfile=f"subtemplates/hyperopt_sell_space_{fallback}.j2",
|
||||
)
|
||||
|
||||
strategy_text = render_template(templatefile='base_hyperopt.py.j2',
|
||||
arguments={"hyperopt": hyperopt_name,
|
||||
"buy_guards": buy_guards,
|
||||
"sell_guards": sell_guards,
|
||||
"buy_space": buy_space,
|
||||
"sell_space": sell_space,
|
||||
})
|
||||
|
||||
logger.info(f"Writing hyperopt to `{hyperopt_path}`.")
|
||||
hyperopt_path.write_text(strategy_text)
|
||||
|
||||
|
||||
def start_new_hyperopt(args: Dict[str, Any]) -> None:
|
||||
|
||||
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
||||
|
||||
if 'hyperopt' in args and args['hyperopt']:
|
||||
|
||||
new_path = config['user_data_dir'] / USERPATH_HYPEROPTS / (args['hyperopt'] + '.py')
|
||||
|
||||
if new_path.exists():
|
||||
raise OperationalException(f"`{new_path}` already exists. "
|
||||
"Please choose another Hyperopt Name.")
|
||||
deploy_new_hyperopt(args['hyperopt'], new_path, args['template'])
|
||||
else:
|
||||
raise OperationalException("`new-hyperopt` requires --hyperopt to be set.")
|
||||
|
||||
|
||||
def clean_ui_subdir(directory: Path):
|
||||
if directory.is_dir():
|
||||
logger.info("Removing UI directory content.")
|
||||
|
@@ -10,7 +10,7 @@ from colorama import init as colorama_init
|
||||
from tabulate import tabulate
|
||||
|
||||
from freqtrade.configuration import setup_utils_configuration
|
||||
from freqtrade.constants import USERPATH_HYPEROPTS, USERPATH_STRATEGIES
|
||||
from freqtrade.constants import USERPATH_STRATEGIES
|
||||
from freqtrade.enums import RunMode
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.exchange import market_is_active, validate_exchanges
|
||||
@@ -92,25 +92,6 @@ def start_list_strategies(args: Dict[str, Any]) -> None:
|
||||
_print_objs_tabular(strategy_objs, config.get('print_colorized', False))
|
||||
|
||||
|
||||
def start_list_hyperopts(args: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Print files with HyperOpt custom classes available in the directory
|
||||
"""
|
||||
from freqtrade.resolvers.hyperopt_resolver import HyperOptResolver
|
||||
|
||||
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
||||
|
||||
directory = Path(config.get('hyperopt_path', config['user_data_dir'] / USERPATH_HYPEROPTS))
|
||||
hyperopt_objs = HyperOptResolver.search_all_objects(directory, not args['print_one_column'])
|
||||
# Sort alphabetically
|
||||
hyperopt_objs = sorted(hyperopt_objs, key=lambda x: x['name'])
|
||||
|
||||
if args['print_one_column']:
|
||||
print('\n'.join([s['name'] for s in hyperopt_objs]))
|
||||
else:
|
||||
_print_objs_tabular(hyperopt_objs, config.get('print_colorized', False))
|
||||
|
||||
|
||||
def start_list_timeframes(args: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Print timeframes available on Exchange
|
||||
|
@@ -69,9 +69,7 @@ DUST_PER_COIN = {
|
||||
# Source files with destination directories within user-directory
|
||||
USER_DATA_FILES = {
|
||||
'sample_strategy.py': USERPATH_STRATEGIES,
|
||||
'sample_hyperopt_advanced.py': USERPATH_HYPEROPTS,
|
||||
'sample_hyperopt_loss.py': USERPATH_HYPEROPTS,
|
||||
'sample_hyperopt.py': USERPATH_HYPEROPTS,
|
||||
'strategy_analysis_example.ipynb': USERPATH_NOTEBOOKS,
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,7 @@ from pandas import DataFrame
|
||||
from freqtrade.constants import DATETIME_PRINT_FORMAT, FTHYPT_FILEVERSION, LAST_BT_RESULT_FN
|
||||
from freqtrade.data.converter import trim_dataframes
|
||||
from freqtrade.data.history import get_timerange
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.misc import deep_merge_dicts, file_dump_json, plural
|
||||
from freqtrade.optimize.backtesting import Backtesting
|
||||
# Import IHyperOpt and IHyperOptLoss to allow unpickling classes from these modules
|
||||
@@ -30,7 +31,7 @@ from freqtrade.optimize.hyperopt_interface import IHyperOpt # noqa: F401
|
||||
from freqtrade.optimize.hyperopt_loss_interface import IHyperOptLoss # noqa: F401
|
||||
from freqtrade.optimize.hyperopt_tools import HyperoptTools, hyperopt_serializer
|
||||
from freqtrade.optimize.optimize_reports import generate_strategy_stats
|
||||
from freqtrade.resolvers.hyperopt_resolver import HyperOptLossResolver, HyperOptResolver
|
||||
from freqtrade.resolvers.hyperopt_resolver import HyperOptLossResolver
|
||||
|
||||
|
||||
# Suppress scikit-learn FutureWarnings from skopt
|
||||
@@ -78,10 +79,10 @@ class Hyperopt:
|
||||
|
||||
if not self.config.get('hyperopt'):
|
||||
self.custom_hyperopt = HyperOptAuto(self.config)
|
||||
self.auto_hyperopt = True
|
||||
else:
|
||||
self.custom_hyperopt = HyperOptResolver.load_hyperopt(self.config)
|
||||
self.auto_hyperopt = False
|
||||
raise OperationalException(
|
||||
"Using separate Hyperopt files has been removed in 2021.9. Please convert "
|
||||
"your existing Hyperopt file to the new Hyperoptable strategy interface")
|
||||
|
||||
self.backtesting._set_strategy(self.backtesting.strategylist[0])
|
||||
self.custom_hyperopt.strategy = self.backtesting.strategy
|
||||
@@ -103,31 +104,6 @@ class Hyperopt:
|
||||
self.num_epochs_saved = 0
|
||||
self.current_best_epoch: Optional[Dict[str, Any]] = None
|
||||
|
||||
if not self.auto_hyperopt:
|
||||
# Populate "fallback" functions here
|
||||
# (hasattr is slow so should not be run during "regular" operations)
|
||||
if hasattr(self.custom_hyperopt, 'populate_indicators'):
|
||||
logger.warning(
|
||||
"DEPRECATED: Using `populate_indicators()` in the hyperopt file is deprecated. "
|
||||
"Please move these methods to your strategy."
|
||||
)
|
||||
self.backtesting.strategy.populate_indicators = ( # type: ignore
|
||||
self.custom_hyperopt.populate_indicators) # type: ignore
|
||||
if hasattr(self.custom_hyperopt, 'populate_buy_trend'):
|
||||
logger.warning(
|
||||
"DEPRECATED: Using `populate_buy_trend()` in the hyperopt file is deprecated. "
|
||||
"Please move these methods to your strategy."
|
||||
)
|
||||
self.backtesting.strategy.populate_buy_trend = ( # type: ignore
|
||||
self.custom_hyperopt.populate_buy_trend) # type: ignore
|
||||
if hasattr(self.custom_hyperopt, 'populate_sell_trend'):
|
||||
logger.warning(
|
||||
"DEPRECATED: Using `populate_sell_trend()` in the hyperopt file is deprecated. "
|
||||
"Please move these methods to your strategy."
|
||||
)
|
||||
self.backtesting.strategy.populate_sell_trend = ( # type: ignore
|
||||
self.custom_hyperopt.populate_sell_trend) # type: ignore
|
||||
|
||||
# Use max_open_trades for hyperopt as well, except --disable-max-market-positions is set
|
||||
if self.config.get('use_max_market_positions', True):
|
||||
self.max_open_trades = self.config['max_open_trades']
|
||||
@@ -256,7 +232,7 @@ class Hyperopt:
|
||||
"""
|
||||
Assign the dimensions in the hyperoptimization space.
|
||||
"""
|
||||
if self.auto_hyperopt and HyperoptTools.has_space(self.config, 'protection'):
|
||||
if HyperoptTools.has_space(self.config, 'protection'):
|
||||
# Protections can only be optimized when using the Parameter interface
|
||||
logger.debug("Hyperopt has 'protection' space")
|
||||
# Enable Protections if protection space is selected.
|
||||
@@ -285,6 +261,15 @@ class Hyperopt:
|
||||
self.dimensions = (self.buy_space + self.sell_space + self.protection_space
|
||||
+ self.roi_space + self.stoploss_space + self.trailing_space)
|
||||
|
||||
def assign_params(self, params_dict: Dict, category: str) -> None:
|
||||
"""
|
||||
Assign hyperoptable parameters
|
||||
"""
|
||||
for attr_name, attr in self.backtesting.strategy.enumerate_parameters(category):
|
||||
if attr.optimize:
|
||||
# noinspection PyProtectedMember
|
||||
attr.value = params_dict[attr_name]
|
||||
|
||||
def generate_optimizer(self, raw_params: List[Any], iteration=None) -> Dict:
|
||||
"""
|
||||
Used Optimize function.
|
||||
@@ -296,18 +281,13 @@ class Hyperopt:
|
||||
|
||||
# Apply parameters
|
||||
if HyperoptTools.has_space(self.config, 'buy'):
|
||||
self.backtesting.strategy.advise_buy = ( # type: ignore
|
||||
self.custom_hyperopt.buy_strategy_generator(params_dict))
|
||||
self.assign_params(params_dict, 'buy')
|
||||
|
||||
if HyperoptTools.has_space(self.config, 'sell'):
|
||||
self.backtesting.strategy.advise_sell = ( # type: ignore
|
||||
self.custom_hyperopt.sell_strategy_generator(params_dict))
|
||||
self.assign_params(params_dict, 'sell')
|
||||
|
||||
if HyperoptTools.has_space(self.config, 'protection'):
|
||||
for attr_name, attr in self.backtesting.strategy.enumerate_parameters('protection'):
|
||||
if attr.optimize:
|
||||
# noinspection PyProtectedMember
|
||||
attr.value = params_dict[attr_name]
|
||||
self.assign_params(params_dict, 'protection')
|
||||
|
||||
if HyperoptTools.has_space(self.config, 'roi'):
|
||||
self.backtesting.strategy.minimal_roi = ( # type: ignore
|
||||
@@ -517,11 +497,10 @@ class Hyperopt:
|
||||
f"saved to '{self.results_file}'.")
|
||||
|
||||
if self.current_best_epoch:
|
||||
if self.auto_hyperopt:
|
||||
HyperoptTools.try_export_params(
|
||||
self.config,
|
||||
self.backtesting.strategy.get_strategy_name(),
|
||||
self.current_best_epoch)
|
||||
HyperoptTools.try_export_params(
|
||||
self.config,
|
||||
self.backtesting.strategy.get_strategy_name(),
|
||||
self.current_best_epoch)
|
||||
|
||||
HyperoptTools.show_epoch_details(self.current_best_epoch, self.total_epochs,
|
||||
self.print_json)
|
||||
|
@@ -4,9 +4,9 @@ This module implements a convenience auto-hyperopt class, which can be used toge
|
||||
that implement IHyperStrategy interface.
|
||||
"""
|
||||
from contextlib import suppress
|
||||
from typing import Any, Callable, Dict, List
|
||||
from typing import Callable, Dict, List
|
||||
|
||||
from pandas import DataFrame
|
||||
from freqtrade.exceptions import OperationalException
|
||||
|
||||
|
||||
with suppress(ImportError):
|
||||
@@ -15,6 +15,14 @@ with suppress(ImportError):
|
||||
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||
|
||||
|
||||
def _format_exception_message(space: str) -> str:
|
||||
raise OperationalException(
|
||||
f"The '{space}' space is included into the hyperoptimization "
|
||||
f"but no parameter for this space was not found in your Strategy. "
|
||||
f"Please make sure to have parameters for this space enabled for optimization "
|
||||
f"or remove the '{space}' space from hyperoptimization.")
|
||||
|
||||
|
||||
class HyperOptAuto(IHyperOpt):
|
||||
"""
|
||||
This class delegates functionality to Strategy(IHyperStrategy) and Strategy.HyperOpt classes.
|
||||
@@ -22,26 +30,6 @@ class HyperOptAuto(IHyperOpt):
|
||||
sell_indicator_space methods, but other hyperopt methods can be overridden as well.
|
||||
"""
|
||||
|
||||
def buy_strategy_generator(self, params: Dict[str, Any]) -> Callable:
|
||||
def populate_buy_trend(dataframe: DataFrame, metadata: dict):
|
||||
for attr_name, attr in self.strategy.enumerate_parameters('buy'):
|
||||
if attr.optimize:
|
||||
# noinspection PyProtectedMember
|
||||
attr.value = params[attr_name]
|
||||
return self.strategy.populate_buy_trend(dataframe, metadata)
|
||||
|
||||
return populate_buy_trend
|
||||
|
||||
def sell_strategy_generator(self, params: Dict[str, Any]) -> Callable:
|
||||
def populate_sell_trend(dataframe: DataFrame, metadata: dict):
|
||||
for attr_name, attr in self.strategy.enumerate_parameters('sell'):
|
||||
if attr.optimize:
|
||||
# noinspection PyProtectedMember
|
||||
attr.value = params[attr_name]
|
||||
return self.strategy.populate_sell_trend(dataframe, metadata)
|
||||
|
||||
return populate_sell_trend
|
||||
|
||||
def _get_func(self, name) -> Callable:
|
||||
"""
|
||||
Return a function defined in Strategy.HyperOpt class, or one defined in super() class.
|
||||
@@ -60,21 +48,22 @@ class HyperOptAuto(IHyperOpt):
|
||||
if attr.optimize:
|
||||
yield attr.get_space(attr_name)
|
||||
|
||||
def _get_indicator_space(self, category, fallback_method_name):
|
||||
def _get_indicator_space(self, category):
|
||||
# TODO: is this necessary, or can we call "generate_space" directly?
|
||||
indicator_space = list(self._generate_indicator_space(category))
|
||||
if len(indicator_space) > 0:
|
||||
return indicator_space
|
||||
else:
|
||||
return self._get_func(fallback_method_name)()
|
||||
_format_exception_message(category)
|
||||
|
||||
def indicator_space(self) -> List['Dimension']:
|
||||
return self._get_indicator_space('buy', 'indicator_space')
|
||||
return self._get_indicator_space('buy')
|
||||
|
||||
def sell_indicator_space(self) -> List['Dimension']:
|
||||
return self._get_indicator_space('sell', 'sell_indicator_space')
|
||||
return self._get_indicator_space('sell')
|
||||
|
||||
def protection_space(self) -> List['Dimension']:
|
||||
return self._get_indicator_space('protection', 'protection_space')
|
||||
return self._get_indicator_space('protection')
|
||||
|
||||
def generate_roi_table(self, params: Dict) -> Dict[int, float]:
|
||||
return self._get_func('generate_roi_table')(params)
|
||||
|
@@ -5,11 +5,10 @@ This module defines the interface to apply for hyperopt
|
||||
import logging
|
||||
import math
|
||||
from abc import ABC
|
||||
from typing import Any, Callable, Dict, List
|
||||
from typing import Dict, List
|
||||
|
||||
from skopt.space import Categorical, Dimension, Integer
|
||||
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.exchange import timeframe_to_minutes
|
||||
from freqtrade.misc import round_dict
|
||||
from freqtrade.optimize.space import SKDecimal
|
||||
@@ -19,13 +18,6 @@ from freqtrade.strategy import IStrategy
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _format_exception_message(method: str, space: str) -> str:
|
||||
return (f"The '{space}' space is included into the hyperoptimization "
|
||||
f"but {method}() method is not found in your "
|
||||
f"custom Hyperopt class. You should either implement this "
|
||||
f"method or remove the '{space}' space from hyperoptimization.")
|
||||
|
||||
|
||||
class IHyperOpt(ABC):
|
||||
"""
|
||||
Interface for freqtrade hyperopt
|
||||
@@ -45,37 +37,6 @@ class IHyperOpt(ABC):
|
||||
IHyperOpt.ticker_interval = str(config['timeframe']) # DEPRECATED
|
||||
IHyperOpt.timeframe = str(config['timeframe'])
|
||||
|
||||
def buy_strategy_generator(self, params: Dict[str, Any]) -> Callable:
|
||||
"""
|
||||
Create a buy strategy generator.
|
||||
"""
|
||||
raise OperationalException(_format_exception_message('buy_strategy_generator', 'buy'))
|
||||
|
||||
def sell_strategy_generator(self, params: Dict[str, Any]) -> Callable:
|
||||
"""
|
||||
Create a sell strategy generator.
|
||||
"""
|
||||
raise OperationalException(_format_exception_message('sell_strategy_generator', 'sell'))
|
||||
|
||||
def protection_space(self) -> List[Dimension]:
|
||||
"""
|
||||
Create a protection space.
|
||||
Only supported by the Parameter interface.
|
||||
"""
|
||||
raise OperationalException(_format_exception_message('indicator_space', 'protection'))
|
||||
|
||||
def indicator_space(self) -> List[Dimension]:
|
||||
"""
|
||||
Create an indicator space.
|
||||
"""
|
||||
raise OperationalException(_format_exception_message('indicator_space', 'buy'))
|
||||
|
||||
def sell_indicator_space(self) -> List[Dimension]:
|
||||
"""
|
||||
Create a sell indicator space.
|
||||
"""
|
||||
raise OperationalException(_format_exception_message('sell_indicator_space', 'sell'))
|
||||
|
||||
def generate_roi_table(self, params: Dict) -> Dict[int, float]:
|
||||
"""
|
||||
Create a ROI table.
|
||||
|
@@ -9,7 +9,6 @@ from typing import Dict
|
||||
|
||||
from freqtrade.constants import HYPEROPT_LOSS_BUILTIN, USERPATH_HYPEROPTS
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||
from freqtrade.optimize.hyperopt_loss_interface import IHyperOptLoss
|
||||
from freqtrade.resolvers import IResolver
|
||||
|
||||
@@ -17,43 +16,6 @@ from freqtrade.resolvers import IResolver
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HyperOptResolver(IResolver):
|
||||
"""
|
||||
This class contains all the logic to load custom hyperopt class
|
||||
"""
|
||||
object_type = IHyperOpt
|
||||
object_type_str = "Hyperopt"
|
||||
user_subdir = USERPATH_HYPEROPTS
|
||||
initial_search_path = None
|
||||
|
||||
@staticmethod
|
||||
def load_hyperopt(config: Dict) -> IHyperOpt:
|
||||
"""
|
||||
Load the custom hyperopt class from config parameter
|
||||
:param config: configuration dictionary
|
||||
"""
|
||||
if not config.get('hyperopt'):
|
||||
raise OperationalException("No Hyperopt set. Please use `--hyperopt` to specify "
|
||||
"the Hyperopt class to use.")
|
||||
|
||||
hyperopt_name = config['hyperopt']
|
||||
|
||||
hyperopt = HyperOptResolver.load_object(hyperopt_name, config,
|
||||
kwargs={'config': config},
|
||||
extra_dir=config.get('hyperopt_path'))
|
||||
|
||||
if not hasattr(hyperopt, 'populate_indicators'):
|
||||
logger.info("Hyperopt class does not provide populate_indicators() method. "
|
||||
"Using populate_indicators from the strategy.")
|
||||
if not hasattr(hyperopt, 'populate_buy_trend'):
|
||||
logger.info("Hyperopt class does not provide populate_buy_trend() method. "
|
||||
"Using populate_buy_trend from the strategy.")
|
||||
if not hasattr(hyperopt, 'populate_sell_trend'):
|
||||
logger.info("Hyperopt class does not provide populate_sell_trend() method. "
|
||||
"Using populate_sell_trend from the strategy.")
|
||||
return hyperopt
|
||||
|
||||
|
||||
class HyperOptLossResolver(IResolver):
|
||||
"""
|
||||
This class contains all the logic to load custom hyperopt loss class
|
||||
|
@@ -1,137 +0,0 @@
|
||||
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
|
||||
# --- Do not remove these libs ---
|
||||
from functools import reduce
|
||||
from typing import Any, Callable, Dict, List
|
||||
|
||||
import numpy as np # noqa
|
||||
import pandas as pd # noqa
|
||||
from pandas import DataFrame
|
||||
from skopt.space import Categorical, Dimension, Integer, Real # noqa
|
||||
|
||||
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||
|
||||
# --------------------------------
|
||||
# Add your lib to import here
|
||||
import talib.abstract as ta # noqa
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
|
||||
|
||||
class {{ hyperopt }}(IHyperOpt):
|
||||
"""
|
||||
This is a Hyperopt template to get you started.
|
||||
|
||||
More information in the documentation: https://www.freqtrade.io/en/latest/hyperopt/
|
||||
|
||||
You should:
|
||||
- Add any lib you need to build your hyperopt.
|
||||
|
||||
You must keep:
|
||||
- The prototypes for the methods: populate_indicators, indicator_space, buy_strategy_generator.
|
||||
|
||||
The methods roi_space, generate_roi_table and stoploss_space are not required
|
||||
and are provided by default.
|
||||
However, you may override them if you need 'roi' and 'stoploss' spaces that
|
||||
differ from the defaults offered by Freqtrade.
|
||||
Sample implementation of these methods will be copied to `user_data/hyperopts` when
|
||||
creating the user-data directory using `freqtrade create-userdir --userdir user_data`,
|
||||
or is available online under the following URL:
|
||||
https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_hyperopt_advanced.py.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def indicator_space() -> List[Dimension]:
|
||||
"""
|
||||
Define your Hyperopt space for searching buy strategy parameters.
|
||||
"""
|
||||
return [
|
||||
{{ buy_space | indent(12) }}
|
||||
]
|
||||
|
||||
@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
|
||||
{{ buy_guards | indent(12) }}
|
||||
|
||||
# TRIGGERS
|
||||
if 'trigger' in params:
|
||||
if params['trigger'] == 'bb_lower':
|
||||
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']
|
||||
))
|
||||
|
||||
# Check that the candle had volume
|
||||
conditions.append(dataframe['volume'] > 0)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'buy'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
return populate_buy_trend
|
||||
|
||||
@staticmethod
|
||||
def sell_indicator_space() -> List[Dimension]:
|
||||
"""
|
||||
Define your Hyperopt space for searching sell strategy parameters.
|
||||
"""
|
||||
return [
|
||||
{{ sell_space | indent(12) }}
|
||||
]
|
||||
|
||||
@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
|
||||
{{ sell_guards | indent(12) }}
|
||||
|
||||
# TRIGGERS
|
||||
if 'sell-trigger' in params:
|
||||
if params['sell-trigger'] == 'sell-bb_upper':
|
||||
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']
|
||||
))
|
||||
|
||||
# Check that the candle had volume
|
||||
conditions.append(dataframe['volume'] > 0)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'sell'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
return populate_sell_trend
|
||||
|
@@ -1,174 +0,0 @@
|
||||
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
# isort: skip_file
|
||||
|
||||
# --- Do not remove these libs ---
|
||||
from functools import reduce
|
||||
from typing import Any, Callable, Dict, List
|
||||
|
||||
import numpy as np # noqa
|
||||
import pandas as pd # noqa
|
||||
from pandas import DataFrame
|
||||
from skopt.space import Categorical, Dimension, Integer, Real # noqa
|
||||
|
||||
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||
|
||||
# --------------------------------
|
||||
# Add your lib to import here
|
||||
import talib.abstract as ta # noqa
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
|
||||
|
||||
class SampleHyperOpt(IHyperOpt):
|
||||
"""
|
||||
This is a sample Hyperopt to inspire you.
|
||||
|
||||
More information in the documentation: https://www.freqtrade.io/en/latest/hyperopt/
|
||||
|
||||
You should:
|
||||
- Rename the class name to some unique name.
|
||||
- Add any methods you want to build your hyperopt.
|
||||
- Add any lib you need to build your hyperopt.
|
||||
|
||||
An easier way to get a new hyperopt file is by using
|
||||
`freqtrade new-hyperopt --hyperopt MyCoolHyperopt`.
|
||||
|
||||
You must keep:
|
||||
- The prototypes for the methods: populate_indicators, indicator_space, buy_strategy_generator.
|
||||
|
||||
The methods roi_space, generate_roi_table and stoploss_space are not required
|
||||
and are provided by default.
|
||||
However, you may override them if you need 'roi' and 'stoploss' spaces that
|
||||
differ from the defaults offered by Freqtrade.
|
||||
Sample implementation of these methods will be copied to `user_data/hyperopts` when
|
||||
creating the user-data directory using `freqtrade create-userdir --userdir user_data`,
|
||||
or is available online under the following URL:
|
||||
https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_hyperopt_advanced.py.
|
||||
"""
|
||||
|
||||
@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(['bb_lower', 'macd_cross_signal', 'sar_reversal'], name='trigger')
|
||||
]
|
||||
|
||||
@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'] == 'bb_lower':
|
||||
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']
|
||||
))
|
||||
|
||||
# Check that volume is not 0
|
||||
conditions.append(dataframe['volume'] > 0)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'buy'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
return populate_buy_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-bb_upper',
|
||||
'sell-macd_cross_signal',
|
||||
'sell-sar_reversal'], name='sell-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-bb_upper':
|
||||
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']
|
||||
))
|
||||
|
||||
# Check that volume is not 0
|
||||
conditions.append(dataframe['volume'] > 0)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'sell'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
return populate_sell_trend
|
@@ -1,269 +0,0 @@
|
||||
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
# isort: skip_file
|
||||
# --- Do not remove these libs ---
|
||||
from functools import reduce
|
||||
from typing import Any, Callable, Dict, List
|
||||
|
||||
import numpy as np # noqa
|
||||
import pandas as pd # noqa
|
||||
from pandas import DataFrame
|
||||
from freqtrade.optimize.space import Categorical, Dimension, Integer, SKDecimal, Real # noqa
|
||||
|
||||
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||
|
||||
# --------------------------------
|
||||
# Add your lib to import here
|
||||
import talib.abstract as ta # noqa
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
|
||||
|
||||
class AdvancedSampleHyperOpt(IHyperOpt):
|
||||
"""
|
||||
This is a sample hyperopt to inspire you.
|
||||
Feel free to customize it.
|
||||
|
||||
More information in the documentation: https://www.freqtrade.io/en/latest/hyperopt/
|
||||
|
||||
You should:
|
||||
- Rename the class name to some unique name.
|
||||
- Add any methods you want to build your hyperopt.
|
||||
- Add any lib you need to build your hyperopt.
|
||||
|
||||
You must keep:
|
||||
- The prototypes for the methods: populate_indicators, indicator_space, buy_strategy_generator.
|
||||
|
||||
The methods roi_space, generate_roi_table and stoploss_space are not required
|
||||
and are provided by default.
|
||||
However, you may override them if you need the
|
||||
'roi' and the 'stoploss' spaces that differ from the defaults offered by Freqtrade.
|
||||
|
||||
This sample illustrates how to override these methods.
|
||||
"""
|
||||
@staticmethod
|
||||
def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
This method can also be loaded from the strategy, if it doesn't exist in the hyperopt class.
|
||||
"""
|
||||
dataframe['adx'] = ta.ADX(dataframe)
|
||||
macd = ta.MACD(dataframe)
|
||||
dataframe['macd'] = macd['macd']
|
||||
dataframe['macdsignal'] = macd['macdsignal']
|
||||
dataframe['mfi'] = ta.MFI(dataframe)
|
||||
dataframe['rsi'] = ta.RSI(dataframe)
|
||||
stoch_fast = ta.STOCHF(dataframe)
|
||||
dataframe['fastd'] = stoch_fast['fastd']
|
||||
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']
|
||||
dataframe['sar'] = ta.SAR(dataframe)
|
||||
return dataframe
|
||||
|
||||
@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(['bb_lower', 'macd_cross_signal', 'sar_reversal'], name='trigger')
|
||||
]
|
||||
|
||||
@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'] == 'bb_lower':
|
||||
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']
|
||||
))
|
||||
|
||||
# Check that volume is not 0
|
||||
conditions.append(dataframe['volume'] > 0)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'buy'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
return populate_buy_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-bb_upper',
|
||||
'sell-macd_cross_signal',
|
||||
'sell-sar_reversal'], name='sell-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
|
||||
"""
|
||||
# print(params)
|
||||
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-bb_upper':
|
||||
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']
|
||||
))
|
||||
|
||||
# Check that volume is not 0
|
||||
conditions.append(dataframe['volume'] > 0)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'sell'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
return populate_sell_trend
|
||||
|
||||
@staticmethod
|
||||
def generate_roi_table(params: Dict) -> Dict[int, float]:
|
||||
"""
|
||||
Generate the ROI table that will be used by Hyperopt
|
||||
|
||||
This implementation generates the default legacy Freqtrade ROI tables.
|
||||
|
||||
Change it if you need different number of steps in the generated
|
||||
ROI tables or other structure of the ROI tables.
|
||||
|
||||
Please keep it aligned with parameters in the 'roi' optimization
|
||||
hyperspace defined by the roi_space method.
|
||||
"""
|
||||
roi_table = {}
|
||||
roi_table[0] = params['roi_p1'] + params['roi_p2'] + params['roi_p3']
|
||||
roi_table[params['roi_t3']] = params['roi_p1'] + params['roi_p2']
|
||||
roi_table[params['roi_t3'] + params['roi_t2']] = params['roi_p1']
|
||||
roi_table[params['roi_t3'] + params['roi_t2'] + params['roi_t1']] = 0
|
||||
|
||||
return roi_table
|
||||
|
||||
@staticmethod
|
||||
def roi_space() -> List[Dimension]:
|
||||
"""
|
||||
Values to search for each ROI steps
|
||||
|
||||
Override it if you need some different ranges for the parameters in the
|
||||
'roi' optimization hyperspace.
|
||||
|
||||
Please keep it aligned with the implementation of the
|
||||
generate_roi_table method.
|
||||
"""
|
||||
return [
|
||||
Integer(10, 120, name='roi_t1'),
|
||||
Integer(10, 60, name='roi_t2'),
|
||||
Integer(10, 40, name='roi_t3'),
|
||||
SKDecimal(0.01, 0.04, decimals=3, name='roi_p1'),
|
||||
SKDecimal(0.01, 0.07, decimals=3, name='roi_p2'),
|
||||
SKDecimal(0.01, 0.20, decimals=3, name='roi_p3'),
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def stoploss_space() -> List[Dimension]:
|
||||
"""
|
||||
Stoploss Value to search
|
||||
|
||||
Override it if you need some different range for the parameter in the
|
||||
'stoploss' optimization hyperspace.
|
||||
"""
|
||||
return [
|
||||
SKDecimal(-0.35, -0.02, decimals=3, name='stoploss'),
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def trailing_space() -> List[Dimension]:
|
||||
"""
|
||||
Create a trailing stoploss space.
|
||||
|
||||
You may override it in your custom Hyperopt class.
|
||||
"""
|
||||
return [
|
||||
# It was decided to always set trailing_stop is to True if the 'trailing' hyperspace
|
||||
# is used. Otherwise hyperopt will vary other parameters that won't have effect if
|
||||
# trailing_stop is set False.
|
||||
# This parameter is included into the hyperspace dimensions rather than assigning
|
||||
# it explicitly in the code in order to have it printed in the results along with
|
||||
# other 'trailing' hyperspace parameters.
|
||||
Categorical([True], name='trailing_stop'),
|
||||
|
||||
SKDecimal(0.01, 0.35, decimals=3, name='trailing_stop_positive'),
|
||||
|
||||
# 'trailing_stop_positive_offset' should be greater than 'trailing_stop_positive',
|
||||
# so this intermediate parameter is used as the value of the difference between
|
||||
# them. The value of the 'trailing_stop_positive_offset' is constructed in the
|
||||
# generate_trailing_params() method.
|
||||
# This is similar to the hyperspace dimensions used for constructing the ROI tables.
|
||||
SKDecimal(0.001, 0.1, decimals=3, name='trailing_stop_positive_offset_p1'),
|
||||
|
||||
Categorical([True, False], name='trailing_only_offset_is_reached'),
|
||||
]
|
@@ -1,8 +0,0 @@
|
||||
if params.get('mfi-enabled'):
|
||||
conditions.append(dataframe['mfi'] < params['mfi-value'])
|
||||
if params.get('fastd-enabled'):
|
||||
conditions.append(dataframe['fastd'] < params['fastd-value'])
|
||||
if params.get('adx-enabled'):
|
||||
conditions.append(dataframe['adx'] > params['adx-value'])
|
||||
if params.get('rsi-enabled'):
|
||||
conditions.append(dataframe['rsi'] < params['rsi-value'])
|
@@ -1,2 +0,0 @@
|
||||
if params.get('rsi-enabled'):
|
||||
conditions.append(dataframe['rsi'] < params['rsi-value'])
|
@@ -1,9 +0,0 @@
|
||||
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(['bb_lower', 'macd_cross_signal', 'sar_reversal'], name='trigger')
|
@@ -1,3 +0,0 @@
|
||||
Integer(20, 40, name='rsi-value'),
|
||||
Categorical([True, False], name='rsi-enabled'),
|
||||
Categorical(['bb_lower', 'macd_cross_signal', 'sar_reversal'], name='trigger')
|
@@ -1,8 +0,0 @@
|
||||
if params.get('sell-mfi-enabled'):
|
||||
conditions.append(dataframe['mfi'] > params['sell-mfi-value'])
|
||||
if params.get('sell-fastd-enabled'):
|
||||
conditions.append(dataframe['fastd'] > params['sell-fastd-value'])
|
||||
if params.get('sell-adx-enabled'):
|
||||
conditions.append(dataframe['adx'] < params['sell-adx-value'])
|
||||
if params.get('sell-rsi-enabled'):
|
||||
conditions.append(dataframe['rsi'] > params['sell-rsi-value'])
|
@@ -1,2 +0,0 @@
|
||||
if params.get('sell-rsi-enabled'):
|
||||
conditions.append(dataframe['rsi'] > params['sell-rsi-value'])
|
@@ -1,11 +0,0 @@
|
||||
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-bb_upper',
|
||||
'sell-macd_cross_signal',
|
||||
'sell-sar_reversal'], name='sell-trigger')
|
@@ -1,5 +0,0 @@
|
||||
Integer(60, 100, name='sell-rsi-value'),
|
||||
Categorical([True, False], name='sell-rsi-enabled'),
|
||||
Categorical(['sell-bb_upper',
|
||||
'sell-macd_cross_signal',
|
||||
'sell-sar_reversal'], name='sell-trigger')
|
Reference in New Issue
Block a user