|
|
|
|
@ -30,15 +30,15 @@ from freqtrade.optimize.optimize_reports import generate_strategy_stats
|
|
|
|
|
from freqtrade.resolvers.hyperopt_resolver import HyperOptLossResolver
|
|
|
|
|
from freqtrade.util.dry_run_wallet import get_dry_run_wallet
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Suppress scikit-learn FutureWarnings from skopt
|
|
|
|
|
with warnings.catch_warnings():
|
|
|
|
|
warnings.filterwarnings("ignore", category=FutureWarning)
|
|
|
|
|
# from skopt import Optimizer
|
|
|
|
|
from freqtrade.optimize.space.decimalspace import SKDecimal
|
|
|
|
|
from skopt.space import Categorical, Integer, Real
|
|
|
|
|
import optuna
|
|
|
|
|
import optunahub
|
|
|
|
|
from skopt.space import Dimension
|
|
|
|
|
from skopt.space import Categorical, Dimension, Integer, Real
|
|
|
|
|
|
|
|
|
|
from freqtrade.optimize.space.decimalspace import SKDecimal
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
@ -61,7 +61,7 @@ class HyperOptimizer:
|
|
|
|
|
self.trailing_space: list[Dimension] = []
|
|
|
|
|
self.max_open_trades_space: list[Dimension] = []
|
|
|
|
|
self.dimensions: list[Dimension] = []
|
|
|
|
|
self.o_dimensions: Dict = {}
|
|
|
|
|
self.o_dimensions: dict = {}
|
|
|
|
|
|
|
|
|
|
self.config = config
|
|
|
|
|
self.min_date: datetime
|
|
|
|
|
@ -131,7 +131,9 @@ class HyperOptimizer:
|
|
|
|
|
self.hyperopt_pickle_magic(modules.__bases__)
|
|
|
|
|
|
|
|
|
|
def _get_params_dict(
|
|
|
|
|
self, dimensions: list[Dimension], raw_params: dict[str, Any] # list[Any]
|
|
|
|
|
self,
|
|
|
|
|
dimensions: list[Dimension],
|
|
|
|
|
raw_params: dict[str, Any],
|
|
|
|
|
) -> dict[str, Any]:
|
|
|
|
|
# logger.info(f"_get_params_dict: {raw_params}")
|
|
|
|
|
# Ensure the number of dimensions match
|
|
|
|
|
@ -253,7 +255,7 @@ class HyperOptimizer:
|
|
|
|
|
# noinspection PyProtectedMember
|
|
|
|
|
attr.value = params_dict[attr_name]
|
|
|
|
|
|
|
|
|
|
def generate_optimizer(self, raw_params: list[Any]) -> dict[str, Any]:
|
|
|
|
|
def generate_optimizer(self, raw_params: dict[str, Any]) -> dict[str, Any]: # list[Any]
|
|
|
|
|
"""
|
|
|
|
|
Used Optimize function.
|
|
|
|
|
Called once per epoch to optimize whatever is configured.
|
|
|
|
|
@ -385,41 +387,32 @@ class HyperOptimizer:
|
|
|
|
|
"total_profit": total_profit,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def convert_dimensions_to_optuna_space(self, s_dimensions: list[Dimension]) -> dict:
|
|
|
|
|
o_dimensions = {}
|
|
|
|
|
for original_dim in s_dimensions:
|
|
|
|
|
if type(original_dim) == Integer: # isinstance(original_dim, Integer):
|
|
|
|
|
if isinstance(original_dim, Integer):
|
|
|
|
|
o_dimensions[original_dim.name] = optuna.distributions.IntDistribution(
|
|
|
|
|
original_dim.low, original_dim.high, log=False, step=1
|
|
|
|
|
)
|
|
|
|
|
elif (
|
|
|
|
|
type(original_dim) == SKDecimal
|
|
|
|
|
):
|
|
|
|
|
elif isinstance(original_dim, SKDecimal):
|
|
|
|
|
o_dimensions[original_dim.name] = optuna.distributions.FloatDistribution(
|
|
|
|
|
original_dim.low_orig,
|
|
|
|
|
original_dim.high_orig,
|
|
|
|
|
log=False,
|
|
|
|
|
step=1 / pow(10, original_dim.decimals)
|
|
|
|
|
step=1 / pow(10, original_dim.decimals),
|
|
|
|
|
)
|
|
|
|
|
elif (
|
|
|
|
|
type(original_dim) == Real
|
|
|
|
|
):
|
|
|
|
|
elif isinstance(original_dim, Real):
|
|
|
|
|
o_dimensions[original_dim.name] = optuna.distributions.FloatDistribution(
|
|
|
|
|
original_dim.low,
|
|
|
|
|
original_dim.high,
|
|
|
|
|
log=False,
|
|
|
|
|
)
|
|
|
|
|
elif (
|
|
|
|
|
type(original_dim) == Categorical
|
|
|
|
|
):
|
|
|
|
|
elif isinstance(original_dim, Categorical):
|
|
|
|
|
o_dimensions[original_dim.name] = optuna.distributions.CategoricalDistribution(
|
|
|
|
|
list(original_dim.bounds)
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
raise Exception(
|
|
|
|
|
f"Unknown search space {original_dim} / {type(original_dim)}"
|
|
|
|
|
)
|
|
|
|
|
raise Exception(f"Unknown search space {original_dim} / {type(original_dim)}")
|
|
|
|
|
# logger.info(f"convert_dimensions_to_optuna_space: {s_dimensions} - {o_dimensions}")
|
|
|
|
|
return o_dimensions
|
|
|
|
|
|
|
|
|
|
@ -427,7 +420,6 @@ class HyperOptimizer:
|
|
|
|
|
self,
|
|
|
|
|
random_state: int,
|
|
|
|
|
):
|
|
|
|
|
|
|
|
|
|
o_sampler = self.custom_hyperopt.generate_estimator(dimensions=self.dimensions)
|
|
|
|
|
self.o_dimensions = self.convert_dimensions_to_optuna_space(self.dimensions)
|
|
|
|
|
|
|
|
|
|
@ -437,9 +429,14 @@ class HyperOptimizer:
|
|
|
|
|
# restored_sampler = pickle.load(open("sampler.pkl", "rb"))
|
|
|
|
|
|
|
|
|
|
if isinstance(o_sampler, str):
|
|
|
|
|
if o_sampler not in ("TPESampler", "GPSampler", "CmaEsSampler",
|
|
|
|
|
"NSGAIISampler", "NSGAIIISampler", "QMCSampler"
|
|
|
|
|
):
|
|
|
|
|
if o_sampler not in (
|
|
|
|
|
"TPESampler",
|
|
|
|
|
"GPSampler",
|
|
|
|
|
"CmaEsSampler",
|
|
|
|
|
"NSGAIISampler",
|
|
|
|
|
"NSGAIIISampler",
|
|
|
|
|
"QMCSampler",
|
|
|
|
|
):
|
|
|
|
|
raise OperationalException(f"Optuna Sampler {o_sampler} not supported.")
|
|
|
|
|
|
|
|
|
|
if o_sampler == "TPESampler":
|
|
|
|
|
|