avatarSofien Kaabar, CFA

Summary

The website content discusses the application of a trailing stop to a moving average strategy in Python, emphasizing risk management in trend following strategies and introducing a new book on the subject.

Abstract

The article delves into the enhancement of trend following strategies by implementing solid risk management rules through the use of trailing stops in conjunction with moving averages. It provides Python code for creating and applying these strategies, including functions for moving averages, trailing stops based on the Average True Range (ATR), and the logic for entering and exiting trades. The author also promotes their new book, which covers advanced trend following indicators and strategies, and encourages readers to join Medium and subscribe to their newsletter for further insights and trading strategies. Additionally, the author mentions their NFT collection aimed at supporting humanitarian and medical causes.

Opinions

  • The author believes in the importance of moving averages as a versatile tool in trading arsenals, confirming and riding trends.
  • A trailing stop is presented as a crucial component in managing risk and locking in profits during trend following.
  • The author emphasizes the value of their new book and the continuously updated code on GitHub, suggesting that these resources are beneficial for traders interested in advanced strategies.
  • The author values reader engagement and learning by doing, encouraging readers to explore and improve upon the strategies provided rather than simply copying them.
  • There is a clear endorsement for joining Medium through the author's referral link and subscribing to their newsletter for additional content and learning opportunities.
  • The author expresses a philanthropic view by creating an NFT collection that supports charitable causes and offers potential financial gains and art collection as incentives for purchasing these NFTs.

Applying a Trailing Stop to a Moving Average Strategy in Python.

How to Apply Basic Risk Management Rules on Trend Following Strategies.

Trend following strategies require solid risk management rules which are hard to create. The aim of trend following is to squeeze out the most of the trend before it eventually ends. Hence, we need to move our stop in the direction of the trend when the market moves in our favor. This article discusses the creation and application of a trailing stop with moving average strategies.

I have just released a new book after the success of the previous book. 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.

Creating the Rules of the Strategy: 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)

Medium is a hub to many interesting reads. I read a lot of articles before I decided to start writing here. Consider joining Medium using my referral link!

Creating the Trailing Stop Indicator

The trailing stop indicator we will be creating is based on the average true range. We have previously discussed this indicator and now we will code a variation of it that transforms it into a trailing stop.

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.

EURUSD hourly values with the trailing stop indicator(13, 3).
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
USDCAD hourly values with the trailing stop indicator(13, 3).

If you are also interested by more technical indicators and strategies, then my book might interest you:

Coding and Analyzing the Results of the Strategy

The strategy is simple as it relies on the principle of a cross between the market price and its moving average. The full trading conditions can be found as follows:

  • Long (Buy) whenever the market surpasses the 200-period moving average and pulls-back to it. The exit will only occur whenever the market breaks the trailing stop indicator.
  • Short (Sell) whenever the market breaks the 200-period moving average and pulls-back to it. The exit will only occur whenever the market surpasses the trailing stop indicator.
Signal chart.
def signal(data, high_price, low_price, close_price, ma_column, buy_column, sell_column):
    
    data = adder(data, 2)
    
    for i in range(len(data)):
        
       if data[i, close_price] > data[i, ma_column] and data[i - 1, close_price] < data[i - 1, ma_column]:
           
           for a in range(i + 1, len(data)):
               
               if data[a, low_price] <= data[a, ma_column] and \
                  data[a, close_price] > data[a, ma_column]:
                   
                   data[a, buy_column] = 1
                   break
               
               elif data[a, close_price] < data[a, ma_column]:
                    break
                
       elif data[i, close_price] < data[i, ma_column] and data[i - 1, close_price] > data[i - 1, ma_column]:
           
           for a in range(i + 1, len(data)):
               
               if data[a, high_price] >= data[a, ma_column] and \
                  data[a, close_price] < data[a, ma_column]:
                   
                   data[a, sell_column] = -1
                   break
               elif data[a, close_price] > data[a, ma_column]:
                    break
                   
    return data
Signal chart.
# With 7 as buy signals columns, 6 as the trailing stop indicator, 9 as the index where to put the buy PnL, 8 as sell signals, and 10 as the index where to put the sell PnL
for i in range(len(my_data)):
    
    if my_data[i, 7] == 1:
        
        for a in range(i + 1, len(my_data)):
            
            if my_data[a, 3] < my_data[a, 6]:
                
                my_data[a, 9] = my_data[a, 3] - my_data[i, 3]
                break
            
            elif my_data[a, 8] == -1:
                
                my_data[a, 9] = my_data[a, 3] - my_data[i, 3]
                
                break
if my_data[i, 8] == -1:
        
        for a in range(i + 1, len(my_data)):
            
            if my_data[a, 3] > my_data[a, 6]:
                
                my_data[a, 10] = my_data[i, 3] - my_data[a, 3]
                break
            
            elif my_data[a, 7] == 1:
                
                my_data[a, 10] = my_data[i, 3] - my_data[a, 3]
                
                break
Signal chart.

If you want to see more articles relating to trading strategies, consider subscribing to my DAILY Newsletter (A Free Plan is Available) via the below link. It features my Medium articles, more trading strategies, coding lessons related to research and analysis, also, subscribers get a free PDF copy of my first book. You can expect 5–7 articles per week with your paid subscription and 1–2 articles per week with the free plan. This would help me continue sharing my research. Thank 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.

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.
Click here to buy Ahmed to support his cause against human-trafficking.
Finance
Trading
Investing
Cryptocurrency
Machine Learning
Recommended from ReadMedium