]> Piment Noir Git Repositories - freqai-strategies.git/commitdiff
fix(quickadapter): resolve initial and comprehensive review findings (#261)
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Fri, 18 Sep 2026 14:36:25 +0000 (16:36 +0200)
committerGitHub <noreply@github.com>
Fri, 18 Sep 2026 14:36:25 +0000 (16:36 +0200)
* fix(quickadapter): resolve six initial review findings

* fix(quickadapter): preserve nonnegative trade volatility

* fix(quickadapter): align prediction history and guard deployment state

* docs(quickadapter): align prose with current behavior

* chore(quickadapter): refresh basedpyright snapshot positions

* fix(quickadapter): remove unreleased selection schema increments

* docs(quickadapter): remove redundant versioning commentary

* docs(quickadapter): clarify schema version release boundary

* fix(quickadapter): slice label weights before normalization

* style(quickadapter): harmonize log message capitalization

* fix(quickadapter): validate original weights before projection fallback

* docs(quickadapter): clarify weight validation and normalization order

* chore(quickadapter): bump release candidate to 3.13.0-rc.10

README.md
quickadapter/.basedpyright/diagnostics.json
quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py
quickadapter/user_data/strategies/LabelTransformer.py
quickadapter/user_data/strategies/QuickAdapterV3.py
quickadapter/user_data/strategies/Utils.py

index 3d252d3de91127b51685f435832ce5d45638f3dc..79801d66dabc3ee16c63dc1a239c3e59da1faf18 100644 (file)
--- a/README.md
+++ b/README.md
@@ -62,7 +62,7 @@ below.
 | _Leverage_                                                     |                          |                                                                                                                                                                                                              |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
 | leverage                                                       | `proposed_leverage`      | float [1.0, max_leverage]                                                                                                                                                                                    | Leverage. Fallback to `proposed_leverage` for the pair.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
 | _Exit pricing_                                                 |                          |                                                                                                                                                                                                              |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
-| exit_pricing.trade_natr_method                                 | `moving_average`         | enum {`moving_average`,`quantile_interpolation`,`weighted_average`}                                                                                                                                          | Trade NATR (Normalized Average True Range) aggregation method used to derive stoploss and take-profit distances.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
+| exit_pricing.trade_natr_method                                 | `moving_average`         | enum {`moving_average`,`quantile_interpolation`,`weighted_average`} | Trade NATR (Normalized Average True Range) aggregation for stoploss and take-profit distances. `moving_average` uses KAMA to preserve nonnegative volatility. The stoploss never loosens, including after partial exits, and remains unchanged on order fills. |
 | exit_pricing.final_take_profit_retracement_fraction            | 0.25                     | float (0,1]                                                                                                                                                                                                  | Fraction of the final take-profit target distance used as the frozen trailing retracement distance after the final target arms the exit. The final exit tracks the best subsequent per-candle rate and exits only after this material adverse move; elapsed stagnation alone does not exit. Plot annotations show only the current trail boundary from the candle that established it; earlier boundaries are not retained.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
 | _Reversal confirmation_                                        |                          |                                                                                                                                                                                                              |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
 | reversal_confirmation.lookback_period_candles                  | 0                        | int >= 0                                                                                                                                                                                                     | Prior confirming candles; 0 = none. With confirmation enabled, unmeasurable history rejects entries, while a valid current exit may still reduce exposure.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
@@ -70,8 +70,8 @@ below.
 | reversal_confirmation.min_natr_multiplier_fraction             | 0.0095                   | float [0,1]                                                                                                                                                                                                  | Lower bound fraction (< upper bound) for volatility adjusted reversal threshold.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
 | reversal_confirmation.max_natr_multiplier_fraction             | 0.0125                   | float [0,1]                                                                                                                                                                                                  | Upper bound fraction (> lower bound) for volatility adjusted reversal threshold.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
 | _Regressor model_                                              |                          |                                                                                                                                                                                                              |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
-| freqai.regressor                                               | `xgboost`                | enum {`xgboost`,`lightgbm`,`histgradientboostingregressor`,`ngboost`,`catboost`}                                                                                                                             | Machine learning regressor algorithm.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
-| freqai.continual_learning                                      | false                    | bool                                                                                                                                                                                                         | Continue XGBoost, LightGBM, or CPU CatBoost training from the previously deployed model, so its booster grows at every retrain; delete trained models to reset. Under `test_size` two-stage selection, HPO and the pre-refit selection model cold-start and only the final refit continues, growing by the selection model's round count (see `test_size`). GPU CatBoost and other regressors cold-start instead.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
+| freqai.regressor                                               | `xgboost`                | enum {`xgboost`,`lightgbm`,`histgradientboostingregressor`,`ngboost`,`catboost`}                                                                                                                             | Machine learning regressor. With validation and early stopping enabled, NGBoost uses the iteration with the best validation score for prediction and to determine the final refit size. |
+| freqai.continual_learning                                      | false                    | bool                                                                                                                                                                                                         | Continue training the deployed XGBoost, LightGBM or CPU CatBoost model. GPU CatBoost and other regressors train from scratch. With two-stage selection (see `test_size`), HPO and selection train from scratch; only the final refit continues the deployed model, adding the selected number of boosting rounds. Continued training reuses the saved feature and label transformations, including after restart. Missing or incompatible transformations or deployment metadata prevent continuation. Reset trained models or use a new `freqai.identifier` to change pipeline settings or recover from incompatible saved state. |
 | _Model training parameters_                                    |                          |                                                                                                                                                                                                              |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
 | freqai.model_training_parameters.gpu_vram_gb                   | 80                       | int > 0                                                                                                                                                                                                      | Available GPU VRAM (GB) for CatBoost, not total. Any positive value is floored to the nearest supported tier `<= value` (tiers 8, 10, 12, 16, 24, 32, 40, 48, 64, 80; values below 8 use tier 8). Constrains `depth`, `border_count`, and `max_ctr_complexity` ranges.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
 | _Data split parameters_                                        |                          |                                                                                                                                                                                                              |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
@@ -95,7 +95,7 @@ below.
 | freqai.label_weighting.fill_method                             | `zero`                   | enum {`zero`,`epsilon`,`gaussian`,`epsilon_gaussian`}                                                                                                                                                        | Off-pivot weighting scheme. `zero` hard-zeros off-pivot rows; `epsilon` applies the epsilon floor `fill_epsilon * <fill_epsilon_baseline>(pivot_weights)`; `gaussian` applies per-pivot Gaussian bumps; `epsilon_gaussian` sums the `epsilon` floor and the `gaussian` bumps. Pivot rows take the max of their raw weight and the off-pivot field at their index (no-op for `zero`). Under `causal_mode=true` the epsilon baseline is computed causally (see `causal_mode`). Switching away from `zero` may require retuning tree-leaf regularization (`min_child_weight`, `lambda`) and resetting any prior Optuna study. Changing this parameter requires deleting trained models.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
 | freqai.label_weighting.fill_epsilon                            | 0.000001                 | float [0,1]                                                                                                                                                                                                  | Off-pivot fraction of the pivot baseline. Ignored when `fill_method` not in {`epsilon`,`epsilon_gaussian`}.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
 | freqai.label_weighting.fill_epsilon_baseline                   | `mean`                   | enum {`mean`,`median`}                                                                                                                                                                                       | Pivot baseline statistic. `mean` tracks central tendency; `median` is robust against pivot-weight skew. Ignored when `fill_method` not in {`epsilon`,`epsilon_gaussian`}.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
-| freqai.label_weighting.fill_sigma_candles                      | 25.0                     | float >= 0.5                                                                                                                                                                                                 | Gaussian standard deviation in candles for the per-pivot bumps. Acts as the upper bound on per-pivot sigma when `fill_bandwidth == "knn"`. Lower bound 0.5 prevents severe underflow in the Gaussian tail. Under `causal_mode=true` the bumps use a finite support `ceil(4 * fill_sigma_candles)` (see `causal_mode`). Ignored when `fill_method` not in {`gaussian`,`epsilon_gaussian`}.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
+| freqai.label_weighting.fill_sigma_candles                      | 25.0                     | float >= 0.5                                                                                                                                                                                                 | Gaussian standard deviation in candles for the per-pivot bumps. Acts as the upper bound on per-pivot sigma when `fill_bandwidth == "knn"`. Lower bound 0.5 prevents severe underflow in the Gaussian tail. Under `causal_mode=true` the bumps use a finite support `ceil(4 * fill_sigma_candles)` (see `causal_mode`). Ignored when `fill_method` not in {`gaussian`,`epsilon_gaussian`}. Gaussian weight availability also waits for resolution of possible pivots throughout that support; pure-Gaussian uniform pivot centers retain their own confirmation time. |
 | freqai.label_weighting.fill_sigma_min_candles                  | 0.5                      | float >= 0.5                                                                                                                                                                                                 | Lower bound on per-pivot sigma in candles when `fill_bandwidth == "knn"`. Clipped to `fill_sigma_candles` when larger. Ignored when `fill_method` not in {`gaussian`,`epsilon_gaussian`} or `fill_bandwidth != "knn"`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
 | freqai.label_weighting.fill_bandwidth                          | `fixed`                  | enum {`fixed`,`knn`}                                                                                                                                                                                         | Per-pivot Gaussian bandwidth selector. `fixed` applies a constant `fill_sigma_candles` to every pivot. `knn` adapts each pivot's sigma to local pivot density via `sigma_p = clip(fill_bandwidth_alpha * d_k(p), fill_sigma_min_candles, fill_sigma_candles)` where `d_k(p)` is the index distance to the `k`-th nearest pivot neighbor ([Loftsgaarden and Quesenberry][knn-density]; [Silverman, §5.2][silverman-density]). Mitigates the crushing of weaker pivots by stronger neighbors in dense clusters. Ignored when `fill_method` not in {`gaussian`,`epsilon_gaussian`}.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
 | freqai.label_weighting.fill_bandwidth_neighbors                | 1                        | int >= 1                                                                                                                                                                                                     | `k` for the k-nearest-neighbor bandwidth selector. Ignored when `fill_method` not in {`gaussian`,`epsilon_gaussian`} or `fill_bandwidth != "knn"`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
@@ -122,7 +122,7 @@ below.
 | freqai.feature_parameters.min_label_natr_multiplier            | 9.0                      | float > 0                                                                                                                                                                                                    | Minimum labeling NATR multiplier used for reversals labeling HPO.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
 | freqai.feature_parameters.max_label_natr_multiplier            | 12.0                     | float > 0                                                                                                                                                                                                    | Maximum labeling NATR multiplier used for reversals labeling HPO.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
 | freqai.feature_parameters.label_frequency_candles              | `auto`                   | int [2, 10000] \| `auto`                                                                                                                                                                                     | Reversals labeling frequency. `auto` = max(2, 2 \* number of whitelisted pairs).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
-| freqai.feature_parameters.label_weights                        | uniform                  | list of 7 finite floats >= 0; sum > 0                                                                                                                                                                        | Per-objective weights for trial selection methods, normalized internally. Objectives: (1) number of detected reversals, (2) median swing amplitude, (3) median (swing amplitude / median volatility-threshold ratio), (4) median swing volume per candle, (5) median swing speed, (6) median swing efficiency ratio, (7) median swing volume-weighted efficiency ratio.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
+| freqai.feature_parameters.label_weights                        | uniform                  | list of 7 finite floats >= 0; sum > 0                                                                                                                                                                        | Per-objective weights for trial selection methods, normalized internally. Objectives: (1) number of detected reversals, (2) median swing amplitude, (3) median (swing amplitude / median volatility-threshold ratio), (4) median swing ratio of mean volume per candle to median volume (dimensionless), (5) median swing speed, (6) median swing efficiency ratio, (7) median swing volume-weighted efficiency ratio. Zero-weight objectives do not contribute to power means, including negative and zero orders; positive-weight zero values retain their usual power-mean semantics. Clustering excludes zero-weight dimensions before estimating the cluster count and forming clusters; positive weights score clusters and candidates without rescaling cluster coordinates. Weights are validated before constant-objective projection; an all-zero projected vector falls back to uniform weights. |
 | freqai.feature_parameters.label_p_order                        | null                     | `minkowski`: finite float > 0; `power_mean`: finite float; null otherwise                                                                                                                                    | Lp exponent for parameterized distance metrics. Used by `minkowski` distance (default 2.0) and `power_mean` distance (default 1.0). The KNN `power_mean` aggregation exponent is configured by `label_density_aggregation_param`. Ignored by other metrics.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
 | freqai.feature_parameters.label_method                         | `compromise_programming` | enum {`compromise_programming`,`topsis`,`kmeans`,`kmeans2`,`knn`,`medoid`}                                                                                                                                   | HPO `label` Pareto front trial selection method. `kmedoids` is unavailable in the current Python 3.14 image.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
 | freqai.feature_parameters.label_distance_metric                | `euclidean`              | enum {`euclidean`,`minkowski`,`chebyshev`,`cityblock`,`sqeuclidean`,`seuclidean`,`mahalanobis`,`harmonic_mean`,`geometric_mean`,`arithmetic_mean`,`quadratic_mean`,`cubic_mean`,`power_mean`,`weighted_sum`} | Distance metric for `compromise_programming` and `topsis` methods. Invalid values warn and fall back to `euclidean`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
@@ -136,7 +136,7 @@ below.
 | freqai.feature_parameters.scaler                               | `minmax`                 | enum {`minmax`,`maxabs`,`standard`,`robust`}                                                                                                                                                                 | Feature scaling method. `minmax`=MinMaxScaler, `maxabs`=MaxAbsScaler, `standard`=StandardScaler, `robust`=RobustScaler. Changing this parameter requires deleting trained models.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
 | freqai.feature_parameters.range                                | [-1.0, 1.0]              | list[float], low < high                                                                                                                                                                                      | Target range for `minmax` scaler, min and max. Changing this parameter requires deleting trained models.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
 | _Label prediction_                                             |                          |                                                                                                                                                                                                              |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
-| freqai.label_prediction.method                                 | `thresholding`           | enum {`none`,`thresholding`}                                                                                                                                                                                 | Prediction method. `none` disables threshold computation, `thresholding` enables adaptive threshold calculation.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
+| freqai.label_prediction.method                                 | `thresholding`           | enum {`none`,`thresholding`}                                                                                                                                                                                 | Prediction method. `none` disables threshold computation; `thresholding` enables adaptive thresholds. See the calibration warmup rules below. |
 | freqai.label_prediction.selection_method                       | `rank_extrema`           | enum {`rank_extrema`,`rank_peaks`,`partition`}                                                                                                                                                               | Extrema selection method. `rank_extrema` ranks extrema values, `rank_peaks` ranks detected peak values, `partition` uses sign-based partitioning.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
 | freqai.label_prediction.threshold_method                       | `mean`                   | enum {`mean`,`isodata`,`li`,`minimum`,`otsu`,`triangle`,`yen`,`median`,`soft_extremum`}                                                                                                                      | Thresholding method for prediction thresholds.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
 | freqai.label_prediction.soft_extremum_alpha                    | 12.0                     | float >= 0                                                                                                                                                                                                   | Alpha for `soft_extremum` threshold method.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
@@ -169,6 +169,13 @@ ignored with a warning. Matching column patterns are applied from least to most
 specific; equally specific patterns follow declaration order, so the later one
 wins.
 
+In live and dry-run modes, each pair requires
+`freqai.fit_live_predictions_candles` model predictions after session startup
+before adaptive thresholds become available. Restarting requires a new warmup.
+Downtime and expired-model rows are excluded; genuine zero and outlier-rejected
+predictions count. Predictions align to candle dates; candles without
+predictions have `do_predict=0` and downtime zeros display but never calibrate.
+
 ### Backtest evaluation protocol
 
 Evaluate a proposed change against the current configuration on the same unseen
index 87a578ed7a41e51f15eb6f72191f387908f75a4b..8536c67223e6a6ff04f35ccd885e0a371910349e 100644 (file)
   "diagnostics": [
     {
       "endCharacter": 46,
-      "endLine": 1308,
+      "endLine": 1353,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"str | None\" cannot be assigned to parameter \"default\" of type \"str\" in function \"_validate_label_selection_metric\"\n  Type \"str | None\" is not assignable to type \"str\"\n    \"None\" is not assignable to \"str\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 24,
-      "startLine": 1308
+      "startLine": 1353
     },
     {
       "endCharacter": 79,
-      "endLine": 2090,
+      "endLine": 2135,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"index\" for class \"NDArray[Unknown]\"\n  Attribute \"index\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 74,
-      "startLine": 2090
+      "startLine": 2135
     },
     {
       "endCharacter": 72,
-      "endLine": 2092,
+      "endLine": 2137,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"index\" for class \"NDArray[Unknown]\"\n  Attribute \"index\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 67,
-      "startLine": 2092
+      "startLine": 2137
     },
     {
       "endCharacter": 90,
-      "endLine": 2101,
+      "endLine": 2146,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"index\" for class \"NDArray[Unknown]\"\n  Attribute \"index\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 85,
-      "startLine": 2101
+      "startLine": 2146
     },
     {
       "endCharacter": 34,
-      "endLine": 2114,
+      "endLine": 2159,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Unknown | NDArray[Unknown] | Any | list[Unknown]\" cannot be assigned to parameter \"train_features\" of type \"DataFrame\" in function \"_filter_train_by_mask\"\n  Type \"Unknown | NDArray[Unknown] | Any | list[Unknown]\" is not assignable to type \"DataFrame\"\n    \"list[Unknown]\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 2114
+      "startLine": 2159
     },
     {
       "endCharacter": 32,
-      "endLine": 2115,
+      "endLine": 2160,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Unknown | NDArray[Unknown] | Any | list[Unknown]\" cannot be assigned to parameter \"train_labels\" of type \"DataFrame\" in function \"_filter_train_by_mask\"\n  Type \"Unknown | NDArray[Unknown] | Any | list[Unknown]\" is not assignable to type \"DataFrame\"\n    \"list[Unknown]\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 2115
+      "startLine": 2160
     },
     {
       "endCharacter": 38,
-      "endLine": 2116,
+      "endLine": 2161,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Unknown | NDArray[Unknown] | Any | list[Unknown]\" cannot be assigned to parameter \"train_weights\" of type \"NDArray[floating[Any]]\" in function \"_filter_train_by_mask\"\n  Type \"Unknown | NDArray[Unknown] | Any | list[Unknown]\" is not assignable to type \"NDArray[floating[Any]]\"\n    \"list[Unknown]\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 2116
+      "startLine": 2161
     },
     {
       "endCharacter": 59,
-      "endLine": 2119,
+      "endLine": 2164,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Unknown | NDArray[Unknown] | Any | list[Unknown] | None\" cannot be assigned to parameter \"train_label_weights\" of type \"NDArray[floating[Any]] | None\" in function \"_filter_train_by_mask\"\n  Type \"Unknown | NDArray[Unknown] | Any | list[Unknown] | None\" is not assignable to type \"NDArray[floating[Any]] | None\"\n    Type \"list[Unknown]\" is not assignable to type \"NDArray[floating[Any]] | None\"\n      \"list[Unknown]\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"\n      \"list[Unknown]\" is not assignable to \"None\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 40,
-      "startLine": 2119
+      "startLine": 2164
     },
     {
       "endCharacter": 34,
-      "endLine": 2153,
+      "endLine": 2198,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"DataFrame | Unknown | NDArray[Unknown] | Any | list[Unknown]\" cannot be assigned to parameter \"features\" of type \"DataFrame\" in function \"_shuffle_split_rows\"\n  Type \"DataFrame | Unknown | NDArray[Unknown] | Any | list[Unknown]\" is not assignable to type \"DataFrame\"\n    \"list[Unknown]\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 2153
+      "startLine": 2198
     },
     {
       "endCharacter": 32,
-      "endLine": 2154,
+      "endLine": 2199,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"DataFrame | Unknown | NDArray[Unknown] | Any | list[Unknown]\" cannot be assigned to parameter \"labels\" of type \"DataFrame\" in function \"_shuffle_split_rows\"\n  Type \"DataFrame | Unknown | NDArray[Unknown] | Any | list[Unknown]\" is not assignable to type \"DataFrame\"\n    \"list[Unknown]\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 2154
+      "startLine": 2199
     },
     {
       "endCharacter": 38,
-      "endLine": 2155,
+      "endLine": 2200,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"NDArray[floating[Any]] | Unknown | NDArray[Unknown] | Any | list[Unknown]\" cannot be assigned to parameter \"base_weights\" of type \"NDArray[floating[Any]]\" in function \"_shuffle_split_rows\"\n  Type \"NDArray[floating[Any]] | Unknown | NDArray[Unknown] | Any | list[Unknown]\" is not assignable to type \"NDArray[floating[Any]]\"\n    \"list[Unknown]\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 2155
+      "startLine": 2200
     },
     {
       "endCharacter": 39,
-      "endLine": 2156,
+      "endLine": 2201,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"NDArray[floating[Any]] | Unknown | NDArray[Unknown] | Any | list[Unknown] | None\" cannot be assigned to parameter \"label_weights\" of type \"NDArray[floating[Any]] | None\" in function \"_shuffle_split_rows\"\n  Type \"NDArray[floating[Any]] | Unknown | NDArray[Unknown] | Any | list[Unknown] | None\" is not assignable to type \"NDArray[floating[Any]] | None\"\n    Type \"list[Unknown]\" is not assignable to type \"NDArray[floating[Any]] | None\"\n      \"list[Unknown]\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"\n      \"list[Unknown]\" is not assignable to \"None\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 2156
+      "startLine": 2201
     },
     {
       "endCharacter": 37,
-      "endLine": 2163,
+      "endLine": 2208,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Unknown | NDArray[Unknown] | Any | list[Unknown] | DataFrame\" cannot be assigned to parameter \"features\" of type \"DataFrame\" in function \"_shuffle_split_rows\"\n  Type \"Unknown | NDArray[Unknown] | Any | list[Unknown] | DataFrame\" is not assignable to type \"DataFrame\"\n    \"list[Unknown]\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 24,
-      "startLine": 2163
+      "startLine": 2208
     },
     {
       "endCharacter": 35,
-      "endLine": 2164,
+      "endLine": 2209,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Unknown | NDArray[Unknown] | Any | list[Unknown] | DataFrame\" cannot be assigned to parameter \"labels\" of type \"DataFrame\" in function \"_shuffle_split_rows\"\n  Type \"Unknown | NDArray[Unknown] | Any | list[Unknown] | DataFrame\" is not assignable to type \"DataFrame\"\n    \"list[Unknown]\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 24,
-      "startLine": 2164
+      "startLine": 2209
     },
     {
       "endCharacter": 41,
-      "endLine": 2165,
+      "endLine": 2210,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Unknown | NDArray[Unknown] | Any | list[Unknown] | ndarray[_AnyShape, dtype[floating[Any]]]\" cannot be assigned to parameter \"base_weights\" of type \"NDArray[floating[Any]]\" in function \"_shuffle_split_rows\"\n  Type \"Unknown | NDArray[Unknown] | Any | list[Unknown] | ndarray[_AnyShape, dtype[floating[Any]]]\" is not assignable to type \"NDArray[floating[Any]]\"\n    \"list[Unknown]\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 24,
-      "startLine": 2165
+      "startLine": 2210
     },
     {
       "endCharacter": 42,
-      "endLine": 2166,
+      "endLine": 2211,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Unknown | NDArray[Unknown] | Any | list[Unknown] | ndarray[_AnyShape, dtype[floating[Any]]] | None\" cannot be assigned to parameter \"label_weights\" of type \"NDArray[floating[Any]] | None\" in function \"_shuffle_split_rows\"\n  Type \"Unknown | NDArray[Unknown] | Any | list[Unknown] | ndarray[_AnyShape, dtype[floating[Any]]] | None\" is not assignable to type \"NDArray[floating[Any]] | None\"\n    Type \"list[Unknown]\" is not assignable to type \"NDArray[floating[Any]] | None\"\n      \"list[Unknown]\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"\n      \"list[Unknown]\" is not assignable to \"None\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 24,
-      "startLine": 2166
+      "startLine": 2211
     },
     {
       "endCharacter": 30,
-      "endLine": 2184,
+      "endLine": 2229,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"NDArray[floating[Any]] | Unknown | NDArray[Unknown] | Any | list[Unknown]\" cannot be assigned to parameter \"base_weights\" of type \"NDArray[floating[Any]]\" in function \"_compose_train_weights_with_support\"\n  Type \"NDArray[floating[Any]] | Unknown | NDArray[Unknown] | Any | list[Unknown]\" is not assignable to type \"NDArray[floating[Any]]\"\n    \"list[Unknown]\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 2184
+      "startLine": 2229
     },
     {
       "endCharacter": 31,
-      "endLine": 2185,
+      "endLine": 2230,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"NDArray[floating[Any]] | Unknown | NDArray[Unknown] | Any | list[Unknown] | None\" cannot be assigned to parameter \"label_weights\" of type \"NDArray[floating[Any]] | None\" in function \"_compose_train_weights_with_support\"\n  Type \"NDArray[floating[Any]] | Unknown | NDArray[Unknown] | Any | list[Unknown] | None\" is not assignable to type \"NDArray[floating[Any]] | None\"\n    Type \"list[Unknown]\" is not assignable to type \"NDArray[floating[Any]] | None\"\n      \"list[Unknown]\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"\n      \"list[Unknown]\" is not assignable to \"None\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 2185
+      "startLine": 2230
     },
     {
       "endCharacter": 33,
-      "endLine": 2191,
+      "endLine": 2236,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"NDArray[floating[Any]] | Unknown | NDArray[Unknown] | Any | list[Unknown]\" cannot be assigned to parameter \"base_weights\" of type \"NDArray[floating[Any]]\" in function \"_compose_eval_weights\"\n  Type \"NDArray[floating[Any]] | Unknown | NDArray[Unknown] | Any | list[Unknown]\" is not assignable to type \"NDArray[floating[Any]]\"\n    \"list[Unknown]\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2191
+      "startLine": 2236
     },
     {
       "endCharacter": 34,
-      "endLine": 2192,
+      "endLine": 2237,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"NDArray[floating[Any]] | Unknown | NDArray[Unknown] | Any | list[Unknown] | None\" cannot be assigned to parameter \"label_weights\" of type \"NDArray[floating[Any]] | None\" in function \"_compose_eval_weights\"\n  Type \"NDArray[floating[Any]] | Unknown | NDArray[Unknown] | Any | list[Unknown] | None\" is not assignable to type \"NDArray[floating[Any]] | None\"\n    Type \"list[Unknown]\" is not assignable to type \"NDArray[floating[Any]] | None\"\n      \"list[Unknown]\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"\n      \"list[Unknown]\" is not assignable to \"None\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2192
+      "startLine": 2237
     },
     {
       "endCharacter": 26,
-      "endLine": 2199,
+      "endLine": 2244,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"DataFrame | Unknown | NDArray[Unknown] | Any | list[Unknown]\" cannot be assigned to parameter \"train_df\" of type \"DataFrame\" in function \"build_data_dictionary\"\n  Type \"DataFrame | Unknown | NDArray[Unknown] | Any | list[Unknown]\" is not assignable to type \"DataFrame\"\n    \"list[Unknown]\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 2199
+      "startLine": 2244
     },
     {
       "endCharacter": 25,
-      "endLine": 2200,
+      "endLine": 2245,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"DataFrame | Unknown | NDArray[Unknown] | Any | list[Unknown]\" cannot be assigned to parameter \"test_df\" of type \"DataFrame\" in function \"build_data_dictionary\"\n  Type \"DataFrame | Unknown | NDArray[Unknown] | Any | list[Unknown]\" is not assignable to type \"DataFrame\"\n    \"list[Unknown]\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 2200
+      "startLine": 2245
     },
     {
       "endCharacter": 24,
-      "endLine": 2201,
+      "endLine": 2246,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"DataFrame | Unknown | NDArray[Unknown] | Any | list[Unknown]\" cannot be assigned to parameter \"train_labels\" of type \"DataFrame\" in function \"build_data_dictionary\"\n  Type \"DataFrame | Unknown | NDArray[Unknown] | Any | list[Unknown]\" is not assignable to type \"DataFrame\"\n    \"list[Unknown]\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 2201
+      "startLine": 2246
     },
     {
       "endCharacter": 23,
-      "endLine": 2202,
+      "endLine": 2247,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"DataFrame | Unknown | NDArray[Unknown] | Any | list[Unknown]\" cannot be assigned to parameter \"test_labels\" of type \"DataFrame\" in function \"build_data_dictionary\"\n  Type \"DataFrame | Unknown | NDArray[Unknown] | Any | list[Unknown]\" is not assignable to type \"DataFrame\"\n    \"list[Unknown]\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 2202
+      "startLine": 2247
     },
     {
       "endCharacter": 87,
-      "endLine": 2416,
+      "endLine": 2551,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"index\" for class \"NDArray[Unknown]\"\n  Attribute \"index\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 82,
-      "startLine": 2416
+      "startLine": 2551
     },
     {
       "endCharacter": 68,
-      "endLine": 2417,
+      "endLine": 2552,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"index\" for class \"NDArray[Unknown]\"\n  Attribute \"index\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 63,
-      "startLine": 2417
+      "startLine": 2552
     },
     {
       "endCharacter": 63,
-      "endLine": 2428,
+      "endLine": 2563,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"index\" for class \"NDArray[Unknown]\"\n  Attribute \"index\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 58,
-      "startLine": 2428
+      "startLine": 2563
     },
     {
       "endCharacter": 47,
-      "endLine": 2430,
+      "endLine": 2565,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"loc\" for class \"NDArray[Unknown]\"\n  Attribute \"loc\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 44,
-      "startLine": 2430
+      "startLine": 2565
     },
     {
       "endCharacter": 47,
-      "endLine": 2430,
+      "endLine": 2565,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"loc\" for class \"list[Unknown]\"\n  Attribute \"loc\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 44,
-      "startLine": 2430
+      "startLine": 2565
     },
     {
       "endCharacter": 43,
-      "endLine": 2431,
+      "endLine": 2566,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"loc\" for class \"NDArray[Unknown]\"\n  Attribute \"loc\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 40,
-      "startLine": 2431
+      "startLine": 2566
     },
     {
       "endCharacter": 43,
-      "endLine": 2431,
+      "endLine": 2566,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"loc\" for class \"list[Unknown]\"\n  Attribute \"loc\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 40,
-      "startLine": 2431
+      "startLine": 2566
     },
     {
       "endCharacter": 31,
-      "endLine": 2452,
+      "endLine": 2587,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"empty\" for class \"NDArray[Unknown]\"\n  Attribute \"empty\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 26,
-      "startLine": 2452
+      "startLine": 2587
     },
     {
       "endCharacter": 31,
-      "endLine": 2452,
+      "endLine": 2587,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"empty\" for class \"list[Unknown]\"\n  Attribute \"empty\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 26,
-      "startLine": 2452
+      "startLine": 2587
     },
     {
       "endCharacter": 60,
-      "endLine": 2452,
+      "endLine": 2587,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"empty\" for class \"NDArray[Unknown]\"\n  Attribute \"empty\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 55,
-      "startLine": 2452
+      "startLine": 2587
     },
     {
       "endCharacter": 60,
-      "endLine": 2452,
+      "endLine": 2587,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"empty\" for class \"list[Unknown]\"\n  Attribute \"empty\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 55,
-      "startLine": 2452
+      "startLine": 2587
     },
     {
       "endCharacter": 73,
-      "endLine": 2464,
+      "endLine": 2599,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Unknown | Any | ((value: Unknown, start: SupportsIndex = 0, stop: SupportsIndex = sys.maxsize, /) -> int)\" cannot be assigned to parameter \"target\" of type \"Index[Any]\" in function \"get_indexer\"\n  Type \"Unknown | Any | ((value: Unknown, start: SupportsIndex = 0, stop: SupportsIndex = sys.maxsize, /) -> int)\" is not assignable to type \"Index[Any]\"\n    \"MethodType\" is not assignable to \"Index[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 53,
-      "startLine": 2464
+      "startLine": 2599
     },
     {
       "endCharacter": 73,
-      "endLine": 2464,
+      "endLine": 2599,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"index\" for class \"NDArray[Unknown]\"\n  Attribute \"index\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 68,
-      "startLine": 2464
+      "startLine": 2599
     },
     {
       "endCharacter": 83,
-      "endLine": 2465,
+      "endLine": 2600,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Unknown | Any | ((value: Unknown, start: SupportsIndex = 0, stop: SupportsIndex = sys.maxsize, /) -> int)\" cannot be assigned to parameter \"target\" of type \"Index[Any]\" in function \"get_indexer\"\n  Type \"Unknown | Any | ((value: Unknown, start: SupportsIndex = 0, stop: SupportsIndex = sys.maxsize, /) -> int)\" is not assignable to type \"Index[Any]\"\n    \"MethodType\" is not assignable to \"Index[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 58,
-      "startLine": 2465
+      "startLine": 2600
     },
     {
       "endCharacter": 83,
-      "endLine": 2465,
+      "endLine": 2600,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"index\" for class \"NDArray[Unknown]\"\n  Attribute \"index\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 78,
-      "startLine": 2465
-    },
-    {
-      "endCharacter": 9,
-      "endLine": 2613,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Type \"ArrayLike\" is not assignable to declared type \"DataFrame\"\n  Type \"ArrayLike\" is not assignable to type \"DataFrame\"\n    \"Buffer\" is not assignable to \"DataFrame\"",
-      "rule": "reportAssignmentType",
-      "severity": "error",
-      "startCharacter": 45,
-      "startLine": 2611
-    },
-    {
-      "endCharacter": 9,
-      "endLine": 2613,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Type \"ArrayLike\" is not assignable to declared type \"NDArray[floating[Any]]\"\n  Type \"ArrayLike\" is not assignable to type \"NDArray[floating[Any]]\"\n    \"Buffer\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"",
-      "rule": "reportAssignmentType",
-      "severity": "error",
-      "startCharacter": 45,
-      "startLine": 2611
-    },
-    {
-      "endCharacter": 60,
-      "endLine": 2623,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"pop\" for class \"Buffer\"\n  Attribute \"pop\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 57,
-      "startLine": 2623
-    },
-    {
-      "endCharacter": 60,
-      "endLine": 2623,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"pop\" for class \"_NestedSequence[_SupportsArray[dtype[Any]]]\"\n  Attribute \"pop\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 57,
-      "startLine": 2623
-    },
-    {
-      "endCharacter": 60,
-      "endLine": 2623,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"pop\" for class \"_NestedSequence[complex | bytes | str]\"\n  Attribute \"pop\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 57,
-      "startLine": 2623
-    },
-    {
-      "endCharacter": 60,
-      "endLine": 2623,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"pop\" for class \"_SupportsArray[dtype[Any]]\"\n  Attribute \"pop\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 57,
-      "startLine": 2623
-    },
-    {
-      "endCharacter": 60,
-      "endLine": 2623,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"pop\" for class \"bytes\"\n  Attribute \"pop\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 57,
-      "startLine": 2623
-    },
-    {
-      "endCharacter": 60,
-      "endLine": 2623,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"pop\" for class \"complex\"\n  Attribute \"pop\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 57,
-      "startLine": 2623
-    },
-    {
-      "endCharacter": 60,
-      "endLine": 2623,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"pop\" for class \"str\"\n  Attribute \"pop\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 57,
-      "startLine": 2623
-    },
-    {
-      "endCharacter": 79,
-      "endLine": 2623,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "\"base_weight_column\" is possibly unbound",
-      "rule": "reportPossiblyUnboundVariable",
-      "severity": "error",
-      "startCharacter": 61,
-      "startLine": 2623
-    },
-    {
-      "endCharacter": 61,
-      "endLine": 2626,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"pop\" for class \"Buffer\"\n  Attribute \"pop\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 58,
-      "startLine": 2626
-    },
-    {
-      "endCharacter": 61,
-      "endLine": 2626,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"pop\" for class \"_NestedSequence[_SupportsArray[dtype[Any]]]\"\n  Attribute \"pop\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 58,
-      "startLine": 2626
-    },
-    {
-      "endCharacter": 61,
-      "endLine": 2626,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"pop\" for class \"_NestedSequence[complex | bytes | str]\"\n  Attribute \"pop\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 58,
-      "startLine": 2626
-    },
-    {
-      "endCharacter": 61,
-      "endLine": 2626,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"pop\" for class \"_SupportsArray[dtype[Any]]\"\n  Attribute \"pop\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 58,
-      "startLine": 2626
-    },
-    {
-      "endCharacter": 61,
-      "endLine": 2626,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"pop\" for class \"bytes\"\n  Attribute \"pop\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 58,
-      "startLine": 2626
-    },
-    {
-      "endCharacter": 61,
-      "endLine": 2626,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"pop\" for class \"complex\"\n  Attribute \"pop\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 58,
-      "startLine": 2626
-    },
-    {
-      "endCharacter": 61,
-      "endLine": 2626,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"pop\" for class \"str\"\n  Attribute \"pop\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 58,
-      "startLine": 2626
-    },
-    {
-      "endCharacter": 81,
-      "endLine": 2626,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "\"label_weight_column\" is possibly unbound",
-      "rule": "reportPossiblyUnboundVariable",
-      "severity": "error",
-      "startCharacter": 62,
-      "startLine": 2626
-    },
-    {
-      "endCharacter": 68,
-      "endLine": 2632,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"columns\" for class \"Buffer\"\n  Attribute \"columns\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 61,
-      "startLine": 2632
-    },
-    {
-      "endCharacter": 68,
-      "endLine": 2632,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"columns\" for class \"_NestedSequence[_SupportsArray[dtype[Any]]]\"\n  Attribute \"columns\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 61,
-      "startLine": 2632
-    },
-    {
-      "endCharacter": 68,
-      "endLine": 2632,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"columns\" for class \"_NestedSequence[complex | bytes | str]\"\n  Attribute \"columns\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 61,
-      "startLine": 2632
-    },
-    {
-      "endCharacter": 68,
-      "endLine": 2632,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"columns\" for class \"_SupportsArray[dtype[Any]]\"\n  Attribute \"columns\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 61,
-      "startLine": 2632
-    },
-    {
-      "endCharacter": 68,
-      "endLine": 2632,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"columns\" for class \"bytes\"\n  Attribute \"columns\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 61,
-      "startLine": 2632
-    },
-    {
-      "endCharacter": 68,
-      "endLine": 2632,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"columns\" for class \"complex\"\n  Attribute \"columns\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 61,
-      "startLine": 2632
-    },
-    {
-      "endCharacter": 68,
-      "endLine": 2632,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Cannot access attribute \"columns\" for class \"str\"\n  Attribute \"columns\" is unknown",
-      "rule": "reportAttributeAccessIssue",
-      "severity": "error",
-      "startCharacter": 61,
-      "startLine": 2632
-    },
-    {
-      "endCharacter": 32,
-      "endLine": 2640,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Type \"ArrayLike\" is not assignable to declared type \"DataFrame\"\n  Type \"ArrayLike\" is not assignable to type \"DataFrame\"\n    \"Buffer\" is not assignable to \"DataFrame\"",
-      "rule": "reportAssignmentType",
-      "severity": "error",
-      "startCharacter": 17,
-      "startLine": 2640
-    },
-    {
-      "endCharacter": 62,
-      "endLine": 2641,
-      "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
-      "message": "Type \"ArrayLike\" is not assignable to declared type \"DataFrame\"\n  Type \"ArrayLike\" is not assignable to type \"DataFrame\"\n    \"Buffer\" is not assignable to \"DataFrame\"",
-      "rule": "reportAssignmentType",
-      "severity": "error",
-      "startCharacter": 23,
-      "startLine": 2641
+      "startLine": 2600
     },
     {
       "endCharacter": 46,
-      "endLine": 2674,
+      "endLine": 2835,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"empty\" for class \"Buffer\"\n  Attribute \"empty\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 41,
-      "startLine": 2674
+      "startLine": 2835
     },
     {
       "endCharacter": 46,
-      "endLine": 2674,
+      "endLine": 2835,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"empty\" for class \"_NestedSequence[_SupportsArray[dtype[Any]]]\"\n  Attribute \"empty\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 41,
-      "startLine": 2674
+      "startLine": 2835
     },
     {
       "endCharacter": 46,
-      "endLine": 2674,
+      "endLine": 2835,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"empty\" for class \"_NestedSequence[complex | bytes | str]\"\n  Attribute \"empty\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 41,
-      "startLine": 2674
+      "startLine": 2835
     },
     {
       "endCharacter": 46,
-      "endLine": 2674,
+      "endLine": 2835,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"empty\" for class \"_SupportsArray[dtype[Any]]\"\n  Attribute \"empty\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 41,
-      "startLine": 2674
+      "startLine": 2835
     },
     {
       "endCharacter": 46,
-      "endLine": 2674,
+      "endLine": 2835,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"empty\" for class \"bytes\"\n  Attribute \"empty\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 41,
-      "startLine": 2674
+      "startLine": 2835
     },
     {
       "endCharacter": 46,
-      "endLine": 2674,
+      "endLine": 2835,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"empty\" for class \"complex\"\n  Attribute \"empty\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 41,
-      "startLine": 2674
+      "startLine": 2835
     },
     {
       "endCharacter": 46,
-      "endLine": 2674,
+      "endLine": 2835,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Cannot access attribute \"empty\" for class \"str\"\n  Attribute \"empty\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 41,
-      "startLine": 2674
+      "startLine": 2835
     },
     {
       "endCharacter": 41,
-      "endLine": 2681,
+      "endLine": 2842,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"ArrayLike\" cannot be assigned to parameter \"features\" of type \"DataFrame\" in function \"_sanitize_pipeline_weights\"\n  Type \"ArrayLike\" is not assignable to type \"DataFrame\"\n    \"Buffer\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2681
+      "startLine": 2842
     },
     {
       "endCharacter": 39,
-      "endLine": 2730,
+      "endLine": 2891,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"ArrayLike\" cannot be assigned to parameter \"features\" of type \"DataFrame\" in function \"_sanitize_pipeline_weights\"\n  Type \"ArrayLike\" is not assignable to type \"DataFrame\"\n    \"Buffer\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 2730
+      "startLine": 2891
     },
     {
       "endCharacter": 19,
-      "endLine": 2840,
+      "endLine": 3001,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"int | Any | None\" cannot be assigned to parameter \"gap\" of type \"int\" in function \"__init__\"\n  Type \"int | Any | None\" is not assignable to type \"int\"\n    \"None\" is not assignable to \"int\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2840
+      "startLine": 3001
     },
     {
       "endCharacter": 21,
-      "endLine": 2951,
+      "endLine": 3113,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"X\" of type \"DataFrame\" in function \"hp_objective\"\n  Type \"Any | None\" is not assignable to type \"DataFrame\"\n    \"None\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 2951
+      "startLine": 3113
     },
     {
       "endCharacter": 21,
-      "endLine": 2952,
+      "endLine": 3114,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"y\" of type \"DataFrame\" in function \"hp_objective\"\n  Type \"Any | None\" is not assignable to type \"DataFrame\"\n    \"None\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 2952
+      "startLine": 3114
     },
     {
       "endCharacter": 33,
-      "endLine": 2953,
+      "endLine": 3115,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"train_weights\" of type \"NDArray[floating[Any]]\" in function \"hp_objective\"\n  Type \"Any | None\" is not assignable to type \"NDArray[floating[Any]]\"\n    \"None\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 2953
+      "startLine": 3115
     },
     {
       "endCharacter": 32,
-      "endLine": 2954,
+      "endLine": 3116,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"X_validation\" of type \"DataFrame\" in function \"hp_objective\"\n  Type \"Any | None\" is not assignable to type \"DataFrame\"\n    \"None\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 2954
+      "startLine": 3116
     },
     {
       "endCharacter": 32,
-      "endLine": 2955,
+      "endLine": 3117,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"y_validation\" of type \"DataFrame\" in function \"hp_objective\"\n  Type \"Any | None\" is not assignable to type \"DataFrame\"\n    \"None\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 2955
+      "startLine": 3117
     },
     {
       "endCharacter": 38,
-      "endLine": 2956,
+      "endLine": 3118,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"validation_weights\" of type \"NDArray[floating[Any]]\" in function \"hp_objective\"\n  Type \"Any | None\" is not assignable to type \"NDArray[floating[Any]]\"\n    \"None\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 2956
+      "startLine": 3118
     },
     {
       "endCharacter": 24,
-      "endLine": 2977,
+      "endLine": 3139,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"X_test\" of type \"DataFrame\" in function \"make_test_set_and_weights\"\n  Type \"Any | None\" is not assignable to type \"DataFrame\"\n    \"None\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 2977
+      "startLine": 3139
     },
     {
       "endCharacter": 24,
-      "endLine": 2978,
+      "endLine": 3140,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"y_test\" of type \"DataFrame\" in function \"make_test_set_and_weights\"\n  Type \"Any | None\" is not assignable to type \"DataFrame\"\n    \"None\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 2978
+      "startLine": 3140
     },
     {
       "endCharacter": 30,
-      "endLine": 2979,
+      "endLine": 3141,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"test_weights\" of type \"NDArray[floating[Any]]\" in function \"make_test_set_and_weights\"\n  Type \"Any | None\" is not assignable to type \"NDArray[floating[Any]]\"\n    \"None\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 2979
+      "startLine": 3141
     },
     {
       "endCharacter": 15,
-      "endLine": 2985,
+      "endLine": 3147,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"X\" of type \"DataFrame\" in function \"fit_regressor\"\n  Type \"Any | None\" is not assignable to type \"DataFrame\"\n    \"None\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 14,
-      "startLine": 2985
+      "startLine": 3147
     },
     {
       "endCharacter": 15,
-      "endLine": 2986,
+      "endLine": 3148,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"y\" of type \"DataFrame\" in function \"fit_regressor\"\n  Type \"Any | None\" is not assignable to type \"DataFrame\"\n    \"None\" is not assignable to \"DataFrame\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 14,
-      "startLine": 2986
+      "startLine": 3148
     },
     {
       "endCharacter": 39,
-      "endLine": 2987,
+      "endLine": 3149,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"train_weights\" of type \"NDArray[floating[Any]]\" in function \"fit_regressor\"\n  Type \"Any | None\" is not assignable to type \"NDArray[floating[Any]]\"\n    \"None\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 26,
-      "startLine": 2987
+      "startLine": 3149
     },
     {
       "endCharacter": 38,
-      "endLine": 2997,
+      "endLine": 3159,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "\"columns\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 31,
-      "startLine": 2997
+      "startLine": 3159
     },
     {
       "endCharacter": 34,
-      "endLine": 2998,
+      "endLine": 3160,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "\"index\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 29,
-      "startLine": 2998
+      "startLine": 3160
     },
     {
       "endCharacter": 82,
-      "endLine": 3000,
+      "endLine": 3162,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "\"copy\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 78,
-      "startLine": 3000
+      "startLine": 3162
     },
     {
       "endCharacter": 62,
-      "endLine": 3283,
+      "endLine": 3461,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "\"get_pair_dataframe\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 44,
-      "startLine": 3283
+      "startLine": 3461
     },
     {
       "endCharacter": 68,
-      "endLine": 3658,
+      "endLine": 3841,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Type \"floating[Any] | NDArray[float64]\" is not assignable to return type \"NDArray[floating[Any]]\"\n  Type \"floating[Any] | NDArray[float64]\" is not assignable to type \"NDArray[floating[Any]]\"\n    \"floating[Any]\" is not assignable to \"ndarray[_AnyShape, dtype[floating[Any]]]\"",
       "rule": "reportReturnType",
       "severity": "error",
       "startCharacter": 15,
-      "startLine": 3654
+      "startLine": 3837
     },
     {
       "endCharacter": 13,
-      "endLine": 3687,
+      "endLine": 3870,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "No overloads for \"cdist\" match the provided arguments",
       "rule": "reportCallIssue",
       "severity": "error",
       "startCharacter": 19,
-      "startLine": 3682
+      "startLine": 3865
     },
     {
       "endCharacter": 38,
-      "endLine": 3685,
+      "endLine": 3868,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"str\" cannot be assigned to parameter \"metric\" of type \"_MetricFunc\" in function \"cdist\"\n  Type \"str\" is not assignable to type \"_MetricFunc\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 23,
-      "startLine": 3685
+      "startLine": 3868
     },
     {
       "endCharacter": 9,
-      "endLine": 3790,
+      "endLine": 3973,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "No overloads for \"pdist\" match the provided arguments",
       "rule": "reportCallIssue",
       "severity": "error",
       "startCharacter": 36,
-      "startLine": 3788
+      "startLine": 3971
     },
     {
       "endCharacter": 42,
-      "endLine": 3789,
+      "endLine": 3972,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"str\" cannot be assigned to parameter \"metric\" of type \"_MetricFunc\" in function \"pdist\"\n  Type \"str\" is not assignable to type \"_MetricFunc\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 3789
+      "startLine": 3972
     },
     {
       "endCharacter": 9,
-      "endLine": 3867,
+      "endLine": 4050,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "No overloads for \"cdist\" match the provided arguments",
       "rule": "reportCallIssue",
       "severity": "error",
       "startCharacter": 15,
-      "startLine": 3862
+      "startLine": 4045
     },
     {
       "endCharacter": 34,
-      "endLine": 3865,
+      "endLine": 4048,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"str\" cannot be assigned to parameter \"metric\" of type \"_MetricFunc\" in function \"cdist\"\n  Type \"str\" is not assignable to type \"_MetricFunc\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 19,
-      "startLine": 3865
+      "startLine": 4048
     },
     {
       "endCharacter": 99,
-      "endLine": 4056,
+      "endLine": 4239,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "No overloads for \"pdist\" match the provided arguments",
       "rule": "reportCallIssue",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 4056
+      "startLine": 4239
     },
     {
       "endCharacter": 79,
-      "endLine": 4056,
+      "endLine": 4239,
       "file": "quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py",
       "message": "Argument of type \"str\" cannot be assigned to parameter \"metric\" of type \"_MetricFunc\" in function \"pdist\"\n  Type \"str\" is not assignable to type \"_MetricFunc\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 64,
-      "startLine": 4056
+      "startLine": 4239
     },
     {
       "endCharacter": 55,
       "startLine": 1150
     },
     {
-      "endCharacter": 73,
+      "endCharacter": 70,
       "endLine": 1281,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Expected 1 more positional argument",
       "rule": "reportCallIssue",
       "severity": "error",
-      "startCharacter": 51,
+      "startCharacter": 48,
       "startLine": 1281
     },
     {
     },
     {
       "endCharacter": 96,
-      "endLine": 1420,
+      "endLine": 1424,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"get_analyzed_dataframe\"\n  Type \"Any | None\" is not assignable to type \"str\"\n    \"None\" is not assignable to \"str\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 68,
-      "startLine": 1420
+      "startLine": 1424
     },
     {
       "endCharacter": 77,
-      "endLine": 1454,
+      "endLine": 1458,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"<=\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 57,
-      "startLine": 1454
+      "startLine": 1458
     },
     {
       "endCharacter": 9,
-      "endLine": 1459,
+      "endLine": 1463,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"+\" not supported for types \"float\" and \"float | None\"\n  Operator \"+\" not supported for types \"float\" and \"None\"",
       "rule": "reportOperatorIssue",
       "severity": "error",
       "startCharacter": 28,
-      "startLine": 1457
+      "startLine": 1461
     },
     {
       "endCharacter": 33,
-      "endLine": 1458,
+      "endLine": 1462,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"-\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 13,
-      "startLine": 1458
+      "startLine": 1462
     },
     {
       "endCharacter": 67,
-      "endLine": 1464,
+      "endLine": 1468,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 47,
-      "startLine": 1464
+      "startLine": 1468
     },
     {
       "endCharacter": 67,
-      "endLine": 1464,
+      "endLine": 1468,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n  ...",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 47,
-      "startLine": 1464
+      "startLine": 1468
     },
     {
       "endCharacter": 64,
-      "endLine": 1618,
+      "endLine": 1622,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "\"isoformat\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 55,
-      "startLine": 1618
+      "startLine": 1622
     },
     {
       "endCharacter": 37,
-      "endLine": 1669,
+      "endLine": 1673,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"<=\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 15,
-      "startLine": 1669
+      "startLine": 1673
     },
     {
       "endCharacter": 48,
-      "endLine": 1671,
+      "endLine": 1675,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"<=\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 15,
-      "startLine": 1671
+      "startLine": 1675
     },
     {
       "endCharacter": 96,
-      "endLine": 1851,
+      "endLine": 1855,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"get_analyzed_dataframe\"\n  Type \"Any | None\" is not assignable to type \"str\"\n    \"None\" is not assignable to \"str\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 68,
-      "startLine": 1851
+      "startLine": 1855
     },
     {
       "endCharacter": 39,
-      "endLine": 1928,
+      "endLine": 1932,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"+\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 21,
-      "startLine": 1928
+      "startLine": 1932
     },
     {
       "endCharacter": 90,
-      "endLine": 1928,
+      "endLine": 1932,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"*\" not supported for types \"float\" and \"Any | None\"\n  Operator \"*\" not supported for types \"float\" and \"None\"",
       "rule": "reportOperatorIssue",
       "severity": "error",
       "startCharacter": 62,
-      "startLine": 1928
+      "startLine": 1932
     },
     {
       "endCharacter": 96,
-      "endLine": 2232,
+      "endLine": 2236,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"get_analyzed_dataframe\"\n  Type \"Any | None\" is not assignable to type \"str\"\n    \"None\" is not assignable to \"str\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 68,
-      "startLine": 2232
+      "startLine": 2236
     },
     {
       "endCharacter": 85,
-      "endLine": 2257,
+      "endLine": 2261,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "\"isoformat\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 76,
-      "startLine": 2257
+      "startLine": 2261
     },
     {
       "endCharacter": 47,
-      "endLine": 2263,
+      "endLine": 2267,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"<\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2263
+      "startLine": 2267
     },
     {
       "endCharacter": 42,
-      "endLine": 2267,
+      "endLine": 2271,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"str\" cannot be assigned to parameter \"side\" of type \"TradeDirection\" in function \"reversal_confirmed\"\n  Type \"str\" is not assignable to type \"TradeDirection\"\n    \"str\" is not assignable to type \"Literal['long']\"\n    \"str\" is not assignable to type \"Literal['short']\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2267
+      "startLine": 2271
     },
     {
       "endCharacter": 42,
-      "endLine": 2268,
+      "endLine": 2272,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"str\" cannot be assigned to parameter \"order\" of type \"OrderType\" in function \"reversal_confirmed\"\n  Type \"str\" is not assignable to type \"OrderType\"\n    \"str\" is not assignable to type \"Literal['entry']\"\n    \"str\" is not assignable to type \"Literal['exit']\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2268
+      "startLine": 2272
     },
     {
       "endCharacter": 69,
-      "endLine": 2270,
+      "endLine": 2274,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"int | float\" cannot be assigned to parameter \"lookback_period_candles\" of type \"int\" in function \"reversal_confirmed\"\n  Type \"int | float\" is not assignable to type \"int\"\n    \"float\" is not assignable to \"int\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2270
+      "startLine": 2274
     },
     {
       "endCharacter": 47,
-      "endLine": 2281,
+      "endLine": 2285,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \">\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2281
+      "startLine": 2285
     },
     {
       "endCharacter": 43,
-      "endLine": 2285,
+      "endLine": 2289,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"str\" cannot be assigned to parameter \"side\" of type \"TradeDirection\" in function \"reversal_confirmed\"\n  Type \"str\" is not assignable to type \"TradeDirection\"\n    \"str\" is not assignable to type \"Literal['long']\"\n    \"str\" is not assignable to type \"Literal['short']\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2285
+      "startLine": 2289
     },
     {
       "endCharacter": 42,
-      "endLine": 2286,
+      "endLine": 2290,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"str\" cannot be assigned to parameter \"order\" of type \"OrderType\" in function \"reversal_confirmed\"\n  Type \"str\" is not assignable to type \"OrderType\"\n    \"str\" is not assignable to type \"Literal['entry']\"\n    \"str\" is not assignable to type \"Literal['exit']\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2286
+      "startLine": 2290
     },
     {
       "endCharacter": 69,
-      "endLine": 2288,
+      "endLine": 2292,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"int | float\" cannot be assigned to parameter \"lookback_period_candles\" of type \"int\" in function \"reversal_confirmed\"\n  Type \"int | float\" is not assignable to type \"int\"\n    \"float\" is not assignable to \"int\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2288
+      "startLine": 2292
     },
     {
       "endCharacter": 52,
-      "endLine": 2317,
+      "endLine": 2321,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"datetime | None\" cannot be assigned to parameter \"current_candle_date\" of type \"datetime\" in function \"_normalize_final_take_profit_state\"\n  Type \"datetime | None\" is not assignable to type \"datetime\"\n    \"None\" is not assignable to \"datetime\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 36,
-      "startLine": 2317
+      "startLine": 2321
     },
     {
       "endCharacter": 96,
-      "endLine": 2437,
+      "endLine": 2441,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"get_analyzed_dataframe\"\n  Type \"Any | None\" is not assignable to type \"str\"\n    \"None\" is not assignable to \"str\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 68,
-      "startLine": 2437
+      "startLine": 2441
     },
     {
       "endCharacter": 43,
-      "endLine": 2446,
+      "endLine": 2450,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"str\" cannot be assigned to parameter \"order\" of type \"OrderType\" in function \"reversal_confirmed\"\n  Type \"str\" is not assignable to type \"OrderType\"\n    \"str\" is not assignable to type \"Literal['entry']\"\n    \"str\" is not assignable to type \"Literal['exit']\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2446
+      "startLine": 2450
     },
     {
       "endCharacter": 69,
-      "endLine": 2448,
+      "endLine": 2452,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"int | float\" cannot be assigned to parameter \"lookback_period_candles\" of type \"int\" in function \"reversal_confirmed\"\n  Type \"int | float\" is not assignable to type \"int\"\n    \"float\" is not assignable to \"int\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2448
+      "startLine": 2452
     },
     {
       "endCharacter": 32,
-      "endLine": 2524,
+      "endLine": 2528,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"LocalTrade\" cannot be assigned to parameter \"trade\" of type \"Trade\" in function \"get_trade_annotation_line_start_date\"\n  \"LocalTrade\" is not assignable to \"Trade\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 2524
+      "startLine": 2528
     },
     {
       "endCharacter": 72,
-      "endLine": 2527,
+      "endLine": 2531,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"LocalTrade\" cannot be assigned to parameter \"trade\" of type \"Trade\" in function \"get_trade_exit_stage\"\n  \"LocalTrade\" is not assignable to \"Trade\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 67,
-      "startLine": 2527
+      "startLine": 2531
     },
     {
       "endCharacter": 36,
-      "endLine": 2534,
+      "endLine": 2538,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"LocalTrade\" cannot be assigned to parameter \"trade\" of type \"Trade\" in function \"get_take_profit_target\"\n  \"LocalTrade\" is not assignable to \"Trade\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 31,
-      "startLine": 2534
+      "startLine": 2538
     },
     {
       "endCharacter": 71,
-      "endLine": 2565,
+      "endLine": 2569,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"LocalTrade\" cannot be assigned to parameter \"trade\" of type \"Trade\" in function \"get_trade_entry_date\"\n  \"LocalTrade\" is not assignable to \"Trade\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 66,
-      "startLine": 2565
+      "startLine": 2569
     },
     {
       "endCharacter": 32,
-      "endLine": 2596,
+      "endLine": 2600,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"LocalTrade\" cannot be assigned to parameter \"trade\" of type \"Trade\" in function \"get_take_profit_target\"\n  \"LocalTrade\" is not assignable to \"Trade\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 2596
+      "startLine": 2600
     },
     {
       "endCharacter": 34,
     },
     {
       "endCharacter": 38,
-      "endLine": 3407,
+      "endLine": 3414,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Cannot access attribute \"__func__\" for class \"FunctionType\"\n  Attribute \"__func__\" is unknown",
       "rule": "reportFunctionMemberAccess",
       "severity": "error",
       "startCharacter": 30,
-      "startLine": 3407
+      "startLine": 3414
     },
     {
       "endCharacter": 34,
-      "endLine": 3409,
+      "endLine": 3416,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Cannot access attribute \"__func__\" for class \"FunctionType\"\n  Attribute \"__func__\" is unknown",
       "rule": "reportFunctionMemberAccess",
       "severity": "error",
       "startCharacter": 26,
-      "startLine": 3409
+      "startLine": 3416
     },
     {
       "endCharacter": 55,
-      "endLine": 3637,
+      "endLine": 3644,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"rolling\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 48,
-      "startLine": 3637
+      "startLine": 3644
     },
     {
       "endCharacter": 38,
-      "endLine": 3662,
+      "endLine": 3669,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"rolling\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 31,
-      "startLine": 3662
+      "startLine": 3669
     },
     {
       "endCharacter": 55,
-      "endLine": 3688,
+      "endLine": 3695,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"rolling\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 48,
-      "startLine": 3688
+      "startLine": 3695
     },
     {
       "endCharacter": 56,
-      "endLine": 3689,
+      "endLine": 3696,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"rolling\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 49,
-      "startLine": 3689
+      "startLine": 3696
     },
     {
       "endCharacter": 33,
-      "endLine": 3761,
+      "endLine": 3768,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"Series[Any] | NDArray[floating[Any]]\" cannot be assigned to parameter \"series\" of type \"Series[Any]\" in function \"calculate_zero_lag\"\n  Type \"Series[Any] | NDArray[floating[Any]]\" is not assignable to type \"Series[Any]\"\n    \"ndarray[_AnyShape, dtype[floating[Any]]]\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 3761
+      "startLine": 3768
     },
     {
       "endCharacter": 69,
-      "endLine": 3761,
+      "endLine": 3768,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Expected 1 more positional argument",
       "rule": "reportCallIssue",
       "severity": "error",
       "startCharacter": 59,
-      "startLine": 3761
+      "startLine": 3768
     },
     {
       "endCharacter": 40,
-      "endLine": 3816,
+      "endLine": 3823,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"series\" of type \"Series[Any]\" in function \"calculate_zero_lag\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 35,
-      "startLine": 3816
+      "startLine": 3823
     },
     {
       "endCharacter": 38,
-      "endLine": 3817,
+      "endLine": 3824,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"series\" of type \"Series[Any]\" in function \"calculate_zero_lag\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 34,
-      "startLine": 3817
+      "startLine": 3824
     },
     {
       "endCharacter": 42,
-      "endLine": 3818,
+      "endLine": 3825,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"series\" of type \"Series[Any]\" in function \"calculate_zero_lag\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 36,
-      "startLine": 3818
+      "startLine": 3825
     },
     {
       "endCharacter": 45,
-      "endLine": 3820,
+      "endLine": 3827,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"index\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 40,
-      "startLine": 3820
+      "startLine": 3827
     },
     {
       "endCharacter": 33,
-      "endLine": 3822,
+      "endLine": 3829,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"iloc\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 29,
-      "startLine": 3822
+      "startLine": 3829
     },
     {
       "endCharacter": 31,
-      "endLine": 3823,
+      "endLine": 3830,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"iloc\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 3823
+      "startLine": 3830
     },
     {
       "endCharacter": 48,
-      "endLine": 3828,
+      "endLine": 3835,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"index\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 43,
-      "startLine": 3828
+      "startLine": 3835
     },
     {
       "endCharacter": 40,
-      "endLine": 3829,
+      "endLine": 3836,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"iloc\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 36,
-      "startLine": 3829
+      "startLine": 3836
     },
     {
       "endCharacter": 59,
-      "endLine": 3831,
+      "endLine": 3838,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Cannot access attribute \"iloc\" for class \"NDArray[Any]\"\n  Attribute \"iloc\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 55,
-      "startLine": 3831
+      "startLine": 3838
     },
     {
       "endCharacter": 34,
-      "endLine": 3833,
+      "endLine": 3840,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Cannot access attribute \"iloc\" for class \"NDArray[Any]\"\n  Attribute \"iloc\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 30,
-      "startLine": 3833
+      "startLine": 3840
     },
     {
       "endCharacter": 51,
-      "endLine": 3833,
+      "endLine": 3840,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"iloc\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 47,
-      "startLine": 3833
+      "startLine": 3840
     },
     {
       "endCharacter": 72,
-      "endLine": 3833,
+      "endLine": 3840,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Cannot access attribute \"iloc\" for class \"NDArray[Any]\"\n  Attribute \"iloc\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 68,
-      "startLine": 3833
+      "startLine": 3840
     },
     {
       "endCharacter": 40,
-      "endLine": 3900,
+      "endLine": 3907,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Type \"(Series[Any] | NDArray[floating[Any]], int) -> (Series[Any] | NDArray[floating[Any]])\" is not assignable to declared type \"(series: Unknown, timeperiod: Unknown) -> Series[Any]\"\n  Type \"(Series[Any] | NDArray[floating[Any]], int) -> (Series[Any] | NDArray[floating[Any]])\" is not assignable to type \"(series: Unknown, timeperiod: Unknown) -> Series[Any]\"\n    Missing keyword parameter \"series\"\n    Missing keyword parameter \"timeperiod\"\n      Position-only parameter mismatch; parameter \"series\" is not position-only\n      Position-only parameter mismatch; parameter \"timeperiod\" is not position-only\n      Position-only parameter mismatch; expected 2 but received 0\n      Function return type \"Series[Any] | NDArray[floating[Any]]\" is incompatible with type \"Series[Any]\"\n        Type \"Series[Any] | NDArray[floating[Any]]\" is not assignable to type \"Series[Any]\"\n  ...",
       "rule": "reportAssignmentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 3900
+      "startLine": 3907
     },
     {
       "endCharacter": 33,
-      "endLine": 3902,
+      "endLine": 3909,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Type \"(Series[Any] | NDArray[floating[Any]], int) -> (Series[Any] | NDArray[floating[Any]])\" is not assignable to declared type \"(series: Unknown, timeperiod: Unknown) -> Series[Any]\"\n  Type \"(Series[Any] | NDArray[floating[Any]], int) -> (Series[Any] | NDArray[floating[Any]])\" is not assignable to type \"(series: Unknown, timeperiod: Unknown) -> Series[Any]\"\n    Missing keyword parameter \"series\"\n    Missing keyword parameter \"timeperiod\"\n      Position-only parameter mismatch; parameter \"series\" is not position-only\n      Position-only parameter mismatch; parameter \"timeperiod\" is not position-only\n      Position-only parameter mismatch; expected 2 but received 0\n      Function return type \"Series[Any] | NDArray[floating[Any]]\" is incompatible with type \"Series[Any]\"\n        Type \"Series[Any] | NDArray[floating[Any]]\" is not assignable to type \"Series[Any]\"\n  ...",
       "rule": "reportAssignmentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 3902
+      "startLine": 3909
     },
     {
       "endCharacter": 35,
-      "endLine": 3948,
+      "endLine": 3955,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"to_numpy\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 3948
+      "startLine": 3955
     },
     {
       "endCharacter": 33,
-      "endLine": 3949,
+      "endLine": 3956,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"to_numpy\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 25,
-      "startLine": 3949
+      "startLine": 3956
     },
     {
       "endCharacter": 37,
-      "endLine": 4061,
+      "endLine": 4068,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"to_numpy\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 29,
-      "startLine": 4061
+      "startLine": 4068
     },
     {
       "endCharacter": 35,
-      "endLine": 4062,
+      "endLine": 4069,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"to_numpy\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 4062
+      "startLine": 4069
     },
     {
       "endCharacter": 33,
-      "endLine": 4063,
+      "endLine": 4070,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"to_numpy\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 25,
-      "startLine": 4063
+      "startLine": 4070
     },
     {
       "endCharacter": 39,
-      "endLine": 4083,
+      "endLine": 4090,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"to_numpy\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 31,
-      "startLine": 4083
+      "startLine": 4090
     },
     {
       "endCharacter": 92,
-      "endLine": 4442,
+      "endLine": 4449,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Type \"bool_ | bool\" is not assignable to return type \"bool\"\n  Type \"bool_ | bool\" is not assignable to type \"bool\"\n    \"numpy.bool[builtins.bool]\" is not assignable to \"bool\"",
       "rule": "reportReturnType",
       "severity": "error",
       "startCharacter": 15,
-      "startLine": 4442
+      "startLine": 4449
     },
     {
       "endCharacter": 85,
-      "endLine": 4843,
+      "endLine": 4850,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"XGBoostPruningCallback\" cannot be assigned to parameter \"object\" of type \"RegressorCallback\" in function \"append\"\n  Type \"XGBoostPruningCallback\" is not assignable to type \"RegressorCallback\"\n    Type \"XGBoostPruningCallback\" is not assignable to type \"(...) -> Any\"\n    \"XGBoostPruningCallback\" is not assignable to \"TrainingCallback\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 4843
+      "startLine": 4850
     },
     {
       "endCharacter": 29,
-      "endLine": 4886,
+      "endLine": 4893,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"list[tuple[DataFrame, DataFrame]] | None\" cannot be assigned to parameter \"eval_set\" of type \"List[_LGBM_ScikitValidSet] | None\" in function \"fit\"\n  Type \"list[tuple[DataFrame, DataFrame]] | None\" is not assignable to type \"List[_LGBM_ScikitValidSet] | None\"\n    Type \"list[tuple[DataFrame, DataFrame]]\" is not assignable to type \"List[_LGBM_ScikitValidSet] | None\"\n      \"list[tuple[DataFrame, DataFrame]]\" is not assignable to \"List[_LGBM_ScikitValidSet]\"\n        Type parameter \"_T@list\" is invariant, but \"tuple[DataFrame, DataFrame]\" is not the same as \"_LGBM_ScikitValidSet\"\n        Consider switching from \"list\" to \"Sequence\" which is covariant\n      \"list[tuple[DataFrame, DataFrame]]\" is not assignable to \"None\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 21,
-      "startLine": 4886
+      "startLine": 4893
     },
     {
       "endCharacter": 43,
-      "endLine": 4887,
+      "endLine": 4894,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"list[NDArray[floating[Any]]] | None\" cannot be assigned to parameter \"eval_sample_weight\" of type \"List[_LGBM_WeightType] | None\" in function \"fit\"\n  Type \"list[NDArray[floating[Any]]] | None\" is not assignable to type \"List[_LGBM_WeightType] | None\"\n    Type \"list[NDArray[floating[Any]]]\" is not assignable to type \"List[_LGBM_WeightType] | None\"\n      \"list[NDArray[floating[Any]]]\" is not assignable to \"List[_LGBM_WeightType]\"\n        Type parameter \"_T@list\" is invariant, but \"NDArray[floating[Any]]\" is not the same as \"_LGBM_WeightType\"\n        Consider switching from \"list\" to \"Sequence\" which is covariant\n      \"list[NDArray[floating[Any]]]\" is not assignable to \"None\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 31,
-      "startLine": 4887
+      "startLine": 4894
     },
     {
       "endCharacter": 62,
-      "endLine": 4890,
+      "endLine": 4897,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"list[RegressorCallback] | None\" cannot be assigned to parameter \"callbacks\" of type \"List[(...) -> Unknown] | None\" in function \"fit\"\n  Type \"list[RegressorCallback] | None\" is not assignable to type \"List[(...) -> Unknown] | None\"\n    Type \"list[RegressorCallback]\" is not assignable to type \"List[(...) -> Unknown] | None\"\n      \"list[RegressorCallback]\" is not assignable to \"List[(...) -> Unknown]\"\n        Type parameter \"_T@list\" is invariant, but \"RegressorCallback\" is not the same as \"(...) -> Unknown\"\n        Consider switching from \"list\" to \"Sequence\" which is covariant\n      \"list[RegressorCallback]\" is not assignable to \"None\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 22,
-      "startLine": 4890
+      "startLine": 4897
     },
     {
       "endCharacter": 35,
-      "endLine": 4912,
+      "endLine": 4919,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Object of type \"None\" is not subscriptable",
       "rule": "reportOptionalSubscript",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 4912
+      "startLine": 4919
     },
     {
       "endCharacter": 35,
-      "endLine": 4958,
+      "endLine": 4965,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Object of type \"None\" is not subscriptable",
       "rule": "reportOptionalSubscript",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 4958
+      "startLine": 4965
     },
     {
       "endCharacter": 49,
-      "endLine": 5023,
+      "endLine": 5035,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"CatBoostPruningCallback\" cannot be assigned to parameter \"object\" of type \"RegressorCallback\" in function \"append\"\n  Type \"CatBoostPruningCallback\" is not assignable to type \"RegressorCallback\"\n    Type \"CatBoostPruningCallback\" is not assignable to type \"(...) -> Any\"\n    \"CatBoostPruningCallback\" is not assignable to \"TrainingCallback\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 33,
-      "startLine": 5023
+      "startLine": 5035
     },
     {
       "endCharacter": 75,
-      "endLine": 5266,
+      "endLine": 5278,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Operator \"<=\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 54,
-      "startLine": 5266
+      "startLine": 5278
     },
     {
       "endCharacter": 23,
-      "endLine": 5429,
+      "endLine": 5441,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"best_params\" is possibly unbound",
       "rule": "reportPossiblyUnboundVariable",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 5429
+      "startLine": 5441
     },
     {
       "endCharacter": 38,
-      "endLine": 5436,
+      "endLine": 5448,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"best_params\" is possibly unbound",
       "rule": "reportPossiblyUnboundVariable",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 5436
+      "startLine": 5448
     },
     {
       "endCharacter": 22,
-      "endLine": 5448,
+      "endLine": 5460,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"best_params\" is possibly unbound",
       "rule": "reportPossiblyUnboundVariable",
       "severity": "error",
       "startCharacter": 11,
-      "startLine": 5448
+      "startLine": 5460
     },
     {
       "endCharacter": 22,
-      "endLine": 5606,
+      "endLine": 5618,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Declaration \"default_ranges\" is obscured by a declaration of the same name",
       "rule": "reportRedeclaration",
       "severity": "error",
       "startCharacter": 8,
-      "startLine": 5606
+      "startLine": 5618
     },
     {
       "endCharacter": 14,
-      "endLine": 5642,
+      "endLine": 5654,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Declaration \"params\" is obscured by a declaration of the same name",
       "rule": "reportRedeclaration",
       "severity": "error",
       "startCharacter": 8,
-      "startLine": 5642
+      "startLine": 5654
     },
     {
       "endCharacter": 22,
-      "endLine": 5726,
+      "endLine": 5738,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Declaration \"default_ranges\" is obscured by a declaration of the same name",
       "rule": "reportRedeclaration",
       "severity": "error",
       "startCharacter": 8,
-      "startLine": 5726
+      "startLine": 5738
     },
     {
       "endCharacter": 14,
-      "endLine": 5760,
+      "endLine": 5772,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Declaration \"params\" is obscured by a declaration of the same name",
       "rule": "reportRedeclaration",
       "severity": "error",
       "startCharacter": 8,
-      "startLine": 5760
+      "startLine": 5772
     },
     {
       "endCharacter": 22,
-      "endLine": 5831,
+      "endLine": 5843,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Declaration \"default_ranges\" is obscured by a declaration of the same name",
       "rule": "reportRedeclaration",
       "severity": "error",
       "startCharacter": 8,
-      "startLine": 5831
+      "startLine": 5843
     },
     {
       "endCharacter": 22,
-      "endLine": 5932,
+      "endLine": 5944,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Declaration \"default_ranges\" is obscured by a declaration of the same name",
       "rule": "reportRedeclaration",
       "severity": "error",
       "startCharacter": 8,
-      "startLine": 5932
+      "startLine": 5944
     },
     {
       "endCharacter": 26,
-      "endLine": 6015,
+      "endLine": 6027,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Declaration \"default_ranges\" is obscured by a declaration of the same name",
       "rule": "reportRedeclaration",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 6015
+      "startLine": 6027
     }
   ],
   "filesAnalyzed": 5,
index bc1eaeba97f07274961dac1c960fb2838a4e8043..2310197f6070a840445d9034e11b431efdd2253a 100644 (file)
@@ -34,7 +34,12 @@ from datasieve.transforms import SKLearnWrapper
 from freqtrade.enums import TRADE_MODES
 from freqtrade.exceptions import DependencyException
 from freqtrade.freqai.base_models.BaseRegressionModel import BaseRegressionModel
-from freqtrade.freqai.data_drawer import FreqaiDataDrawer
+from freqtrade.freqai.data_drawer import (
+    FEATURE_PIPELINE,
+    LABEL_PIPELINE,
+    METADATA,
+    FreqaiDataDrawer,
+)
 from freqtrade.freqai.data_kitchen import FreqaiDataKitchen
 
 # Disabled: scikit-learn-extra 0.3.0 fails on Python 3.14 (__gxx_personality_v0).
@@ -66,9 +71,11 @@ from sklearn.preprocessing import (
     StandardScaler,
 )
 from Utils import (
+    _CATBOOST_TASK_TYPES,
     _FORMAT_STYLES,
     _OPTUNA_LABEL_SELECTION_SCHEMA_VERSION,
     _OPTUNA_NAMESPACES,
+    _REGRESSOR_SPECS,
     DEFAULT_MAX_LABEL_NATR_MULTIPLIER,
     DEFAULT_MAX_LABEL_PERIOD_CANDLES,
     DEFAULT_MIN_LABEL_NATR_MULTIPLIER,
@@ -120,6 +127,31 @@ from Utils import (
 _DATE_PRED_DEDUP_SENTINEL = "_freqai_strategies_date_pred_repair_patched"
 
 
+def _recorded_prediction_mask(frame: pd.DataFrame) -> NDArray[np.bool_]:
+    """Identify recorded rows from metadata, never from prediction magnitudes."""
+    recorded = np.zeros(len(frame), dtype=bool)
+    if "close_price" in frame:
+        close = pd.to_numeric(frame["close_price"], errors="coerce")
+        recorded |= (close.gt(0) & close.lt(np.inf)).fillna(False).to_numpy(dtype=bool)
+    if "do_predict" in frame:
+        status = pd.to_numeric(frame["do_predict"], errors="coerce")
+        recorded |= (
+            (status.gt(-np.inf) & status.lt(np.inf) & status.ne(0))
+            .fillna(False)
+            .to_numpy(dtype=bool)
+        )
+    return recorded
+
+
+def _produced_prediction_mask(frame: pd.DataFrame) -> NDArray[np.bool_]:
+    """Exclude expired-model placeholders from recorded model observations."""
+    produced = _recorded_prediction_mask(frame)
+    if "do_predict" in frame:
+        status = pd.to_numeric(frame["do_predict"], errors="coerce")
+        produced &= status.ne(2).fillna(True).to_numpy(dtype=bool)
+    return produced
+
+
 def _dedupe_historic_predictions_on_date_pred(frame: pd.DataFrame) -> pd.DataFrame:
     """Normalize dates and retain the latest recorded row per candle, in date order.
 
@@ -138,13 +170,7 @@ def _dedupe_historic_predictions_on_date_pred(frame: pd.DataFrame) -> pd.DataFra
         result["date_pred"] = date_pred
         return result
 
-    recorded = np.zeros(len(frame), dtype=bool)
-    if "close_price" in frame:
-        close = pd.to_numeric(frame["close_price"], errors="coerce")
-        recorded |= (close.gt(0) & close.lt(np.inf)).fillna(False).to_numpy(dtype=bool)
-    if "do_predict" in frame:
-        status = pd.to_numeric(frame["do_predict"], errors="coerce")
-        recorded |= (status.notna() & status.ne(0)).to_numpy(dtype=bool)
+    recorded = _recorded_prediction_mask(frame)
     # Rank only metadata, without copying or coercing all prediction columns.
     order = pd.DataFrame(
         {"date_pred": date_pred.array, "recorded": recorded, "position": np.arange(len(frame))}
@@ -159,6 +185,21 @@ def _dedupe_historic_predictions_on_date_pred(frame: pd.DataFrame) -> pd.DataFra
     return result.reset_index(drop=True)
 
 
+def _align_historic_predictions(history: pd.DataFrame, dataframe: pd.DataFrame) -> pd.DataFrame:
+    """Align unique, normalized history to requested candle dates and exact index."""
+    dates = pd.to_datetime(dataframe["date"], utc=True, errors="coerce", format="mixed")
+    indexed = history.set_index("date_pred", drop=False)
+    aligned = indexed.reindex(pd.DatetimeIndex(dates))
+    missing = ~pd.DatetimeIndex(dates).isin(indexed.index)
+    aligned.index = dataframe.index
+    aligned["date_pred"] = dates.array
+    if "do_predict" in aligned:
+        aligned["do_predict"] = aligned["do_predict"].where(~missing, 0)
+    else:
+        aligned["do_predict"] = 0
+    return aligned
+
+
 def _install_date_pred_dedup_patch() -> None:
     """Repair persisted history and duplicates produced by older Freqtrade writers.
 
@@ -196,14 +237,12 @@ def _install_date_pred_dedup_patch() -> None:
         self.historic_predictions[pair] = _dedupe_historic_predictions_on_date_pred(
             self.historic_predictions[pair]
         )
-        original_set_initial(self, pair, pred_df, dataframe)
-        history = self.historic_predictions[pair]
-        repaired = _dedupe_historic_predictions_on_date_pred(history)
-        if repaired is not history:
-            self.historic_predictions[pair] = repaired
-            self.model_return_values[pair] = repaired.tail(len(dataframe.index)).reset_index(
-                drop=True
-            )
+        original_set_initial(
+            self, pair, pred_df.reset_index(drop=True), dataframe.reset_index(drop=True)
+        )
+        repaired = _dedupe_historic_predictions_on_date_pred(self.historic_predictions[pair])
+        self.historic_predictions[pair] = repaired
+        self.model_return_values[pair] = _align_historic_predictions(repaired, dataframe)
 
     @wraps(original_append)
     def append_model_predictions(
@@ -219,23 +258,24 @@ def _install_date_pred_dedup_patch() -> None:
         )
         if self.historic_predictions[pair].empty and not strat_df.empty:
             # Legacy append requires an initialized row; let upstream construct it.
-            original_set_initial(self, pair, pd.DataFrame(index=pd.RangeIndex(1)), strat_df.tail(1))
-        original_append(self, pair, predictions, do_preds, dk, strat_df)
-        history = self.historic_predictions[pair]
-        repaired = _dedupe_historic_predictions_on_date_pred(history)
-        if repaired is not history:
-            self.historic_predictions[pair] = repaired
-            self.model_return_values[pair] = repaired.tail(len(strat_df.index)).reset_index(
-                drop=True
+            original_set_initial(
+                self,
+                pair,
+                pd.DataFrame(index=pd.RangeIndex(1)),
+                strat_df.tail(1).reset_index(drop=True),
             )
+        original_append(self, pair, predictions, do_preds, dk, strat_df)
+        repaired = _dedupe_historic_predictions_on_date_pred(self.historic_predictions[pair])
+        self.historic_predictions[pair] = repaired
+        self.model_return_values[pair] = _align_historic_predictions(repaired, strat_df)
 
     @wraps(original_attach)
     def attach_return_values_to_return_dataframe(
         self, pair: str, dataframe: pd.DataFrame
     ) -> pd.DataFrame:
-        self.model_return_values[pair] = _dedupe_historic_predictions_on_date_pred(
-            self.model_return_values[pair]
-        )
+        repaired = _dedupe_historic_predictions_on_date_pred(self.historic_predictions[pair])
+        self.historic_predictions[pair] = repaired
+        self.model_return_values[pair] = _align_historic_predictions(repaired, dataframe)
         return original_attach(self, pair, dataframe)
 
     replacements = (
@@ -284,7 +324,7 @@ def _log_known_at_none_once(pair: str, context: str) -> None:
         return
     _KNOWN_AT_NONE_LOGGED.add(key)
     logger.info(
-        f"[{pair}] {context}: no <label>_known_at_lookahead column present; "
+        f"[{pair}] {context}: No <label>_known_at_lookahead column present; "
         "causal guards use position-based purge only (label-aware filtering disabled)"
     )
 
@@ -369,7 +409,10 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
     https://github.com/sponsors/robcaulk
     """
 
-    version = "3.13.0-rc.9"
+    version = "3.13.0-rc.10"
+
+    _DEPLOYMENT_COORDINATE_MARKER_KEY: Final[str] = "quickadapter_deployment_coordinates"
+    _DEPLOYMENT_COORDINATE_GENERATION: Final[str] = "frozen-pipelines-v1"
 
     _TEST_SIZE: Final[float] = 0.1
     _SKLEARN_TRAIN_TEST_SPLIT_KEYS: Final[frozenset[str]] = frozenset(
@@ -388,7 +431,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
     # objective (search space, scoring, or fit protocol): it gates warm-state
     # study reuse and persisted best-params loading; a stale value silently
     # reuses incompatible trials.
-    _OPTUNA_HP_OBJECTIVE_IDENTITY: Final[str] = "candidate-cold-start-v1"
+    _OPTUNA_HP_OBJECTIVE_IDENTITY: Final[str] = "candidate-cold-start-v2"
     _OPTUNA_LABEL_DIRECTIONS: Final[tuple[optuna.study.StudyDirection, ...]] = (
         optuna.study.StudyDirection.MAXIMIZE,
     ) * _OPTUNA_LABEL_N_OBJECTIVES
@@ -720,7 +763,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
     ]:
         removed = int((~keep_mask).sum())
         if removed:
-            logger.info(f"{context}: removed {removed} causal-unsafe train rows")
+            logger.info(f"{context}: Removed {removed} causal-unsafe train rows")
         if not keep_mask.any():
             raise ValueError(
                 f"{context}: causal guard removed all train rows "
@@ -792,7 +835,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
             )
         except LabelWeightSupportError as exc:
             logger.warning(
-                "%s: label-weighted eval weights failed (%s); using base weights",
+                "%s: Label-weighted eval weights failed (%s); using base weights",
                 context,
                 exc,
             )
@@ -822,7 +865,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                 )
             case QuickAdapterRegressorV3._SUPPORT_POLICY_FALLBACK:
                 logger.warning(
-                    "%s: label weighting support failed (%s); "
+                    "%s: Label weighting support failed (%s); "
                     "falling back to sanitized base weights (support_policy='fallback')",
                     context,
                     reason_text,
@@ -950,7 +993,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                 reasons=reasons,
             )
         logger.debug(
-            "%s: label weighting support passed "
+            "%s: Label weighting support passed "
             "(pivot_equivalent_count=%d, positive_label_weight_fraction=%.6g, "
             "effective_sample_size=%.6g)",
             context,
@@ -1124,7 +1167,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
         *,
         ctx: str,
         mode: ValidationMode = _VALIDATION_MODES[1],
-    ) -> NDArray[np.floating] | None:
+    ) -> NDArray[np.floating]:
         if weights is None:
             return np.full(n_objectives, 1.0 / n_objectives)
 
@@ -1136,7 +1179,9 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
             except (ValueError, TypeError):
                 msg = f"Invalid {ctx} value: must contain numeric weights"
             else:
-                if np_weights.size != n_objectives:
+                if np_weights.ndim != 1:
+                    msg = f"Invalid {ctx}: must be a one-dimensional vector"
+                elif np_weights.size != n_objectives:
                     msg = f"Invalid {ctx}: must contain {n_objectives} weights"
                 elif not np.all(np.isfinite(np_weights)):
                     msg = f"Invalid {ctx} value: contains non-finite values"
@@ -2262,11 +2307,11 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
             label_weights = unfiltered_df.loc[features_filtered.index, weight_col].to_numpy(
                 dtype=float
             )
-            logger.debug("label weight column active: %r", weight_col)
+            logger.debug("Label weight column active: %r", weight_col)
         else:
             label_weights = None
             logger.debug(
-                "label weight column absent (%r); using base weights only",
+                "Label weight column absent (%r); using base weights only",
                 weight_col,
             )
         return SampleWeightInputs(
@@ -2275,6 +2320,84 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
             label_weighting_config=label_weighting_config,
         )
 
+    def _resolve_deployment_state(
+        self, dk: FreqaiDataKitchen, pair: str
+    ) -> tuple[Any, Pipeline, Pipeline] | None:
+        """Restore the deployed model with independent copies of its fitted pipelines."""
+        if not self.continual_learning:
+            return None
+        if self.regressor == _REGRESSOR_SPECS.xgboost.name:
+            from xgboost import XGBRegressor
+
+            model_class = XGBRegressor
+        elif self.regressor == _REGRESSOR_SPECS.lightgbm.name:
+            from lightgbm import LGBMRegressor
+
+            model_class = LGBMRegressor
+        elif self.regressor == _REGRESSOR_SPECS.catboost.name:
+            if (
+                self.model_training_parameters.get("task_type", _CATBOOST_TASK_TYPES[0])
+                == _CATBOOST_TASK_TYPES[1]
+            ):
+                return None
+            from catboost import CatBoostRegressor
+
+            model_class = CatBoostRegressor
+        else:
+            return None
+
+        model = self.dd.model_dictionary.get(pair)
+        previous = self.dd.pair_dict.get(pair, {})
+        if model is None and not previous.get("model_filename"):
+            return None
+        try:
+            cached = self.dd.meta_data_dictionary.get(pair)
+            if model is not None and cached is not None:
+                metadata = cached[METADATA]
+                feature_pipeline = cached[FEATURE_PIPELINE]
+                label_pipeline = cached[LABEL_PIPELINE]
+            else:
+                # dk points to the current training window, not the deployed model's files.
+                previous_dk = copy.copy(dk)
+                previous_dk.data_path = Path(previous["data_path"])
+                previous_dk.model_filename = previous["model_filename"]
+                model = self.dd.load_data(pair, previous_dk)
+                metadata = previous_dk.data
+                feature_pipeline = previous_dk.feature_pipeline
+                label_pipeline = previous_dk.label_pipeline
+            if (
+                metadata.get(self._DEPLOYMENT_COORDINATE_MARKER_KEY)
+                != self._DEPLOYMENT_COORDINATE_GENERATION
+            ):
+                raise ValueError(
+                    "persisted deployment coordinate generation is missing or incompatible"
+                )
+            if not isinstance(model, model_class):
+                raise ValueError("persisted regressor type differs from the configured regressor")
+            for name, expected, actual in (
+                ("features", dk.training_features_list, metadata["training_features_list"]),
+                ("labels", dk.label_list, metadata["label_list"]),
+                (
+                    "feature pipeline inputs",
+                    dk.training_features_list,
+                    feature_pipeline.features_in,
+                ),
+                ("label pipeline inputs", dk.label_list, label_pipeline.features_in),
+            ):
+                if list(expected) != list(actual):
+                    raise ValueError(f"persisted {name} differ in names or order")
+            state = model, copy.deepcopy(feature_pipeline), copy.deepcopy(label_pipeline)
+        except Exception as exc:
+            raise DependencyException(
+                f"[{pair}] Cannot continue training with matching persisted pipelines: {exc}. "
+                "Reset trained models or use a new freqai.identifier."
+            ) from exc
+        logger.info(
+            f"[{pair}] Continuing deployment in the persisted feature/label coordinate system; "
+            "reset trained models to change pipeline configuration"
+        )
+        return state
+
     def _train_common(
         self,
         unfiltered_df: pd.DataFrame,
@@ -2283,6 +2406,9 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
         split_fn: SplitFn,
         **kwargs,
     ) -> Any:
+        # Drawer metadata may alias this kitchen; do not invalidate the deployed artifact.
+        dk.data = dk.data.copy()
+        dk.data.pop(self._DEPLOYMENT_COORDINATE_MARKER_KEY, None)
         logger.info(f"-------------------- Starting training {pair} --------------------")
         start_time = time.time()
         features_filtered, labels_filtered = dk.filter_features(
@@ -2322,10 +2448,19 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
         )
         if not self.freqai_info.get("fit_live_predictions_candles", 0) or not self.live:
             dk.fit_labels()
-        dd = self._apply_pipelines(dd, train_weight_inputs, dk, pair)
+        deployment_state = self._resolve_deployment_state(dk, pair)
+        dd = self._apply_pipelines(
+            dd,
+            train_weight_inputs,
+            dk,
+            pair,
+            deployment_state=deployment_state if self._get_validation_size() == 0 else None,
+        )
         logger.info(f"Training model on {len(dd['train_features'].columns)} features")
         logger.info(f"Training model on {len(dd['train_features'])} data points")
-        model = self.fit(dd, dk, **kwargs)
+        model = self.fit(dd, dk, deployment_state=deployment_state, **kwargs)
+        if model is not None:
+            dk.data[self._DEPLOYMENT_COORDINATE_MARKER_KEY] = self._DEPLOYMENT_COORDINATE_GENERATION
         end_time = time.time()
         logger.info(
             f"-------------------- Done training {pair} "
@@ -2444,7 +2579,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                 data_dictionary["test_weights"] = data_dictionary["test_weights"][holdout_mask]
                 if data_dictionary["test_features"].empty:
                     logger.warning(
-                        f"[{pair}] causal purge emptied the holdout (label horizon "
+                        f"[{pair}] Causal purge emptied the holdout (label horizon "
                         f">= holdout span); skipping holdout evaluation "
                         f"(holdout_rmse=inf)"
                     )
@@ -2592,45 +2727,65 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
         dk: FreqaiDataKitchen,
         pair: str,
         context: str,
+        deployment_state: tuple[Any, Pipeline, Pipeline] | None = None,
     ) -> tuple[pd.DataFrame, pd.DataFrame, NDArray[np.floating]]:
-        """Fit FreqAI pipelines and enforce support on the surviving train rows."""
-        dk.feature_pipeline = self.define_data_pipeline(threads=dk.thread_count)
-        dk.label_pipeline = self.define_label_pipeline(threads=dk.thread_count)
+        """Prepare training rows without changing a reused booster's coordinates."""
+        if deployment_state is None:
+            dk.feature_pipeline = self.define_data_pipeline(threads=dk.thread_count)
+            dk.label_pipeline = self.define_label_pipeline(threads=dk.thread_count)
+        else:
+            _, dk.feature_pipeline, dk.label_pipeline = deployment_state
         pipeline_labels = labels
+        # Temporary label columns keep weights aligned through feature row filters;
+        # feature transforms must preserve label values. Object keys avoid collisions.
+        base_weight_column = object()
+        label_weight_column = object()
         if weight_inputs.label is not None:
-            # Smuggle base/label weights as extra label columns so datasieve
-            # row-filters them in lockstep with the features. Relies on datasieve
-            # not altering y VALUES (X-only transforms + row drops) and restoring
-            # them via ``label_list``. ``_sanitize_pipeline_weights`` guards
-            # row count, not a silent y-value transform: a future y-transforming
-            # step would corrupt these vectors undetected.
-            base_weight_column = object()
-            label_weight_column = object()
             pipeline_labels = labels.copy()
             pipeline_labels[base_weight_column] = weight_inputs.base
             pipeline_labels[label_weight_column] = weight_inputs.label
-        features, pipeline_labels, weights = dk.feature_pipeline.fit_transform(
-            features, pipeline_labels, weights
-        )
+        original_label_list = list(labels.columns)
+        try:
+            if deployment_state is None:
+                transformed_features, transformed_labels, transformed_weights = (
+                    dk.feature_pipeline.fit_transform(features, pipeline_labels, weights)
+                )
+                features = cast("pd.DataFrame", transformed_features)
+                pipeline_labels = cast("pd.DataFrame", transformed_labels)
+            else:
+                original_label_list = dk.feature_pipeline.label_list
+                dk.feature_pipeline.label_list = list(pipeline_labels.columns)
+                transformed_features, transformed_labels, transformed_weights = (
+                    dk.feature_pipeline.transform(features, pipeline_labels, weights)
+                )
+                # DataFrame inputs are restored as DataFrames by datasieve;
+                # its generic ArrayLike annotation does not express this.
+                features = cast("pd.DataFrame", transformed_features)
+                pipeline_labels = cast("pd.DataFrame", transformed_labels)
+                # Noise.transform is intentionally a no-op in datasieve. Only
+                # this final augmentation is fitted; coordinates remain frozen.
+                for name, transformer in dk.feature_pipeline.steps:
+                    if name == "noise":
+                        noisy, _, _, _ = transformer.fit_transform(features.to_numpy(copy=True))
+                        features = pd.DataFrame(
+                            noisy, columns=features.columns, index=features.index
+                        )
+        finally:
+            dk.feature_pipeline.label_list = original_label_list
         weights = QuickAdapterRegressorV3._sanitize_pipeline_weights(
             features,
-            weights,
+            transformed_weights,
             pair=pair,
             context=context,
         )
         # Label-only re-gate: base-only weights carry no pivot/fraction/ESS
         # support to recheck (settled pre-pipeline), so they skip this stage.
         if weight_inputs.label is not None:
-            post_pipeline_base_weights = pipeline_labels.pop(base_weight_column).to_numpy(
-                dtype=float
+            post_pipeline_base_weights = pipeline_labels[base_weight_column].to_numpy(dtype=float)
+            post_pipeline_label_weights = pipeline_labels[label_weight_column].to_numpy(dtype=float)
+            pipeline_labels = pipeline_labels.drop(
+                columns=[base_weight_column, label_weight_column]
             )
-            post_pipeline_label_weights = pipeline_labels.pop(label_weight_column).to_numpy(
-                dtype=float
-            )
-            # Load-bearing: ``fit_transform`` captured ``label_list`` WITH the smuggled
-            # columns; restore it to the real labels or the next validation/test
-            # transform rebuilds y with the wrong column count (``ValueError``).
-            dk.feature_pipeline.label_list = pipeline_labels.columns
             weights = QuickAdapterRegressorV3._enforce_train_weight_support(
                 post_pipeline_base_weights,
                 post_pipeline_label_weights,
@@ -2639,7 +2794,11 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                 context=f"[{pair}] post_feature_pipeline:{context}",
             )
         labels = pipeline_labels
-        labels, _, _ = dk.label_pipeline.fit_transform(labels)
+        if deployment_state is None:
+            transformed_labels, _, _ = dk.label_pipeline.fit_transform(labels)
+        else:
+            transformed_labels, _, _ = dk.label_pipeline.transform(labels)
+        labels = cast("pd.DataFrame", transformed_labels)
         return features, labels, weights
 
     def _apply_pipelines(
@@ -2648,6 +2807,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
         train_weight_inputs: SampleWeightInputs,
         dk: FreqaiDataKitchen,
         pair: str,
+        deployment_state: tuple[Any, Pipeline, Pipeline] | None = None,
     ) -> dict:
         """Apply feature and label pipelines; renormalize weights post-transform."""
         (dd["train_features"], dd["train_labels"], dd["train_weights"]) = (
@@ -2659,6 +2819,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                 dk,
                 pair,
                 "train",
+                deployment_state=deployment_state,
             )
         )
 
@@ -2938,7 +3099,8 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
         validation_size = self._get_validation_size()
 
         model_training_parameters = copy.deepcopy(self.model_training_parameters)
-        deployment_init_model = self.get_init_model(dk.pair)
+        deployment_state = kwargs.get("deployment_state")
+        deployment_init_model = None if deployment_state is None else deployment_state[0]
         selection_init_model = None if validation_size != 0 else deployment_init_model
 
         start_time = time.time()
@@ -3036,6 +3198,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                 dk,
                 dk.pair,
                 "refit",
+                deployment_state=deployment_state,
             )
             logger.info(
                 f"[{dk.pair}] Refitting final model on "
@@ -3108,23 +3271,31 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                 ),
             )
 
+        history = self.dd.historic_predictions[pair]
         if self.live:
-            if not hasattr(self, "exchange_candles"):
-                self.exchange_candles = len(self.dd.model_return_values[pair].index)
-            candles_diff = len(self.dd.historic_predictions[pair].index) - (
-                fit_live_predictions_candles + self.exchange_candles
-            )
-            if candles_diff < 0:
+            history = _dedupe_historic_predictions_on_date_pred(history)
+            if not hasattr(self, "_prediction_session_cutoffs"):
+                self._prediction_session_cutoffs: dict[str, pd.Timestamp] = {}
+            if pair not in self._prediction_session_cutoffs:
+                initial_dates = pd.to_datetime(
+                    self.dd.model_return_values[pair]["date_pred"],
+                    utc=True,
+                    errors="coerce",
+                    format="mixed",
+                )
+                self._prediction_session_cutoffs[pair] = initial_dates.max()
+            cutoff = self._prediction_session_cutoffs[pair]
+            eligible = (
+                _produced_prediction_mask(history) & history["date_pred"].gt(cutoff).to_numpy()
+            )
+            history = history.loc[eligible]
+            remaining = fit_live_predictions_candles - len(history)
+            warmed_up = remaining <= 0
+            if not warmed_up:
                 logger.warning(
-                    f"[{pair}] Fit live predictions not warmed up: {abs(candles_diff)} candles until warmup completion"
+                    f"[{pair}] Fit live predictions not warmed up: {remaining} produced observations until warmup completion"
                 )
-                warmed_up = False
-
-        pred_df = (
-            self.dd.historic_predictions[pair]
-            .iloc[-fit_live_predictions_candles:]
-            .reset_index(drop=True)
-        )
+        pred_df = history.tail(fit_live_predictions_candles).reset_index(drop=True)
 
         di_values = pred_df.get("DI_values")
         if di_values is not None:
@@ -3199,8 +3370,12 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
 
         dk.data["labels_mean"], dk.data["labels_std"] = {}, {}
         for label_col in dk.label_list + dk.unique_class_list:
-            pred_label = pred_df.get(label_col)
-            if pred_label is None or pred_label.dtype == object:
+            raw_label = pred_df.get(label_col)
+            if raw_label is None:
+                continue
+            # Downtime filling can leave numeric predictions in object-typed columns.
+            pred_label = pd.to_numeric(raw_label, errors="coerce")
+            if raw_label.dtype == object and pred_label.isna().all():
                 continue
             if not warmed_up:
                 f = [0.0, 0.0]
@@ -3252,13 +3427,16 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                 current_holdout_rmse = holdout_series.loc[current_dates.index[0]]
                 if pd.isna(current_holdout_rmse):
                     logger.warning(
-                        f"[{pair}] replayed holdout_rmse is NaN at "
+                        f"[{pair}] Replayed holdout_rmse is NaN at "
                         f"{current_dates.index[0]}; defaulting to inf"
                     )
         elif pair not in self._session_fitted_pairs:
             historic = self.dd.historic_predictions.get(pair)
             if historic is not None and "holdout_rmse" in historic:
-                holdout_values = pd.to_numeric(historic["holdout_rmse"], errors="coerce").dropna()
+                holdout_values = pd.to_numeric(
+                    historic.loc[_produced_prediction_mask(historic), "holdout_rmse"],
+                    errors="coerce",
+                ).dropna()
                 if not holdout_values.empty:
                     current_holdout_rmse = float(holdout_values.iloc[-1])
         holdout_rmse = QuickAdapterRegressorV3.optuna_validate_value(current_holdout_rmse)
@@ -3424,7 +3602,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
         )
 
         logger.debug(
-            f"Extrema filtering | rank_peaks: kept {n_kept_minima}/{minima_indices.size} minima, "
+            f"Extrema filtering | rank_peaks: Kept {n_kept_minima}/{minima_indices.size} minima, "
             f"{n_kept_maxima}/{maxima_indices.size} maxima with keep_fraction={keep_fraction}"
         )
         return pred_label_minima, pred_label_maxima
@@ -3447,7 +3625,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
         )
 
         logger.debug(
-            f"Extrema filtering | rank_extrema: kept {n_kept_minima}/{n_minima} minima, "
+            f"Extrema filtering | rank_extrema: Kept {n_kept_minima}/{n_minima} minima, "
             f"{n_kept_maxima}/{n_maxima} maxima with keep_fraction={keep_fraction}"
         )
         return pred_label_minima, pred_label_maxima
@@ -3649,11 +3827,16 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
         else:
             validated_p = QuickAdapterRegressorV3._validate_power_mean_p(p, ctx=p_ctx, mode=mode)
             power = 1.0 if validated_p is None else validated_p
-        if weights is None:
-            weights = np.ones(matrix.shape[1])
+        weights = QuickAdapterRegressorV3._validate_label_weights(
+            weights, matrix.shape[1], ctx="weights", mode=mode
+        )
+        positive_weight = weights > 0
+        weights = weights[positive_weight]
+        matrix = matrix[:, positive_weight]
+        reference_point = reference_point.reshape(-1)[positive_weight]
 
         return sp.stats.pmean(
-            reference_point.flatten() if reference_point.ndim > 1 else reference_point,
+            reference_point,
             p=power,
             weights=weights,
         ) - sp.stats.pmean(matrix, p=power, weights=weights, axis=1)
@@ -4241,7 +4424,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
         ]
         if not candidates:
             logger.warning(
-                "_select_best_trial_by_distance: all %d candidate distances "
+                "_select_best_trial_by_distance: All %d candidate distances "
                 "are non-finite; falling back to lowest trial number",
                 len(trials),
             )
