From da82a54d8292faed29e31089c67f740bb2bb644b Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Mon, 19 May 2025 14:38:08 +0200 Subject: [PATCH] fix(qav3): improve numerical stability at TP computation MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- .../freqaimodels/QuickAdapterRegressorV3.py | 7 ++- .../user_data/strategies/QuickAdapterV3.py | 51 ++++++++++--------- quickadapter/user_data/strategies/Utils.py | 7 ++- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py b/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py index 100f164..eb3135e 100644 --- a/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py +++ b/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py @@ -915,8 +915,8 @@ def zigzag( def calculate_depth( pos: int, - min_depth: int = 5, - max_depth: int = 30, + min_depth: int = 6, + max_depth: int = 36, ) -> int: if len(pivots_indices) < 2: return depth @@ -974,6 +974,7 @@ def zigzag( pivots_directions.append(direction) last_pivot_pos = pos depth = calculate_depth(pos) + reset_candidate_pivot() def is_reversal_confirmed( candidate_pivot_pos: int, @@ -1128,7 +1129,6 @@ def zigzag( and is_reversal_confirmed(candidate_pivot_pos, i, TrendDirection.DOWN) ): add_pivot(candidate_pivot_pos, candidate_pivot_value, TrendDirection.UP) - reset_candidate_pivot() state = TrendDirection.DOWN elif state == TrendDirection.DOWN: if np.isnan(candidate_pivot_value) or current_low < candidate_pivot_value: @@ -1142,7 +1142,6 @@ def zigzag( add_pivot( candidate_pivot_pos, candidate_pivot_value, TrendDirection.DOWN ) - reset_candidate_pivot() state = TrendDirection.UP return pivots_indices, pivots_values, pivots_directions diff --git a/quickadapter/user_data/strategies/QuickAdapterV3.py b/quickadapter/user_data/strategies/QuickAdapterV3.py index 597eef5..e7bfda6 100644 --- a/quickadapter/user_data/strategies/QuickAdapterV3.py +++ b/quickadapter/user_data/strategies/QuickAdapterV3.py @@ -58,7 +58,7 @@ class QuickAdapterV3(IStrategy): INTERFACE_VERSION = 3 def version(self) -> str: - return "3.3.41" + return "3.3.42" timeframe = "5m" @@ -487,7 +487,7 @@ class QuickAdapterV3(IStrategy): self, df: DataFrame, trade: Trade, current_rate: float ) -> Optional[float]: trade_duration_candles = self.get_trade_duration_candles(df, trade) - if QuickAdapterV3.is_trade_duration_valid(trade_duration_candles) is False: + if not QuickAdapterV3.is_trade_duration_valid(trade_duration_candles): return None current_natr = df["natr_label_period_candles"].iloc[-1] if isna(current_natr) or current_natr < 0: @@ -501,7 +501,7 @@ class QuickAdapterV3(IStrategy): def get_take_profit_distance(self, df: DataFrame, trade: Trade) -> Optional[float]: trade_duration_candles = self.get_trade_duration_candles(df, trade) - if QuickAdapterV3.is_trade_duration_valid(trade_duration_candles) is False: + if not QuickAdapterV3.is_trade_duration_valid(trade_duration_candles): return None entry_natr = self.get_trade_entry_natr(df, trade) if isna(entry_natr) or entry_natr < 0: @@ -511,28 +511,29 @@ class QuickAdapterV3(IStrategy): return None entry_natr_weight = 0.5 current_natr_weight = 0.5 - natr_pct_change = abs(current_natr - entry_natr) / entry_natr - natr_pct_change_thresholds = [ - (1.0, 0.5), # (threshold, adjustment) - (0.8, 0.4), - (0.6, 0.3), - (0.4, 0.2), - (0.2, 0.1), - ] - weight_adjustment = 0.0 - for threshold, adjustment in natr_pct_change_thresholds: - if natr_pct_change > threshold: - weight_adjustment = adjustment - break - if weight_adjustment > 0: - if current_natr > entry_natr: - entry_natr_weight -= weight_adjustment - current_natr_weight += weight_adjustment - else: - entry_natr_weight += weight_adjustment - current_natr_weight -= weight_adjustment - entry_natr_weight = np.clip(entry_natr_weight, 0.0, 1.0) - current_natr_weight = np.clip(current_natr_weight, 0.0, 1.0) + if not np.isclose(entry_natr, 0): + natr_pct_change = abs(current_natr - entry_natr) / entry_natr + natr_pct_change_thresholds = [ + (1.0, 0.5), # (threshold, adjustment) + (0.8, 0.4), + (0.6, 0.3), + (0.4, 0.2), + (0.2, 0.1), + ] + weight_adjustment = 0.0 + for threshold, adjustment in natr_pct_change_thresholds: + if natr_pct_change > threshold: + weight_adjustment = adjustment + break + if weight_adjustment > 0: + if current_natr > entry_natr: + entry_natr_weight -= weight_adjustment + current_natr_weight += weight_adjustment + else: + entry_natr_weight += weight_adjustment + current_natr_weight -= weight_adjustment + entry_natr_weight = np.clip(entry_natr_weight, 0.0, 1.0) + current_natr_weight = np.clip(current_natr_weight, 0.0, 1.0) take_profit_natr = ( entry_natr_weight * entry_natr + current_natr_weight * current_natr ) diff --git a/quickadapter/user_data/strategies/Utils.py b/quickadapter/user_data/strategies/Utils.py index 6315583..84f12a1 100644 --- a/quickadapter/user_data/strategies/Utils.py +++ b/quickadapter/user_data/strategies/Utils.py @@ -412,8 +412,8 @@ def zigzag( def calculate_depth( pos: int, - min_depth: int = 5, - max_depth: int = 30, + min_depth: int = 6, + max_depth: int = 36, ) -> int: if len(pivots_indices) < 2: return depth @@ -471,6 +471,7 @@ def zigzag( pivots_directions.append(direction) last_pivot_pos = pos depth = calculate_depth(pos) + reset_candidate_pivot() def is_reversal_confirmed( candidate_pivot_pos: int, @@ -625,7 +626,6 @@ def zigzag( and is_reversal_confirmed(candidate_pivot_pos, i, TrendDirection.DOWN) ): add_pivot(candidate_pivot_pos, candidate_pivot_value, TrendDirection.UP) - reset_candidate_pivot() state = TrendDirection.DOWN elif state == TrendDirection.DOWN: if np.isnan(candidate_pivot_value) or current_low < candidate_pivot_value: @@ -639,7 +639,6 @@ def zigzag( add_pivot( candidate_pivot_pos, candidate_pivot_value, TrendDirection.DOWN ) - reset_candidate_pivot() state = TrendDirection.UP return pivots_indices, pivots_values, pivots_directions -- 2.43.0