From db3802018d0b6134af35a337aba917972211c6e1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Fri, 20 Jun 2025 14:29:54 +0200 Subject: [PATCH] perf: add some caching on computation helpers 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 | 3 +++ .../freqaimodels/QuickAdapterRegressorV3.py | 2 ++ .../user_data/strategies/QuickAdapterV3.py | 15 ++++++++++++--- quickadapter/user_data/strategies/Utils.py | 3 +++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/ReforceXY/user_data/freqaimodels/ReforceXY.py b/ReforceXY/user_data/freqaimodels/ReforceXY.py index 8f068bb..ab09827 100644 --- a/ReforceXY/user_data/freqaimodels/ReforceXY.py +++ b/ReforceXY/user_data/freqaimodels/ReforceXY.py @@ -1,4 +1,5 @@ import copy +from functools import lru_cache import gc import json import logging @@ -1503,6 +1504,7 @@ def linear_schedule(initial_value: float) -> Callable[[float], float]: return func +@lru_cache(maxsize=32) def hours_to_seconds(hours: float) -> float: """ Converts hours to seconds @@ -1511,6 +1513,7 @@ def hours_to_seconds(hours: float) -> float: return seconds +@lru_cache(maxsize=32) def steps_to_days(steps: int, timeframe: str) -> float: """ Calculate the number of days based on the given number of steps diff --git a/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py b/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py index f9d3a06..795ff67 100644 --- a/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py +++ b/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py @@ -189,6 +189,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel): else: raise ValueError(f"Invalid namespace: {namespace}") + @lru_cache(maxsize=8) def get_optuna_label_all_candles(self) -> list[int]: n_pairs = len(self.pairs) label_frequency_candles = max( @@ -1094,6 +1095,7 @@ def train_objective( candles_step: int, model_training_parameters: dict[str, Any], ) -> float: + @lru_cache(maxsize=128) def calculate_min_extrema( length: int, fit_live_predictions_candles: int, min_extrema: int = 2 ) -> int: diff --git a/quickadapter/user_data/strategies/QuickAdapterV3.py b/quickadapter/user_data/strategies/QuickAdapterV3.py index 0d69185..79364db 100644 --- a/quickadapter/user_data/strategies/QuickAdapterV3.py +++ b/quickadapter/user_data/strategies/QuickAdapterV3.py @@ -1,6 +1,6 @@ import json import logging -from functools import reduce, cached_property +from functools import lru_cache, reduce, cached_property import datetime import math from pathlib import Path @@ -666,6 +666,10 @@ class QuickAdapterV3(IStrategy): f"Invalid trade_price_target: {trade_price_target}. Expected 'interpolation', 'weighted_interpolation' or 'moving_average'." ) + @lru_cache(maxsize=128) + def get_stoploss_log_factor(self, trade_duration_candles: int) -> float: + return 1 / math.log10(3.75 + 0.25 * trade_duration_candles) + def get_stoploss_distance( self, df: DataFrame, trade: Trade, current_rate: float ) -> Optional[float]: @@ -679,9 +683,13 @@ class QuickAdapterV3(IStrategy): current_rate * (trade_natr / 100.0) * self.get_stoploss_natr_ratio(trade.pair) - * (1 / math.log10(3.75 + 0.25 * trade_duration_candles)) + * self.get_stoploss_log_factor(trade_duration_candles) ) + @lru_cache(maxsize=128) + def get_take_profit_log_factor(self, trade_duration_candles: int) -> float: + return math.log10(9.75 + 0.25 * trade_duration_candles) + def get_take_profit_distance(self, df: DataFrame, trade: Trade) -> Optional[float]: trade_duration_candles = self.get_trade_duration_candles(df, trade) if not QuickAdapterV3.is_trade_duration_valid(trade_duration_candles): @@ -693,7 +701,7 @@ class QuickAdapterV3(IStrategy): trade.open_rate * (trade_natr / 100.0) * self.get_take_profit_natr_ratio(trade.pair) - * math.log10(9.75 + 0.25 * trade_duration_candles) + * self.get_take_profit_log_factor(trade_duration_candles) ) def throttle_callback( @@ -850,6 +858,7 @@ class QuickAdapterV3(IStrategy): ) return False + @lru_cache(maxsize=8) def max_open_trades_per_side(self) -> int: max_open_trades = self.config.get("max_open_trades") if max_open_trades < 0: diff --git a/quickadapter/user_data/strategies/Utils.py b/quickadapter/user_data/strategies/Utils.py index 40b5611..42f73e1 100644 --- a/quickadapter/user_data/strategies/Utils.py +++ b/quickadapter/user_data/strategies/Utils.py @@ -22,6 +22,7 @@ def non_zero_diff(s1: pd.Series, s2: pd.Series) -> pd.Series: return diff +@lru_cache(maxsize=8) def get_gaussian_window(std: float, center: bool) -> int: if std is None: raise ValueError("Standard deviation cannot be None") @@ -33,12 +34,14 @@ def get_gaussian_window(std: float, center: bool) -> int: return max(3, window) +@lru_cache(maxsize=8) def get_odd_window(window: int) -> int: if window < 1: raise ValueError("Window size must be greater than 0") return window if window % 2 == 1 else window + 1 +@lru_cache(maxsize=8) def derive_gaussian_std_from_window(window: int) -> float: # Assuming window = 6 * std + 1 => std = (window - 1) / 6 return (window - 1) / 6.0 if window > 1 else 0.5 -- 2.43.0