]> Piment Noir Git Repositories - freqai-strategies.git/commitdiff
perf(qav3): improve pivot labeling algorithm
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Fri, 16 May 2025 08:50:17 +0000 (10:50 +0200)
committerJérôme Benoit <jerome.benoit@piment-noir.org>
Fri, 16 May 2025 08:50:17 +0000 (10:50 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py
quickadapter/user_data/strategies/QuickAdapterV3.py
quickadapter/user_data/strategies/Utils.py

index 3bf4961de879f4b93ec6b4f688762d249e142662..0601ede814642a39cfcc5e7eddcefa44e08967bd 100644 (file)
@@ -45,7 +45,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
     https://github.com/sponsors/robcaulk
     """
 
-    version = "3.7.32"
+    version = "3.7.33"
 
     @cached_property
     def _optuna_config(self) -> dict:
@@ -935,30 +935,55 @@ def zigzag(
 
         slope_ok = True
         if len(next_closes) >= 2:
-            next_slope = np.polyfit(range(len(next_closes)), next_closes, 1)[0]
+            next_slope = (next_closes[-1] - next_closes[0]) / (len(next_closes) - 1)
             if direction == TrendDirection.DOWN:
                 slope_ok = next_slope < 0
             elif direction == TrendDirection.UP:
                 slope_ok = next_slope > 0
 
-        thresholds_ratio = 0.25
+        significant_move_away_thresholds_ratio = 0.25
         significant_move_away_ok = False
         if direction == TrendDirection.DOWN:
             if np.any(
                 next_lows
                 < highs[candidate_pivot_pos]
-                * (1 - thresholds[candidate_pivot_pos] * thresholds_ratio)
+                * (
+                    1
+                    - thresholds[candidate_pivot_pos]
+                    * significant_move_away_thresholds_ratio
+                )
             ):
                 significant_move_away_ok = True
         elif direction == TrendDirection.UP:
             if np.any(
                 next_highs
                 > lows[candidate_pivot_pos]
-                * (1 + thresholds[candidate_pivot_pos] * thresholds_ratio)
+                * (
+                    1
+                    + thresholds[candidate_pivot_pos]
+                    * significant_move_away_thresholds_ratio
+                )
             ):
                 significant_move_away_ok = True
 
-        return local_extrema_ok and slope_ok and significant_move_away_ok
+        min_price_change_thresholds_ratio = 0.125
+        min_price_change_ok = False
+        required_price_change = (
+            thresholds[next_confirmation_pos]
+            * min_price_change_thresholds_ratio
+            * closes[next_confirmation_pos]
+        )
+        if len(next_closes) > 0:
+            actual_price_change = abs(next_closes[-1] - next_closes[0])
+            if actual_price_change >= required_price_change:
+                min_price_change_ok = True
+
+        return (
+            local_extrema_ok
+            and slope_ok
+            and significant_move_away_ok
+            and min_price_change_ok
+        )
 
     start_pos = 0
     initial_high_pos = start_pos
@@ -975,22 +1000,41 @@ def zigzag(
 
         initial_move_from_high = (initial_high - current_low) / initial_high
         initial_move_from_low = (current_high - initial_low) / initial_low
-        if initial_move_from_high >= thresholds[
-            initial_high_pos
-        ] and is_reversal_confirmed(
-            initial_high_pos, initial_high_pos, TrendDirection.DOWN
-        ):
-            add_pivot(initial_high_pos, initial_high, TrendDirection.UP)
-            state = TrendDirection.DOWN
-            break
-        elif initial_move_from_low >= thresholds[
-            initial_low_pos
-        ] and is_reversal_confirmed(
-            initial_low_pos, initial_low_pos, TrendDirection.UP
+        if (
+            initial_move_from_high >= thresholds[initial_high_pos]
+            and initial_move_from_low >= thresholds[initial_low_pos]
         ):
-            add_pivot(initial_low_pos, initial_low, TrendDirection.DOWN)
-            state = TrendDirection.UP
-            break
+            if initial_move_from_high > initial_move_from_low:
+                if is_reversal_confirmed(
+                    initial_high_pos, initial_high_pos, TrendDirection.DOWN
+                ):
+                    add_pivot(initial_high_pos, initial_high, TrendDirection.UP)
+                    state = TrendDirection.DOWN
+                    break
+            else:
+                if is_reversal_confirmed(
+                    initial_low_pos, initial_low_pos, TrendDirection.UP
+                ):
+                    add_pivot(initial_low_pos, initial_low, TrendDirection.DOWN)
+                    state = TrendDirection.UP
+                    break
+        else:
+            if initial_move_from_high >= thresholds[
+                initial_high_pos
+            ] and is_reversal_confirmed(
+                initial_high_pos, initial_high_pos, TrendDirection.DOWN
+            ):
+                add_pivot(initial_high_pos, initial_high, TrendDirection.UP)
+                state = TrendDirection.DOWN
+                break
+            elif initial_move_from_low >= thresholds[
+                initial_low_pos
+            ] and is_reversal_confirmed(
+                initial_low_pos, initial_low_pos, TrendDirection.UP
+            ):
+                add_pivot(initial_low_pos, initial_low, TrendDirection.DOWN)
+                state = TrendDirection.UP
+                break
     else:
         return [], [], []
 
index 9cff745abdc16ade18f6e25cc3048c5ec51fec43..019348454be063b91d76f3325d7ffc8d2e5b24b3 100644 (file)
@@ -58,7 +58,7 @@ class QuickAdapterV3(IStrategy):
     INTERFACE_VERSION = 3
 
     def version(self) -> str:
-        return "3.3.28"
+        return "3.3.29"
 
     timeframe = "5m"
 
index 087ffda0a8caa2113a77f0cb86c729ac231bbe31..90ddafba26f1119df751581fb510e34a49ca55cb 100644 (file)
@@ -431,30 +431,55 @@ def zigzag(
 
         slope_ok = True
         if len(next_closes) >= 2:
-            next_slope = np.polyfit(range(len(next_closes)), next_closes, 1)[0]
+            next_slope = (next_closes[-1] - next_closes[0]) / (len(next_closes) - 1)
             if direction == TrendDirection.DOWN:
                 slope_ok = next_slope < 0
             elif direction == TrendDirection.UP:
                 slope_ok = next_slope > 0
 
-        thresholds_ratio = 0.25
+        significant_move_away_thresholds_ratio = 0.25
         significant_move_away_ok = False
         if direction == TrendDirection.DOWN:
             if np.any(
                 next_lows
                 < highs[candidate_pivot_pos]
-                * (1 - thresholds[candidate_pivot_pos] * thresholds_ratio)
+                * (
+                    1
+                    - thresholds[candidate_pivot_pos]
+                    * significant_move_away_thresholds_ratio
+                )
             ):
                 significant_move_away_ok = True
         elif direction == TrendDirection.UP:
             if np.any(
                 next_highs
                 > lows[candidate_pivot_pos]
-                * (1 + thresholds[candidate_pivot_pos] * thresholds_ratio)
+                * (
+                    1
+                    + thresholds[candidate_pivot_pos]
+                    * significant_move_away_thresholds_ratio
+                )
             ):
                 significant_move_away_ok = True
 
-        return local_extrema_ok and slope_ok and significant_move_away_ok
+        min_price_change_thresholds_ratio = 0.125
+        min_price_change_ok = False
+        required_price_change = (
+            thresholds[next_confirmation_pos]
+            * min_price_change_thresholds_ratio
+            * closes[next_confirmation_pos]
+        )
+        if len(next_closes) > 0:
+            actual_price_change = abs(next_closes[-1] - next_closes[0])
+            if actual_price_change >= required_price_change:
+                min_price_change_ok = True
+
+        return (
+            local_extrema_ok
+            and slope_ok
+            and significant_move_away_ok
+            and min_price_change_ok
+        )
 
     start_pos = 0
     initial_high_pos = start_pos
@@ -471,22 +496,41 @@ def zigzag(
 
         initial_move_from_high = (initial_high - current_low) / initial_high
         initial_move_from_low = (current_high - initial_low) / initial_low
-        if initial_move_from_high >= thresholds[
-            initial_high_pos
-        ] and is_reversal_confirmed(
-            initial_high_pos, initial_high_pos, TrendDirection.DOWN
-        ):
-            add_pivot(initial_high_pos, initial_high, TrendDirection.UP)
-            state = TrendDirection.DOWN
-            break
-        elif initial_move_from_low >= thresholds[
-            initial_low_pos
-        ] and is_reversal_confirmed(
-            initial_low_pos, initial_low_pos, TrendDirection.UP
+        if (
+            initial_move_from_high >= thresholds[initial_high_pos]
+            and initial_move_from_low >= thresholds[initial_low_pos]
         ):
-            add_pivot(initial_low_pos, initial_low, TrendDirection.DOWN)
-            state = TrendDirection.UP
-            break
+            if initial_move_from_high > initial_move_from_low:
+                if is_reversal_confirmed(
+                    initial_high_pos, initial_high_pos, TrendDirection.DOWN
+                ):
+                    add_pivot(initial_high_pos, initial_high, TrendDirection.UP)
+                    state = TrendDirection.DOWN
+                    break
+            else:
+                if is_reversal_confirmed(
+                    initial_low_pos, initial_low_pos, TrendDirection.UP
+                ):
+                    add_pivot(initial_low_pos, initial_low, TrendDirection.DOWN)
+                    state = TrendDirection.UP
+                    break
+        else:
+            if initial_move_from_high >= thresholds[
+                initial_high_pos
+            ] and is_reversal_confirmed(
+                initial_high_pos, initial_high_pos, TrendDirection.DOWN
+            ):
+                add_pivot(initial_high_pos, initial_high, TrendDirection.UP)
+                state = TrendDirection.DOWN
+                break
+            elif initial_move_from_low >= thresholds[
+                initial_low_pos
+            ] and is_reversal_confirmed(
+                initial_low_pos, initial_low_pos, TrendDirection.UP
+            ):
+                add_pivot(initial_low_pos, initial_low, TrendDirection.DOWN)
+                state = TrendDirection.UP
+                break
     else:
         return [], [], []