Skip to content
This repository was archived by the owner on Sep 2, 2022. It is now read-only.

Commit cc3385b

Browse files
authored
Merge pull request #99 from jamesyrose/fix_stc
Fixed STC calculation + test
2 parents 1193e92 + a83574e commit cc3385b

File tree

2 files changed

+32
-29
lines changed

2 files changed

+32
-29
lines changed

finta/finta.py

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def TRIX(
202202
A buy/sell signals are generated when the TRIX crosses above/below the signal line and is also above/below zero.
203203
204204
The TRIX was developed by Jack K. Hutson, publisher of Technical Analysis of Stocks & Commodities magazine,
205-
and was introduced in Volume 1, Number 5 of that magazine.
205+
and was introduced in Volume 1, Number 5 of that magazine.
206206
"""
207207

208208
data = ohlc[column]
@@ -634,7 +634,7 @@ def VBM(
634634
atr_period: int = 26,
635635
column: str = "close",
636636
) -> Series:
637-
"""The Volatility-Based-Momentum (VBM) indicator, The calculation for a volatility based momentum (VBM)
637+
"""The Volatility-Based-Momentum (VBM) indicator, The calculation for a volatility based momentum (VBM)
638638
indicator is very similar to ROC, but divides by the security’s historical volatility instead.
639639
The average true range indicator (ATR) is used to compute historical volatility.
640640
VBM(n,v) = (Close — Close n periods ago) / ATR(v periods)
@@ -719,8 +719,8 @@ def DYMI(
719719
cls, ohlc: DataFrame, column: str = "close", adjust: bool = True
720720
) -> Series:
721721
"""
722-
The Dynamic Momentum Index is a variable term RSI. The RSI term varies from 3 to 30. The variable
723-
time period makes the RSI more responsive to short-term moves. The more volatile the price is,
722+
The Dynamic Momentum Index is a variable term RSI. The RSI term varies from 3 to 30. The variable
723+
time period makes the RSI more responsive to short-term moves. The more volatile the price is,
724724
the shorter the time period is. It is interpreted in the same way as the RSI, but provides signals earlier.
725725
Readings below 30 are considered oversold, and levels over 70 are considered overbought. The indicator
726726
oscillates between 0 and 100.
@@ -828,11 +828,11 @@ def SAR(cls, ohlc: DataFrame, af: int = 0.02, amax: int = 0.2) -> Series:
828828
@classmethod
829829
def PSAR(cls, ohlc: DataFrame, iaf: int = 0.02, maxaf: int = 0.2) -> DataFrame:
830830
"""
831-
The parabolic SAR indicator, developed by J. Wells Wilder, is used by traders to determine trend direction and potential reversals in price.
832-
The indicator uses a trailing stop and reverse method called "SAR," or stop and reverse, to identify suitable exit and entry points.
831+
The parabolic SAR indicator, developed by J. Wells Wilder, is used by traders to determine trend direction and potential reversals in price.
832+
The indicator uses a trailing stop and reverse method called "SAR," or stop and reverse, to identify suitable exit and entry points.
833833
Traders also refer to the indicator as the parabolic stop and reverse, parabolic SAR, or PSAR.
834834
https://www.investopedia.com/terms/p/parabolicindicator.asp
835-
https://virtualizedfrog.wordpress.com/2014/12/09/parabolic-sar-implementation-in-python/
835+
https://virtualizedfrog.wordpress.com/2014/12/09/parabolic-sar-implementation-in-python/
836836
"""
837837

838838
length = len(ohlc)
@@ -1248,7 +1248,7 @@ def UO(cls, ohlc: DataFrame, column: str = "close") -> Series:
12481248

12491249
@classmethod
12501250
def AO(cls, ohlc: DataFrame, slow_period: int = 34, fast_period: int = 5) -> Series:
1251-
"""'EMA',
1251+
"""'EMA',
12521252
Awesome Oscillator is an indicator used to measure market momentum. AO calculates the difference of a 34 Period and 5 Period Simple Moving Averages.
12531253
The Simple Moving Averages that are used are not calculated using closing price but rather each bar's midpoints.
12541254
AO is generally used to affirm trends or to anticipate possible reversals. """
@@ -2109,27 +2109,32 @@ def STC(
21092109
ohlc: DataFrame,
21102110
period_fast: int = 23,
21112111
period_slow: int = 50,
2112-
period: int = 10,
2112+
k_period: int = 10,
2113+
d_period: int = 3,
21132114
column: str = "close",
2114-
adjust: bool = True,
2115+
adjust: bool = True
21152116
) -> Series:
21162117
"""
2118+
The Schaff Trend Cycle (Oscillator) can be viewed as Double Smoothed
2119+
Stochastic of the MACD.
2120+
21172121
Schaff Trend Cycle - Three input values are used with the STC:
21182122
– Sh: shorter-term Exponential Moving Average with a default period of 23
21192123
– Lg: longer-term Exponential Moving Average with a default period of 50
2120-
– Cycle, set at half the cycle length with a default value of 10.
2124+
– Cycle, set at half the cycle length with a default value of 10. (Stoch K-period)
2125+
- Smooth, set at smoothing at 3 (Stoch D-period)
2126+
21212127
The STC is calculated in the following order:
2122-
First, the 23-period and the 50-period EMA and the MACD values are calculated:
2123-
EMA1 = EMA (Close, Short Length);
2124-
EMA2 = EMA (Close, Long Length);
2128+
EMA1 = EMA (Close, fast_period);
2129+
EMA2 = EMA (Close, slow_period);
21252130
MACD = EMA1 – EMA2.
21262131
Second, the 10-period Stochastic from the MACD values is calculated:
2127-
%K (MACD) = %KV (MACD, 10);
2128-
%D (MACD) = %DV (MACD, 10);
2129-
Schaff = 100 x (MACD – %K (MACD)) / (%D (MACD) – %K (MACD)).
2130-
In case the STC indicator is decreasing, this indicates that the trend cycle
2132+
STOCH_K, STOCH_D = StochasticFull(MACD, k_period, d_period) // Stoch of MACD
2133+
STC = average(STOCH_D, d_period) // second smoothed
2134+
2135+
In case the STC indicator is decreasing, this indicates that the trend cycle
21312136
is falling, while the price tends to stabilize or follow the cycle to the downside.
2132-
In case the STC indicator is increasing, this indicates that the trend cycle
2137+
In case the STC indicator is increasing, this indicates that the trend cycle
21332138
is up, while the price tends to stabilize or follow the cycle to the upside.
21342139
"""
21352140
EMA_fast = pd.Series(
@@ -2143,17 +2148,15 @@ def STC(
21432148
)
21442149

21452150
MACD = pd.Series((EMA_fast - EMA_slow), name="MACD")
2146-
STOK = (
2147-
(MACD - MACD.rolling(window=period).min())
2148-
/ (MACD.rolling(window=period).max() - MACD.rolling(window=period).min())
2149-
) * 100
2150-
STOD = STOK.rolling(window=period).mean()
21512151

2152-
return pd.Series(
2153-
100 * (MACD - (STOK * MACD)) / ((STOD * MACD) - (STOK * MACD)),
2154-
name="{0} period STC.".format(period),
2155-
)
2152+
STOK = pd.Series((
2153+
(MACD - MACD.rolling(window=k_period).min())
2154+
/ (MACD.rolling(window=k_period).max() - MACD.rolling(window=k_period).min())
2155+
) * 100)
21562156

2157+
STOD = STOK.rolling(window=d_period).mean()
2158+
STOD_DoubleSmooth = STOD.rolling(window=d_period).mean() # "double smoothed"
2159+
return pd.Series(STOD_DoubleSmooth, name="{0} period STC".format(k_period))
21572160

21582161
if __name__ == "__main__":
21592162
print([k for k in TA.__dict__.keys() if k[0] not in "_"])

tests/test_unit.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -842,5 +842,5 @@ def test_stc():
842842
stc = TA.STC(ohlc)
843843

844844
assert isinstance(stc, series.Series)
845-
assert stc.values[-1] == 10.000000000000165
845+
assert stc.values[-1] == 1.1131836193574902e-13
846846

0 commit comments

Comments
 (0)