There are a lot of technical indicators out there to be used for research or trading purposes, but one common similarity among them is that they all serve only one specific task. For example, RSI can be used to identify overbought and oversold levels in a market, the Choppiness Index can be used to observe market volatility, and so on. But today we are going to explore an indicator that can be used for either acknowledging the market trend or market volatility. Behold, the Aroon Indicator! In this article, we will discuss what the Aroon Indicator is all about, its usage and calculation, and how a trading strategy based on it can be built using Python. Without further ado, let’s hop into the article.

Register & Get Data

Aroon Indicator

Founded by Tushar Chande in 1995, the Aroon indicator is a momentum oscillator that is specifically designed to track a market’s trend and how strong the trend is. This indicator is widely used by traders to identify a new trend in the market and make potential entry and exit points accordingly. Being an oscillator, the values of the Aroon indicator bound between 0 to 100.

The Aroon indicator is composed of two components: The Aroon up line and the Aroon down line. The Aroon up line measures the strength of the uptrend in a market and similarly, the Aroon down line measures the strength of the downtrend in a market. The traditional setting for the Aroon indicator is either 14 for short-term or 25 for long-term as the lookback period. In this article, we will be using 25 as the setting since we will be dealing with a year and a half of data. The formula to calculate these two lines with 25 as the lookback period are as follows:

AROON UP = [ 25 - PERIODS SINCE 25 PERIOD HIGH ] / 25 * [ 100 ]
AROON DOWN = [ 25 - PERIODS SINCE 25 PERIOD LOW ] / 25 * [ 100 ]

The Aroon up line is calculated by first determining how long has it been since the stock has reached a new high over a 25-day timeframe, then, subtract and divide this value by 25 and finally multiply it by 100. This applies to calculating the Aroon down line too but here we are determining the number of days since a new low has occurred instead of observing new highs.

The main concept of the Aroon indicator is that the market tends to attain more new highs during a strong uptrend, and similarly, the market is bound to reach more new lows during a sturdy downtrend. With that said, let’s explore how the Aroon indicator can be used to build a trading strategy.

Aroon Trading Strategies

To my knowledge, the Aroon Indicator can be used in two ways to build a trading strategy. First is the crossover trading strategy. This strategy reveals a buy signal if the Aroon up line crosses from below to above the Aroon down line, similarly, a sell signal is revealed if the Aroon up line moves from above to below the Aroon down line. The crossover strategy can be represented as follows:

IF P.UP LINE < P.DOWN LINE AND C.UP LINE > C.DOWN LINE --> BUY
IF P.UP LINE > P.DOWN LINE AND C.UP LINE < C.DOWN LINE --> SELL

The second strategy is constructing a higher and lower threshold which represents a buy signal if the Aroon up line has a reading of and above 70 and parallelly, the Aroon down line has a reading of and below 30. Likewise, when the Aroon up line has a reading of or below 30 and the reading of Aroon down line is observed to be at or above 70, a sell signal is revealed. This strategy can be represented as follows:

IF AROON UP LINE => 70 AND AROON DOWN LINE <= 30 --> BUY SIGNAL
IF AROON UP LINE <= 30 AND AROON DOWN LINE >= 70 --> SELL SIGNAL

Both trading strategies are highly effective and can be used to trade any stock. In this article, we are going to implement the second trading strategy of constructing thresholds just to make things simple. Now that we have an idea of what the Aroon indicator is all about, its calculation and usage. Let’s proceed to the programming part where we will build the second Aroon indicator strategy from scratch in Python and backtest it on Tesla. 

Before moving on, a disclaimer: This article’s sole purpose is to educate people and must be considered as an information piece but not as investment advice.

Implementation in Python

The coding part is classified into various steps as follows:

1. Importing Packages
2. API KEY Activation
3. Extracting Historical Data
4. Extracting the Aroon Indicator values
5. Aroon Indicator Plot
6. Creating the Trading Strategy
7. Plotting the Trading Lists
8. Creating our Position
9. Backtesting
10. SPY ETF Comparison

We will be following the order mentioned in the above list and buckle up your seat belts to follow every upcoming coding part.

Step-1: Importing Packages

Importing the required packages into the Python environment is a non-skippable step. The primary packages are going to be eodhd for extracting historical stock data, Pandas for data formatting and manipulations, NumPy to work with arrays and for complex functions, and Matplotlib for plotting purposes. The secondary packages are going to be Math for mathematical functions and Termcolor for font customization (optional).

Python Implementation:

