### Quick start
-Change the timezone according to your location in [`docker-compose.yml`](./quickadapter/docker-compose.yml).
+Change the timezone according to your location in
+[`docker-compose.yml`](./quickadapter/docker-compose.yml).
From the repository root, configure, build and start the QuickAdapter container:
cp user_data/config-template.json user_data/config.json
```
-Adapt the configuration to your needs: edit `user_data/config.json` to set your exchange API keys and tune the `freqai` section.
+Adapt the configuration to your needs: edit `user_data/config.json` to set your
+exchange API keys and tune the `freqai` section.
Then build and start the container:
| freqai.extrema_smoothing.beta | 8.0 | float > 0 | Shape parameter for `kaiser` kernel. |
| freqai.extrema_smoothing.polyorder | 3 | int >= 1 | Polynomial order for `savgol` smoothing. |
| freqai.extrema_smoothing.mode | `mirror` | enum {`mirror`,`constant`,`nearest`,`wrap`,`interp`} | Boundary mode for `savgol` and `nadaraya_watson`. |
-| freqai.extrema_smoothing.bandwidth | 1.0 | float > 0 | Gaussian bandwidth for `nadaraya_watson`. |
+| freqai.extrema_smoothing.bandwidth | 1.0 | float > 0 | Gaussian bandwidth for `nadaraya_watson` smoothing. |
| _Extrema weighting_ | | | |
-| freqai.extrema_weighting.strategy | `none` | enum {`none`,`amplitude`,`amplitude_threshold_ratio`,`volume`,`speed`,`efficiency_ratio`,`hybrid`} | Extrema weighting source: unweighted (`none`), single-source (`amplitude`,`amplitude_threshold_ratio`,`volume`,`speed`,`efficiency_ratio`), or `hybrid` (combine multiple sources via `freqai.extrema_weighting.source_weights`). |
-| freqai.extrema_weighting.source_weights | all sources = 1.0 | object with keys in {`amplitude`,`amplitude_threshold_ratio`,`volume`,`speed`,`efficiency_ratio`} and float >= 0 | Hybrid-only: per-source coefficients. If not set (or invalid/empty), defaults to equal weights. Coefficients are L1-normalized (sum to 1.0) before aggregation; zero/NaN/Inf entries are ignored. |
-| freqai.extrema_weighting.aggregation | `weighted_sum` | enum {`weighted_sum`,`geometric_mean`} | Hybrid-only: how normalized per-source weights are combined into a single per-extremum weight. `geometric_mean` uses abs(values) for numerical stability. |
-| freqai.extrema_weighting.aggregation_normalization | `none` | enum {`minmax`,`sigmoid`,`softmax`,`l1`,`l2`,`rank`,`none`} | Hybrid-only: optional post-aggregation normalization. Applies after aggregation without re-standardization and without a second gamma correction. |
+| freqai.extrema_weighting.strategy | `none` | enum {`none`,`amplitude`,`amplitude_threshold_ratio`,`volume`,`speed`,`efficiency_ratio`,`hybrid`} | Extrema weighting source: unweighted (`none`), swing amplitude (`amplitude`), swing amplitude / median volatility-threshold ratio (`amplitude_threshold_ratio`), swing volume (`volume`), swing speed (`speed`), swing efficiency ratio (`efficiency_ratio`), or `hybrid`. |
+| freqai.extrema_weighting.source_weights | `{}` | dict[str, float] | Weights on extrema extrema weighting sources for `hybrid`. |
+| freqai.extrema_weighting.aggregation | `weighted_sum` | enum {`weighted_sum`,`geometric_mean`} | Aggregation method applied to weighted extrema weighting sources for `hybrid`. |
+| freqai.extrema_weighting.aggregation_normalization | `none` | enum {`minmax`,`sigmoid`,`softmax`,`l1`,`l2`,`rank`,`none`} | Normalization method applied to the aggregated extrema weighting source for `hybrid`. |
| freqai.extrema_weighting.standardization | `none` | enum {`none`,`zscore`,`robust`,`mmad`} | Standardization method applied before normalization. `none`=no standardization, `zscore`=(w-μ)/σ, `robust`=(w-median)/IQR, `mmad`=(w-median)/MAD. |
| freqai.extrema_weighting.robust_quantiles | [0.25, 0.75] | list[float] where 0 <= Q1 < Q3 <= 1 | Quantile range for robust standardization, Q1 and Q3. |
| freqai.extrema_weighting.mmad_scaling_factor | 1.4826 | float > 0 | Scaling factor for MMAD standardization. |
| _Predictions extrema_ | | | |
| freqai.predictions_extrema.selection_method | `rank` | enum {`rank`,`values`,`partition`} | Extrema selection method. `rank` uses ranked extrema values, `values` uses reversal values, `partition` uses sign-based partitioning. |
| freqai.predictions_extrema.thresholds_smoothing | `mean` | enum {`mean`,`isodata`,`li`,`minimum`,`otsu`,`triangle`,`yen`,`median`,`soft_extremum`} | Thresholding method for prediction thresholds smoothing. |
-| freqai.predictions_extrema.thresholds_alpha | 12.0 | float > 0 | Alpha for `soft_extremum`. |
+| freqai.predictions_extrema.thresholds_alpha | 12.0 | float > 0 | Alpha for `soft_extremum` for thesholds smoothing. |
| freqai.predictions_extrema.threshold_outlier | 0.999 | float (0,1) | Quantile threshold for predictions outlier filtering. |
| freqai.predictions_extrema.extrema_fraction | 1.0 | float (0,1] | Fraction of extrema used for thresholds. `1.0` uses all, lower values keep only most significant. Applies to `rank` and `values`; ignored for `partition`. |
| _Optuna / HPO_ | | | |
### Quick start
-Change the timezone according to your location in [`docker-compose.yml`](./ReforceXY/docker-compose.yml).
+Change the timezone according to your location in
+[`docker-compose.yml`](./ReforceXY/docker-compose.yml).
From the repository root, configure, build and start the ReforceXY container:
cp user_data/config-template.json user_data/config.json
```
-Adapt the configuration to your needs: edit `user_data/config.json` to set your exchange API keys and tune the `freqai` section.
+Adapt the configuration to your needs: edit `user_data/config.json` to set your
+exchange API keys and tune the `freqai` section.
Then build and start the container:
### Configuration tunables
-The documented list of model tunables is at the top of the [ReforceXY.py](./ReforceXY/user_data/freqaimodels/ReforceXY.py) file.
+The documented list of model tunables is at the top of the
+[ReforceXY.py](./ReforceXY/user_data/freqaimodels/ReforceXY.py) file.
-The rewarding logic and tunables are documented in the [reward space analysis](./ReforceXY/reward_space_analysis/README.md).
+The rewarding logic and tunables are documented in the
+[reward space analysis](./ReforceXY/reward_space_analysis/README.md).
## Common workflows
./docker-upgrade.sh
```
-The script checks for new Freqtrade image versions on Docker Hub, rebuilds and restarts containers if updates are found, sends Telegram notifications (if configured), and cleans up unused images.
+The script checks for new Freqtrade image versions on Docker Hub, rebuilds and
+restarts containers if updates are found, sends Telegram notifications (if
+configured), and cleans up unused images.
_Configuration and environment variables:_
## Note
-> Do not expect any support of any kind on the Internet. Nevertheless, PRs implementing documentation, bug fixes, cleanups or sensible features will be discussed and might get merged.
+> Do not expect any support of any kind on the Internet. Nevertheless, PRs
+> implementing documentation, bug fixes, cleanups or sensible features will be
+> discussed and might get merged.
def calculate_hybrid_extrema_weights(
- series: pd.Series,
+ extrema: pd.Series,
indices: list[int],
amplitudes: list[float],
amplitude_threshold_ratios: list[float],
) -> pd.Series:
n = len(indices)
if n == 0:
- return pd.Series(DEFAULT_EXTREMA_WEIGHT, index=series.index)
+ return pd.Series(DEFAULT_EXTREMA_WEIGHT, index=extrema.index)
if not isinstance(source_weights, dict):
source_weights = {}
)
source_weights_sum = np.nansum(np.abs(np_source_weights))
if not np.isfinite(source_weights_sum) or source_weights_sum <= 0:
- return pd.Series(DEFAULT_EXTREMA_WEIGHT, index=series.index)
+ return pd.Series(DEFAULT_EXTREMA_WEIGHT, index=extrema.index)
np_source_weights = np_source_weights / source_weights_sum
normalized_source_weights: list[NDArray[np.floating]] = []
combined_source_weights.size == 0
or not np.isfinite(combined_source_weights).all()
):
- return pd.Series(DEFAULT_EXTREMA_WEIGHT, index=series.index)
+ return pd.Series(DEFAULT_EXTREMA_WEIGHT, index=extrema.index)
return _weights_array_to_series(
- index=series.index,
+ index=extrema.index,
indices=indices,
weights=combined_source_weights,
default_weight=np.nanmedian(combined_source_weights),
def compute_extrema_weights(
- series: pd.Series,
+ extrema: pd.Series,
indices: list[int],
amplitudes: list[float],
amplitude_threshold_ratios: list[float],
gamma: float = DEFAULTS_EXTREMA_WEIGHTING["gamma"],
) -> pd.Series:
if len(indices) == 0 or strategy == WEIGHT_STRATEGIES[0]: # "none"
- return pd.Series(DEFAULT_EXTREMA_WEIGHT, index=series.index)
+ return pd.Series(DEFAULT_EXTREMA_WEIGHT, index=extrema.index)
if strategy in {
WEIGHT_STRATEGIES[1],
weights = np.asarray([], dtype=float)
if weights.size == 0:
- return pd.Series(DEFAULT_EXTREMA_WEIGHT, index=series.index)
+ return pd.Series(DEFAULT_EXTREMA_WEIGHT, index=extrema.index)
return calculate_extrema_weights(
- series=series,
+ series=extrema,
indices=indices,
weights=weights,
standardization=standardization,
if strategy == WEIGHT_STRATEGIES[6]: # "hybrid"
return calculate_hybrid_extrema_weights(
- series=series,
+ extrema=extrema,
indices=indices,
amplitudes=amplitudes,
amplitude_threshold_ratios=amplitude_threshold_ratios,
raise ValueError(f"Unknown extrema weighting strategy: {strategy}")
-def apply_weights(series: pd.Series, weights: pd.Series) -> pd.Series:
+def _apply_weights(extrema: pd.Series, weights: pd.Series) -> pd.Series:
if weights.empty:
- return series
+ return extrema
if np.allclose(weights.to_numpy(dtype=float), DEFAULT_EXTREMA_WEIGHT):
- return series
- return series * weights
+ return extrema
+ return extrema * weights
def get_weighted_extrema(
- series: pd.Series,
+ extrema: pd.Series,
indices: list[int],
amplitudes: list[float],
amplitude_threshold_ratios: list[float],
# Phase 3: Post-processing
gamma: float = DEFAULTS_EXTREMA_WEIGHTING["gamma"],
) -> tuple[pd.Series, pd.Series]:
- """Apply extrema weighting and return (weighted_extrema, extrema_weights)."""
-
weights = compute_extrema_weights(
- series=series,
+ extrema=extrema,
indices=indices,
amplitudes=amplitudes,
amplitude_threshold_ratios=amplitude_threshold_ratios,
gamma=gamma,
)
- weighted_extrema = apply_weights(series, weights)
+ weighted_extrema = _apply_weights(extrema, weights)
return weighted_extrema, weights