]> Piment Noir Git Repositories - freqai-strategies.git/commitdiff
fix(quickadapter): handle config reload
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Mon, 29 Dec 2025 12:44:58 +0000 (13:44 +0100)
committerJérôme Benoit <jerome.benoit@piment-noir.org>
Mon, 29 Dec 2025 12:44:58 +0000 (13:44 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
ReforceXY/reward_space_analysis/reward_space_analysis.py
ReforceXY/user_data/freqaimodels/ReforceXY.py
ReforceXY/user_data/strategies/RLAgentStrategy.py
quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py
quickadapter/user_data/strategies/QuickAdapterV3.py
quickadapter/user_data/strategies/Utils.py

index 1db151c596db80b0692662d289ba0b4375114ee9..a8ac936e0be2ff41e81e80281d079f40775362db 100644 (file)
@@ -3371,7 +3371,8 @@ def _compute_pnl_duration_signal(
 
     t_pnl = apply_transform(transform_pnl, gain * pnl_ratio)
     t_dur = apply_transform(transform_duration, gain * duration_ratio)
-    value = scale * 0.5 * (t_pnl + np.sign(pnl_ratio) * duration_multiplier * t_dur)
+    pnl_sign = np.sign(pnl_ratio) if not np.isclose(pnl_ratio, 0.0) else 0.0
+    value = scale * 0.5 * (t_pnl + pnl_sign * duration_multiplier * t_dur)
     if not np.isfinite(value):
         return _fail_safely(non_finite_key)
     return float(value)
index 82459f989a54c12ca599f1f7ba42ca3a152ad584..be8e942b77d2b150ef82297e19cf469d342fe247 100644 (file)
@@ -2140,11 +2140,8 @@ class MyRLEnv(Base5ActionRLEnv):
 
         pnl_term = self._potential_transform(transform_pnl, gain * pnl_ratio)
         dur_term = self._potential_transform(transform_duration, gain * duration_ratio)
-        value = (
-            scale
-            * 0.5
-            * (pnl_term + np.sign(pnl_ratio) * duration_multiplier * dur_term)
-        )
+        pnl_sign = np.sign(pnl_ratio) if not np.isclose(pnl_ratio, 0.0) else 0.0
+        value = scale * 0.5 * (pnl_term + pnl_sign * duration_multiplier * dur_term)
         return float(value) if np.isfinite(value) else 0.0
 
     def _compute_hold_potential(
index 3a0db9fb7285e163183f7c6f5fec048d36bf6409..29487ff0e8856933fd0402780aaeef1e4f007c2d 100644 (file)
@@ -30,7 +30,7 @@ class RLAgentStrategy(IStrategy):
     _ACTION_ENTER_SHORT: Final[int] = 3
     _ACTION_EXIT_SHORT: Final[int] = 4
 
-    @cached_property
+    @property
     def can_short(self) -> bool:
         return self.is_short_allowed()
 
index 0bf15eb1a8e4be069b8922cc80a39af5e029e051..034d0df61918230e5781e13be76bd9c393067330 100644 (file)
@@ -4,7 +4,6 @@ import logging
 import random
 import time
 import warnings
-from functools import cached_property
 from pathlib import Path
 from typing import Any, Callable, Final, Literal, Optional, Union
 
@@ -33,11 +32,11 @@ from Utils import (
     eval_set_and_weights,
     fit_regressor,
     format_number,
-    get_config_value,
     get_label_defaults,
     get_min_max_label_period_candles,
     get_optuna_study_model_parameters,
     soft_extremum,
+    update_config_value,
     zigzag,
 )
 
@@ -240,7 +239,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
             return 0.5
         return None
 
-    @cached_property
+    @property
     def _optuna_config(self) -> dict[str, Any]:
         optuna_default_config = {
             "enabled": False,
@@ -265,7 +264,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
             "seed": 1,
         }
         optuna_hyperopt = self.config.get("freqai", {}).get("optuna_hyperopt", {})
-        get_config_value(
+        update_config_value(
             optuna_hyperopt,
             new_key="space_fraction",
             old_key="expansion_ratio",
@@ -279,35 +278,35 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
             **optuna_hyperopt,
         }
 
-    @cached_property
+    @property
     def _min_label_period_candles(self) -> int:
         return self.ft_params.get(
             "min_label_period_candles",
             QuickAdapterRegressorV3.MIN_LABEL_PERIOD_CANDLES_DEFAULT,
         )
 
-    @cached_property
+    @property
     def _max_label_period_candles(self) -> int:
         return self.ft_params.get(
             "max_label_period_candles",
             QuickAdapterRegressorV3.MAX_LABEL_PERIOD_CANDLES_DEFAULT,
         )
 
-    @cached_property
+    @property
     def _min_label_natr_multiplier(self) -> float:
         return self.ft_params.get(
             "min_label_natr_multiplier",
             QuickAdapterRegressorV3.MIN_LABEL_NATR_MULTIPLIER_DEFAULT,
         )
 
-    @cached_property
+    @property
     def _max_label_natr_multiplier(self) -> float:
         return self.ft_params.get(
             "max_label_natr_multiplier",
             QuickAdapterRegressorV3.MAX_LABEL_NATR_MULTIPLIER_DEFAULT,
         )
 
-    @cached_property
+    @property
     def _label_frequency_candles(self) -> int:
         """
         Calculate label_frequency_candles.
@@ -355,13 +354,13 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
 
         return label_frequency_candles
 
-    @cached_property
+    @property
     def predictions_extrema(self) -> dict[str, Any]:
         predictions_extrema = self.freqai_info.get("predictions_extrema", {})
         if not isinstance(predictions_extrema, dict):
             predictions_extrema = {}
 
-        outlier_threshold_quantile = get_config_value(
+        outlier_threshold_quantile = update_config_value(
             predictions_extrema,
             new_key="outlier_threshold_quantile",
             old_key="threshold_outlier",
@@ -390,7 +389,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
             selection_method = QuickAdapterRegressorV3._EXTREMA_SELECTION_METHODS[0]
 
         threshold_smoothing_method = str(
-            get_config_value(
+            update_config_value(
                 predictions_extrema,
                 new_key="threshold_smoothing_method",
                 old_key="thresholds_smoothing",
@@ -408,7 +407,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                 0
             ]  # "mean"
 
-        soft_extremum_alpha = get_config_value(
+        soft_extremum_alpha = update_config_value(
             predictions_extrema,
             new_key="soft_extremum_alpha",
             old_key="thresholds_alpha",
@@ -426,7 +425,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                 QuickAdapterRegressorV3.PREDICTIONS_EXTREMA_SOFT_EXTREMUM_ALPHA_DEFAULT
             )
 
-        keep_extrema_fraction = get_config_value(
+        keep_extrema_fraction = update_config_value(
             predictions_extrema,
             new_key="keep_extrema_fraction",
             old_key="extrema_fraction",
@@ -448,6 +447,10 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
             "keep_extrema_fraction": float(keep_extrema_fraction),
         }
 
+    @property
+    def _label_defaults(self) -> tuple[int, float]:
+        return get_label_defaults(self.ft_params, logger)
+
     @property
     def _optuna_label_candle_pool_full(self) -> list[int]:
         label_frequency_candles = self._label_frequency_candles
@@ -496,8 +499,8 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
         self._optuna_label_candle: dict[str, int] = {}
         self._optuna_label_candles: dict[str, int] = {}
         self._optuna_label_incremented_pairs: list[str] = []
-        self._default_label_natr_multiplier, self._default_label_period_candles = (
-            get_label_defaults(self.ft_params, logger)
+        default_label_period_candles, default_label_natr_multiplier = (
+            self._label_defaults
         )
         for pair in self.pairs:
             self._optuna_hp_value[pair] = -1
@@ -533,12 +536,12 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                 else {
                     "label_period_candles": self.ft_params.get(
                         "label_period_candles",
-                        self._default_label_period_candles,
+                        default_label_period_candles,
                     ),
                     "label_natr_multiplier": float(
                         self.ft_params.get(
                             "label_natr_multiplier",
-                            self._default_label_natr_multiplier,
+                            default_label_natr_multiplier,
                         )
                     ),
                 }
@@ -830,12 +833,15 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                         f"label_natr_multiplier={format_number(params.get('label_natr_multiplier'))}"
                     )
         else:
+            default_label_period_candles, default_label_natr_multiplier = (
+                self._label_defaults
+            )
             logger.info("Label Parameters:")
             logger.info(
-                f"  label_period_candles: {self.ft_params.get('label_period_candles', self._default_label_period_candles)}"
+                f"  label_period_candles: {self.ft_params.get('label_period_candles', default_label_period_candles)}"
             )
             logger.info(
-                f"  label_natr_multiplier: {format_number(float(self.ft_params.get('label_natr_multiplier', self._default_label_natr_multiplier)))}"
+                f"  label_natr_multiplier: {format_number(float(self.ft_params.get('label_natr_multiplier', default_label_natr_multiplier)))}"
             )
 
         logger.info("=" * 60)
@@ -1276,7 +1282,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
     ) -> tuple[float, float]:
         if not isinstance(label_period_candles, int) or label_period_candles <= 0:
             label_period_candles = self.ft_params.get(
-                "label_period_candles", self._default_label_period_candles
+                "label_period_candles", self._label_defaults[0]
             )
         thresholds_candles = (
             max(2, int(fit_live_predictions_candles / label_period_candles))
index f92587770c22b614c0a5c37870acd0109dfc158c..63f053b119c4eb0a29debce0160767e07ac09168 100644 (file)
@@ -48,7 +48,6 @@ from Utils import (
     ewo,
     format_number,
     get_callable_sha256,
-    get_config_value,
     get_distance,
     get_label_defaults,
     get_weighted_extrema,
@@ -58,6 +57,7 @@ from Utils import (
     price_retracement_percent,
     smooth_extrema,
     top_change_percent,
+    update_config_value,
     validate_range,
     vwapb,
     zigzag,
@@ -177,7 +177,7 @@ class QuickAdapterV3(IStrategy):
     def _order_types_set() -> set[OrderType]:
         return {QuickAdapterV3._ORDER_TYPES[0], QuickAdapterV3._ORDER_TYPES[1]}
 
-    @cached_property
+    @property
     def can_short(self) -> bool:
         return self.is_short_allowed()
 
@@ -202,7 +202,7 @@ class QuickAdapterV3(IStrategy):
             },
         }
 
-    @cached_property
+    @property
     def protections(self) -> list[dict[str, Any]]:
         fit_live_predictions_candles = int(
             self.config.get("freqai", {}).get(
@@ -277,14 +277,14 @@ class QuickAdapterV3(IStrategy):
 
     use_exit_signal = True
 
-    @cached_property
+    @property
     def startup_candle_count(self) -> int:
         # Match the predictions warmup period
         return self.config.get("freqai", {}).get(
             "fit_live_predictions_candles", DEFAULT_FIT_LIVE_PREDICTIONS_CANDLES
         )
 
-    @cached_property
+    @property
     def max_open_trades_per_side(self) -> int:
         max_open_trades = self.config.get("max_open_trades", 0)
         if max_open_trades < 0:
@@ -296,20 +296,135 @@ class QuickAdapterV3(IStrategy):
         else:
             return max_open_trades
 
-    @cached_property
+    @property
     def extrema_weighting(self) -> dict[str, Any]:
         extrema_weighting = self.freqai_info.get("extrema_weighting", {})
         if not isinstance(extrema_weighting, dict):
             extrema_weighting = {}
         return QuickAdapterV3._get_extrema_weighting_params(extrema_weighting)
 
-    @cached_property
+    @property
     def extrema_smoothing(self) -> dict[str, Any]:
         extrema_smoothing = self.freqai_info.get("extrema_smoothing", {})
         if not isinstance(extrema_smoothing, dict):
             extrema_smoothing = {}
         return QuickAdapterV3._get_extrema_smoothing_params(extrema_smoothing)
 
+    @property
+    def trade_price_target_method(self) -> str:
+        exit_pricing = self.config.get("exit_pricing", {})
+        trade_price_target_method = update_config_value(
+            exit_pricing,
+            new_key="trade_price_target_method",
+            old_key="trade_price_target",
+            default=TRADE_PRICE_TARGETS[0],  # "moving_average"
+            logger=logger,
+            new_path="exit_pricing.trade_price_target_method",
+            old_path="exit_pricing.trade_price_target",
+        )
+        if trade_price_target_method not in set(TRADE_PRICE_TARGETS):
+            logger.warning(
+                f"Invalid trade_price_target_method {trade_price_target_method!r}. "
+                f"Supported: {', '.join(TRADE_PRICE_TARGETS)}. "
+                f"Using default {TRADE_PRICE_TARGETS[0]!r}"
+            )
+            trade_price_target_method = TRADE_PRICE_TARGETS[0]
+        return str(trade_price_target_method)
+
+    @property
+    def reversal_confirmation(self) -> dict[str, int | float]:
+        reversal_confirmation = self.config.get("reversal_confirmation", {})
+
+        lookback_period_candles = update_config_value(
+            reversal_confirmation,
+            new_key="lookback_period_candles",
+            old_key="lookback_period",
+            default=QuickAdapterV3.default_reversal_confirmation[
+                "lookback_period_candles"
+            ],
+            logger=logger,
+            new_path="reversal_confirmation.lookback_period_candles",
+            old_path="reversal_confirmation.lookback_period",
+        )
+        decay_fraction = update_config_value(
+            reversal_confirmation,
+            new_key="decay_fraction",
+            old_key="decay_ratio",
+            default=QuickAdapterV3.default_reversal_confirmation["decay_fraction"],
+            logger=logger,
+            new_path="reversal_confirmation.decay_fraction",
+            old_path="reversal_confirmation.decay_ratio",
+        )
+
+        min_natr_multiplier_fraction = update_config_value(
+            reversal_confirmation,
+            new_key="min_natr_multiplier_fraction",
+            old_key="min_natr_ratio_percent",
+            default=QuickAdapterV3.default_reversal_confirmation[
+                "min_natr_multiplier_fraction"
+            ],
+            logger=logger,
+            new_path="reversal_confirmation.min_natr_multiplier_fraction",
+            old_path="reversal_confirmation.min_natr_ratio_percent",
+        )
+        max_natr_multiplier_fraction = update_config_value(
+            reversal_confirmation,
+            new_key="max_natr_multiplier_fraction",
+            old_key="max_natr_ratio_percent",
+            default=QuickAdapterV3.default_reversal_confirmation[
+                "max_natr_multiplier_fraction"
+            ],
+            logger=logger,
+            new_path="reversal_confirmation.max_natr_multiplier_fraction",
+            old_path="reversal_confirmation.max_natr_ratio_percent",
+        )
+
+        if not isinstance(lookback_period_candles, int) or lookback_period_candles < 0:
+            logger.warning(
+                f"Invalid reversal_confirmation lookback_period_candles {lookback_period_candles!r}: must be >= 0. Using default {QuickAdapterV3.default_reversal_confirmation['lookback_period_candles']!r}"
+            )
+            lookback_period_candles = QuickAdapterV3.default_reversal_confirmation[
+                "lookback_period_candles"
+            ]
+
+        if not isinstance(decay_fraction, (int, float)) or not (
+            0.0 < decay_fraction <= 1.0
+        ):
+            logger.warning(
+                f"Invalid reversal_confirmation decay_fraction {decay_fraction!r}: must be in range (0, 1]. Using default {QuickAdapterV3.default_reversal_confirmation['decay_fraction']!r}"
+            )
+            decay_fraction = QuickAdapterV3.default_reversal_confirmation[
+                "decay_fraction"
+            ]
+
+        min_natr_multiplier_fraction, max_natr_multiplier_fraction = validate_range(
+            min_natr_multiplier_fraction,
+            max_natr_multiplier_fraction,
+            logger,
+            name="natr_multiplier_fraction",
+            default_min=QuickAdapterV3.default_reversal_confirmation[
+                "min_natr_multiplier_fraction"
+            ],
+            default_max=QuickAdapterV3.default_reversal_confirmation[
+                "max_natr_multiplier_fraction"
+            ],
+            allow_equal=False,
+            non_negative=True,
+            finite_only=True,
+        )
+
+        return {
+            "lookback_period_candles": int(lookback_period_candles),
+            "decay_fraction": float(decay_fraction),
+            "min_natr_multiplier_fraction": float(min_natr_multiplier_fraction),
+            "max_natr_multiplier_fraction": float(max_natr_multiplier_fraction),
+        }
+
+    @property
+    def _label_defaults(self) -> tuple[int, float]:
+        feature_parameters = self.freqai_info.get("feature_parameters", {})
+        return get_label_defaults(feature_parameters, logger)
+
     def bot_start(self, **kwargs) -> None:
         self.pairs: list[str] = self.config.get("exchange", {}).get("pair_whitelist")
         if not self.pairs:
@@ -329,8 +444,8 @@ class QuickAdapterV3(IStrategy):
             / self.freqai_info.get("identifier")
         )
         feature_parameters = self.freqai_info.get("feature_parameters", {})
-        self._default_label_natr_multiplier, self._default_label_period_candles = (
-            get_label_defaults(feature_parameters, logger)
+        default_label_period_candles, default_label_natr_multiplier = (
+            self._label_defaults
         )
         self._label_params: dict[str, dict[str, Any]] = {}
         for pair in self.pairs:
@@ -340,17 +455,16 @@ class QuickAdapterV3(IStrategy):
                 else {
                     "label_period_candles": feature_parameters.get(
                         "label_period_candles",
-                        self._default_label_period_candles,
+                        default_label_period_candles,
                     ),
                     "label_natr_multiplier": float(
                         feature_parameters.get(
                             "label_natr_multiplier",
-                            self._default_label_natr_multiplier,
+                            default_label_natr_multiplier,
                         )
                     ),
                 }
             )
-        self._init_reversal_confirmation_defaults()
         self._candle_duration_secs = int(
             timeframe_to_minutes(self.config.get("timeframe")) * 60
         )
@@ -416,28 +530,20 @@ class QuickAdapterV3(IStrategy):
 
         logger.info("Reversal Confirmation:")
         logger.info(
-            f"  lookback_period_candles: {self._reversal_lookback_period_candles}"
+            f"  lookback_period_candles: {self.reversal_confirmation['lookback_period_candles']}"
         )
-        logger.info(f"  decay_fraction: {format_number(self._reversal_decay_fraction)}")
         logger.info(
-            f"  min_natr_multiplier_fraction: {format_number(self._reversal_min_natr_multiplier_fraction)}"
+            f"  decay_fraction: {format_number(self.reversal_confirmation['decay_fraction'])}"
         )
         logger.info(
-            f"  max_natr_multiplier_fraction: {format_number(self._reversal_max_natr_multiplier_fraction)}"
+            f"  min_natr_multiplier_fraction: {format_number(self.reversal_confirmation['min_natr_multiplier_fraction'])}"
         )
-
-        exit_pricing = self.config.get("exit_pricing", {})
-        trade_price_target_method = get_config_value(
-            exit_pricing,
-            new_key="trade_price_target_method",
-            old_key="trade_price_target",
-            default=TRADE_PRICE_TARGETS[0],  # "moving_average"
-            logger=logger,
-            new_path="exit_pricing.trade_price_target_method",
-            old_path="exit_pricing.trade_price_target",
+        logger.info(
+            f"  max_natr_multiplier_fraction: {format_number(self.reversal_confirmation['max_natr_multiplier_fraction'])}"
         )
+
         logger.info("Exit Pricing:")
-        logger.info(f"  trade_price_target_method: {trade_price_target_method}")
+        logger.info(f"  trade_price_target_method: {self.trade_price_target_method}")
         logger.info(f"  thresholds_calibration: {self._exit_thresholds_calibration}")
 
         logger.info("Custom Stoploss:")
@@ -486,95 +592,6 @@ class QuickAdapterV3(IStrategy):
         dates = df.get("date")
         return (n, dates.iloc[-1] if dates is not None and not dates.empty else None)
 
-    def _init_reversal_confirmation_defaults(self) -> None:
-        reversal_confirmation = self.config.get("reversal_confirmation", {})
-        lookback_period_candles = get_config_value(
-            reversal_confirmation,
-            new_key="lookback_period_candles",
-            old_key="lookback_period",
-            default=QuickAdapterV3.default_reversal_confirmation[
-                "lookback_period_candles"
-            ],
-            logger=logger,
-            new_path="reversal_confirmation.lookback_period_candles",
-            old_path="reversal_confirmation.lookback_period",
-        )
-        decay_fraction = get_config_value(
-            reversal_confirmation,
-            new_key="decay_fraction",
-            old_key="decay_ratio",
-            default=QuickAdapterV3.default_reversal_confirmation["decay_fraction"],
-            logger=logger,
-            new_path="reversal_confirmation.decay_fraction",
-            old_path="reversal_confirmation.decay_ratio",
-        )
-
-        min_natr_multiplier_fraction = get_config_value(
-            reversal_confirmation,
-            new_key="min_natr_multiplier_fraction",
-            old_key="min_natr_ratio_percent",
-            default=QuickAdapterV3.default_reversal_confirmation[
-                "min_natr_multiplier_fraction"
-            ],
-            logger=logger,
-            new_path="reversal_confirmation.min_natr_multiplier_fraction",
-            old_path="reversal_confirmation.min_natr_ratio_percent",
-        )
-        max_natr_multiplier_fraction = get_config_value(
-            reversal_confirmation,
-            new_key="max_natr_multiplier_fraction",
-            old_key="max_natr_ratio_percent",
-            default=QuickAdapterV3.default_reversal_confirmation[
-                "max_natr_multiplier_fraction"
-            ],
-            logger=logger,
-            new_path="reversal_confirmation.max_natr_multiplier_fraction",
-            old_path="reversal_confirmation.max_natr_ratio_percent",
-        )
-
-        if not isinstance(lookback_period_candles, int) or lookback_period_candles < 0:
-            logger.warning(
-                f"Invalid reversal_confirmation lookback_period_candles {lookback_period_candles!r}: must be >= 0. Using default {QuickAdapterV3.default_reversal_confirmation['lookback_period_candles']!r}"
-            )
-            lookback_period_candles = QuickAdapterV3.default_reversal_confirmation[
-                "lookback_period_candles"
-            ]
-
-        if not isinstance(decay_fraction, (int, float)) or not (
-            0.0 < decay_fraction <= 1.0
-        ):
-            logger.warning(
-                f"Invalid reversal_confirmation decay_fraction {decay_fraction!r}: must be in range (0, 1]. Using default {QuickAdapterV3.default_reversal_confirmation['decay_fraction']!r}"
-            )
-            decay_fraction = QuickAdapterV3.default_reversal_confirmation[
-                "decay_fraction"
-            ]
-
-        min_natr_multiplier_fraction, max_natr_multiplier_fraction = validate_range(
-            min_natr_multiplier_fraction,
-            max_natr_multiplier_fraction,
-            logger,
-            name="natr_multiplier_fraction",
-            default_min=QuickAdapterV3.default_reversal_confirmation[
-                "min_natr_multiplier_fraction"
-            ],
-            default_max=QuickAdapterV3.default_reversal_confirmation[
-                "max_natr_multiplier_fraction"
-            ],
-            allow_equal=False,
-            non_negative=True,
-            finite_only=True,
-        )
-
-        self._reversal_lookback_period_candles = int(lookback_period_candles)
-        self._reversal_decay_fraction = float(decay_fraction)
-        self._reversal_min_natr_multiplier_fraction = float(
-            min_natr_multiplier_fraction
-        )
-        self._reversal_max_natr_multiplier_fraction = float(
-            max_natr_multiplier_fraction
-        )
-
     def feature_engineering_expand_all(
         self, dataframe: DataFrame, period: int, metadata: dict[str, Any], **kwargs
     ) -> DataFrame:
@@ -750,7 +767,7 @@ class QuickAdapterV3(IStrategy):
             return label_period_candles
         return self.freqai_info.get("feature_parameters", {}).get(
             "label_period_candles",
-            self._default_label_period_candles,
+            self._label_defaults[0],
         )
 
     def set_label_period_candles(self, pair: str, label_period_candles: int) -> None:
@@ -765,9 +782,7 @@ class QuickAdapterV3(IStrategy):
             return label_natr_multiplier
         feature_parameters = self.freqai_info.get("feature_parameters", {})
         return float(
-            feature_parameters.get(
-                "label_natr_multiplier", self._default_label_natr_multiplier
-            )
+            feature_parameters.get("label_natr_multiplier", self._label_defaults[1])
         )
 
     def set_label_natr_multiplier(
@@ -1049,7 +1064,7 @@ class QuickAdapterV3(IStrategy):
             )
             smoothing_method = SMOOTHING_METHODS[0]
 
-        smoothing_window_candles = get_config_value(
+        smoothing_window_candles = update_config_value(
             extrema_smoothing,
             new_key="window_candles",
             old_key="window",
@@ -1456,16 +1471,6 @@ class QuickAdapterV3(IStrategy):
     def get_trade_natr(
         self, df: DataFrame, trade: Trade, trade_duration_candles: int
     ) -> Optional[float]:
-        exit_pricing = self.config.get("exit_pricing", {})
-        trade_price_target_method = get_config_value(
-            exit_pricing,
-            new_key="trade_price_target_method",
-            old_key="trade_price_target",
-            default=TRADE_PRICE_TARGETS[0],  # "moving_average"
-            logger=logger,
-            new_path="exit_pricing.trade_price_target_method",
-            old_path="exit_pricing.trade_price_target",
-        )
         trade_price_target_methods: dict[str, Callable[[], Optional[float]]] = {
             # 0 - "moving_average"
             TRADE_PRICE_TARGETS[0]: lambda: self.get_trade_moving_average_natr(
@@ -1481,11 +1486,11 @@ class QuickAdapterV3(IStrategy):
             ),
         }
         trade_price_target_method_fn = trade_price_target_methods.get(
-            trade_price_target_method
+            self.trade_price_target_method
         )
         if trade_price_target_method_fn is None:
             raise ValueError(
-                f"Invalid trade_price_target_method {trade_price_target_method!r}. "
+                f"Invalid trade_price_target_method {self.trade_price_target_method!r}. "
                 f"Supported: {', '.join(TRADE_PRICE_TARGETS)}"
             )
         return trade_price_target_method_fn()
@@ -2075,8 +2080,10 @@ class QuickAdapterV3(IStrategy):
 
         trade_direction = side
 
-        max_lookback_period = max(0, len(df) - 1)
-        lookback_period_candles = min(lookback_period_candles, max_lookback_period)
+        max_lookback_period_candles = max(0, len(df) - 1)
+        lookback_period_candles = min(
+            lookback_period_candles, max_lookback_period_candles
+        )
         if not isinstance(decay_fraction, (int, float)):
             logger.debug(
                 f"[{pair}] Denied {trade_direction} {order}: invalid decay_fraction type"
@@ -2353,10 +2360,10 @@ class QuickAdapterV3(IStrategy):
                 QuickAdapterV3._TRADE_DIRECTIONS[0],  # "long"
                 QuickAdapterV3._ORDER_TYPES[1],  # "exit"
                 current_rate,
-                self._reversal_lookback_period_candles,
-                self._reversal_decay_fraction,
-                self._reversal_min_natr_multiplier_fraction,
-                self._reversal_max_natr_multiplier_fraction,
+                self.reversal_confirmation["lookback_period_candles"],
+                self.reversal_confirmation["decay_fraction"],
+                self.reversal_confirmation["min_natr_multiplier_fraction"],
+                self.reversal_confirmation["max_natr_multiplier_fraction"],
             )
         ):
             return "minima_detected_short"
@@ -2371,10 +2378,10 @@ class QuickAdapterV3(IStrategy):
                 QuickAdapterV3._TRADE_DIRECTIONS[1],  # "short"
                 QuickAdapterV3._ORDER_TYPES[1],  # "exit"
                 current_rate,
-                self._reversal_lookback_period_candles,
-                self._reversal_decay_fraction,
-                self._reversal_min_natr_multiplier_fraction,
-                self._reversal_max_natr_multiplier_fraction,
+                self.reversal_confirmation["lookback_period_candles"],
+                self.reversal_confirmation["decay_fraction"],
+                self.reversal_confirmation["min_natr_multiplier_fraction"],
+                self.reversal_confirmation["max_natr_multiplier_fraction"],
             )
         ):
             return "maxima_detected_long"
@@ -2534,10 +2541,10 @@ class QuickAdapterV3(IStrategy):
             side,
             QuickAdapterV3._ORDER_TYPES[0],  # "entry"
             rate,
-            self._reversal_lookback_period_candles,
-            self._reversal_decay_fraction,
-            self._reversal_min_natr_multiplier_fraction,
-            self._reversal_max_natr_multiplier_fraction,
+            self.reversal_confirmation["lookback_period_candles"],
+            self.reversal_confirmation["decay_fraction"],
+            self.reversal_confirmation["min_natr_multiplier_fraction"],
+            self.reversal_confirmation["max_natr_multiplier_fraction"],
         ):
             return True
         return False
index 920096c61cdbe99dd47168bcfd7e6308d482d4c0..af9c6f3cc5f0fb02b61fca3df2c79b94b9c840b5 100644 (file)
@@ -2672,7 +2672,7 @@ def floor_to_step(value: float | int, step: int) -> int:
     return int(math.floor(float(value) / step) * step)
 
 
-def get_config_value(
+def update_config_value(
     config: Any,
     *,
     new_key: str,
@@ -2773,8 +2773,8 @@ def get_label_defaults(
     default_max_label_period_candles: int = 24,
     default_min_label_natr_multiplier: float = 9.0,
     default_max_label_natr_multiplier: float = 12.0,
-) -> tuple[float, int]:
-    min_label_natr_multiplier = get_config_value(
+) -> tuple[int, float]:
+    min_label_natr_multiplier = update_config_value(
         feature_parameters,
         new_key="min_label_natr_multiplier",
         old_key="min_label_natr_ratio",
@@ -2783,7 +2783,7 @@ def get_label_defaults(
         new_path="freqai.feature_parameters.min_label_natr_multiplier",
         old_path="freqai.feature_parameters.min_label_natr_ratio",
     )
-    max_label_natr_multiplier = get_config_value(
+    max_label_natr_multiplier = update_config_value(
         feature_parameters,
         new_key="max_label_natr_multiplier",
         old_key="max_label_natr_ratio",
@@ -2806,7 +2806,7 @@ def get_label_defaults(
     default_label_natr_multiplier = float(
         midpoint(min_label_natr_multiplier, max_label_natr_multiplier)
     )
-    get_config_value(
+    update_config_value(
         feature_parameters,
         new_key="label_natr_multiplier",
         old_key="label_natr_ratio",
@@ -2837,4 +2837,4 @@ def get_label_defaults(
         round(midpoint(min_label_period_candles, max_label_period_candles))
     )
 
-    return default_label_natr_multiplier, default_label_period_candles
+    return default_label_period_candles, default_label_natr_multiplier