# IMPORTING PACKAGES

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from termcolor import colored as cl
from math import floor
from eodhd import APIClient

plt.rcParams['figure.figsize'] = (20,10)
plt.style.use('fivethirtyeight')

With the required packages imported into Python, we can proceed to fetch historical data for Tesla using EODHD’s eodhd Python library. Also, if you haven’t installed any of the imported packages, make sure to do so using the pip command in your terminal.

Step-2: API Key Activation

It is essential to register the EODHD API key with the package in order to use its functions. If you don’t have an EODHD API key, firstly, head over to their website, then, finish the registration process to create an EODHD account, and finally, navigate to the ‘Settings’ page where you could find your secret EODHD API key. It is important to ensure that this secret API key is not revealed to anyone. You can activate the API key by following this code:

api_key = '<YOUR API KEY>'
client = APIClient(api_key)

The code is pretty simple. In the first line, we are storing the secret EODHD API key into the api_key and then in the second line, we are using the APIClient class provided by the eodhd package to activate the API key and stored the response in the client variable.

Note that you need to replace <YOUR API KEY> with your secret EODHD API key. Apart from directly storing the API key with text, there are other ways for better security such as utilizing environmental variables, and so on.

Register & Get Data

Step-3: Extracting Historical Data

Before heading into the extraction part, it is first essential to have some background about historical or end-of-day data. In a nutshell, historical data consists of information accumulated over a period of time. It helps in identifying patterns and trends in the data. It also assists in studying market behavior. Now, you can easily extract the historical data of any tradeable assets using the eod package by following this code:

# EXTRACTING HISTORICAL DATA

def extract_historical_data(ticker, start_date):
    json_resp = client.get_eod_historical_stock_market_data(symbol = ticker, period = 'd', from_date = start_date, order = 'a')
    df = pd.DataFrame(json_resp)
    df = df.set_index('date')
    df.index = pd.to_datetime(df.index)
    return df

tsla = extract_historical_data('TSLA', '2020-01-01')
tsla.tail()

In the above code, we are using the get_eod_historical_stock_market_data function provided by the eodhd package to extract the split-adjusted historical stock data of Tesla. The function consists of the following parameters:

  • the ticker parameter where the symbol of the stock we are interested in extracting the data should be mentioned
  • the period refers to the time interval between each data point (one-day interval in our case).
  • the from_date and to_date parameters which indicate the starting and ending date of the data respectively. The format of the input should be “YYYY-MM-DD”
  • the order parameter which is an optional parameter that can be used to order the dataframe either in ascending (a) or descending (d). It is ordered based on the dates.

After extracting the historical data, we are performing some data-wrangling processes to clean and format the data. The final dataframe looks like this:

Step-4: Extracting the Aroon Indicator values

In this step, we are going to calculate the values of the Aroon indicator using some majorly used functions provided by the Pandas package.

Python Implementation:

# AROON INDICATOR CALCULATION

def get_aroon(data, lb):

    df = data.copy()
    df['up'] = 100 * df.high.rolling(lb + 1).apply(lambda x: x.argmax()) / lb
    df['dn'] = 100 * df.low.rolling(lb + 1).apply(lambda x: x.argmin()) / lb

    return df['up'], df['dn'] 

tsla['aroon_up'], tsla['aroon_down'] = get_aroon(tsla, 25)
tsla = tsla.dropna()
tsla.tail()

Output:

Code Explanation: Firstly, we are defining a function named ‘get_aroon’ which takes the stock data (‘data’), and the lookback period for the indicator (‘lb’). Inside the function, we are first creating a copy of the given dataframe and stored it in the ‘df’ variable. Then, we are creating two new columns inside the dataframe to store the two components of the Aroon indicator. To calculate the values, we are using some commonly utilized Pandas functions like ‘rolling’, ‘apply’, ‘argmax’, and ‘argmin’. Finally, we are calling the created function to attain the Aroon indicator values of Tesla.

Step-5: Aroon Indicator Plot

In this step, we are going to plot the extracted Aroon indicator values of Tesla to make more sense of it. The main aim of this part is not on the coding section but instead to observe the plot to gain a solid understanding of the Aroon indicator.

Python Implementation:

ax1 = plt.subplot2grid((11,1), (0,0), rowspan = 5, colspan = 1)
ax2 = plt.subplot2grid((11,1), (6,0), rowspan = 4, colspan = 1)
ax1.plot(tsla['close'], linewidth = 2.5, color = '#2196f3')
ax1.set_title('TSLA CLOSE PRICES')
ax2.plot(tsla['aroon_up'], color = '#26a69a', linewidth = 2, label = 'AROON UP')
ax2.plot(tsla['aroon_down'], color = '#ef5350', linewidth = 2, label = 'AROON DOWN')
ax2.legend()
ax2.set_title('TSLA AROON 25')
plt.show()

