Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GH-175] z-score based kdj is invalid. #176

Merged
merged 1 commit into from
Jul 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![codecov](https://codecov.io/gh/jealous/stockstats/branch/master/graph/badge.svg?token=IFMD1pVJ7T)](https://codecov.io/gh/jealous/stockstats)
[![pypi](https://img.shields.io/pypi/v/stockstats.svg)](https://pypi.python.org/pypi/stockstats)

VERSION: 0.6.1
VERSION: 0.6.2

## Introduction

Expand Down
27 changes: 15 additions & 12 deletions stockstats.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ def _get_r(self, meta: _Meta):
self[meta.name] = self.roc(self[meta.column], shift)

@staticmethod
def _shift(series: pd.Series, window: int):
def s_shift(series: pd.Series, window: int):
""" Shift the series

When window is negative, shift the past period to current.
Expand All @@ -386,11 +386,11 @@ def _get_s(self, meta: _Meta):
negative values meaning data in the past,
positive values meaning data in the future.
"""
self[meta.name] = self._shift(self[meta.column], meta.int)
self[meta.name] = self.s_shift(self[meta.column], meta.int)

def _get_log_ret(self, _: _Meta):
close = self['close']
self['log-ret'] = np.log(close / self._shift(close, -1))
self['log-ret'] = np.log(close / self.s_shift(close, -1))

def _get_c(self, meta: _Meta) -> pd.Series:
""" get the count of column in range (shifts)
Expand Down Expand Up @@ -424,7 +424,7 @@ def _shifted_columns(self,
col = self.get(column)
res = pd.DataFrame()
for i in shifts:
res[int(i)] = self._shift(col, i).values
res[int(i)] = self.s_shift(col, i).values
return res

def _get_max(self, meta: _Meta):
Expand Down Expand Up @@ -538,7 +538,7 @@ def _get_trix(self, meta: _Meta):
single = self.ema(self[meta.column], window)
double = self.ema(single, window)
triple = self.ema(double, window)
prev_triple = self._shift(triple, -1)
prev_triple = self.s_shift(triple, -1)
triple_change = self._delta(triple, -1)
self[meta.name] = triple_change * 100 / prev_triple

Expand Down Expand Up @@ -585,7 +585,7 @@ def _get_cci(self, meta: _Meta):
self[meta.name] = (tp - tp_sma) / (.015 * mad)

def _tr(self):
prev_close = self._shift(self['close'], -1)
prev_close = self.s_shift(self['close'], -1)
high = self['high']
low = self['low']
c1 = high - low
Expand Down Expand Up @@ -724,7 +724,10 @@ def _get_z(self, meta: _Meta):
col = self[meta.column]
mean = self.sma(col, window)
std = self.mov_std(col, window)
self[meta.name] = ((col - mean) / std).fillna(0.0)
value = (col - mean) / std
if len(value) > 1:
value.iloc[0] = value.iloc[1]
self[meta.name] = value

def _atr(self, window):
tr = self._tr()
Expand Down Expand Up @@ -854,8 +857,8 @@ def _get_cr(self, meta: _Meta):
"""
window = meta.int
middle = self._tp()
last_middle = self._shift(middle, -1)
ym = self._shift(middle, -1)
last_middle = self.s_shift(middle, -1)
ym = self.s_shift(middle, -1)
high = self['high']
low = self['low']
p1_m = pd.concat((last_middle, high), axis=1).min(axis=1)
Expand All @@ -871,7 +874,7 @@ def _get_cr(self, meta: _Meta):

def _shifted_cr_sma(self, cr, window):
cr_sma = self.sma(cr, window)
return self._shift(cr_sma, -int(window / 2.5 + 1))
return self.s_shift(cr_sma, -int(window / 2.5 + 1))

def _tp(self):
if 'amount' in self:
Expand Down Expand Up @@ -1336,7 +1339,7 @@ def _get_mfi(self, meta: _Meta):
window = meta.int
middle = self._tp()
money_flow = (middle * self["volume"]).fillna(0.0)
shifted = self._shift(middle, -1)
shifted = self.s_shift(middle, -1)
delta = (middle - shifted).fillna(0)
pos_flow = money_flow.mask(delta < 0, 0)
neg_flow = money_flow.mask(delta >= 0, 0)
Expand Down Expand Up @@ -1407,7 +1410,7 @@ def _get_cmo(self, meta: _Meta):

def ker(self, column, window):
col = self[column]
col_window_s = self._shift(col, -window)
col_window_s = self.s_shift(col, -window)
window_diff = (col - col_window_s).abs()
diff = self._col_diff(column).abs()
volatility = self.mov_sum(diff, window)
Expand Down
12 changes: 11 additions & 1 deletion test.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,16 @@ def test_column_kdjj(self):
assert_that(kdjk_3.loc[20110104], near_to(74.5614))
assert_that(kdjk_3.loc[20110120], near_to(7.37))

def test_z_kdj(self):
stock = self.get_stock_90days()
for col in ['open', 'high', 'low', 'close', 'volume']:
stock[col] = stock[f'{col}_20_z']
_ = stock[['kdjk', 'kdjd', 'kdjj']]
row = stock.loc[20110104]
assert_that(row['kdjk'], near_to(66.666))
assert_that(row['kdjd'], near_to(55.555))
assert_that(row['kdjj'], near_to(88.888))

def test_column_cross(self):
stock = self.get_stock_30days()
cross = stock['kdjk_3_x_kdjd_3']
Expand Down Expand Up @@ -865,7 +875,7 @@ def test_aroon(self):
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[20040817, 'close_14_z'], near_to(-0.7071))
assert_that(stock.loc[20040915, 'close_14_z'], near_to(2.005))
assert_that(stock.loc[20041014, 'close_14_z'], near_to(-2.014))

Expand Down
Loading