@@ -4311,17 +4494,19 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                 if label_weights_array.size != original_n_objectives:
                     raise ValueError(
                         f"Invalid label_weights size {label_weights_array.size}: "
-                        f"must match original objective count "
-                        f"{original_n_objectives}"
+                        f"must match original objective count {original_n_objectives}"
                     )
+                # Validate the full vector so projection cannot hide invalid weights.
+                # Slice the original weights before normalizing the active objectives
+                # to avoid underflow from a huge weight on a dropped constant objective.
+                QuickAdapterRegressorV3._validate_label_weights(
+                    label_weights_array,
+                    original_n_objectives,
+                    ctx="label_weights",
+                    mode=_VALIDATION_MODES[1],
+                )
                 sliced_weights = label_weights_array[objective_indices]
                 if np.all(sliced_weights == 0.0):
-                    # All user-positive weights project onto dropped
-                    # (constant) objectives; uniform fallback keeps
-                    # selection deterministic and avoids
-                    # ``_validate_label_weights`` raising on sum-zero.
-                    # Negative or non-finite slices flow through to the
-                    # validator.
                     logger.warning(
                         "label_weights sliced to non-constant objectives "
                         "is all-zero (indices=%s, original=%s); "
@@ -4332,19 +4517,17 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                     label_weights = None
                 else:
                     label_weights = sliced_weights
-                    logger.debug(
-                        "label_weights sliced to non-constant objectives "
-                        "(indices=%s, original_size=%d, sliced_size=%d)",
-                        objective_indices.tolist(),
-                        label_weights_array.size,
-                        sliced_weights.size,
-                    )
         weights = QuickAdapterRegressorV3._validate_label_weights(
             label_weights,
             n_objectives,
             ctx="label_weights",
             mode=_VALIDATION_MODES[1],
         )
+        if category == QuickAdapterRegressorV3._CATEGORY_CLUSTER:
+            positive_weight = weights > 0.0
+            if not np.all(positive_weight):
+                normalized_matrix = normalized_matrix[:, positive_weight]
+                weights = weights[positive_weight]
 
         if n_samples == 1 and method in {
             QuickAdapterRegressorV3._SELECTION_MEDOID,
@@ -4887,7 +5070,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
                 reset_study = study_marker.reset_on_mismatch
                 logger.warning(
                     f"[{pair}] Optuna {namespace} study {study_name}: "
-                    f"stored {study_marker.user_attr_key} {existing_marker!r} "
+                    f"Stored {study_marker.user_attr_key} {existing_marker!r} "
                     f"incompatible with current; "
                     f"{'resetting' if reset_study else 'preserving'} study"
                 )
index 0bac06b01051553b26cdac2f0ff978f529f75e03..75ec461233aa02685fbdc6ea5ddf0e1268330e32 100644 (file)
@@ -386,7 +386,7 @@ class LabelTransformer(BaseTransform):
             )
             if clipped_count:
                 logger.warning(
-                    "sigmoid_inverse_normalize: clipped %d value(s) outside the open (-1, 1) domain",
+                    "sigmoid_inverse_normalize: Clipped %d value(s) outside the open (-1, 1) domain",
                     clipped_count,
                 )
             out[mask] = sp.special.logit((clipped + 1.0) / 2.0) / scale
@@ -525,7 +525,7 @@ class LabelTransformer(BaseTransform):
         finite_values = values[np.isfinite(values)]
         if finite_values.size == 0:
             logger.warning(
-                f"Column {column_name!r}: no finite values found, using fallback [0.0, 1.0]"
+                f"Column {column_name!r}: No finite values found, using fallback [0.0, 1.0]"
             )
             fit_values = np.array([0.0, 1.0])
         else:
index 1d398825274e2df494d72b92bf41ebf47bd8dd5b..cfc3dd00efb010a235a8aad7bf218e29d680f7ff 100644 (file)
@@ -73,9 +73,9 @@ from Utils import (
     get_label_horizon_candles,
     get_label_smoothing_config,
     get_label_weighting_config,
+    get_ma_fn,
     get_reversal_confirmation_config,
     get_smoothing_kernel_half_width,
-    get_zl_ma_fn,
     is_finite_number,
     label_known_at_lookahead_column_name,
     label_weight_column_name,
@@ -217,7 +217,7 @@ class QuickAdapterV3(IStrategy):
     _ANNOTATION_LINE_OFFSET_CANDLES: Final[int] = 10
 
     def version(self) -> str:
-        return "3.13.0-rc.9"
+        return "3.13.0-rc.10"
 
     timeframe = "5m"
     timeframe_minutes = timeframe_to_minutes(timeframe)
@@ -585,7 +585,7 @@ class QuickAdapterV3(IStrategy):
                 or (method == QuickAdapterV3._SMOOTHING_SAVGOL and col_smoothing["polyorder"] >= 2)
             ):
                 logger.warning(
-                    f"  Label [{label_col}]: smoothing method {method!r} can "
+                    f"  Label [{label_col}]: Smoothing method {method!r} can "
                     f"collapse sparse weight signals (smm zeroes them when "
                     f"fewer than half the window rows are nonzero; savgol "
                     f"with polyorder>=2 adds negative lobes that are clipped "
@@ -1276,10 +1276,10 @@ class QuickAdapterV3(IStrategy):
         if label_natr is None or label_natr.empty:
             return None
         if trade_duration_candles >= 2:
-            zl_kama = get_zl_ma_fn(MA_MODES[6])
+            kama = get_ma_fn(MA_MODES[6])
             try:
                 trade_kama_natr_values = np.asarray(
-                    zl_kama(label_natr, timeperiod=trade_duration_candles), dtype=float
+                    kama(label_natr, timeperiod=trade_duration_candles), dtype=float
                 )
                 trade_kama_natr_values = trade_kama_natr_values[np.isfinite(trade_kama_natr_values)]
                 if trade_kama_natr_values.size > 0:
@@ -1418,6 +1418,10 @@ class QuickAdapterV3(IStrategy):
         after_fill: bool,
         **kwargs,
     ) -> float | None:
+        # Post-fill updates can widen the stop; preserve the existing stop instead.
+        if after_fill:
+            return None
+
         df, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.config.get("timeframe"))
         if df.empty:
             return None