Output:

The above chart is divided into two panels: the above panel comprising the plot of the closing prices of Tesla and the lower panel with both the Aroon up and down lines. I mentioned that the Aroon indicator is not only useful for identifying trends but also for identifying ranging markets. To identify ranging market periods, we have to carefully observe the up and down lines. Whenever the space between the two lines is less, then the market is said to be ranging. Similarly, trending markets are observed when the space between the two lines is wider.

You could also see that whenever the market seems to be rising in a strong uptrend, the readings of the Aroon up line also rises, parallelly, the readings of the Aroon down line decreases. Likewise, during a period of a strong downtrend, the readings of the Aroon down line crosses above the Aroon up line. From this, we could say that both the lines are inversely proportional to each other.

Sometimes, it is observable that the Aroon up line stays at 100 for a while. This represents that market is in a very strong uptrend creating new highs. This applies to the Aroon down line too. The market is said to be highly bearish creating new lows when the Aroon down line stays at 100 for a while. This feature of the Aroon indicator to identify very strong uptrends and downtrends comes in handy for traders in the real-world market.

Step-6: Creating the trading strategy

In this step, we are going to implement the discussed Aroon Indicator trading strategy in Python.

Python Implementation:

def implement_aroon_strategy(prices, up, down):
    buy_price = []
    sell_price = []
    aroon_signal = []
    signal = 0
    
    for i in range(len(prices)):
        if up[i] >= 70 and down[i] <= 30:
            if signal != 1:
                buy_price.append(prices[i])
                sell_price.append(np.nan)
                signal = 1
                aroon_signal.append(signal)
            else:
                buy_price.append(np.nan)
                sell_price.append(np.nan)
                aroon_signal.append(0)
        elif up[i] <= 30 and down[i] >= 70:
            if signal != -1:
                buy_price.append(np.nan)
                sell_price.append(prices[i])
                signal = -1
                aroon_signal.append(signal)
            else:
                buy_price.append(np.nan)
                sell_price.append(np.nan)
                aroon_signal.append(0)
        else:
            buy_price.append(np.nan)
            sell_price.append(np.nan)
            aroon_signal.append(0)
            
    return buy_price, sell_price, aroon_signal

buy_price, sell_price, aroon_signal = implement_aroon_strategy(tsla['close'], tsla['aroon_up'], tsla['aroon_down'])

Code Explanation: First, we are defining a function named ‘implement_aroon_strategy’ which takes the stock prices (‘price), and the lines of the Aroon indicator (‘up’, ‘down’) as parameters.

Inside the function, we are creating three empty lists (buy_price, sell_price, and aroon_signal) in which the values will be appended while creating the trading strategy.

After that, we are implementing the trading strategy through a for-loop. Inside the for-loop, we are passing certain conditions, and if the conditions are satisfied, the respective values will be appended to the empty lists. If the condition to buy the stock gets satisfied, the buying price will be appended to the ‘buy_price’ list, and the signal value will be appended as 1 representing to buy the stock. Similarly, if the condition to sell the stock gets satisfied, the selling price will be appended to the ‘sell_price’ list, and the signal value will be appended as -1 representing to sell the stock.

Finally, we are returning the lists appended with values. Then, we are calling the created function and stored the values into their respective variables. The list doesn’t make any sense unless we plot the values. So, let’s plot the values of the created trading lists.

Step-7: Plotting the trading signals

In this step, we are going to plot the created trading lists to make sense of them.

Python Implementation:

ax1 = plt.subplot2grid((11,1), (0,0), rowspan = 5, colspan = 1)
ax2 = plt.subplot2grid((11,1), (6,0), rowspan = 4, colspan = 1)
ax1.plot(tsla['close'], linewidth = 2.5, color = '#2196f3')
ax1.plot(tsla.index, buy_price, marker = '^', color = '#26a69a', markersize = 12)
ax1.plot(tsla.index, sell_price, marker = 'v', color = '#ef5350', markersize = 12)
ax1.set_title('TSLA CLOSE PRICES')
ax2.plot(tsla['aroon_up'], color = '#26a69a', linewidth = 2, label = 'AROON UP')
ax2.plot(tsla['aroon_down'], color = '#ef5350', linewidth = 2, label = 'AROON DOWN')
ax2.legend()
ax2.set_title('TSLA AROON 25')
plt.show()

