Add range property to CategoricalParameter and DecimalParameter, add their tests.
At the moment we can keep a single code path when using IntParameter, but we have to make a special hyperopt case for CategoricalParameter/DecimalParameter. Range property solves this.
This commit is contained in:
parent
9d6860337f
commit
3686efa08a
@ -403,6 +403,9 @@ While this strategy is most likely too simple to provide consistent profit, it s
|
||||
!!! Note
|
||||
`self.buy_ema_short.range` will act differently between hyperopt and other modes. For hyperopt, the above example may generate 48 new columns, however for all other modes (backtesting, dry/live), it will only generate the column for the selected value. You should therefore avoid using the resulting column with explicit values (values other than `self.buy_ema_short.value`).
|
||||
|
||||
!!! Note
|
||||
`range` property may also be used with `DecimalParameter` and `CategoricalParameter`. `RealParameter` does not provide this property due to infinite search space.
|
||||
|
||||
??? Hint "Performance tip"
|
||||
By doing the calculation of all possible indicators in `populate_indicators()`, the calculation of the indicator happens only once for every parameter.
|
||||
While this may slow down the hyperopt startup speed, the overall performance will increase as the Hyperopt execution itself may pick the same value for multiple epochs (changing other values).
|
||||
|
@ -205,6 +205,21 @@ class DecimalParameter(NumericParameter):
|
||||
return SKDecimal(low=self.low, high=self.high, decimals=self._decimals, name=name,
|
||||
**self._space_params)
|
||||
|
||||
@property
|
||||
def range(self):
|
||||
"""
|
||||
Get each value in this space as list.
|
||||
Returns a List from low to high (inclusive) in Hyperopt mode.
|
||||
Returns a List with 1 item (`value`) in "non-hyperopt" mode, to avoid
|
||||
calculating 100ds of indicators.
|
||||
"""
|
||||
if self.in_space and self.optimize:
|
||||
low = int(self.low * pow(10, self._decimals))
|
||||
high = int(self.high * pow(10, self._decimals)) + 1
|
||||
return [round(n * pow(0.1, self._decimals), self._decimals) for n in range(low, high)]
|
||||
else:
|
||||
return [self.value]
|
||||
|
||||
|
||||
class CategoricalParameter(BaseParameter):
|
||||
default: Any
|
||||
@ -239,6 +254,19 @@ class CategoricalParameter(BaseParameter):
|
||||
"""
|
||||
return Categorical(self.opt_range, name=name, **self._space_params)
|
||||
|
||||
@property
|
||||
def range(self):
|
||||
"""
|
||||
Get each value in this space as list.
|
||||
Returns a List of categories in Hyperopt mode.
|
||||
Returns a List with 1 item (`value`) in "non-hyperopt" mode, to avoid
|
||||
calculating 100ds of indicators.
|
||||
"""
|
||||
if self.in_space and self.optimize:
|
||||
return self.opt_range
|
||||
else:
|
||||
return [self.value]
|
||||
|
||||
|
||||
class HyperStrategyMixin(object):
|
||||
"""
|
||||
|
@ -12,6 +12,7 @@ from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.data.history import load_data
|
||||
from freqtrade.enums import SellType
|
||||
from freqtrade.exceptions import OperationalException, StrategyError
|
||||
from freqtrade.optimize.space import SKDecimal
|
||||
from freqtrade.persistence import PairLocks, Trade
|
||||
from freqtrade.resolvers import StrategyResolver
|
||||
from freqtrade.strategy.hyper import (BaseParameter, CategoricalParameter, DecimalParameter,
|
||||
@ -657,17 +658,31 @@ def test_hyperopt_parameters():
|
||||
assert list(intpar.range) == [0, 1, 2, 3, 4, 5]
|
||||
|
||||
fltpar = RealParameter(low=0.0, high=5.5, default=1.0, space='buy')
|
||||
assert fltpar.value == 1
|
||||
assert isinstance(fltpar.get_space(''), Real)
|
||||
assert fltpar.value == 1
|
||||
|
||||
fltpar = DecimalParameter(low=0.0, high=5.5, default=1.0004, decimals=3, space='buy')
|
||||
assert isinstance(fltpar.get_space(''), Integer)
|
||||
assert fltpar.value == 1
|
||||
fltpar = DecimalParameter(low=0.0, high=0.5, default=0.14, decimals=1, space='buy')
|
||||
assert fltpar.value == 0.1
|
||||
assert isinstance(fltpar.get_space(''), SKDecimal)
|
||||
assert isinstance(fltpar.range, list)
|
||||
assert len(list(fltpar.range)) == 1
|
||||
# Range contains ONLY the default / value.
|
||||
assert list(fltpar.range) == [fltpar.value]
|
||||
fltpar.in_space = True
|
||||
assert len(list(fltpar.range)) == 6
|
||||
assert list(fltpar.range) == [0.0, 0.1, 0.2, 0.3, 0.4, 0.5]
|
||||
|
||||
catpar = CategoricalParameter(['buy_rsi', 'buy_macd', 'buy_none'],
|
||||
default='buy_macd', space='buy')
|
||||
assert isinstance(catpar.get_space(''), Categorical)
|
||||
assert catpar.value == 'buy_macd'
|
||||
assert isinstance(catpar.get_space(''), Categorical)
|
||||
assert isinstance(catpar.range, list)
|
||||
assert len(list(catpar.range)) == 1
|
||||
# Range contains ONLY the default / value.
|
||||
assert list(catpar.range) == [catpar.value]
|
||||
catpar.in_space = True
|
||||
assert len(list(catpar.range)) == 3
|
||||
assert list(catpar.range) == ['buy_rsi', 'buy_macd', 'buy_none']
|
||||
|
||||
|
||||
def test_auto_hyperopt_interface(default_conf):
|
||||
|
Loading…
Reference in New Issue
Block a user