| freqai.feature_parameters.label_natr_ratio | 9.0 | float > 0 | Zigzag NATR ratio. |
| freqai.feature_parameters.min_label_natr_ratio | 9.0 | float > 0 | Minimum NATR ratio bound used by label HPO. |
| freqai.feature_parameters.max_label_natr_ratio | 12.0 | float > 0 | Maximum NATR ratio bound used by label HPO. |
-| freqai.feature_parameters.label_frequency_candles | 12 | int >= 2 | Reversals labeling frequency. |
+| freqai.feature_parameters.label_frequency_candles | `auto` | int >= 2 \| `auto` | Reversals labeling frequency. `auto` = max(2, 2 * number of whitelisted pairs). |
| freqai.feature_parameters.label_metric | `euclidean` | string (supported: `euclidean`,`minkowski`,`cityblock`,`chebyshev`,`mahalanobis`,`seuclidean`,`jensenshannon`,`sqeuclidean`,...) | Metric used in distance calculations to ideal point. |
| freqai.feature_parameters.label_weights | [0.5,0.5] | list[float] | Per-objective weights used in distance calculations to ideal point. |
| freqai.feature_parameters.label_p_order | `None` | float | p-order used by Minkowski / power-mean calculations (optional). |
**self.config.get("freqai", {}).get("optuna_hyperopt", {}),
}
- @property
- def _optuna_label_candle_pool_full(self) -> list[int]:
- if not hasattr(self, "pairs") or not self.pairs:
- raise RuntimeError(
- "Failed to initialize optuna label candle pool full: pairs property is not defined or empty"
- )
+ def _get_label_frequency_candles(self) -> int:
+ """
+ Calculate label_frequency_candles.
+
+ Default behavior is 'auto' which equals max(2, 2 * number_of_pairs).
+ User can override with:
+ - "auto" string value
+ - Integer value between 2 and 10000
+
+ Returns:
+ int: The calculated label_frequency_candles value
+
+ Raises:
+ ValueError: If no trading pairs are configured
+ """
n_pairs = len(self.pairs)
- label_frequency_candles = max(
- 2,
- 2 * n_pairs,
- int(
- self.config.get("feature_parameters", {}).get(
- "label_frequency_candles", 12
- )
- ),
+ default_label_frequency_candles = max(2, 2 * n_pairs)
+
+ label_frequency_candles = self.config.get("feature_parameters", {}).get(
+ "label_frequency_candles"
)
+
+ if label_frequency_candles is None:
+ label_frequency_candles = default_label_frequency_candles
+ logger.info(f"{label_frequency_candles=} (default)")
+ elif isinstance(label_frequency_candles, str):
+ if label_frequency_candles == "auto":
+ label_frequency_candles = default_label_frequency_candles
+ logger.info(f"{label_frequency_candles=} (auto)")
+ else:
+ logger.warning(
+ f"Invalid string value for label_frequency_candles: '{label_frequency_candles}'. "
+ f"Only 'auto' is supported. Using fallback"
+ )
+ label_frequency_candles = default_label_frequency_candles
+ logger.info(f"{label_frequency_candles=} (fallback)")
+ elif isinstance(label_frequency_candles, (int, float)):
+ if label_frequency_candles >= 2 and label_frequency_candles <= 10000:
+ label_frequency_candles = int(label_frequency_candles)
+ logger.info(f"{label_frequency_candles=} (configuration)")
+ else:
+ logger.warning(
+ f"Invalid numeric value for label_frequency_candles: {label_frequency_candles}. "
+ f"Must be between 2 and 10000. Using fallback"
+ )
+ label_frequency_candles = default_label_frequency_candles
+ logger.info(f"{label_frequency_candles=} (fallback)")
+ else:
+ logger.warning(
+ f"Invalid type for label_frequency_candles: {type(label_frequency_candles).__name__}. "
+ f"Expected int, float, or 'auto'. Using fallback"
+ )
+ label_frequency_candles = default_label_frequency_candles
+ logger.info(f"{label_frequency_candles=} (fallback)")
+
+ return label_frequency_candles
+
+ @property
+ def _optuna_label_candle_pool_full(self) -> list[int]:
+ label_frequency_candles = self._get_label_frequency_candles()
cache_key = label_frequency_candles
if cache_key not in self._optuna_label_candle_pool_full_cache:
half_label_frequency_candles = int(label_frequency_candles / 2)