diff --git a/README.md b/README.md index a70be88..8ea4809 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ Supported statistics/indicators are: * WT: LazyBear's Wave Trend * Supertrend: with the Upper Band and Lower Band * Aroon: Aroon Oscillator +* Z: Z-Score ## Installation @@ -670,6 +671,27 @@ Examples: * `df['aroon']` returns Aroon oscillator with a window of 25 * `df['aroon_14']` returns Aroon oscillator with a window of 14 +#### [Z-Score](https://www.investopedia.com/terms/z/zscore.asp) + +Z-score is a statistical measurement that describes a value's relationship to +the mean of a group of values. + +There is no default column name or window for Z-Score. + +The statistical formula for a value's z-score is calculated using +the following formula: + +```z = ( x - μ ) / σ``` + +Where: + +* `z` = Z-score +* `x` = the value being evaluated +* `μ` = the mean +* `σ` = the standard deviation + +Examples: +* `df['close_75_z']` returns the Z-Score of close price with a window of 75 ## Issues diff --git a/stockstats.py b/stockstats.py index 1971cc0..e1bd045 100644 --- a/stockstats.py +++ b/stockstats.py @@ -604,6 +604,18 @@ def _get_supertrend(self, window=None): self['supertrend'] = st def _get_aroon(self, window=None): + """ Aroon Oscillator + + The Aroon Oscillator measures the strength of a trend and + the likelihood that it will continue. + + The default window is 25. + + * Aroon Oscillator = Aroon Up - Aroon Down + * Aroon Up = 100 * (n - periods since n-period high) / n + * Aroon Down = 100 * (n - periods since n-period low) / n + * n = window size + """ if window is None: window = 25 column_name = 'aroon' @@ -628,6 +640,37 @@ def _window_pct(s): aroon_down = _window_pct(low_since) self[column_name] = aroon_up - aroon_down + def _get_z(self, column, window): + """ Z score + + Z-score is a statistical measurement that describes a value's + relationship to the mean of a group of values. + + The statistical formula for a value's z-score is calculated using + the following formula: + + z = ( x - μ ) / σ + + Where: + + * z = Z-score + * x = the value being evaluated + * μ = the mean + * σ = the standard deviation + """ + window = self.get_int_positive(window) + column_name = '{}_{}_z'.format(column, window) + col = self[column] + mean = col.rolling( + min_periods=1, + window=window, + center=False).mean() + std = col.rolling( + min_periods=1, + window=window, + center=False).std() + self[column_name] = ((col - mean) / std).fillna(0.0) + def _atr(self, window): tr = self._tr() return self._smma(tr, window) diff --git a/test.py b/test.py index c2b6524..f623936 100644 --- a/test.py +++ b/test.py @@ -738,3 +738,10 @@ def test_aroon(self): _ = stock['aroon_5'] assert_that(stock.loc[20040924, 'aroon_5'], equal_to(40)) assert_that(stock.loc[20041020, 'aroon_5'], equal_to(-80)) + + def test_close_z(self): + stock = self._supor[:100] + _ = stock['close_14_z'] + assert_that(stock.loc[20040817, 'close_14_z'], equal_to(0)) + assert_that(stock.loc[20040915, 'close_14_z'], near_to(2.005)) + assert_that(stock.loc[20041014, 'close_14_z'], near_to(-2.014))