refactor(quickadapter): harmonize patterns and consolidate common logic (#126)
* refactor(quickadapter): harmonize patterns and consolidate common logic
Behavior-preserving refactor of the QuickAdapter codebase (Utils.py,
QuickAdapterV3.py, QuickAdapterRegressorV3.py). Every change verified in the
project Docker image (freqtrade + optuna/ngboost/catboost) via import smoke and
per-change golden/behavior tests; py_compile clean, ruff E,F,W baseline unchanged
or reduced, ruff format clean.
Consolidation:
- C1: single _get_validation_size() replaces 3 identical test_size None-coerce blocks (None-vs-0 distinction preserved).
- C2: _resolve_optuna_store() registry replaces 6 near-duplicate get/set_optuna_* dispatchers; hp-only/label-only asymmetry and per-accessor defaults preserved.
- C4: as_dict() helper replaces 7 dict-guard blocks across both classes.
- C5: _distance_to_reference() extracts the 4-family distance dispatch shared by _compromise_programming_scores and _topsis_scores (apply_abs flag preserves the TOPSIS-only np.abs asymmetry); golden differential over all 17 metrics is bit-identical.
- C6: _trade_natr_window() extracts the shared NATR preamble of the weighted/quantile trade-NATR methods (single-candle sentinel preserved).
- C7: _invalidate_pair_cache() replaces 2 identical per-pair cache-invalidation blocks (rebind-on-change / same-object-on-noop preserved).
- C8: _validate_step_args() shares the guard preamble of round/ceil/floor_to_step.
- C9: _pop_early_stopping_rounds() and _apply_verbosity_alias() replace repeated fit_regressor boilerplate (verbose precedence preserved).
- C10: drop dead default 2nd-args on _optuna_config[...] lookups (merge is exhaustive; constant_liar path kept).
Harmonization:
- H2/C3: fold 3 near-identical scalar validators into one _validate_scalar(predicate, constraint); exact messages preserved (subsumes H1 predicate sharing).
- H4: single canonical source for label defaults in Utils; RV3 ClassVars reference it (fixes value duplication).
- H6: enum_error_message() builder; identical-text regressor/aggregation raises routed through it.
- H7: make the intended mode="raise" explicit for label_method and scaler validation (no behavior change).
Notes:
- H5 (DEFAULT_X vs X_DEFAULT naming): the duplicated default values were removed by H4; the remaining prefix/suffix difference is a consistent module-scalar vs class-ClassVar convention, left as-is.
- H3 (magic-index TUPLE[n] -> named members) remains as a follow-up; behavior-neutral cosmetic cleanup.
* refactor(quickadapter): replace magic-index dispatch with named constants (H3)
Every fragile TUPLE[n] dispatch/comparison site (~64 across the three files) now
reads a named Final constant defined next to its tuple, extending the existing
_OPTUNA_NAMESPACES / _REGRESSOR_SPECS idiom. Reordering a literals tuple can no
longer silently break dispatch, and the trailing `# "name"` comments are removed
as redundant.
The canonical named-derivation definitions (_UNSUPPORTED_WEIGHTS_METRICS and the
LABEL_*_DEFAULT / *_DEFAULT ClassVars) keep their index form: they are the single
source that maps index -> name. Behaviour preserved by construction (each named
constant is bound to the same tuple element); verified in the project Docker image
by asserting every constant equals its tuple value and that CP/TOPSIS scoring is
unchanged.
- M1: hoist the scipy cdist kwargs in _topsis_scores and pass them into both
_distance_to_reference calls, so _prepare_distance_kwargs (and its warn-mode
validators) run once instead of twice for scipy metrics — restores the
original single-warning behavior on an invalid label_distance_p / unsupported
weights. Distance scores stay bit-identical (kwargs are deterministic).
- N1: make _validate_scalar's predicate/constraint optional; _validate_power_mean_p
now calls it with no predicate (finite-only), dropping the dead always-true
lambda + unreachable constraint string.
- N2: type _invalidate_pair_cache with a bound TypeVar so each caller's cache
type flows through instead of a bare dict.
- N3: drop 3 redundant `# "name"` comments left next to named constants.
Verified in the project Docker image: CP/TOPSIS golden differential vs the prior
commit is bit-identical across all 17 metrics; TOPSIS invalid-p warnings 2 -> 1;
validator messages unchanged; py_compile clean, ruff E,F,W <= main baseline,
ruff format clean.
- NEW-1: rebuild the invalidated cache via type(cache)(...) in _invalidate_pair_cache
so the _PairCacheT TypeVar return is sound. pyright: prior plain-dict-comprehension
reassignment reported reportAssignmentType (1 error); type(cache)(...) reports 0.
Runtime identical (type(cache) is dict for the two concrete caches).
- NEW-2: drop the 32 remaining tautological `# "name"` comments sitting next to a
named constant (e.g. `== _TRADE_LONG # "long"`), consistent with the H3 cleanup.
Index-resolving comments on the canonical definitions (e.g. `_DISTANCE_METRICS[6]
# "mahalanobis"`) are kept — they document the literal an index maps to.
Verified in the project Docker image: CP/TOPSIS bit-identical vs prior commit across
all metrics; _invalidate_pair_cache runtime unchanged; py_compile clean, ruff E,F,W
<= main baseline, ruff format clean.
Complete NEW-2 cleanup: remove 14 tautological `# "name"` comments on
multi-line comparison/closing-paren lines that the single-line strip
missed (e.g. `): # "power_mean"`, `) # "short"`), fixing the
long-removed/short-kept asymmetry. Removing the pinning comments lets
ruff format collapse the parenthesized `if (...)` forms to single lines.
Keeps index-resolving comments (`_ARRAY[n] # "x"`) and the
LABEL_METHOD_DEFAULT value-documenting comment. Comment-only + format
change: AST verified identical to prior commit; ruff E,F,W within
baseline; container import smoke passes.