Technical indicators Average True Range (ATR)


Background

The average true range (ATR) is a technical analysis indicator that measures market volatility by decomposing the entire range of an asset price for that period.

The true range indicator is taken as the greatest of the following: current high less the current low; the absolute value of the current high less the previous close; and the absolute value of the current low less the previous close. The ATR is then a moving average, generally using 14 days, of the true ranges.

For a higher ATR, it indicates the stock is experiencing a high level of volatility, in contrast that a lower ATR indicates lower volatility for the period evaluated. Therefore the ATR may be used to decide when to enter and exit trades and is a useful tool to add to a trading system.

Chuck LeBeau developed a popular technique using ATR to make exit decision called “chandelier exit”, it places a trailing stop under the highest high the stock has reached since you entered the trade.

The main limitations of using ATR as an indicator are it is a subjective measure therefore it is open to interpretation, which means a single ATR value could not tell you with any certainty that a trend is about to reverse or not. It needs to be compared against earlier readings to review a trend’s strength or weakness. Another limitation is the ATR only measures volatility and not the direction of an asset’s price.

A normal ATR is 1.18, if it is much higher or lower than this alue, it might indicate that further investigation is required.

Python Implementation

import pandas as pd
import sqlite3

# load S&P500 data from stored database
sp500_db = sqlite3.connect(database="sp500_data.sqlite")

df = pd.read_sql_query(sql="SELECT * FROM SP500",
                       con=sp500_db,
                       parse_dates={"Date"})
df.head()

level_0indexDateTickerAdj CloseCloseHighLowOpenVolumegarmin_klass_volrsi
0002014-04-29A35.04953438.12589338.30472237.17453438.1187404688612.0-0.002274NaN
1112014-04-29AAL33.47674235.50999835.65000234.97000135.2000018994200.0-0.000788NaN
2222014-04-29AAPL18.63333321.15464221.28500021.05392821.205000337377600.0-0.006397NaN
3332014-04-29ABBV34.03498551.36999951.52999950.75999850.9399995601300.0-0.062705NaN
4442014-04-29ABT31.83151838.54000138.72000138.25999838.3699994415600.0-0.013411NaN
# remove irrelevant columns
df = df.drop('level_0', axis=1)
df = df.drop('index', axis=1)
df.head()

DateTickerAdj CloseCloseHighLowOpenVolumegarmin_klass_volrsi
02014-04-29A35.04953438.12589338.30472237.17453438.1187404688612.0-0.002274NaN
12014-04-29AAL33.47674235.50999835.65000234.97000135.2000018994200.0-0.000788NaN
22014-04-29AAPL18.63333321.15464221.28500021.05392821.205000337377600.0-0.006397NaN
32014-04-29ABBV34.03498551.36999951.52999950.75999850.9399995601300.0-0.062705NaN
42014-04-29ABT31.83151838.54000138.72000138.25999838.3699994415600.0-0.013411NaN
import pandas_ta

# calculate ATR
def compute_atr(stock_data):
    atr = pandas_ta.atr(high=stock_data['High'],
                        low=stock_data['Low'],
                        close=stock_data['Close'],
                        length=14)
    return atr.sub(atr.mean()).div(atr.std())

df = df.set_index(['Date','Ticker'])
df['atr'] = df.groupby(level=1, group_keys=False).apply(compute_atr)
df.tail()

Adj CloseCloseHighLowOpenVolumegarmin_klass_volrsiatr
DateTicker
2024-04-25XYL130.610001130.610001131.199997128.100006129.619995963600.00.00026461.4827450.665306
YUM141.559998141.559998142.169998140.389999141.9799961693100.00.00007665.6681630.322566
ZBH119.750000119.750000121.349998118.769997120.7099991078800.00.00020635.636078-0.350196
ZBRA292.529999292.529999293.290009271.630005274.359985674700.00.00135556.1722720.500501
ZTS153.360001153.360001153.589996150.039993150.9700014567200.00.00017839.8096191.374957
# update the database
df = df.reset_index()
df.to_sql(name="SP500",
          con=sp500_db,
          if_exists="replace",
          index=True)
sp500_db.close()
import matplotlib.pyplot as plt
from datetime import datetime

# select AAPL
aapl = df[df['Ticker'] == 'AAPL'].set_index('Date')

# only select the data from 2022-01-01
aapl_new = aapl[aapl.index > datetime(2022,1,1)]

# set the theme of the chart
plt.style.use('fivethirtyeight')
plt.rcParams['figure.figsize'] = (20,16)

# create two charts on the same figure
ax1 = plt.subplot2grid((10,1),(0,0), rowspan=4, colspan=1)
ax2 = plt.subplot2grid((10,1),(5,0), rowspan=4, colspan=1)

# plot the closing price on the first chart
ax1.plot(aapl_new['Adj Close'])
ax1.set_title('AAPL Adjust Close Price')

# plot the RSI on the second chart
ax2.plot(aapl_new['atr'], color='orange', linewidth=1)
ax2.set_title('AAPL Average True Range')

# add a horizontal line, signaling the normal ATR
ax2.axhline(1.8, linestyle='--', linewidth=1.5, color='green')
<matplotlib.lines.Line2D at 0x1ce20e36990>

AAPL Average True Range

Reference

Average True Range (ATR) Formula, What It Means, and How to Use It by Adam Hayes on Investopedia


Author: wenvenn
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source wenvenn !