Developed by the legendary technical analyst J. Welles Wilder Jr., the Average True Range (ATR) is a cornerstone indicator for measuring market volatility. A key characteristic of ATR is that it is not directional; it quantifies the degree of price movement or “choppiness” but does not indicate the trend’s direction.
The ATR calculation is based on the “True Range” (TR). The True Range aims to capture the full extent of price movement for a given period, including any price gaps that might occur when the market is closed (e.g., overnight or over a weekend).
For each period, the True Range (TR) is defined as the greatest of
the following three values: 1. The difference between the current
period’s High and its Low: 2. The absolute value of the difference between
the current period’s High and the previous period’s Close:
3. The absolute value of the difference between
the current period’s Low and the previous period’s Close:
So, for each period:
Once the True Range is calculated for each period, the Average True Range (ATR) is typically an N-period smoothed moving average of these TR values. J. Welles Wilder Jr. used a specific smoothing method (a form of exponential moving average) for his indicators, and this is generally what ATR calculations (including TA-Lib’s) employ. The common default period (N) for ATR is 14 periods.
Usage: ATR is a versatile tool used by traders and analysts in various aspects of trading:
Entry Price - (Multiplier × ATR)Entry Price + (Multiplier × ATR) The
Multiplier is typically a value like 1.5, 2, 2.5, or 3,
chosen based on the trader’s risk tolerance and the asset’s
characteristics. This method helps prevent stops from being too close in
volatile markets (risking premature exit) or too wide in calm markets
(risking excessive loss).TA-Lib Function: The Technical Analysis Library (TA-Lib) provides a function to calculate ATR:
talib.ATR(high_prices, low_prices, close_prices, timeperiod=14)
high_prices: An array or series of high prices.low_prices: An array or series of low prices.close_prices: An array or series of closing
prices.timeperiod: The lookback period for the ATR calculation
(default is 14). TA-Lib’s ATR uses Wilder’s smoothing method.Code Example (Calculation & Plot with yfinance Data):
The following Python code demonstrates how to fetch HLC data using
yfinance, calculate the ATR, and plot the price alongside
the ATR indicator.
import yfinance as yf
import talib
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# --- 1. Data Fetching using yfinance ---
ticker_symbol = "SPY" # Example: SPDR S&P 500 ETF Trust
# Fetching a bit more data initially to ensure enough for indicator calculation start
data_start_date = "2022-11-01" # Ensure enough data for lookback period
plot_start_date = "2023-01-01" # Start plotting from here
data_end_date = "2024-05-01"
try:
data = yf.download(ticker_symbol, start=data_start_date, end=data_end_date, auto_adjust=False, progress=False)
if isinstance(data.columns, pd.MultiIndex) and data.columns.nlevels > 1: # Droplevel based on user history
data.columns = data.columns.droplevel(level=1)
except Exception as e:
print(f"Error downloading data for {ticker_symbol}: {e}")
data = pd.DataFrame() # Ensure data is an empty DataFrame on error
if data.empty or not all(col in data.columns for col in ['High', 'Low', 'Close']) or \
any(data[col].isnull().all() for col in ['High', 'Low', 'Close']):
print(f"Insufficient HLC data found for {ticker_symbol}. Exiting.")
else:
# Prepare data: ensure no NaNs in HLC for the period used by TA-Lib
hlc_data = data[['High', 'Low', 'Close']].dropna()
high_prices = hlc_data['High']
low_prices = hlc_data['Low']
close_prices_for_atr = hlc_data['Close'] # Name distinct from plotting close prices
# --- 2. Average True Range (ATR) Calculation ---
time_period_atr = 14 # Standard period for ATR
# ATR needs HLC data and sufficient lookback period for smoothing.
# TA-Lib will output NaNs for the initial 'timeperiod' entries.
if len(close_prices_for_atr) > time_period_atr:
atr_values = talib.ATR(
high_prices, low_prices, close_prices_for_atr,
timeperiod=time_period_atr
)
indicator_name = f"ATR({time_period_atr})"
print(f"\n--- {indicator_name} - Average True Range for {ticker_symbol} ---")
valid_atr = atr_values[~np.isnan(atr_values)]
if len(valid_atr) >= 5:
print(f"Output {indicator_name} (last 5 valid): {valid_atr[-5:].round(2)}")
elif len(valid_atr) > 0:
print(f"Output {indicator_name} (all valid): {valid_atr.round(2)}")
else:
print(f"Output {indicator_name}: No valid ATR values calculated (all NaNs).")
# Filter data for the desired plotting period
atr_series = pd.Series(atr_values, index=hlc_data.index)
plot_hlc_data = hlc_data[hlc_data.index >= plot_start_date]
plot_atr_values = atr_series[plot_hlc_data.index]
plot_date_index = plot_hlc_data.index
plot_close_prices = plot_hlc_data['Close']
# --- 3. Plotting ---
if not plot_date_index.empty:
fig, axes = plt.subplots(2, 1, figsize=(14, 10), sharex=True,
gridspec_kw={'height_ratios': [3, 1]})
# Plot Price (using 'Close' from the plotting data slice)
axes[0].plot(plot_date_index, plot_close_prices, label=f'{ticker_symbol} Close Price', color='blue')
axes[0].set_title(f'{ticker_symbol} Price and {indicator_name}')
axes[0].set_ylabel('Price')
axes[0].legend(loc='upper left')
axes[0].grid(True)
# Plot Average True Range
axes[1].plot(plot_date_index, plot_atr_values, label=indicator_name, color='brown')
axes[1].set_ylabel('ATR Value')
axes[1].set_xlabel('Date')
axes[1].legend(loc='upper left')
axes[1].grid(True)
plt.tight_layout()
plt.show()
else:
print(f"No data available for the plotting period starting {plot_start_date}.")
else:
print(f"\nSkipping ATR plot for {ticker_symbol}: Insufficient data (need > {time_period_atr} points after cleaning).")
if not hlc_data.empty:
print(f"Cleaned data available for {len(hlc_data)} periods. ATR period is {time_period_atr}.")Explanation of the Code:
yfinance
for data, talib for ATR, numpy,
matplotlib.pyplot for plotting, and
pandas.yf.download() retrieves High, Low, and Close (HLC)
data. Your preference for auto_adjust=False and
droplevel is incorporated. Basic error handling is
added.dropna() on the selected columns to ensure clean input for
TA-Lib.time_period_atr is set (commonly 14).if len(close_prices_for_atr) > time_period_atr: ensures
sufficient data. TA-Lib’s ATR will produce NaN values for
the initial timeperiod due to its smoothing
calculation.talib.ATR() computes the ATR values.plot_start_date for a clearer chart if a longer history
was fetched. The ATR numpy array is converted to a Pandas Series with
the correct index for this alignment.plt.subplots(2, 1, ...) creates two stacked subplots:
one for price and one for ATR.plt.tight_layout() adjusts subplot spacing.plt.show() displays the generated chart.By providing a clear measure of an asset’s typical price range, the ATR empowers traders to make more informed decisions regarding risk management, position sizing, and strategy selection in varying market conditions.