Output:

Code Explanation: We are plotting the Aroon indicator components along with the buy and sell signals generated by the trading strategy. We can observe that whenever the Aroon up line has a reading of and above 70 and the Aroon down line has a reading of and below 30, a green-colored buy signal is plotted in the chart. Similarly, whenever the Aroon up line has a reading of and below 30 and the Aroon down line has a reading of and above 70, a red-colored sell signal is plotted in the chart.

Step-8: Creating our Position

In this step, we are going to create a list that indicates 1 if we hold the stock or 0 if we don’t own or hold the stock.

Python Implementation:

position = []
for i in range(len(aroon_signal)):
    if aroon_signal[i] > 1:
        position.append(0)
    else:
        position.append(1)
        
for i in range(len(tsla['close'])):
    if aroon_signal[i] == 1:
        position[i] = 1
    elif aroon_signal[i] == -1:
        position[i] = 0
    else:
        position[i] = position[i-1]
        
aroon_up = tsla['aroon_up']
aroon_down = tsla['aroon_down']
close_price = tsla['close']
aroon_signal = pd.DataFrame(aroon_signal).rename(columns = {0:'aroon_signal'}).set_index(tsla.index)
position = pd.DataFrame(position).rename(columns = {0:'aroon_position'}).set_index(tsla.index)

frames = [close_price, aroon_up, aroon_down, aroon_signal, position]
strategy = pd.concat(frames, join = 'inner', axis = 1)

strategy

Output:

Code Explanation: First, we are creating an empty list named ‘position’. We are passing two for-loops, one is to generate values for the ‘position’ list to just match the length of the ‘signal’ list. The other for-loop is the one we are using to generate actual position values. Inside the second for-loop, we are iterating over the values of the ‘signal’ list, and the values of the ‘position’ list get appended concerning which condition gets satisfied. The value of the position remains 1 if we hold the stock or remains 0 if we sold or don’t own the stock. Finally, we are doing some data manipulations to combine all the created lists into one dataframe.

From the output being shown, we can see that in the first row our position in the stock has remained 1 (since there isn’t any change in the Aroon indicator signal) but our position suddenly turned to -1 as we sold the stock when the Aroon indicator trading signal represents a sell signal (-1). Our position will remain 0 until some changes in the trading signal occur. Now it’s time to implement some backtesting process!

Step-9: Backtesting

Before moving on, it is essential to know what backtesting is. Backtesting is the process of seeing how well our trading strategy has performed on the given stock data. In our case, we are going to implement a backtesting process for our Aroon indicator trading strategy over the Tesla stock data.

Python Implementation:

tsla_ret = pd.DataFrame(np.diff(tsla['close'])).rename(columns = {0:'returns'})
aroon_strategy_ret = []

for i in range(len(tsla_ret)):
    returns = tsla_ret['returns'][i]*strategy['aroon_position'][i]
    aroon_strategy_ret.append(returns)
    
aroon_strategy_ret_df = pd.DataFrame(aroon_strategy_ret).rename(columns = {0:'aroon_returns'})
investment_value = 100000
aroon_investment_ret = []

for i in range(len(aroon_strategy_ret_df['aroon_returns'])):
    number_of_stocks = floor(investment_value/tsla['close'][i])
    returns = number_of_stocks*aroon_strategy_ret_df['aroon_returns'][i]
    aroon_investment_ret.append(returns)

aroon_investment_ret_df = pd.DataFrame(aroon_investment_ret).rename(columns = {0:'investment_returns'})
total_investment_ret = round(sum(aroon_investment_ret_df['investment_returns']), 2)
profit_percentage = floor((total_investment_ret/investment_value)*100)
print(cl('Profit gained from the Aroon strategy by investing $100k in TSLA : {}'.format(total_investment_ret), attrs = ['bold']))
print(cl('Profit percentage of the Aroon strategy : {}%'.format(profit_percentage), attrs = ['bold']))

Output:

Profit gained from the Aroon strategy by investing $100k in TSLA : 183148.71
Profit percentage of the Aroon strategy : 183%

Code Explanation: First, we are calculating the returns of the Tesla stock using the ‘diff’ function provided by the NumPy package and we have stored it as a dataframe into the ‘tsla_ret’ variable. Next, we are passing a for-loop to iterate over the values of the ‘tsla_ret’ variable to calculate the returns we gained from our Aroon indicator trading strategy, and these returns values are appended to the ‘aroon_strategy_ret’ list. Next, we are converting the ‘aroon_strategy_ret’ list into a dataframe and stored it into the ‘aroon_strategy_ret_df’ variable.

