From 4865399770f25f07f5b7e5b22c0cd68285f5fa96 Mon Sep 17 00:00:00 2001 From: Luis Barrancos Date: Tue, 30 Mar 2021 00:19:20 +0100 Subject: [PATCH] Fix Chande-Kroll stop #256, and #257 Add an optional "tvmode" parameter that controls the behaviour of the Chande-Kroll volatility stop. The default, True, retains the used behaviour, compatibility with Trading View. When False however, the moving average mode used is now a simple moving average instead of the Welles Wilder moving average and the periods used are different as well, (10/1/9 vs 10/3/20). Update the unit tests to account for the optional parameter, though sadly we have no TA-lib implementation to compare with, and the Japanese Yen Futures 09/93 contract used in figure 7.4 page 95 of the book, has no freely available OHLC data i could find. --- pandas_ta/trend/cksp.py | 40 ++++++++++++++++++++----------- tests/test_ext_indicator_trend.py | 1 + 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/pandas_ta/trend/cksp.py b/pandas_ta/trend/cksp.py index 88dde58..2be31bd 100644 --- a/pandas_ta/trend/cksp.py +++ b/pandas_ta/trend/cksp.py @@ -4,27 +4,32 @@ from pandas_ta.volatility import atr from pandas_ta.utils import get_offset, verify_series -def cksp(high, low, close, p=None, x=None, q=None, offset=None, **kwargs): +def cksp(high, low, close, p=None, x=None, q=None, offset=None, tvmode=None, **kwargs): """Indicator: Chande Kroll Stop (CKSP)""" # Validate Arguments + # TV defaults=(10,1,9), book defaults = (10,3,20) p = int(p) if p and p > 0 else 10 - x = float(x) if x and x > 0 else 1 - q = int(q) if q and q > 0 else 9 + x = float(x) if x and x > 0 else 1 if tvmode is True else 3 + q = int(q) if q and q > 0 else 9 if tvmode is True else 20 + _length = max(p, q, x) + high = verify_series(high, _length) low = verify_series(low, _length) close = verify_series(close, _length) - offset = get_offset(offset) if high is None or low is None or close is None: return - # Calculate Result - atr_ = atr(high=high, low=low, close=close, length=p) + offset = get_offset(offset) + tvmode = tvmode if isinstance(tvmode, bool) else True + + mamode = "rma" if tvmode is True else "sma" + atr_ = atr(high=high, low=low, close=close, length=p, mamode = mamode) long_stop_ = high.rolling(p).max() - x * atr_ long_stop = long_stop_.rolling(q).max() - short_stop_ = high.rolling(p).min() + x * atr_ + short_stop_ = low.rolling(p).min() + x * atr_ short_stop = short_stop_.rolling(q).min() # Offset @@ -57,16 +62,22 @@ def cksp(high, low, close, p=None, x=None, q=None, offset=None, **kwargs): cksp.__doc__ = \ """Chande Kroll Stop (CKSP) -The Tushar Chande and Stanley Kroll in their book “The New Technical Trader”. -It is a trend-following indicator, identifying your stop by calculating the -average true range of the recent market volatility. +The Tushar Chande and Stanley Kroll in their book +“The New Technical Trader”. It is a trend-following indicator, +identifying your stop by calculating the average true range of +the recent market volatility. The indicator defaults to the implementation +found on tradingview but it provides the original book implementation as well, +which differs by the default periods and moving average mode. While the trading +view implementation uses the Welles Wilder moving average, the book uses a +simple moving average. Sources: https://www.multicharts.com/discussion/viewtopic.php?t=48914 + "The New Technical Trader", Wikey 1st ed. ISBN 9780471597803, page 95 Calculation: Default Inputs: - p=10, x=1, q=9 + p=10, x=1, q=9, tvmode=True ATR = Average True Range LS0 = high.rolling(p).max() - x * ATR(length=p) @@ -77,10 +88,11 @@ Calculation: Args: close (pd.Series): Series of 'close's - p (int): ATR and first stop period. Default: 10 - x (float): ATR scalar. Default: 1 - q (int): Second stop period. Default: 9 + p (int): ATR and first stop period. Default: 10 in both modes + x (float): ATR scalar. Default: 1 in TV mode, 3 otherwise + q (int): Second stop period. Default: 9 in TV mode, 20 otherwise offset (int): How many periods to offset the result. Default: 0 + tvmode (bool): Trading View or book implementation mode. Default: True Kwargs: fillna (value, optional): pd.DataFrame.fillna(value) diff --git a/tests/test_ext_indicator_trend.py b/tests/test_ext_indicator_trend.py index 6e73504..cc0f338 100644 --- a/tests/test_ext_indicator_trend.py +++ b/tests/test_ext_indicator_trend.py @@ -40,6 +40,7 @@ class TestTrendExtension(TestCase): def test_cksp_ext(self): self.data.ta.cksp(append=True) + self.data.ta.cksp(tv=True) self.assertIsInstance(self.data, DataFrame) self.assertEqual(self.data.columns[-1], "CKSPs_10_1_9")