]> Piment Noir Git Repositories - freqai-strategies.git/commitdiff
fix(quickadapter): make best params pair-safe (#183)
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Thu, 30 Jul 2026 19:19:35 +0000 (21:19 +0200)
committerGitHub <noreply@github.com>
Thu, 30 Jul 2026 19:19:35 +0000 (21:19 +0200)
* fix(quickadapter): make best params pair-safe

* style(quickadapter): order pair_to_filename import per isort

Place the freqtrade.misc import after the straight third-party imports so the block satisfies ruff's isort ordering (I001), which the pair-safe best-params change had regressed. No behavior change.

* docs(quickadapter): drop internal best-params filename details from warm_start

The warm_start tunable description exposed the on-disk best-params filename convention and legacy base-only cold-start handling: internal implementation detail with no bearing on setting the tunable (AGENTS.md: omit internal details unless necessary for usage). Revert the row to its pre-change wording; the pair-safe fix needs no tunable-doc change.

quickadapter/user_data/strategies/Utils.py

index 561bf58e1ee4d401bff5fd13d35b5427b99e6400..6bf8ad9f1743837876556275ee269ac2b4bec4ba 100644 (file)
@@ -30,6 +30,7 @@ import optuna
 import pandas as pd
 import scipy as sp
 import talib.abstract as ta
+from freqtrade.misc import pair_to_filename
 from LabelTransformer import (
     COMBINED_AGGREGATIONS,
     COMBINED_METRICS,
@@ -5212,8 +5213,14 @@ class _OptunaNamespaces(NamedTuple):
 _OPTUNA_NAMESPACES: Final[_OptunaNamespaces] = _OptunaNamespaces()
 
 
+def _optuna_best_params_path(
+    base_path: Path, pair: str, namespace: OptunaNamespace
+) -> Path:
+    return base_path / f"optuna-{namespace}-best-params-{pair_to_filename(pair)}.json"
+
+
 _OPTUNA_LABEL_BEST_PARAMS_SCHEMA_VERSION: Final[int] = 2
-"""Wire format version of optuna-label-best-params-{pair}.json.
+"""Wire format version of pair-specific Optuna label best-params JSON files.
 
 Incremented on every on-disk JSON shape change (top-level keys, params layout).
 """
@@ -5368,9 +5375,7 @@ def optuna_load_best_params(
     expected_selection_metadata: dict[str, Any] | None = None,
     expected_objective_identity: str | None = None,
 ) -> dict[str, Any] | None:
-    best_params_path = (
-        base_path / f"optuna-{namespace}-best-params-{pair.split('/')[0]}.json"
-    )
+    best_params_path = _optuna_best_params_path(base_path, pair, namespace)
     if best_params_path.is_file():
         with best_params_path.open("r", encoding="utf-8") as read_file:
             best_params = json.load(read_file)
@@ -5396,6 +5401,19 @@ def optuna_load_best_params(
                 return None
             return best_params["params"]
         return best_params
+    legacy_best_params_path = (
+        base_path / f"optuna-{namespace}-best-params-{pair.split('/')[0]}.json"
+    )
+    if (
+        logger is not None
+        and legacy_best_params_path != best_params_path
+        and legacy_best_params_path.is_file()
+    ):
+        logger.warning(
+            f"[{pair}] Ignoring ambiguous legacy Optuna {namespace} best params "
+            f"at {legacy_best_params_path}: filename does not encode the complete "
+            f"pair identity"
+        )
     return None
 
 
@@ -5408,9 +5426,7 @@ def optuna_save_best_params(
     selection_metadata: dict[str, Any] | None = None,
     objective_identity: str | None = None,
 ) -> None:
-    best_params_path = (
-        base_path / f"optuna-{namespace}-best-params-{pair.split('/')[0]}.json"
-    )
+    best_params_path = _optuna_best_params_path(base_path, pair, namespace)
     try:
         if namespace == _OPTUNA_NAMESPACES.label:
             best_params: dict[str, Any] = {