# Kalman-ADX-MA TrendChop Detection Using the Difference Between DI+ and DI-
# by whoDAT
# 3/2026
# 1. Smooths high, low, and close data with a Kalman
# 2. Determines DI+ and DI- with a Wilders MA.
# 3. Determines the difference between DI+ and DI-
# 4. Does another moving average on the difference to smooth the result.
# 5. Determines if that smoothed difference exceeds a level that indicates Chop/Trend switching. Trends are larger than then switch level.
# 6. Plots and cloud (indicating trending area.)
declare lower;
# Kalman-Smoothed +DI and -DI
input agg = AggregationPeriod.FOUR_HOURS;
input gain = 0.5;
input adxLength = 14;
# --- Fetch Data (Top-Down Flow) ---
def aggClose = close(period = agg);
def aggHigh = high(period = agg);
def aggLow = low(period = agg);
# --- Kalman Filter Initialization ---
# Formula: Value = Prior + Gain * (Current - Prior)
def kClose = CompoundValue(1, kClose[1] + (gain * (aggClose - kClose[1])), aggClose);
def kHigh = CompoundValue(1, kHigh[1] + (gain * (aggHigh - kHigh[1])), aggHigh);
def kLow = CompoundValue(1, kLow[1] + (gain * (aggLow - kLow[1])), aggLow);
# --- ADX Directional Movement Logic ---
def hiDiff = kHigh - kHigh[1];
def loDiff = kLow[1] - kLow;
# True Range based on Kalman-smoothed inputs
def tr = Max(kHigh - kLow, Max(AbsValue(kHigh - kClose[1]), AbsValue(kLow - kClose[1])));
# ADX Directional Movement (DM) components
def plusDM = if hiDiff > loDiff and hiDiff > 0 then hiDiff else 0;
def minusDM = if loDiff > hiDiff and loDiff > 0 then loDiff else 0;
# ADX Smoothing via Wilders Average
def atrWilders = WildersAverage(tr, adxLength);
# --- Plotting the Indicators ---
plot DIPlus = 100 * WildersAverage(plusDM, adxLength) / atrWilders;
plot DIMinus = 100 * WildersAverage(minusDM, adxLength) / atrWilders;
# --- Level of determination for Chop or Trend
input ChopTrendSwitch = 7.0;
plot ChopTrendLevel = ChopTrendSwitch;
# --- Visual Settings ---
DIPlus.SetDefaultColor(Color.GREEN);
DIPlus.SetLineWeight(2);
DIMinus.SetDefaultColor(Color.RED);
DIMinus.SetLineWeight(2);
ChopTrendLevel.SetDefaultColor(Color.LIGHt_GRAY);
ChopTrendLevel.SetStyle(Curve.SHORT_DASH);
plot DI_Diff = DIPlus - DIMinus;
DI_Diff.SetDefaultColor(Color.WHITE);
DI_Diff.SetLineWeight(2);
input DI_Diff_MA_Type = averagetype.SIMPLE;
input DI_Diff_MA_Length = 12;
plot DI_Diff_MA = movingaverage(DI_Diff_MA_Type, DI_Diff, DI_Diff_MA_Length);
DI_Diff.SetDefaultColor(Color.ORANGE);
DI_Diff.SetLineWeight(2);
AddCloud(if(DI_Diff_MA > ChopTrendLevel) then 0 else Double.NaN, DI_Diff_MA, Color.MAGENTA, Color.MAGENTA);