Add BooleanParameter

This commit is contained in:
Matthias 2021-08-04 20:52:56 +02:00
parent b73768acd1
commit ad0e4a8567
8 changed files with 61 additions and 21 deletions

View File

@ -253,7 +253,7 @@ We continue to define hyperoptable parameters:
class MyAwesomeStrategy(IStrategy): class MyAwesomeStrategy(IStrategy):
buy_adx = DecimalParameter(20, 40, decimals=1, default=30.1, space="buy") buy_adx = DecimalParameter(20, 40, decimals=1, default=30.1, space="buy")
buy_rsi = IntParameter(20, 40, default=30, space="buy") buy_rsi = IntParameter(20, 40, default=30, space="buy")
buy_adx_enabled = CategoricalParameter([True, False], default=True, space="buy") buy_adx_enabled = BooleanParameter(default=True, space="buy")
buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy")
buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy")
``` ```
@ -316,6 +316,7 @@ There are four parameter types each suited for different purposes.
* `DecimalParameter` - defines a floating point parameter with a limited number of decimals (default 3). Should be preferred instead of `RealParameter` in most cases. * `DecimalParameter` - defines a floating point parameter with a limited number of decimals (default 3). Should be preferred instead of `RealParameter` in most cases.
* `RealParameter` - defines a floating point parameter with upper and lower boundaries and no precision limit. Rarely used as it creates a space with a near infinite number of possibilities. * `RealParameter` - defines a floating point parameter with upper and lower boundaries and no precision limit. Rarely used as it creates a space with a near infinite number of possibilities.
* `CategoricalParameter` - defines a parameter with a predetermined number of choices. * `CategoricalParameter` - defines a parameter with a predetermined number of choices.
* `BooleanParameter` - Shorthand for `CategoricalParameter([True, False])` - great for "enable" parameters.
!!! Tip "Disabling parameter optimization" !!! Tip "Disabling parameter optimization"
Each parameter takes two boolean parameters: Each parameter takes two boolean parameters:
@ -336,8 +337,8 @@ from functools import reduce
import talib.abstract as ta import talib.abstract as ta
from freqtrade.strategy import IStrategy from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
from freqtrade.strategy import CategoricalParameter, DecimalParameter, IntParameter IStrategy, IntParameter)
import freqtrade.vendor.qtpylib.indicators as qtpylib import freqtrade.vendor.qtpylib.indicators as qtpylib
class MyAwesomeStrategy(IStrategy): class MyAwesomeStrategy(IStrategy):
@ -425,8 +426,8 @@ from functools import reduce
import talib.abstract as ta import talib.abstract as ta
from freqtrade.strategy import IStrategy from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
from freqtrade.strategy import CategoricalParameter, DecimalParameter, IntParameter IStrategy, IntParameter)
import freqtrade.vendor.qtpylib.indicators as qtpylib import freqtrade.vendor.qtpylib.indicators as qtpylib
class MyAwesomeStrategy(IStrategy): class MyAwesomeStrategy(IStrategy):
@ -435,7 +436,7 @@ class MyAwesomeStrategy(IStrategy):
# Define the parameter spaces # Define the parameter spaces
cooldown_lookback = IntParameter(2, 48, default=5, space="protection", optimize=True) cooldown_lookback = IntParameter(2, 48, default=5, space="protection", optimize=True)
stop_duration = IntParameter(12, 200, default=5, space="protection", optimize=True) stop_duration = IntParameter(12, 200, default=5, space="protection", optimize=True)
use_stop_protection = CategoricalParameter([True, False], default=True, space="protection", optimize=True) use_stop_protection = BooleanParameter(default=True, space="protection", optimize=True)
@property @property

View File

@ -25,6 +25,9 @@ class IProtection(LoggingMixin, ABC):
def __init__(self, config: Dict[str, Any], protection_config: Dict[str, Any]) -> None: def __init__(self, config: Dict[str, Any], protection_config: Dict[str, Any]) -> None:
self._config = config self._config = config
self._protection_config = protection_config self._protection_config = protection_config
self._stop_duration_candles: Optional[int] = None
self._lookback_period_candles: Optional[int] = None
tf_in_min = timeframe_to_minutes(config['timeframe']) tf_in_min = timeframe_to_minutes(config['timeframe'])
if 'stop_duration_candles' in protection_config: if 'stop_duration_candles' in protection_config:
self._stop_duration_candles = int(protection_config.get('stop_duration_candles', 1)) self._stop_duration_candles = int(protection_config.get('stop_duration_candles', 1))

View File

@ -1,7 +1,7 @@
# flake8: noqa: F401 # flake8: noqa: F401
from freqtrade.exchange import (timeframe_to_minutes, timeframe_to_msecs, timeframe_to_next_date, from freqtrade.exchange import (timeframe_to_minutes, timeframe_to_msecs, timeframe_to_next_date,
timeframe_to_prev_date, timeframe_to_seconds) timeframe_to_prev_date, timeframe_to_seconds)
from freqtrade.strategy.hyper import (CategoricalParameter, DecimalParameter, IntParameter, from freqtrade.strategy.hyper import (BooleanParameter, CategoricalParameter, DecimalParameter,
RealParameter) IntParameter, RealParameter)
from freqtrade.strategy.interface import IStrategy from freqtrade.strategy.interface import IStrategy
from freqtrade.strategy.strategy_helper import merge_informative_pair, stoploss_from_open from freqtrade.strategy.strategy_helper import merge_informative_pair, stoploss_from_open

View File