index 3542b3f35e35b7fc7e29d7f4b8c112afa867091b..4a309f94de8b0641357b01e6b9df99e375f69b20 100644 (file)
@@ -149,7 +149,7 @@ def safe_distribution_fit(
     if sample.finite_count < min_count:
         if logger is not None:
             logger.warning(
-                "%s: insufficient finite sample for distribution fit "
+                "%s: Insufficient finite sample for distribution fit "
                 "(usable=%d, total=%d, dropped=%d); using fallback %r",
                 context,
                 sample.finite_count,
@@ -163,7 +163,7 @@ def safe_distribution_fit(
     if require_variance and np.isclose(sample_range, 0.0):
         if logger is not None:
             logger.warning(
-                "%s: constant finite sample for distribution fit "
+                "%s: Constant finite sample for distribution fit "
                 "(usable=%d, dropped=%d); using fallback %r",
                 context,
                 sample.finite_count,
@@ -177,7 +177,7 @@ def safe_distribution_fit(
     except (RuntimeError, ValueError, FloatingPointError, np.linalg.LinAlgError) as exc:
         if logger is not None:
             logger.warning(
-                "%s: distribution fit failed (%s); using fallback %r",
+                "%s: Distribution fit failed (%s); using fallback %r",
                 context,
                 exc,
                 fallback_tuple,
@@ -187,7 +187,7 @@ def safe_distribution_fit(
     if len(params) != len(fallback_tuple) or not all(np.isfinite(params)):
         if logger is not None:
             logger.warning(
-                "%s: distribution fit returned invalid params %r; using fallback %r",
+                "%s: Distribution fit returned invalid params %r; using fallback %r",
                 context,
                 params,
                 fallback_tuple,
@@ -196,7 +196,7 @@ def safe_distribution_fit(
 
     if sample.dropped_count and logger is not None:
         logger.debug(
-            "%s: dropped %d/%d non-finite values before distribution fit",
+            "%s: Dropped %d/%d non-finite values before distribution fit",
             context,
             sample.dropped_count,
             sample.total_count,
@@ -266,7 +266,7 @@ def safe_divide(
     result = np.where(finite_mask, result, fallback)
     if invalid_count and logger is not None:
         logger.debug(
-            "%s: replaced %d invalid division result(s) with %r",
+            "%s: Replaced %d invalid division result(s) with %r",
             context,
             invalid_count,
             fallback,
@@ -312,7 +312,7 @@ def safe_log_ratio(
     result = np.where(finite_mask, result, fallback)
     if invalid_count and logger is not None:
         logger.debug(
-            "%s: replaced %d invalid log-ratio result(s) with %r",
+            "%s: Replaced %d invalid log-ratio result(s) with %r",
             context,
             invalid_count,
             fallback,
@@ -1716,14 +1716,14 @@ def sanitize_and_renormalize(
     if logger is not None:
         if rescale_overflow:
             logger.warning(
-                "%s: rescale factor non-finite (n=%d, total=%r); falling back to uniform weights",
+                "%s: Rescale factor non-finite (n=%d, total=%r); falling back to uniform weights",
                 context,
                 n,
                 total,
             )
         else:
             logger.warning(
-                "%s: weights collapsed (total=%r, n=%d); falling back to uniform weights",
+                "%s: Weights collapsed (total=%r, n=%d); falling back to uniform weights",
                 context,
                 total,
                 n,
@@ -1886,7 +1886,7 @@ def compose_sample_weights(
     nonzero = _pivot_equivalent_count(arr, drop_mask)
     if nonzero / n < SPARSE_TRAINING_MASS_THRESHOLD:
         logger.warning(
-            "%s: sparse weighting mass "
+            "%s: Sparse weighting mass "
             "(%d/%d rows above %.0f%% of surviving max = %.2f%%, "
             "threshold=%.2f%%)",
             context,
@@ -1914,7 +1914,7 @@ def compose_sample_weights(
             )
         case "fallback":
             logger.warning(
-                "%s: composed weights collapsed on surviving rows "
+                "%s: Composed weights collapsed on surviving rows "
                 "(survivor_total=%.6g); falling back to base weights",
                 context,
                 survivor_total,
@@ -1971,7 +1971,7 @@ def nan_average(
     if not np.isfinite(weight_sum) or np.isclose(weight_sum, 0.0):
         if logger is not None:
             logger.warning(
-                "nan_average: finite weights sum to %g; using fallback NaN",
+                "nan_average: Finite weights sum to %g; using fallback NaN",
                 weight_sum,
             )
         return np.nan
@@ -2344,7 +2344,7 @@ def _gaussian_fill_weights(
     M = pivot_indices_array.size
     if logger is not None and n_values > 0 and M / n_values > _GAUSSIAN_FILL_DENSITY_WARN:
         logger.warning(
-            "gaussian_fill: pivot density M/N=%.3f > %.2f (M=%d, N=%d); "
+            "gaussian_fill: Pivot density M/N=%.3f > %.2f (M=%d, N=%d); "
             "consider tightening zigzag detection",
             M / n_values,
             _GAUSSIAN_FILL_DENSITY_WARN,
@@ -3254,11 +3254,11 @@ def compute_label_weight_known_at_lookahead(
     ``i_{k+1} == known_at_positions[indices[k+1]]``; the terminal pivot has no
     closing swing (weight 0 via ``_impute_weights``) and never resolves in-frame
     -> ``n``. A uniform pivot instead has a unit weight at its own label
-    availability. Off-pivot rows keep their label availability, except that a
-    Gaussian fill spreads each pivot's weight over a LOCAL band
-    ``[idx-fill_radius, idx+fill_radius]`` (0 disables) -- never a global max,
-    which would force ``n`` on all rows (total train purge). Folded via
-    ``max(label, weight)`` by the causal purge.
+    availability. With Gaussian fill, rows wait for label availability throughout
+    ``[row-fill_radius, row+fill_radius]`` because unconfirmed pivots can change
+    their weights. They also wait for contributing pivots' metric weights;
+    zero terminal-pivot weights add no dependency. The causal purge uses
+    ``max(label, weight)`` availability.
 
     For adaptive k-NN bandwidths a pivot's band additionally waits until every
     confirmable finite suffix of the frame yields the same clipped sigma --
@@ -3314,6 +3314,13 @@ def compute_label_weight_known_at_lookahead(
     dependency_mask = raw_dependency_mask[valid_mask][order]
     leading_stable_mask = raw_leading_stable_mask[valid_mask][order]
     base = known_at_positions.copy()
+    if idx.size and fill_radius > 0:
+        base = (
+            pd.Series(known_at_positions)
+            .rolling(window=2 * min(fill_radius, n - 1) + 1, center=True, min_periods=1)
+            .max()
+            .to_numpy(dtype=np.int64)
+        )
     if idx.size:
         weight_availability = np.empty(idx.size, dtype=np.int64)
         weight_availability[:-1] = known_at_positions[idx[1:]]
@@ -3627,10 +3634,10 @@ def top_log_return(
     *,
     logger: Logger | None = None,
 ) -> pd.Series:
-    """Logarithmic return from rolling maximum: ``log(close / rolling_max)``.
+    """Log return relative to the maximum close over the previous ``period`` bars.
 
-    Measures distance below the highest close in previous ``period`` bars.
-    Returns <= 0 (e.g. -0.10 ~ -9.5% below peak), zero when at peak.
+    Excludes the current bar: ``log(close / previous_rolling_max)``. Negative
+    below that reference, zero at it, and positive on an upside breakout.
     """
     if period < 1:
         raise ValueError(f"Invalid period value {period!r}: must be >= 1")
@@ -3651,10 +3658,10 @@ def bottom_log_return(
     *,
     logger: Logger | None = None,
 ) -> pd.Series:
-    """Logarithmic return from rolling minimum: ``log(close / rolling_min)``.
+    """Log return relative to the minimum close over the previous ``period`` bars.
 
-    Measures distance above the lowest close in previous ``period`` bars.
-    Returns >= 0 (e.g. +0.10 ~ +10.5% above bottom), zero when at bottom.
+    Excludes the current bar: ``log(close / previous_rolling_min)``. Positive
+    above that reference, zero at it, and negative on a downside breakout.
     """
     if period < 1:
         raise ValueError(f"Invalid period value {period!r}: must be >= 1")
@@ -4982,6 +4989,11 @@ def fit_regressor(
             val_sample_weight=val_sample_weight,
             early_stopping_rounds=early_stopping_rounds,
         )
+        if early_stopping_rounds is not None and model.best_val_loss_itr is not None:
+            selected_count = model.best_val_loss_itr + 1
+            del model.base_models[selected_count:]
+            del model.scalings[selected_count:]
+            del model.col_idxs[selected_count:]
     elif regressor == _REGRESSOR_SPECS.catboost.name:
         from catboost import CatBoostRegressor, Pool
 
@@ -5154,7 +5166,7 @@ Incremented on every on-disk JSON shape change (top-level keys, params layout).
 _OPTUNA_LABEL_SELECTION_SCHEMA_VERSION: Final[int] = 3
 """Version of the label-namespace Optuna best-trial selection algorithm.
 
-Incremented on any change to tie-break, normalization, distance-metric
+Incremented for released changes to tie-break, normalization, distance-metric
 whitelist, or selection metadata. Independent of
 ``_OPTUNA_LABEL_BEST_PARAMS_SCHEMA_VERSION`` (on-disk JSON layout vs
 selection-algorithm semantics are versioned separately).