From a6a72f74dbd0b9b0a9ce7125d391b3dd4d81d5e1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sat, 17 May 2025 11:59:40 +0200 Subject: [PATCH] perf(qav3): optimize pivot labeling confirmation MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- .../freqaimodels/QuickAdapterRegressorV3.py | 28 +++++++++++++++---- .../user_data/strategies/QuickAdapterV3.py | 2 +- quickadapter/user_data/strategies/Utils.py | 26 ++++++++++++++--- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py b/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py index 26af86e..59beb5c 100644 --- a/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py +++ b/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py @@ -45,7 +45,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel): https://github.com/sponsors/robcaulk """ - version = "3.7.35" + version = "3.7.36" @cached_property def _optuna_config(self) -> dict: @@ -851,7 +851,7 @@ def zigzag( natr_period: int = 14, natr_ratio: float = 1.0, confirmation_window: int = 3, - depth: int = 12, + initial_depth: int = 12, ) -> tuple[list[int], list[float], list[int]]: n = len(df) if df.empty or n < max(natr_period, 2 * confirmation_window + 1): @@ -866,6 +866,7 @@ def zigzag( lows = df["low"].values state: TrendDirection = TrendDirection.NEUTRAL + depth = initial_depth last_pivot_pos = -depth - 1 pivots_indices, pivots_values, pivots_directions = [], [], [] @@ -874,6 +875,19 @@ def zigzag( candidate_pivot_value = np.nan candidate_pivot_direction: TrendDirection = TrendDirection.NEUTRAL + def calculate_depth( + pivots_indices: list[int], + min_depth: int = 6, + max_depth: int = 24, + depth_scaling_factor: float = 0.75, + ) -> int: + if len(pivots_indices) < 2: + return initial_depth + previous_interval = pivots_indices[-1] - pivots_indices[-2] + return max( + min_depth, min(max_depth, int(previous_interval * depth_scaling_factor)) + ) + def update_candidate_pivot(pos: int, value: float, direction: TrendDirection): nonlocal candidate_pivot_pos, candidate_pivot_value, candidate_pivot_direction if 0 <= pos < n: @@ -888,13 +902,14 @@ def zigzag( candidate_pivot_direction = TrendDirection.NEUTRAL def add_pivot(pos: int, value: float, direction: TrendDirection): - nonlocal last_pivot_pos + nonlocal last_pivot_pos, depth if pivots_indices and indices[pos] == pivots_indices[-1]: return pivots_indices.append(indices[pos]) pivots_values.append(value) pivots_directions.append(direction) last_pivot_pos = pos + depth = calculate_depth(pivots_indices) def is_reversal_confirmed( candidate_pivot_pos: int, @@ -942,6 +957,8 @@ def zigzag( >= extrema_threshold ) local_extrema_ok = valid_next and valid_previous + if not local_extrema_ok: + return False slope_ok = False next_closes_std = np.std(next_closes) @@ -955,6 +972,8 @@ def zigzag( slope_ok = next_slope_strength < -min_slope_strength elif direction == TrendDirection.UP: slope_ok = next_slope_strength > min_slope_strength + if not slope_ok: + return False significant_move_away_ok = False if direction == TrendDirection.DOWN: @@ -971,8 +990,7 @@ def zigzag( * (1 + thresholds[candidate_pivot_pos] * move_away_ratio) ): significant_move_away_ok = True - - return local_extrema_ok and slope_ok and significant_move_away_ok + return significant_move_away_ok start_pos = 0 initial_high_pos = start_pos diff --git a/quickadapter/user_data/strategies/QuickAdapterV3.py b/quickadapter/user_data/strategies/QuickAdapterV3.py index 65c612d..d65dd69 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.31" + return "3.3.32" timeframe = "5m" diff --git a/quickadapter/user_data/strategies/Utils.py b/quickadapter/user_data/strategies/Utils.py index fc91306..7f23853 100644 --- a/quickadapter/user_data/strategies/Utils.py +++ b/quickadapter/user_data/strategies/Utils.py @@ -347,7 +347,7 @@ def zigzag( natr_period: int = 14, natr_ratio: float = 1.0, confirmation_window: int = 3, - depth: int = 12, + initial_depth: int = 12, ) -> tuple[list[int], list[float], list[int]]: n = len(df) if df.empty or n < max(natr_period, 2 * confirmation_window + 1): @@ -362,6 +362,7 @@ def zigzag( lows = df["low"].values state: TrendDirection = TrendDirection.NEUTRAL + depth = initial_depth last_pivot_pos = -depth - 1 pivots_indices, pivots_values, pivots_directions = [], [], [] @@ -370,6 +371,19 @@ def zigzag( candidate_pivot_value = np.nan candidate_pivot_direction: TrendDirection = TrendDirection.NEUTRAL + def calculate_depth( + pivots_indices: list[int], + min_depth: int = 6, + max_depth: int = 24, + depth_scaling_factor: float = 0.75, + ) -> int: + if len(pivots_indices) < 2: + return initial_depth + previous_interval = pivots_indices[-1] - pivots_indices[-2] + return max( + min_depth, min(max_depth, int(previous_interval * depth_scaling_factor)) + ) + def update_candidate_pivot(pos: int, value: float, direction: TrendDirection): nonlocal candidate_pivot_pos, candidate_pivot_value, candidate_pivot_direction if 0 <= pos < n: @@ -384,13 +398,14 @@ def zigzag( candidate_pivot_direction = TrendDirection.NEUTRAL def add_pivot(pos: int, value: float, direction: TrendDirection): - nonlocal last_pivot_pos + nonlocal last_pivot_pos, depth if pivots_indices and indices[pos] == pivots_indices[-1]: return pivots_indices.append(indices[pos]) pivots_values.append(value) pivots_directions.append(direction) last_pivot_pos = pos + depth = calculate_depth(pivots_indices) def is_reversal_confirmed( candidate_pivot_pos: int, @@ -438,6 +453,8 @@ def zigzag( >= extrema_threshold ) local_extrema_ok = valid_next and valid_previous + if not local_extrema_ok: + return False slope_ok = False next_closes_std = np.std(next_closes) @@ -451,6 +468,8 @@ def zigzag( slope_ok = next_slope_strength < -min_slope_strength elif direction == TrendDirection.UP: slope_ok = next_slope_strength > min_slope_strength + if not slope_ok: + return False significant_move_away_ok = False if direction == TrendDirection.DOWN: @@ -467,8 +486,7 @@ def zigzag( * (1 + thresholds[candidate_pivot_pos] * move_away_ratio) ): significant_move_away_ok = True - - return local_extrema_ok and slope_ok and significant_move_away_ok + return significant_move_away_ok start_pos = 0 initial_high_pos = start_pos -- 2.43.0