mirror of
https://github.com/freqtrade/freqtrade.git
synced 2026-01-26 08:50:47 +00:00
change from skopt.space.Real to optuna.distributions.FloatDistribution
This commit is contained in:
@@ -9,13 +9,17 @@ from abc import ABC
|
||||
from typing import TypeAlias
|
||||
|
||||
from sklearn.base import RegressorMixin
|
||||
from skopt.space import Categorical, Dimension, Integer
|
||||
from skopt.space import Dimension # , Integer, Categorical,
|
||||
|
||||
from freqtrade.constants import Config
|
||||
from freqtrade.exchange import timeframe_to_minutes
|
||||
from freqtrade.misc import round_dict
|
||||
from freqtrade.optimize.space import SKDecimal
|
||||
from freqtrade.strategy import IStrategy
|
||||
from freqtrade.strategy.parameters import (
|
||||
ft_CategoricalDistribution,
|
||||
ft_IntDistribution,
|
||||
)
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -133,9 +137,12 @@ class IHyperOpt(ABC):
|
||||
logger.info(f"Max roi table: {round_dict(self.generate_roi_table(p), 3)}")
|
||||
|
||||
return [
|
||||
Integer(roi_limits["roi_t1_min"], roi_limits["roi_t1_max"], name="roi_t1"),
|
||||
Integer(roi_limits["roi_t2_min"], roi_limits["roi_t2_max"], name="roi_t2"),
|
||||
Integer(roi_limits["roi_t3_min"], roi_limits["roi_t3_max"], name="roi_t3"),
|
||||
# Integer(roi_limits["roi_t1_min"], roi_limits["roi_t1_max"], name="roi_t1"),
|
||||
ft_IntDistribution("roi_t1", roi_limits["roi_t1_min"], roi_limits["roi_t1_max"]),
|
||||
# Integer(roi_limits["roi_t2_min"], roi_limits["roi_t2_max"], name="roi_t2"),
|
||||
ft_IntDistribution("roi_t2", roi_limits["roi_t2_min"], roi_limits["roi_t2_max"]),
|
||||
# Integer(roi_limits["roi_t3_min"], roi_limits["roi_t3_max"], name="roi_t3"),
|
||||
ft_IntDistribution("roi_t3", roi_limits["roi_t3_min"], roi_limits["roi_t3_max"]),
|
||||
SKDecimal(
|
||||
roi_limits["roi_p1_min"], roi_limits["roi_p1_max"], decimals=3, name="roi_p1"
|
||||
),
|
||||
@@ -184,7 +191,8 @@ class IHyperOpt(ABC):
|
||||
# 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"),
|
||||
# Categorical([True], name="trailing_stop"),
|
||||
ft_CategoricalDistribution("trailing_stop", [True]),
|
||||
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
|
||||
@@ -192,7 +200,8 @@ class IHyperOpt(ABC):
|
||||
# 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"),
|
||||
# Categorical([True, False], name="trailing_only_offset_is_reached"),
|
||||
ft_CategoricalDistribution("trailing_only_offset_is_reached", [True, False]),
|
||||
]
|
||||
|
||||
def max_open_trades_space(self) -> list[Dimension]:
|
||||
@@ -201,9 +210,10 @@ class IHyperOpt(ABC):
|
||||
|
||||
You may override it in your custom Hyperopt class.
|
||||
"""
|
||||
return [
|
||||
Integer(-1, 10, name="max_open_trades"),
|
||||
]
|
||||
# return [
|
||||
# Integer(-1, 10, name="max_open_trades"),
|
||||
# ]
|
||||
return [ft_IntDistribution("max_open_trades", -1, 10)]
|
||||
|
||||
# This is needed for proper unpickling the class attribute timeframe
|
||||
# which is set to the actual value by the resolver.
|
||||
|
||||
@@ -36,10 +36,14 @@ with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", category=FutureWarning)
|
||||
# from skopt import Optimizer
|
||||
import optuna
|
||||
from skopt.space import Categorical, Dimension, Integer, Real
|
||||
from skopt.space import Dimension
|
||||
|
||||
from freqtrade.optimize.space.decimalspace import SKDecimal
|
||||
from freqtrade.strategy.parameters import ft_CategoricalDistribution, ft_IntDistribution
|
||||
from freqtrade.strategy.parameters import (
|
||||
ft_CategoricalDistribution,
|
||||
ft_FloatDistribution,
|
||||
ft_IntDistribution,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -407,27 +411,18 @@ class HyperOptimizer:
|
||||
log=False,
|
||||
step=1 / pow(10, original_dim.decimals),
|
||||
)
|
||||
elif isinstance(original_dim, Integer):
|
||||
o_dimensions[original_dim.name] = optuna.distributions.IntDistribution(
|
||||
original_dim.low, original_dim.high, log=False, step=1
|
||||
)
|
||||
elif isinstance(original_dim, Real):
|
||||
o_dimensions[original_dim.name] = optuna.distributions.FloatDistribution(
|
||||
original_dim.low,
|
||||
original_dim.high,
|
||||
log=False,
|
||||
)
|
||||
elif isinstance(original_dim, Categorical):
|
||||
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
|
||||
elif (
|
||||
isinstance(original_dim, ft_CategoricalDistribution)
|
||||
or isinstance(original_dim, ft_IntDistribution)
|
||||
or isinstance(original_dim, ft_FloatDistribution)
|
||||
):
|
||||
o_dimensions[original_dim.name] = original_dim
|
||||
else:
|
||||
raise Exception(f"Unknown search space {original_dim} / {type(original_dim)}")
|
||||
raise Exception(
|
||||
f"Unknown search space {original_dim.name} - {original_dim} / \
|
||||
{type(original_dim)}"
|
||||
)
|
||||
# logger.info(f"convert_dimensions_to_optuna_space: {s_dimensions} - {o_dimensions}")
|
||||
return o_dimensions
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@ from freqtrade.optimize.hyperopt_tools import HyperoptStateContainer
|
||||
|
||||
|
||||
with suppress(ImportError):
|
||||
from optuna.distributions import CategoricalDistribution, IntDistribution
|
||||
from skopt.space import Integer, Real # Categorical
|
||||
from optuna.distributions import CategoricalDistribution, FloatDistribution, IntDistribution
|
||||
|
||||
# from skopt.space import Integer, Real # Categorical
|
||||
from freqtrade.optimize.space import SKDecimal
|
||||
|
||||
from freqtrade.exceptions import OperationalException
|
||||
@@ -26,25 +26,37 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ft_CategoricalDistribution(CategoricalDistribution):
|
||||
name: str
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
categories: Sequence[Any],
|
||||
**kwargs,
|
||||
):
|
||||
self.name = name
|
||||
return super().__init__(categories)
|
||||
|
||||
|
||||
class ft_IntDistribution(IntDistribution):
|
||||
name: str
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
low: int,
|
||||
high: int,
|
||||
name: str,
|
||||
low: int | float,
|
||||
high: int | float,
|
||||
**kwargs,
|
||||
):
|
||||
self.name = name
|
||||
return super().__init__(int(low), int(high), **kwargs)
|
||||
|
||||
|
||||
class ft_FloatDistribution(FloatDistribution):
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
low: float,
|
||||
high: float,
|
||||
**kwargs,
|
||||
):
|
||||
self.name = name
|
||||
return super().__init__(low, high, **kwargs)
|
||||
|
||||
|
||||
@@ -76,7 +88,7 @@ class BaseParameter(ABC):
|
||||
:param optimize: Include parameter in hyperopt optimizations.
|
||||
:param load: Load parameter value from {space}_params.
|
||||
:param kwargs: Extra parameters to optuna.distributions.
|
||||
(IntDistribution|Real|CategoricalDistribution).
|
||||
(IntDistribution|FloatDistribution|CategoricalDistribution).
|
||||
"""
|
||||
if "name" in kwargs:
|
||||
raise OperationalException(
|
||||
@@ -94,7 +106,9 @@ class BaseParameter(ABC):
|
||||
@abstractmethod
|
||||
def get_space(
|
||||
self, name: str
|
||||
) -> Union["ft_IntDistribution", "Real", "SKDecimal", "ft_CategoricalDistribution"]:
|
||||
) -> Union[
|
||||
"ft_IntDistribution", "ft_FloatDistribution", "SKDecimal", "ft_CategoricalDistribution"
|
||||
]:
|
||||
"""
|
||||
Get-space - will be used by Hyperopt to get the hyperopt Space
|
||||
"""
|
||||
@@ -136,7 +150,7 @@ class NumericParameter(BaseParameter):
|
||||
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.*.
|
||||
:param kwargs: Extra parameters to optuna.distributions.*.
|
||||
"""
|
||||
if high is not None and isinstance(low, Sequence):
|
||||
raise OperationalException(f"{self.__class__.__name__} space invalid.")
|
||||
@@ -185,15 +199,13 @@ class IntParameter(NumericParameter):
|
||||
low=low, high=high, default=default, space=space, optimize=optimize, load=load, **kwargs
|
||||
)
|
||||
|
||||
def get_space(self, name: str) -> "Integer":
|
||||
def get_space(self, name: str) -> "ft_IntDistribution":
|
||||
"""
|
||||
Create optuna distribution space.
|
||||
:param name: A name of parameter field.
|
||||
"""
|
||||
# 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
|
||||
return ft_IntDistribution(name, self.low, self.high, **self._space_params)
|
||||
|
||||
@property
|
||||
def range(self):
|
||||
@@ -235,18 +247,19 @@ class RealParameter(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.Real.
|
||||
:param kwargs: Extra parameters to optuna.distributions.FloatDistribution.
|
||||
"""
|
||||
super().__init__(
|
||||
low=low, high=high, default=default, space=space, optimize=optimize, load=load, **kwargs
|
||||
)
|
||||
|
||||
def get_space(self, name: str) -> "Real":
|
||||
def get_space(self, name: str) -> "ft_FloatDistribution":
|
||||
"""
|
||||
Create skopt optimization space.
|
||||
:param name: A name of parameter field.
|
||||
"""
|
||||
return Real(low=self.low, high=self.high, name=name, **self._space_params)
|
||||
return ft_FloatDistribution(name, self.low, self.high, **self._space_params)
|
||||
# return Real(low=self.low, high=self.high, name=name, **self._space_params)
|
||||
|
||||
|
||||
class DecimalParameter(NumericParameter):
|
||||
@@ -349,10 +362,8 @@ class CategoricalParameter(BaseParameter):
|
||||
Create optuna distribution space.
|
||||
:param name: A name of parameter field.
|
||||
"""
|
||||
# Categorical(self.opt_range, name=name, **self._space_params)
|
||||
result = ft_CategoricalDistribution(self.opt_range)
|
||||
result.name = name
|
||||
return result
|
||||
# return Categorical(self.opt_range, name=name, **self._space_params)
|
||||
return ft_CategoricalDistribution(name, self.opt_range)
|
||||
|
||||
@property
|
||||
def range(self):
|
||||
|
||||
@@ -7,7 +7,6 @@ from unittest.mock import ANY, MagicMock, PropertyMock
|
||||
import pandas as pd
|
||||
import pytest
|
||||
from filelock import Timeout
|
||||
from skopt.space import Integer
|
||||
|
||||
from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_hyperopt
|
||||
from freqtrade.data.history import load_data
|
||||
@@ -19,6 +18,9 @@ from freqtrade.optimize.hyperopt_tools import HyperoptTools
|
||||
from freqtrade.optimize.optimize_reports import generate_strategy_stats
|
||||
from freqtrade.optimize.space import SKDecimal
|
||||
from freqtrade.strategy import IntParameter
|
||||
|
||||
# from skopt.space import Integer
|
||||
from freqtrade.strategy.parameters import ft_IntDistribution
|
||||
from freqtrade.util import dt_utc
|
||||
from tests.conftest import (
|
||||
CURRENT_TEST_STRATEGY,
|
||||
@@ -1304,7 +1306,8 @@ def test_max_open_trades_consistency(mocker, hyperopt_conf, tmp_path, fee) -> No
|
||||
assert isinstance(hyperopt.hyperopter.custom_hyperopt, HyperOptAuto)
|
||||
|
||||
hyperopt.hyperopter.custom_hyperopt.max_open_trades_space = lambda: [
|
||||
Integer(1, 10, name="max_open_trades")
|
||||
# Integer(1, 10, name="max_open_trades")
|
||||
ft_IntDistribution("max_open_trades", 1, 10)
|
||||
]
|
||||
|
||||
first_time_evaluated = False
|
||||
|
||||
@@ -895,8 +895,7 @@ def test_is_informative_pairs_callback(default_conf):
|
||||
|
||||
def test_hyperopt_parameters():
|
||||
HyperoptStateContainer.set_state(HyperoptState.INDICATORS)
|
||||
from optuna.distributions import CategoricalDistribution, IntDistribution
|
||||
from skopt.space import Real
|
||||
from optuna.distributions import CategoricalDistribution, FloatDistribution, IntDistribution
|
||||
|
||||
with pytest.raises(OperationalException, match=r"Name is determined.*"):
|
||||
IntParameter(low=0, high=5, default=1, name="hello")
|
||||
@@ -939,7 +938,7 @@ def test_hyperopt_parameters():
|
||||
|
||||
fltpar = RealParameter(low=0.0, high=5.5, default=1.0, space="buy")
|
||||
assert fltpar.value == 1
|
||||
assert isinstance(fltpar.get_space(""), Real)
|
||||
assert isinstance(fltpar.get_space(""), FloatDistribution)
|
||||
|
||||
fltpar = DecimalParameter(low=0.0, high=0.5, default=0.14, decimals=1, space="buy")
|
||||
assert fltpar.value == 0.1
|
||||
|
||||
Reference in New Issue
Block a user