From 345b48a67cd8cdc1c446f94d06657b3228b7a5c3 Mon Sep 17 00:00:00 2001 From: Mark Aron Szulyovszky Date: Tue, 15 Mar 2022 14:32:49 +0100 Subject: [PATCH] feat(Filters): added numba compiled cusum filter (#243) --- labeling/event_filters/cusum.py | 50 +++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/labeling/event_filters/cusum.py b/labeling/event_filters/cusum.py index 88856b7..59e3f69 100644 --- a/labeling/event_filters/cusum.py +++ b/labeling/event_filters/cusum.py @@ -12,28 +12,14 @@ class CUSUMVolatilityEventFilter(EventFilter): self.multiplier = multiplier def get_event_start_times(self, returns: ReturnSeries) -> pd.DatetimeIndex: - rolling_vol = returns.rolling(self.vol_period).std() * self.multiplier + diffed_returns = returns.diff() - filtered_indices = [] - pos_threshold = 0 - neg_threshold = 0 - diff = returns.diff() - for index in diff.index[1:]: - pos_threshold, neg_threshold = ( - max(0, pos_threshold + diff.loc[index]), - min(0, neg_threshold + diff.loc[index]), - ) + int_indicies = _process_vol_based( + List(diffed_returns.to_list()), List(rolling_vol.to_list()) + ) - if neg_threshold < -rolling_vol[index]: - neg_threshold = 0 - filtered_indices.append(index) - - elif pos_threshold > rolling_vol[index]: - pos_threshold = 0 - filtered_indices.append(index) - - return pd.DatetimeIndex(filtered_indices) + return pd.DatetimeIndex([returns.index[i] for i in int_indicies]) class CUSUMFixedEventFilter(EventFilter): @@ -42,7 +28,7 @@ class CUSUMFixedEventFilter(EventFilter): def get_event_start_times(self, returns: ReturnSeries) -> pd.DatetimeIndex: diffed_returns = returns.diff() - int_indicies = _process( + int_indicies = _process_fixed( List(diffed_returns.to_list()), abs(returns.mean()) * self.threshold ) @@ -50,7 +36,7 @@ class CUSUMFixedEventFilter(EventFilter): @njit -def _process(diffed_returns: List, threshold: float32) -> List: +def _process_fixed(diffed_returns: List, threshold: float32) -> List: pos_threshold: float32 = 0.0 # type: ignore neg_threshold: float32 = 0.0 # type: ignore filtered_indicies = List() @@ -69,3 +55,25 @@ def _process(diffed_returns: List, threshold: float32) -> List: filtered_indicies.append(index) return filtered_indicies + + +@njit +def _process_vol_based(diffed_returns: List, rolling_vol: List) -> List: + pos_threshold: float32 = 0.0 # type: ignore + neg_threshold: float32 = 0.0 # type: ignore + filtered_indicies = List() + for index in range(1, len(diffed_returns[1:])): + pos_threshold, neg_threshold = ( # type: ignore + max(0, pos_threshold + diffed_returns[index]), # type: ignore + min(0, neg_threshold + diffed_returns[index]), # type: ignore + ) + + if neg_threshold < -rolling_vol[index]: + neg_threshold = 0.0 # type: ignore + filtered_indicies.append(index) + + elif pos_threshold > rolling_vol[index]: + pos_threshold = 0.0 # type: ignore + filtered_indicies.append(index) + + return filtered_indicies