change CategoricalParameter and IntParameter in parameters.py to use optuna.distributions CategoricalDistribution and IntDistribution instead of skopt

This commit is contained in:
viotemp1
2025-03-30 21:11:26 +03:00
parent b603771242
commit 2595479e43
3 changed files with 57 additions and 17 deletions

View File

@@ -39,6 +39,7 @@ with warnings.catch_warnings():
from skopt.space import Categorical, Dimension, Integer, Real
from freqtrade.optimize.space.decimalspace import SKDecimal
from freqtrade.strategy.parameters import ft_CategoricalDistribution, ft_IntDistribution
logger = logging.getLogger(__name__)
@@ -420,6 +421,11 @@ class HyperOptimizer:
o_dimensions[original_dim.name] = optuna.distributions.CategoricalDistribution(
list(original_dim.bounds)
)
# for preparing to remove old skopt spaces
elif isinstance(
original_dim, ft_CategoricalDistribution
) or isinstance(original_dim, ft_IntDistribution):
o_dimensions[original_dim.name] = original_dim
else:
raise Exception(f"Unknown search space {original_dim} / {type(original_dim)}")
# logger.info(f"convert_dimensions_to_optuna_space: {s_dimensions} - {o_dimensions}")
@@ -429,7 +435,9 @@ class HyperOptimizer:
self,
random_state: int,
):
o_sampler = self.custom_hyperopt.generate_estimator(dimensions=self.dimensions)
o_sampler = self.custom_hyperopt.generate_estimator(
dimensions=self.dimensions, random_state=random_state
)
self.o_dimensions = self.convert_dimensions_to_optuna_space(self.dimensions)
# for save/restore

View File

@@ -14,7 +14,8 @@ from freqtrade.optimize.hyperopt_tools import HyperoptStateContainer
with suppress(ImportError):
from skopt.space import Categorical, Integer, Real
from optuna.distributions import CategoricalDistribution, IntDistribution
from skopt.space import Integer, Real # Categorical
from freqtrade.optimize.space import SKDecimal
@@ -24,6 +25,25 @@ from freqtrade.exceptions import OperationalException
logger = logging.getLogger(__name__)
class ft_CategoricalDistribution(CategoricalDistribution):
name: str
def __init__(
self,
categories: Sequence[Any],
**kwargs,
):
return super().__init__(categories)
class ft_IntDistribution(IntDistribution):
name: str
def __init__(
self,
low: int,
high: int,
**kwargs,
):
return super().__init__(low, high, **kwargs)
class BaseParameter(ABC):
"""
Defines a parameter that can be optimized by hyperopt.
@@ -51,7 +71,8 @@ class BaseParameter(ABC):
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.(Integer|Real|Categorical).
:param kwargs: Extra parameters to optuna.distributions.
(IntDistribution|Real|CategoricalDistribution).
"""
if "name" in kwargs:
raise OperationalException(
@@ -67,7 +88,9 @@ class BaseParameter(ABC):
return f"{self.__class__.__name__}({self.value})"
@abstractmethod
def get_space(self, name: str) -> Union["Integer", "Real", "SKDecimal", "Categorical"]:
def get_space(self, name: str) -> Union[
"ft_IntDistribution", "Real", "SKDecimal", "ft_CategoricalDistribution"
]:
"""
Get-space - will be used by Hyperopt to get the hyperopt Space
"""
@@ -151,7 +174,7 @@ class IntParameter(NumericParameter):
parameter fieldname 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.Integer.
:param kwargs: Extra parameters to optuna.distributions.IntDistribution.
"""
super().__init__(
@@ -160,10 +183,15 @@ class IntParameter(NumericParameter):
def get_space(self, name: str) -> "Integer":
"""
Create skopt optimization space.
Create optuna distribution space.
:param name: A name of parameter field.
"""
return Integer(low=self.low, high=self.high, name=name, **self._space_params)
# return Integer(low=self.low, high=self.high, name=name, **self._space_params)
result = ft_IntDistribution(
self.low, self.high, **self._space_params
)
result.name = name
return result
@property
def range(self):
@@ -174,7 +202,7 @@ class IntParameter(NumericParameter):
calculating 100ds of indicators.
"""
if self.can_optimize():
# Scikit-optimize ranges are "inclusive", while python's "range" is exclusive
# optuna distributions ranges are "inclusive", while python's "range" is exclusive
return range(self.low, self.high + 1)
else:
return range(self.value, self.value + 1)
@@ -305,7 +333,7 @@ class CategoricalParameter(BaseParameter):
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.
:param kwargs: Extra parameters to optuna.distributions.CategoricalDistribution.
"""
if len(categories) < 2:
raise OperationalException(
@@ -314,12 +342,15 @@ class CategoricalParameter(BaseParameter):
self.opt_range = categories
super().__init__(default=default, space=space, optimize=optimize, load=load, **kwargs)
def get_space(self, name: str) -> "Categorical":
def get_space(self, name: str) -> "ft_CategoricalDistribution":
"""
Create skopt optimization space.
Create optuna distribution space.
:param name: A name of parameter field.
"""
return Categorical(self.opt_range, name=name, **self._space_params)
# Categorical(self.opt_range, name=name, **self._space_params)
result = ft_CategoricalDistribution(self.opt_range)
result.name = name
return result
@property
def range(self):
@@ -355,7 +386,7 @@ class BooleanParameter(CategoricalParameter):
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.
:param kwargs: Extra parameters to optuna.distributions.CategoricalDistribution.
"""
categories = [True, False]

View File

@@ -895,7 +895,8 @@ def test_is_informative_pairs_callback(default_conf):
def test_hyperopt_parameters():
HyperoptStateContainer.set_state(HyperoptState.INDICATORS)
from skopt.space import Categorical, Integer, Real
from optuna.distributions import CategoricalDistribution, IntDistribution
from skopt.space import Real
with pytest.raises(OperationalException, match=r"Name is determined.*"):
IntParameter(low=0, high=5, default=1, name="hello")
@@ -926,7 +927,7 @@ def test_hyperopt_parameters():
intpar = IntParameter(low=0, high=5, default=1, space="buy")
assert intpar.value == 1
assert isinstance(intpar.get_space(""), Integer)
assert isinstance(intpar.get_space(""), IntDistribution)
assert isinstance(intpar.range, range)
assert len(list(intpar.range)) == 1
# Range contains ONLY the default / value.
@@ -955,7 +956,7 @@ def test_hyperopt_parameters():
["buy_rsi", "buy_macd", "buy_none"], default="buy_macd", space="buy"
)
assert catpar.value == "buy_macd"
assert isinstance(catpar.get_space(""), Categorical)
assert isinstance(catpar.get_space(""), CategoricalDistribution)
assert isinstance(catpar.range, list)
assert len(list(catpar.range)) == 1
# Range contains ONLY the default / value.
@@ -966,7 +967,7 @@ def test_hyperopt_parameters():
boolpar = BooleanParameter(default=True, space="buy")
assert boolpar.value is True
assert isinstance(boolpar.get_space(""), Categorical)
assert isinstance(boolpar.get_space(""), CategoricalDistribution)
assert isinstance(boolpar.range, list)
assert len(list(boolpar.range)) == 1