diff --git a/docs/advanced-hyperopt.md b/docs/advanced-hyperopt.md index d2237b3e8..bdaafb936 100644 --- a/docs/advanced-hyperopt.md +++ b/docs/advanced-hyperopt.md @@ -6,7 +6,7 @@ class. ## Derived hyperopt classes -Custom hyperop classes can be derived in the same way [it can be done for strategies](strategy-customization.md#derived-strategies). +Custom hyperopt classes can be derived in the same way [it can be done for strategies](strategy-customization.md#derived-strategies). Applying to hyperoptimization, as an example, you may override how dimensions are defined in your optimization hyperspace: @@ -32,6 +32,51 @@ or $ freqtrade hyperopt --hyperopt MyAwesomeHyperOpt2 --hyperopt-loss SharpeHyperOptLossDaily --strategy MyAwesomeStrategy ... ``` +## Sharing methods with your strategy + +Hyperopt classes provide access to the Strategy via the `strategy` class attribute. +This can be a great way to reduce code duplication if used correctly, but will also complicate usage for inexperienced users. + +``` python +from pandas import DataFrame +from freqtrade.strategy.interface import IStrategy +import freqtrade.vendor.qtpylib.indicators as qtpylib + +class MyAwesomeStrategy(IStrategy): + + buy_params = { + 'rsi-value': 30, + 'adx-value': 35, + } + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + return self.buy_strategy_generator(self.buy_params, dataframe, metadata) + + @staticmethod + def buy_strategy_generator(params, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + qtpylib.crossed_above(dataframe['rsi'], params['rsi-value']) & + dataframe['adx'] > params['adx-value']) & + dataframe['volume'] > 0 + ) + , 'buy'] = 1 + return dataframe + +class MyAwesomeHyperOpt(IHyperOpt): + ... + @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: + # Call strategy's buy strategy generator + return self.StrategyClass.buy_strategy_generator(params, dataframe, metadata) + + return populate_buy_trend +``` + ## Creating and using a custom loss function To use a custom loss function class, make sure that the function `hyperopt_loss_function` is defined in your custom hyperopt loss class. diff --git a/docs/hyperopt.md b/docs/hyperopt.md index d6959b457..69bc57d1a 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -283,7 +283,7 @@ So let's write the buy strategy using these values: """ Define the buy strategy parameters to be used by Hyperopt. """ - def populate_buy_trend(dataframe: DataFrame) -> DataFrame: + def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] # GUARDS AND TRENDS if 'adx-enabled' in params and params['adx-enabled']: diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 16a39d7d6..6b5bc171b 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -73,6 +73,7 @@ class Hyperopt: self.backtesting = Backtesting(self.config) self.custom_hyperopt = HyperOptResolver.load_hyperopt(self.config) + self.custom_hyperopt.__class__.strategy = self.backtesting.strategy self.custom_hyperoptloss = HyperOptLossResolver.load_hyperoptloss(self.config) self.calculate_loss = self.custom_hyperoptloss.hyperopt_loss_function diff --git a/freqtrade/optimize/hyperopt_interface.py b/freqtrade/optimize/hyperopt_interface.py index b8c44ed59..561fb8e11 100644 --- a/freqtrade/optimize/hyperopt_interface.py +++ b/freqtrade/optimize/hyperopt_interface.py @@ -12,6 +12,7 @@ from skopt.space import Categorical, Dimension, Integer, Real from freqtrade.exceptions import OperationalException from freqtrade.exchange import timeframe_to_minutes from freqtrade.misc import round_dict +from freqtrade.strategy import IStrategy logger = logging.getLogger(__name__) @@ -34,6 +35,7 @@ class IHyperOpt(ABC): """ ticker_interval: str # DEPRECATED timeframe: str + strategy: IStrategy def __init__(self, config: dict) -> None: self.config = config