Skip to content

Commit

Permalink
Added signal line to TSI and updated SMI to account for the change
Browse files Browse the repository at this point in the history
  • Loading branch information
danlim-wz committed Jul 25, 2021
1 parent 1deb755 commit dfaa903
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,7 @@ of the last bars defined by the length parameter. See ```help(ta.tos_stdevall)``
* _Increasing_ (**increasing**): New argument ```strict``` checks if the series is continuously increasing over period ```length``` with a faster calculation. Default: ```False```. The ```percent``` argument has also been added with default None. See ```help(ta.increasing)```.
* _Parabolic Stop and Reverse_ (**psar**): Bug fix and adjustment to match TradingView's ```sar```. New argument ```af0``` to initialize the Acceleration Factor. See ```help(ta.psar)```.
* _Percentage Price Oscillator_ (**ppo**): Included new argument ```mamode``` as an option. Default is **sma** to match TA Lib. See ```help(ta.ppo)```.
* _True Strength Index_ (**tsi**): Added ```signal``` argument. See ```help(ta.tsi)```.
* _Volume Profile_ (**vp**): Calculation improvements. See [Pull Request #320](https://github.com/twopirllc/pandas-ta/pull/320) See ```help(ta.vp)```.
* _Volume Weighted Moving Average_ (**vwma**): Fixed bug in DataFrame Extension call. See ```help(ta.vwma)```.
* _Volume Weighted Average Price_ (**vwap**): Added a new parameter called ```anchor```. Default: "D" for "Daily". See [Timeseries Offset Aliases](https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#timeseries-offset-aliases) for additional options. **Requires** the DataFrame index to be a DatetimeIndex. See ```help(ta.vwap)```.
Expand Down
5 changes: 3 additions & 2 deletions pandas_ta/momentum/smi.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ def smi(close, fast=None, slow=None, signal=None, scalar=None, offset=None, **kw
if close is None: return

# Calculate Result
smi = tsi(close, fast=fast, slow=slow, scalar=scalar)
signalma = ema(smi, signal)
tsi_df = tsi(close, fast=fast, slow=slow, signal=signal, scalar=scalar)
smi = tsi_df.iloc[:, 0]
signalma = tsi_df.iloc[:, 1]
osc = smi - signalma

# Offset
Expand Down
27 changes: 21 additions & 6 deletions pandas_ta/momentum/tsi.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# -*- coding: utf-8 -*-
from pandas import DataFrame
from pandas_ta.overlap import ema
from pandas_ta.utils import get_drift, get_offset, verify_series


def tsi(close, fast=None, slow=None, scalar=None, drift=None, offset=None, **kwargs):
def tsi(close, fast=None, slow=None, signal=None, scalar=None, drift=None, offset=None, **kwargs):
"""Indicator: True Strength Index (TSI)"""
# Validate Arguments
fast = int(fast) if fast and fast > 0 else 13
slow = int(slow) if slow and slow > 0 else 25
signal = int(signal) if signal and signal > 0 else 13
# if slow < fast:
# fast, slow = slow, fast
scalar = float(scalar) if scalar else 100
Expand All @@ -29,21 +31,32 @@ def tsi(close, fast=None, slow=None, scalar=None, drift=None, offset=None, **kwa

tsi = scalar * fast_slow_ema / abs_fast_slow_ema

tsi_signal = ema(close=tsi, length=signal)

# Offset
if offset != 0:
tsi = tsi.shift(offset)
tsi_signal = tsi_signal.shift(offset)

# Handle fills
if "fillna" in kwargs:
tsi.fillna(kwargs["fillna"], inplace=True)
tsi_signal.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
tsi.fillna(method=kwargs["fill_method"], inplace=True)
tsi_signal.fillna(method=kwargs["fill_method"], inplace=True)

# Name and Categorize it
tsi.name = f"TSI_{fast}_{slow}"
tsi.category = "momentum"
tsi.name = f"TSI_{fast}_{slow}_{signal}"
tsi_signal.name = f"TSIs_{fast}_{slow}_{signal}"
tsi.category = tsi_signal.category = "momentum"

# Prepare DataFrame to return
df = DataFrame({tsi.name: tsi, tsi_signal.name: tsi_signal})
df.name = f"TSI_{fast}_{slow}_{signal}"
df.category = "momentum"

return tsi
return df


tsi.__doc__ = \
Expand All @@ -58,7 +71,7 @@ def tsi(close, fast=None, slow=None, scalar=None, drift=None, offset=None, **kwa
Calculation:
Default Inputs:
fast=13, slow=25, scalar=100, drift=1
fast=13, slow=25, signal=13, scalar=100, drift=1
EMA = Exponential Moving Average
diff = close.diff(drift)
Expand All @@ -69,11 +82,13 @@ def tsi(close, fast=None, slow=None, scalar=None, drift=None, offset=None, **kwa
abema = abs_diff_fast_slow_ema = EMA(abs_diff_slow_ema, fast)
TSI = scalar * fast_slow_ema / abema
Signal = EMA(TSI, signal)
Args:
close (pd.Series): Series of 'close's
fast (int): The short period. Default: 13
slow (int): The long period. Default: 25
signal (int): The signal period. Default: 13
scalar (float): How much to magnify. Default: 100
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Expand All @@ -83,5 +98,5 @@ def tsi(close, fast=None, slow=None, scalar=None, drift=None, offset=None, **kwa
fill_method (value, optional): Type of fill method
Returns:
pd.Series: New feature generated.
pd.DataFrame: tsi, signal.
"""
4 changes: 2 additions & 2 deletions tests/test_indicator_momentum.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,8 +453,8 @@ def test_trix(self):

def test_tsi(self):
result = pandas_ta.tsi(self.close)
self.assertIsInstance(result, Series)
self.assertEqual(result.name, "TSI_13_25")
self.assertIsInstance(result, DataFrame)
self.assertEqual(result.name, "TSI_13_25_13")

def test_uo(self):
result = pandas_ta.uo(self.high, self.low, self.close)
Expand Down

0 comments on commit dfaa903

Please sign in to comment.