From f4be281c1ed9e6e125446e8fc19ac7d95aed1b99 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Mon, 11 Aug 2025 13:53:32 +0200 Subject: [PATCH] fix(qav3): do not tighten stoploss prematurely MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- ReforceXY/user_data/freqaimodels/ReforceXY.py | 4 +-- .../freqaimodels/QuickAdapterRegressorV3.py | 2 +- .../user_data/strategies/QuickAdapterV3.py | 7 ++-- quickadapter/user_data/strategies/Utils.py | 34 +++++++++++++++++-- 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/ReforceXY/user_data/freqaimodels/ReforceXY.py b/ReforceXY/user_data/freqaimodels/ReforceXY.py index 5ca5093..54bb405 100644 --- a/ReforceXY/user_data/freqaimodels/ReforceXY.py +++ b/ReforceXY/user_data/freqaimodels/ReforceXY.py @@ -4,7 +4,7 @@ import json import logging import time import warnings -from enum import Enum +from enum import IntEnum from functools import lru_cache from pathlib import Path from typing import Any, Callable, Dict, Optional, Tuple, Type @@ -51,7 +51,7 @@ warnings.filterwarnings("ignore", category=ExperimentalWarning) logger = logging.getLogger(__name__) -class ForceActions(Enum): +class ForceActions(IntEnum): Take_profit = 1 Stop_loss = 2 Timeout = 3 diff --git a/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py b/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py index dca9aef..4d4e455 100644 --- a/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py +++ b/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py @@ -1341,7 +1341,7 @@ def label_objective( candles_step: int, ) -> tuple[float, int]: min_label_period_candles, max_label_period_candles, candles_step = ( - get_min_max_label_period_candles(candles_step) + get_min_max_label_period_candles(fit_live_predictions_candles, candles_step) ) label_period_candles = trial.suggest_int( diff --git a/quickadapter/user_data/strategies/QuickAdapterV3.py b/quickadapter/user_data/strategies/QuickAdapterV3.py index b06da77..01ec994 100644 --- a/quickadapter/user_data/strategies/QuickAdapterV3.py +++ b/quickadapter/user_data/strategies/QuickAdapterV3.py @@ -765,8 +765,7 @@ class QuickAdapterV3(IStrategy): * (trade_natr / 100.0) * self.get_label_natr_ratio_percent(trade.pair, natr_ratio_percent) * QuickAdapterV3.get_stoploss_log_factor( - trade_duration_candles - + int(round(QuickAdapterV3.get_trade_exit_stage(trade) ** (1.5))) + trade_duration_candles + int(round(trade.nr_of_successful_exits**1.5)) ) ) @@ -1030,8 +1029,8 @@ class QuickAdapterV3(IStrategy): current_deviation = self._calculate_current_deviation( df, pair, - min_natr_ratio_percent=0.00985, - max_natr_ratio_percent=0.0995, + min_natr_ratio_percent=0.00995, + max_natr_ratio_percent=0.0999, interpolation_direction="direct", ) if isna(current_deviation): diff --git a/quickadapter/user_data/strategies/Utils.py b/quickadapter/user_data/strategies/Utils.py index d7b6628..e3ded5f 100644 --- a/quickadapter/user_data/strategies/Utils.py +++ b/quickadapter/user_data/strategies/Utils.py @@ -946,14 +946,42 @@ def soft_extremum(series: pd.Series, alpha: float) -> float: @lru_cache(maxsize=8) def get_min_max_label_period_candles( + fit_live_predictions_candles: int, candles_step: int, min_label_period_candles: int = 8, max_label_period_candles: int = 48, + max_time_candles: int = 48, + max_horizon_fraction: float = 1.0 / 3.0, + min_label_period_candles_fallback: int = 8, + max_label_period_candles_fallback: int = 28, ) -> tuple[int, int, int]: if min_label_period_candles > max_label_period_candles: - min_label_period_candles, max_label_period_candles = ( - max_label_period_candles, - min_label_period_candles, + raise ValueError( + "min_label_period_candles must be less than or equal to max_label_period_candles" + ) + + capped_time_candles = max(1, floor_to_step(max_time_candles, candles_step)) + capped_horizon_candles = max( + 1, + floor_to_step( + max(1, int(fit_live_predictions_candles * max_horizon_fraction)), + candles_step, + ), + ) + max_label_period_candles = min( + max_label_period_candles, capped_time_candles, capped_horizon_candles + ) + + if min_label_period_candles > max_label_period_candles: + fallback_high = min( + max_label_period_candles_fallback, + capped_time_candles, + capped_horizon_candles, + ) + return ( + min(min_label_period_candles_fallback, fallback_high), + fallback_high, + 1, ) if candles_step <= (max_label_period_candles - min_label_period_candles): -- 2.43.0