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.
This commit is contained in:
Luis Barrancos
2021-03-30 01:13:49 +01:00
parent 360a26d71c
commit 4865399770
2 changed files with 27 additions and 14 deletions
+26 -14
View File
@@ -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)
+1
View File
@@ -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")