Creating the Trailing Stop Indicator in Python.
How to Create a Trailing Stop Indicator Using Python for Trading.
Trading is a combination of four things, research, implementation, risk management, and post-trade evaluation. The bulk of what we spend our time doing is the first two, meaning that we spend the vast majority of the time searching for a profitable strategy and implementing it (i.e. trading). However, we forget that the pillar of trading is not losing money. It is even more important than gaining money because it is fine to spend time trading and still have the same capital or slightly less than to spend time trading and find yourself wiped out.
In this article, we will discuss the third pillar as a way of enhancing returns and capital protection. Every trading strategy must be accompanied by its own personalized risk management protocol.
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 Average True Range
To understand the Average True Range, we must first understand the concept of Volatility. It is a key concept in finance, whoever masters it holds a tremendous edge in the markets.
Unfortunately, we cannot always measure and predict it with accuracy. Even though the concept is more important in options trading, we need it pretty much everywhere else. Traders cannot trade without volatility nor manage their positions and risk. Quantitative analysts and risk managers require volatility to be able to do their work. Before we discuss the different types of volatility, why not look at a graph that sums up the concept? Check out the below image to get you started.
You can code the above in Python yourself using the following snippet:
# Importing the necessary libraries import numpy as np import matplotlib.pyplot as plt
# Creating high volatility noise hv_noise = np.random.normal(0, 1, 250)
# Creating low volatility noise lv_noise = np.random.normal(0, 0.1, 250)
# Plotting plt.plot(hv_noise, color = 'red', linewidth = 1.5, label = 'High Volatility') plt.plot(lv_noise, color = 'green', linewidth = 1.5, label = 'Low Volatility')
plt.axhline(y = 0, color = 'black', linewidth = 1)
The different types of volatility around us can be summed up in the following:
Historical volatility: It is the realized volatility over a certain period of time. Even though it is backward looking, historical volatility is used more often than not as an expectation of future volatility. One example of a historical measure is the standard deviation, which we will see later. Another example is the Average True Range, the protagonist of this article.
Implied volatility: In its simplest definition, implied volatility is the measure that when inputted into the Black-Scholes equation, gives out the option’s market price. It is considered as the expected future actual volatility by market participants. It has one time scale, the option’s expiration.
Forward volatility: It is the volatility over a specific period in the future.
Actual volatility: It is the amount of volatility at any given time. Also known as local volatility, this measure is hard to calculate and has no time scale.
Volatility is the average distance away from the mean that we expect to find when we analyze the different components of the time series.
In technical analysis, an indicator called the Average True Range -ATR- can be used as a gauge for historical volatility. Although it is considered as a lagging indicator, it gives some insights as to where volatility is now and where has it been last period (day, week, month, etc.).
But first, we should understand how the True Range is calculated (the ATR is just the average of that calculation). Consider an OHLC data composed of an timely arranged open, high, low, and close prices. For each time period (bar), the true range is simply the greatest of the three price differences:
High — Low
High — Previous close
Previous close — Low
Once we have got the maximum out of the above three, we simply take a smoothed average of n periods of the true ranges to get the average true range. Generally, since in periods of panic and price depreciation we see volatility go up, the ATR will most likely trend higher during these periods, similarly in times of steady uptrends or downtrends, the ATR will tend to go lower. One should always remember that this indicator is lagging and therefore has to be used with extreme caution.
Since it has been created by Welles Wilder Jr., also the creator of the relative strength index, it uses Wilder’s own type of moving average, the smoothed kind. To simplify things, the smoothed moving average can be found through a simple transformation of the exponential moving average.
The above formula means that a 100 smoothed moving average is the same thing as (100 x 2) -1 = 199 exponential moving average. While we are on that, we can code the exponential moving average using this function:
def adder(Data, times): for i in range(1, times + 1): new = np.zeros((len(Data), 1), dtype = float) Data = np.append(Data, new, axis = 1)
def deleter(Data, index, times): for i in range(1, times + 1): Data = np.delete(Data, index, axis = 1)
return Data def jump(Data, jump): Data = Data[jump:, ] return Data
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 # Cleaning Data = jump(Data, lookback) return Data
def ema(Data, alpha, lookback, what, where): alpha = alpha / (lookback + 1.0) beta = 1 - alpha # First value is a simple SMA Data = ma(Data, lookback, what, where) # Calculating first EMA Data[lookback + 1, where] = (Data[lookback + 1, what] * alpha) + (Data[lookback, where] * beta)
# Calculating the rest of EMA 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
And now, to calculate the average true range, we can define the below function:
def atr(data, lookback, high, low, close, where): # adding columns data = adder(data, 2) # true range for i in range(len(data)): try: data[i, where] = max(data[i, high] - data[i, low], abs(data[i, high] - data[i - 1, close]), abs(data[i, low] - data[i - 1, close])) except ValueError: pass data[0, where] = 0 # average true range data = ema(data, 2, (lookback * 2) - 1, where, where + 1)
# Cleaning data = deleter(data, where, 1) data = jump(data, lookback) return data
The Trailing Stop Indicator
The indicator as its name suggests gives us a trailing stop that helps us in out trend-following strategies. Naturally, when we initiate a trend-following position, we are hoping to squeeze out the most of the underlying move and ride it until it ends. Unfortunately, it is extremely complicated to sell exactly at the end of the move. Therefore, we can just move up our stop as the position goes in our favor. Here is a simple illustration:
A buy position is opened on the EURUSD at 1.1000 in expectation that the bullish move will continue. We place the stop at 1.0900 and no take-profit order as we want to remain long as much as possible.
Two days later, the EURUSD is trading at 1.1100. This is a 0.90% increase that we would like to keep at least some of it and to lock in some profits. Therefore, we move our stop to 1.1010. Now, we have a position that is up 100 pips and at worst case will be closed at a profit of 10 pips because we have moved our stop from 1.0900 to 1.1010 in order to lock it.
Five days later the EURUSD is trading at 1.1300. We have bought initially at 1.1000. Therefore, the market is up 2.72% since opening the position. We can move our stop to 1.1200 to lock in at least a 1.81% profit.
Finally, a day after reaching 1.1300, the EURUSD corrects to 1.1800. Our stop is triggered at 1.1200 with a profit of 2.72%.
The trailing stop indicator is an overlay moving line that gives us where exactly we must move our stop when following the move. It is based on volatility, thus uses the average true range. The default version uses 13-period ATR and a multiplier of 3. The multiplier can be thought of as an ingredient in determining the position of the new stop.
def atr_trailing_stop(data, atr_column, multiplier, close, where): # adding columns data = adder(data, 1) # atr trailing stop for i in range(len(data)): try: # stop stop = multiplier * data[i, atr_column]
if data[i, close] > data[i - 1, where] and data[i - 1, close] > data[i - 1, where]: data[i, where] = max(data[i - 1, where], data[i, close] - stop)
elif data[i, close] < data[i - 1, where] and data[i - 1, close] < data[i - 1, where]: data[i, where] = min(data[i - 1, where], data[i, close] + stop) elif data[i, close] > data[i - 1, where] and data[i - 1, close] < data[i - 1, where]: data[i, where] = data[i, close] - stop elif data[i, close] < data[i - 1, where] and data[i - 1, close] > data[i - 1, where]: data[i, where] = data[i, close] + stop except ValueError: pass return data
The indicator can also be used to determine changes in the market regime which is very useful for trend-following. It however needs to be optimized in every market.
Trailing stops are indispensable in trend-following but they must be used correctly. In a future article, we will see how to use this indicator to determine the market regime.
If you are also interested by more technical indicators and strategies, then my book might interest you:
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.
One Last Word
I have recently started an NFT collection that aims to support different humanitarian and medical causes. The Society of Light is a set of limited collectibles which will help make the world slightly better as each sale will see a percentage of it sent directly to the charity attributed to the avatar. As I always say, nothing better than a bullet list to outline the benefits of buying these NFT’s:
High-potential gain: By concentrating the remaining sales proceedings on marketing and promoting The Society of Light, I am aiming to maximize their value as much as possible in the secondary market. Remember that trading in the secondary market also means that a portion of royalties will be donated to the same charity.
Art collection and portfolio diversification: Having a collection of avatars that symbolize good deeds is truly satisfying. Investing does not need to only have selfish needs even though there is nothing wrong with investing to make money. But what about investing to make money, help others, and collect art?
Donating to your preferred cause(s): This is a flexible way of allocating different funds to your charities.
A free copy of my book in PDF: Any buyer of any NFT will receive a free copy of my latest book shown in the link of the article.