From: Jérôme Benoit Date: Wed, 5 Nov 2025 15:28:23 +0000 (+0100) Subject: feat: add tunable for leverage X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=70361e5898f26bd5eb9a9b266547a99529837940;p=freqai-strategies.git feat: add tunable for leverage Signed-off-by: Jérôme Benoit --- diff --git a/README.md b/README.md index be9a4de..04ee891 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,8 @@ docker compose up -d --build |------|------------------|-------------|---------------------------------------------------------------------------------| | _Protections_ | | | | | estimated_trade_duration_candles | 48 | int >= 1 | Heuristic for StoplossGuard tuning. | +| _Leverage_ | | | | | +| leverage | proposed_leverage | float [1.0, max_leverage] | Leverage. Fallback to proposed_leverage for the pair. | | _Exit pricing_ | | | | | exit_pricing.trade_price_target | `moving_average` | enum {`moving_average`,`interpolation`,`weighted_interpolation`} | Trade NATR computation method. | | exit_pricing.thresholds_calibration.decline_quantile | 0.90 | float (0,1) | PNL decline quantile threshold. | @@ -62,7 +64,7 @@ docker compose up -d --build | freqai.feature_parameters.max_label_natr_ratio | 12.0 | float > 0 | Maximum labeling NATR ratio used for reversals labeling HPO. | | freqai.feature_parameters.label_frequency_candles | `auto` | int >= 2 \| `auto` | Reversals labeling frequency. `auto` = max(2, 2 * number of whitelisted pairs). | | freqai.feature_parameters.label_metric | `euclidean` | string (supported: `euclidean`,`minkowski`,`cityblock`,`chebyshev`,`mahalanobis`,`seuclidean`,`jensenshannon`,`sqeuclidean`,...) | Metric used in distance calculations to ideal point. | -| freqai.feature_parameters.label_weights | [0.5,0.5] | list[float] | Per-objective weights used in distance calculations to ideal point. | +| freqai.feature_parameters.label_weights | [0.5,0.5] | list[float] | Per-objective weights used in distance calculations to ideal point. First objective is the median threshold of Zigzag reversals (reversals quality). Second objective is the number of detected reversals. | | freqai.feature_parameters.label_p_order | `None` | float | p-order used by Minkowski / power-mean calculations (optional). | | freqai.feature_parameters.label_medoid_metric | `euclidean` | string | Metric used with `medoid`. | | freqai.feature_parameters.label_kmeans_metric | `euclidean` | string | Metric used for k-means clustering. | diff --git a/ReforceXY/user_data/config-template.json b/ReforceXY/user_data/config-template.json index 9faedfc..0a58257 100644 --- a/ReforceXY/user_data/config-template.json +++ b/ReforceXY/user_data/config-template.json @@ -14,6 +14,7 @@ "cancel_open_orders_on_exit": false, // "trading_mode": "futures", // "margin_mode": "isolated", + // "leverage": 2.0, "trading_mode": "spot", "stoploss": -0.99, "unfilledtimeout": { diff --git a/ReforceXY/user_data/strategies/RLAgentStrategy.py b/ReforceXY/user_data/strategies/RLAgentStrategy.py index 4d8849b..af9251e 100644 --- a/ReforceXY/user_data/strategies/RLAgentStrategy.py +++ b/ReforceXY/user_data/strategies/RLAgentStrategy.py @@ -1,6 +1,7 @@ +import datetime import logging from functools import cached_property, reduce -from typing import Any +from typing import Any, Optional # import talib.abstract as ta from freqtrade.persistence import Trade @@ -118,6 +119,33 @@ class RLAgentStrategy(IStrategy): return dataframe + def leverage( + self, + pair: str, + current_time: datetime.datetime, + current_rate: float, + proposed_leverage: float, + max_leverage: float, + entry_tag: Optional[str], + side: str, + **kwargs: Any, + ) -> float: + """ + Customize leverage for each new trade. This method is only called in trading modes + which allow leverage (margin / futures). The strategy is expected to return a + leverage value between 1.0 and max_leverage. + + :param pair: Pair that's currently analyzed + :param current_time: datetime object, containing the current datetime + :param current_rate: Rate, calculated based on pricing settings in exit_pricing. + :param proposed_leverage: A leverage proposed by the bot. + :param max_leverage: Max leverage allowed on this pair + :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. + :param side: 'long' or 'short' - indicating the direction of the proposed trade + :return: A leverage amount, which will be between 1.0 and max_leverage. + """ + return min(self.config.get("leverage", proposed_leverage), max_leverage) + def is_short_allowed(self) -> bool: trading_mode = self.config.get("trading_mode") if trading_mode in {"margin", "futures"}: diff --git a/quickadapter/user_data/config-template.json b/quickadapter/user_data/config-template.json index f9cf594..e100933 100644 --- a/quickadapter/user_data/config-template.json +++ b/quickadapter/user_data/config-template.json @@ -14,6 +14,7 @@ "cancel_open_orders_on_exit": false, // "trading_mode": "futures", // "margin_mode": "isolated", + // "leverage": 2.0, "trading_mode": "spot", "unfilledtimeout": { "entry": 10, diff --git a/quickadapter/user_data/strategies/QuickAdapterV3.py b/quickadapter/user_data/strategies/QuickAdapterV3.py index 8f89481..f61bad5 100644 --- a/quickadapter/user_data/strategies/QuickAdapterV3.py +++ b/quickadapter/user_data/strategies/QuickAdapterV3.py @@ -1780,6 +1780,33 @@ class QuickAdapterV3(IStrategy): else: raise ValueError(f"Invalid trading_mode: {trading_mode}") + def leverage( + self, + pair: str, + current_time: datetime.datetime, + current_rate: float, + proposed_leverage: float, + max_leverage: float, + entry_tag: Optional[str], + side: str, + **kwargs: Any, + ) -> float: + """ + Customize leverage for each new trade. This method is only called in trading modes + which allow leverage (margin / futures). The strategy is expected to return a + leverage value between 1.0 and max_leverage. + + :param pair: Pair that's currently analyzed + :param current_time: datetime object, containing the current datetime + :param current_rate: Rate, calculated based on pricing settings in exit_pricing. + :param proposed_leverage: A leverage proposed by the bot. + :param max_leverage: Max leverage allowed on this pair + :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. + :param side: 'long' or 'short' - indicating the direction of the proposed trade + :return: A leverage amount, which will be between 1.0 and max_leverage. + """ + return min(self.config.get("leverage", proposed_leverage), max_leverage) + def optuna_load_best_params( self, pair: str, namespace: str ) -> Optional[dict[str, Any]]: