Algorithmic Trading & Indicators
Intermediate
Calculate Wilder's ADX (+DI / -DI) Trend Strength Filter in Python
Filter out sideways market whipsaws in Python by computing Wilder's Average Directional Index (ADX), +DI, and -DI using vectorized Pandas.
#pandas#numpy
Problem Statement
Moving average and Supertrend strategies bleed capital in choppy, range-bound markets. Adding an ADX > 25 regime filter ensures entries only trigger during strong directional trends.
Formula / Core Logic
+DM = High_t - High_{t-1}, -DM = Low_{t-1} - Low_t
DX = 100 * |(+DI - -DI)| / (+DI + -DI)
ADX = Wilder_RMA(DX, 14)
Installation
pip install pandas numpy
adx-average-directional-index-trend-filter-python.py
import pandas as pd
import numpy as np
def calculate_adx(df, period=14):
df = df.copy()
up = df['High'].diff()
down = -df['Low'].diff()
plus_dm = np.where((up > down) & (up > 0), up, 0.0)
minus_dm = np.where((down > up) & (down > 0), down, 0.0)
tr = pd.concat([df['High'] - df['Low'], (df['High'] - df['Close'].shift(1)).abs(), (df['Low'] - df['Close'].shift(1)).abs()], axis=1).max(axis=1)
atr = tr.ewm(alpha=1/period, adjust=False).mean()
plus_di = 100 * (pd.Series(plus_dm, index=df.index).ewm(alpha=1/period, adjust=False).mean() / atr)
minus_di = 100 * (pd.Series(minus_dm, index=df.index).ewm(alpha=1/period, adjust=False).mean() / atr)
dx = 100 * ((plus_di - minus_di).abs() / (plus_di + minus_di))
df['ADX'] = dx.ewm(alpha=1/period, adjust=False).mean()
df['Trending_Regime'] = np.where(df['ADX'] > 25, 1, 0)
return df
Get the Complete 100+ Python Quant & Automation Bundle
Instant lifetime access to all production-ready scripts, valuation models, and trading bots ($19).
Buy Full Bundle on Gumroad ($19) →Frequently Asked Questions
Q: Does ADX indicate bullish or bearish direction?
No, ADX measures trend strength regardless of direction. Compare +DI vs -DI to determine bullish or bearish dominance.