@ -270,6 +270,28 @@ class CategoricalParameter(BaseParameter):
return [self.value] return [self.value]
class BooleanParameter(CategoricalParameter):
def __init__(self, *, default: Optional[Any] = None,
space: Optional[str] = None, optimize: bool = True, load: bool = True, **kwargs):
"""
Initialize hyperopt-optimizable Boolean Parameter.
It's a shortcut to `CategoricalParameter([True, False])`.
:param default: A default value. If not specified, first item from specified space will be
used.
:param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if
parameter field
name is prefixed with 'buy_' or 'sell_'.
:param optimize: Include parameter in hyperopt optimizations.
:param load: Load parameter value from {space}_params.
:param kwargs: Extra parameters to skopt.space.Categorical.
"""
categories = [True, False]
super().__init__(categories=categories, default=default, space=space, optimize=optimize,
load=load, **kwargs)
class HyperStrategyMixin(object): class HyperStrategyMixin(object):
""" """
A helper base class which allows HyperOptAuto class to reuse implementations of buy/sell A helper base class which allows HyperOptAuto class to reuse implementations of buy/sell

View File

@ -6,8 +6,8 @@ import numpy as np # noqa
import pandas as pd # noqa import pandas as pd # noqa
from pandas import DataFrame from pandas import DataFrame
from freqtrade.strategy import IStrategy from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
from freqtrade.strategy import CategoricalParameter, DecimalParameter, IntParameter IStrategy, IntParameter)
# -------------------------------- # --------------------------------
# Add your lib to import here # Add your lib to import here

View File

@ -6,8 +6,8 @@ import numpy as np # noqa
import pandas as pd # noqa import pandas as pd # noqa
from pandas import DataFrame from pandas import DataFrame
from freqtrade.strategy import IStrategy from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
from freqtrade.strategy import CategoricalParameter, DecimalParameter, IntParameter IStrategy, IntParameter)
# -------------------------------- # --------------------------------
# Add your lib to import here # Add your lib to import here

View File

@ -4,7 +4,8 @@ import talib.abstract as ta
from pandas import DataFrame from pandas import DataFrame
import freqtrade.vendor.qtpylib.indicators as qtpylib import freqtrade.vendor.qtpylib.indicators as qtpylib
from freqtrade.strategy import DecimalParameter, IntParameter, IStrategy, RealParameter from freqtrade.strategy import (BooleanParameter, DecimalParameter, IntParameter, IStrategy,
RealParameter)
class HyperoptableStrategy(IStrategy): class HyperoptableStrategy(IStrategy):
@ -64,12 +65,13 @@ class HyperoptableStrategy(IStrategy):
sell_rsi = IntParameter(low=50, high=100, default=70, space='sell') sell_rsi = IntParameter(low=50, high=100, default=70, space='sell')
sell_minusdi = DecimalParameter(low=0, high=1, default=0.5001, decimals=3, space='sell', sell_minusdi = DecimalParameter(low=0, high=1, default=0.5001, decimals=3, space='sell',
load=False) load=False)
protection_enabled = BooleanParameter(default=True)
protection_cooldown_lookback = IntParameter([0, 50], default=30) protection_cooldown_lookback = IntParameter([0, 50], default=30)
@property @property
def protections(self): def protections(self):
prot = [] prot = []
if self.protection_enabled.value:
prot.append({ prot.append({
"method": "CooldownPeriod", "method": "CooldownPeriod",
"stop_duration_candles": self.protection_cooldown_lookback.value "stop_duration_candles": self.protection_cooldown_lookback.value

View File

@ -16,8 +16,8 @@ from freqtrade.exceptions import OperationalException, StrategyError
from freqtrade.optimize.space import SKDecimal from freqtrade.optimize.space import SKDecimal
from freqtrade.persistence import PairLocks, Trade from freqtrade.persistence import PairLocks, Trade
from freqtrade.resolvers import StrategyResolver from freqtrade.resolvers import StrategyResolver
from freqtrade.strategy.hyper import (BaseParameter, CategoricalParameter, DecimalParameter, from freqtrade.strategy.hyper import (BaseParameter, BooleanParameter, CategoricalParameter,
IntParameter, RealParameter) DecimalParameter, IntParameter, RealParameter)
from freqtrade.strategy.interface import SellCheckTuple from freqtrade.strategy.interface import SellCheckTuple
from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper
from tests.conftest import log_has, log_has_re from tests.conftest import log_has, log_has_re
@ -717,6 +717,17 @@ def test_hyperopt_parameters():
assert len(list(catpar.range)) == 3 assert len(list(catpar.range)) == 3
assert list(catpar.range) == ['buy_rsi', 'buy_macd', 'buy_none'] assert list(catpar.range) == ['buy_rsi', 'buy_macd', 'buy_none']
boolpar = BooleanParameter(default=True, space='buy')
assert boolpar.value is True
assert isinstance(boolpar.get_space(''), Categorical)
assert isinstance(boolpar.range, list)
assert len(list(boolpar.range)) == 1
boolpar.in_space = True
assert len(list(boolpar.range)) == 2
assert list(boolpar.range) == [True, False]
def test_auto_hyperopt_interface(default_conf): def test_auto_hyperopt_interface(default_conf):
default_conf.update({'strategy': 'HyperoptableStrategy'}) default_conf.update({'strategy': 'HyperoptableStrategy'})
@ -734,7 +745,8 @@ def test_auto_hyperopt_interface(default_conf):
assert isinstance(all_params, dict) assert isinstance(all_params, dict)
assert len(all_params['buy']) == 2 assert len(all_params['buy']) == 2
assert len(all_params['sell']) == 2 assert len(all_params['sell']) == 2
assert all_params['count'] == 5 # Number of Hyperoptable parameters
assert all_params['count'] == 6
strategy.__class__.sell_rsi = IntParameter([0, 10], default=5, space='buy') strategy.__class__.sell_rsi = IntParameter([0, 10], default=5, space='buy')