Next comes the backtesting process. We are going to backtest our strategy by investing a hundred thousand USD into our trading strategy. So first, we are storing the amount of investment into the ‘investment_value’ variable. After that, we are calculating the number of Tesla stocks we can buy using the investment amount. You can notice that I’ve used the ‘floor’ function provided by the Math package because, while dividing the investment amount by the closing price of Tesla stock, it spits out an output with decimal numbers. The number of stocks should be an integer but not a decimal number. Using the ‘floor’ function, we can cut out the decimals. Remember that the ‘floor’ function is way more complex than the ‘round’ function. Then, we are passing a for-loop to find the investment returns followed by some data manipulations tasks.

Finally, we are printing the total return we got by investing a hundred thousand into our trading strategy and it is revealed that we have made an approximate profit of one hundred and eighty-three thousand USD in three years. That’s not bad at all! Now, let’s compare our returns with SPY ETF (an ETF designed to track the S&P 500 stock market index) returns.

Step-10: SPY ETF Comparison

This step is optional but it is highly recommended as we can get an idea of how well our trading strategy performs against a benchmark (SPY ETF). In this step, we are going to extract the data of the SPY ETF using the ‘get_historical_data’ function we created and compare the returns we get from the SPY ETF with our Aroon indicator strategy returns on Tesla.

Python Implementation:

def get_benchmark(start_date, investment_value):
    spy = get_historical_data('SPY', start_date)['close']
    benchmark = pd.DataFrame(np.diff(spy)).rename(columns = {0:'benchmark_returns'})
    
    investment_value = investment_value
    benchmark_investment_ret = []
    
    for i in range(len(benchmark['benchmark_returns'])):
        number_of_stocks = floor(investment_value/spy[i])
        returns = number_of_stocks*benchmark['benchmark_returns'][i]
        benchmark_investment_ret.append(returns)

    benchmark_investment_ret_df = pd.DataFrame(benchmark_investment_ret).rename(columns = {0:'investment_returns'})
    return benchmark_investment_ret_df

benchmark = get_benchmark('2020-01-01', 100000)

investment_value = 100000
total_benchmark_investment_ret = round(sum(benchmark['investment_returns']), 2)
benchmark_profit_percentage = floor((total_benchmark_investment_ret/investment_value)*100)
print(cl('Benchmark profit by investing $100k : {}'.format(total_benchmark_investment_ret), attrs = ['bold']))
print(cl('Benchmark Profit percentage : {}%'.format(benchmark_profit_percentage), attrs = ['bold']))
print(cl('Aroon Strategy profit is {}% higher than the Benchmark Profit'.format(profit_percentage - benchmark_profit_percentage), attrs = ['bold']))

Output:

Benchmark profit by investing $100k : 38035.26
Benchmark Profit percentage : 38%
Aroon Strategy profit is 145% higher than the Benchmark Profit

Code Explanation: The code used in this step is almost similar to the one used in the previous backtesting step but, instead of investing in Tesla, we are investing in SPY ETF by not implementing any trading strategies. From the output, we can see that our Aroon indicator trading strategy has outperformed the SPY ETF by 145%. That’s great!

Register & Get Data

Final Thoughts!

After a long process of crushing both the theory and coding part, we have successfully learned what the Aroon indicator is all about and how to build a trading strategy based on it. The Aroon indicator has remained my personal favorite since it helps in getting two jobs done at a time (identify trends, and volatility), and it’s unique too. Even though we have surpassed the returns of SPY ETF, there are still spaces to improve the work:

  • Strategy optimization: In this article, we have used one of the most basic trading strategies based on the Aroon indicator, and this strategy can be used just for the purpose of understanding or gaining intuitions about the indicator but it’s not possible to expect visible returns in the real-world market. So, I highly recommend you discover other advanced Aroon-based trading strategies like the breakout strategy, pullback strategy, and so on. Apart from just discovering, backtest the strategy with as many stocks as possible as the results might vary from one to another.
  • Risk Management: When it comes to either trading or long-term investing, this topic is a must to be considered. As long as you hold a tight grasp of this concept, you hold a strong edge in the market. We didn’t cover this topic as the sole purpose of this article is to just understand and brainstorm about the underlying idea of the Aroon indicator but not to make profits. But, it is highly recommended to study in and out about this subject before entering the crazy real-world market.

With that said, we have come to the end of the article. Hope you learned something useful from this article.