]> Piment Noir Git Repositories - freqai-strategies.git/commitdiff
fix(quickadapter): invalidate reversal caches together (#155)
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Mon, 27 Jul 2026 13:30:03 +0000 (15:30 +0200)
committerGitHub <noreply@github.com>
Mon, 27 Jul 2026 13:30:03 +0000 (15:30 +0200)
Purge threshold and deviation entries for a pair before recording its new dataframe signature, and invalidate both caches when live pair-local label period or NATR multiplier state changes.

quickadapter/user_data/strategies/QuickAdapterV3.py

index d68f2cbe86fbb37baa369035ed9593c01507fc59..995357073b6f2670d5c0946fc90e012000928190 100644 (file)
@@ -14,7 +14,6 @@ from typing import (
     Optional,
     Sequence,
     TypedDict,
-    TypeVar,
 )
 
 import numpy as np
@@ -97,7 +96,6 @@ CandleDeviationCacheKey = tuple[
     str, DfSignature, float, float, int, InterpolationDirection, float
 ]
 CandleThresholdCacheKey = tuple[str, DfSignature, str, int, float, float]
-_PairCacheT = TypeVar("_PairCacheT", bound=dict)
 
 
 class _TradeHistory(TypedDict):
@@ -899,7 +897,13 @@ class QuickAdapterV3(IStrategy):
 
     def set_label_period_candles(self, pair: str, label_period_candles: Any) -> None:
         if is_finite_number(label_period_candles) and int(label_period_candles) > 0:
-            self._label_params[pair]["label_period_candles"] = int(label_period_candles)
+            label_period_candles = int(label_period_candles)
+            if (
+                self._label_params[pair].get("label_period_candles")
+                != label_period_candles
+            ):
+                self._label_params[pair]["label_period_candles"] = label_period_candles
+                self._invalidate_pair_caches(pair)
 
     def get_label_horizon_candles(self, pair: str) -> int:
         period = self.get_label_period_candles(pair)
@@ -936,9 +940,15 @@ class QuickAdapterV3(IStrategy):
             is_finite_number(label_natr_multiplier)
             and float(label_natr_multiplier) > 0.0
         ):
-            self._label_params[pair]["label_natr_multiplier"] = float(
-                label_natr_multiplier
-            )
+            label_natr_multiplier = float(label_natr_multiplier)
+            if (
+                self._label_params[pair].get("label_natr_multiplier")
+                != label_natr_multiplier
+            ):
+                self._label_params[pair]["label_natr_multiplier"] = (
+                    label_natr_multiplier
+                )
+                self._invalidate_pair_caches(pair)
 
     def get_label_natr_multiplier_fraction(
         self,
@@ -1765,13 +1775,20 @@ class QuickAdapterV3(IStrategy):
             idx = length + idx
         return min(max(0, idx), length - 1)
 
-    def _invalidate_pair_cache(
-        self, cache: _PairCacheT, pair: str, df_signature: DfSignature
-    ) -> _PairCacheT:
-        if self._cached_df_signature.get(pair) != df_signature:
-            cache = type(cache)({k: v for k, v in cache.items() if k[0] != pair})
-            self._cached_df_signature[pair] = df_signature
-        return cache
+    def _invalidate_pair_caches(
+        self, pair: str, df_signature: Optional[DfSignature] = None
+    ) -> None:
+        if df_signature is None or self._cached_df_signature.get(pair) != df_signature:
+            self._candle_deviation_cache = {
+                k: v for k, v in self._candle_deviation_cache.items() if k[0] != pair
+            }
+            self._candle_threshold_cache = {
+                k: v for k, v in self._candle_threshold_cache.items() if k[0] != pair
+            }
+            if df_signature is None:
+                self._cached_df_signature.pop(pair, None)
+            else:
+                self._cached_df_signature[pair] = df_signature
 
     def _calculate_candle_deviation(
         self,
@@ -1784,9 +1801,7 @@ class QuickAdapterV3(IStrategy):
         quantile_exponent: float = 1.5,
     ) -> float:
         df_signature = QuickAdapterV3._df_signature(df)
-        self._candle_deviation_cache = self._invalidate_pair_cache(
-            self._candle_deviation_cache, pair, df_signature
-        )
+        self._invalidate_pair_caches(pair, df_signature)
         cache_key: CandleDeviationCacheKey = (
             pair,
             df_signature,
@@ -1854,9 +1869,7 @@ class QuickAdapterV3(IStrategy):
         candle_idx: int = -1,
     ) -> float:
         df_signature = QuickAdapterV3._df_signature(df)
-        self._candle_threshold_cache = self._invalidate_pair_cache(
-            self._candle_threshold_cache, pair, df_signature
-        )
+        self._invalidate_pair_caches(pair, df_signature)
         cache_key: CandleThresholdCacheKey = (
             pair,
             df_signature,