The True Strength Index — Coding Technical Indicators.
Coding & Trading the True Strength Index in Python.
The true strength index is another indicator that deserves to be introduced, coded, and discussed. This article gives the details of this technique that uses exponential moving averages.
I have just released a new book after the success of my previous one “The Book of Trading Strategies”. It features advanced trend-following indicators and strategies with a GitHub page dedicated to the continuously updated code. Also, this book features the original colors after having optimized for printing costs. If you feel that this interests you, feel free to visit the below Amazon link, or if you prefer to buy the PDF version, you could contact me on LinkedIn.
The Concept of Moving Averages
Moving averages help us confirm and ride the trend. They are the most known technical indicator and this is because of their simplicity and their proven track record of adding value to the analyses. We can use them to find support and resistance levels, stops and targets, and to understand the underlying trend. This versatility makes them an indispensable tool in our trading arsenal.
As the name suggests, this is your plain simple mean that is used everywhere in statistics and basically any other part in our lives. It is simply the total values of the observations divided by the number of observations. Mathematically speaking, it can be written down as:
The code for the moving average can be written down as the following:
# The function to add a number of columns inside an array
def adder(Data, times):
for i in range(1, times + 1):
new_col = np.zeros((len(Data), 1), dtype = float)
Data = np.append(Data, new_col, axis = 1)
return Data
# The function to delete a number of columns starting from an index
def deleter(Data, index, times):
for i in range(1, times + 1):
Data = np.delete(Data, index, axis = 1)
return Data
# The function to delete a number of rows from the beginning
def jump(Data, jump):
Data = Data[jump:, ]
return Data
# Example of adding 3 empty columns to an array
my_ohlc_array = adder(my_ohlc_array, 3)
# Example of deleting the 2 columns after the column indexed at 3
my_ohlc_array = deleter(my_ohlc_array, 3, 2)
# Example of deleting the first 20 rows
my_ohlc_array = jump(my_ohlc_array, 20)
# Remember, OHLC is an abbreviation of Open, High, Low, and Close and it refers to the standard historical data file
def ma(data, lookback, close, where):
data = adder(data, 1)
for i in range(len(data)):
try:
data[i, where] = (data[i - lookback + 1:i + 1, close].mean())
except IndexError:
pass
data = jump(data, lookback)
return data
The below states that the moving average function will be called on the array named my_data for a lookback period of 200, on the column indexed at 3 (closing prices in an OHLC array). The moving average values will then be put in the column indexed at 4 which is the one we have added using the adder function.
my_data = ma(my_data, 200, 3, 4)
An exponential moving average is a special type that gives more weight to the recent values. To spare you the boring details, here is the code.
def ema(data, alpha, lookback, what, where):
alpha = alpha / (lookback + 1.0)
beta = 1 - alpha
data = ma(data, lookback, what, where)
data[lookback + 1, where] = (data[lookback + 1, what] * alpha) + (data[lookback, where] * beta)
for i in range(lookback + 2, len(data)):
try:
data[i, where] = (data[i, what] * alpha) + (data[i - 1, where] * beta)
except IndexError:
pass
return data
Creating the True Strength Index Step-By-Step
The true strength index (TSI) is a momentum indicator used to detect oversold and overbought conditions. It is created from the price and its exponential moving averages.
It generally fluctuates between negative and positive territory and is calculated the following way:
Calculate the change between the current close and the previous close.
Calculate the 25-period exponential moving average on the difference found from the first step.
Calculate the 13-period exponential moving average of the result found from the second step. Let us call this PCDS which is an abbreviation of price change double smoothed.
Calculate the absolute change between the current close and the previous close.
Calculate the 25-period exponential moving average on the difference found from the first step.
Calculate the 13-period exponential moving average of the result found from the second step. Let us call this APCDS which is an abbreviation of price change double smoothed.
The TSI is therefore found this way:
def tsi(data, close, where):
data = adder(data, 8)
# PC
for i in range(len(data)):
data[i, where] = data[i, close] - data[i - 1, close]
# PCS
data = ema(data, 2, 25, where, where + 1)
# PCDS
data = ema(data, 2, 13, where + 1, where + 2)
# APC
for i in range(len(data)):
data[i, where + 3] = abs(data[i, close] - data[i - 1, close])
# APCS
data = ema(data, 2, 25, where + 3, where + 4)
# APCDS
data = ema(data, 2, 13, where + 4, where + 5)
# TSI
data[:, where + 6] = (data[:, where + 2] / data[:, where + 5]) * 100
return data
my_data = tsi(my_data, 3, 4)
my_data = ema(my_data, 2, 13, 10, 11)
If you are also interested by more technical indicators and strategies, then my book might interest you:
Using the True Strength Index
There are many ways we can use the TSI even though the results are heavily mixed and biased to negative:
Overbought and oversold conditions where certain markets have -20 and 20 as the boundaries and others -30 and 30.
The divergence technique. Remember that when a market is making higher highs while the indicator is making lower highs, a bearish divergence is spotted and a bearish reaction may be looming around. Also, whenever the market is making lower lows while the indicator is making higher lows, a bullish divergence is taking place and a reaction to the upside is to be expected soon.
The cross between the TSI and the signal line (a 13-period exponential moving average applied on it). Whenever the TSI surpasses it, a bullish signal is generated and whenever it breaks it, a bearish signal is generated.
The flip of the zero line. A bullish signal triggered whenever the TSI surpasses zero and a bearish signal is triggered whenever the TSI breaks zero.
Conclusion
Remember to always do your back-tests. You should always believe that other people are wrong. My indicators and style of trading may work for me but maybe not for you.
I am a firm believer of not spoon-feeding. I have learnt by doing and not by copying. You should get the idea, the function, the intuition, the conditions of the strategy, and then elaborate (an even better) one yourself so that you back-test and improve it before deciding to take it live or to eliminate it. My choice of not providing specific Back-testing results should lead the reader to explore more herself the strategy and work on it more.
To sum up, are the strategies I provide realistic? Yes, but only by optimizing the environment (robust algorithm, low costs, honest broker, proper risk management, and order management). Are the strategies provided only for the sole use of trading? No, it is to stimulate brainstorming and getting more trading ideas as we are all sick of hearing about an oversold RSI as a reason to go short or a resistance being surpassed as a reason to go long. I am trying to introduce a new field called Objective Technical Analysis where we use hard data to judge our techniques rather than rely on outdated classical methods.