Knowing if the trend is strong enough to support your position is important. The ADX is popular for assessing that. As a result, I made the ADX adaptive using the EhlersAutocorrelationPeriodogram so there is no question as to whether the ADX is set to the right length.
Here is a screenshot. The adaptive ADX is simply displayed here in a label on the top left corner. It also compares the "DI+" to the "DI-" to determine trend direction and color codes the label Green if ADX > 25 and "DI+" > "DI-" or Red ADX > 25 and "DI+" < "DI-". The script can easily be modified to provide a plot of the adaptive ADX values so the trend of ADX values over time can be readily seen.
Note: Articles from Dr Ehlers use arrays to normalize the periodogram data and then a center of gravity method to pin point the dominant cycle. However, thinkscript does not support arrays as needed to do the drill down further from the periodogram to the precise dominant cycle, per se. However, the cycle value provided by the periodogram in TOS appears to be capable of finding more trading opportunities than found with static fixed length values. Be sure to test it out before using it.
Here is a screenshot. The adaptive ADX is simply displayed here in a label on the top left corner. It also compares the "DI+" to the "DI-" to determine trend direction and color codes the label Green if ADX > 25 and "DI+" > "DI-" or Red ADX > 25 and "DI+" < "DI-". The script can easily be modified to provide a plot of the adaptive ADX values so the trend of ADX values over time can be readily seen.
CSS:
# Adaptive ADX for ThinOrSwim by Sesqui 29AUG2025
#===========================================================================================================================
script GetCycle {
# Returns the dominant market cycle for use in adaptive indicators
#------------------------------------------
# Charles Schwab & Co. (c) 2016-2025
#
def lag = 48;
def x = EhlersRoofingFilter("cutoff length" = 8, "roof cutoff length" = 48);
def cosinePart = fold i = 3 to 48 with cosPart do cosPart + (3 * (x * GetValue(x, i) + GetValue(x, 1) * GetValue(x, i + 1) + GetValue(x, 2) * GetValue(x, i + 2)) - (x + GetValue(x, 1) + GetValue(x, 2)) * (GetValue(x, i) + GetValue(x, i + 1) + GetValue(x, i + 2))) / Sqrt((3 * (x * x + GetValue(x, 1) * GetValue(x, 1) + GetValue(x, 2) * GetValue(x, 2)) - Sqr(x + GetValue(x, 1) + GetValue(x, 2))) * (3 * (GetValue(x, i) * GetValue(x, i) + GetValue(x, i + 1) * GetValue(x, i + 1) + GetValue(x, i + 2) * GetValue(x, i + 2)) - Sqr(GetValue(x, i) + GetValue(x, i + 1) + GetValue(x, i + 2)))) * Cos(2 * Double.Pi * i / lag);
def sinePart = fold j = 3 to 48 with sinPart do sinPart + (3 * (x * GetValue(x, j) + GetValue(x, 1) * GetValue(x, j + 1) + GetValue(x, 2) * GetValue(x, j + 2)) - (x + GetValue(x, 1) + GetValue(x, 2)) * (GetValue(x, j) + GetValue(x, j + 1) + GetValue(x, j + 2))) / Sqrt((3 * (x * x + GetValue(x, 1) * GetValue(x, 1) + GetValue(x, 2) * GetValue(x, 2)) - Sqr(x + GetValue(x, 1) + GetValue(x, 2))) * (3 * (GetValue(x, j) * GetValue(x, j) + GetValue(x, j + 1) * GetValue(x, j + 1) + GetValue(x, j + 2) * GetValue(x, j + 2)) - Sqr(GetValue(x, j) + GetValue(x, j + 1) + GetValue(x, j + 2)))) * Sin(2 * Double.Pi * j / lag);
def sqSum = Sqr(cosinePart) + Sqr(sinePart);
plot Cycle = ExpAverage(sqSum, 9);
#----------------------------------------------
}# end Script GetCycle{}
#------------------------------------------------
script AdaptiveEMA {
input src = close;
input Cycle = 10;
def length = if IsNaN(Floor(Cycle)) then length[1] else Floor(Cycle);
def ExpMovAvg = src*(2/(1+length))+ExpMovAvg[1]*(1-(2/(1+length)));
plot EMA = ExpMovAvg;
EMA.HideBubble();
}# endScript AdaptiveEMA{}
#------------------------------------------------
#==============================================================================================
def CycleLength = GetCycle().Cycle;
def Length = if IsNaN(Floor(CycleLength)) then Length[1] else Floor(CycleLength);
def hiDiff = high - high[1];
def loDiff = low[1] - low;
def plusDM = if hiDiff > loDiff and hiDiff > 0 then hiDiff else 0;
def minusDM = if loDiff > hiDiff and loDiff > 0 then loDiff else 0;
def ATR = AdaptiveEMA(TrueRange(high, close, low), Length);
def DIp = 100 * AdaptiveEMA(plusDM, Length) / ATR;
def DIm = 100 * AdaptiveEMA(minusDM, Length) / ATR;
def DX = if (DIp + DIm > 0) then 100 * AbsValue(DIp - DIm) / (DIp + DIm) else 0;
def ADX = AdaptiveEMA(DX, Length);
AddLabel(yes, "Adaptive ADX = " + ADX, if ADX >=25 and DIP > DIm then Color.GREEN else if ADX >= 25 and DIp < DIm then Color.RED else if ADX < 25 then Color.WHITE else Color.Current);
Note: Articles from Dr Ehlers use arrays to normalize the periodogram data and then a center of gravity method to pin point the dominant cycle. However, thinkscript does not support arrays as needed to do the drill down further from the periodogram to the precise dominant cycle, per se. However, the cycle value provided by the periodogram in TOS appears to be capable of finding more trading opportunities than found with static fixed length values. Be sure to test it out before using it.
Last edited: