Adaptive ADX for ThinkOrSwim

Sesqui

Member
VIP
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 a three different methods so you can experiment to find the method that leaves you with no question as to whether the ADX is set to the right length. The three methods are TOS Periodogram, Dr Ehlers' Band-Pass Filter method, and an AMA like volatility adapter using the efficiency ratio.

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.

1756670636994.png


CSS:
# Adaptive ADX for ThinOrSwim by Sesqui 
# [29AUG2025] - TOS periodogram used to make it adpative (not precise)
# [12OCT2025] - Added more precise DC method - Dominant Cycle measured using Band-Pass Filter zero crossings method per ch 5 of Dr Ehlers "Cycle Analytics for Traders".  
# [12OCT2025] - Added method to adapt length to volatility similar to AMA method
#===========================================================================================================================

input useDC_BandPassFilter = yes;
input useVolatilityAdapter = no;
input usePeriodogram = no;
#======================================================================================================
script GetCycle { 
    # Returns variable estimate of dominant market cycle for use in adaptive indicators
    # Note, the value returned is not the detailed spectral analysis that provides the precise
    # dominant cycle period since TOS does not support matrices as needed to complete the detailed
    # and elaborate calculations required for the spectral analysis
    # As a result, this method is not recommended if you need values that are representative of the 
    # market dominant cycle lengths. 
    #------------------------------------------
    # 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 = if !IsNaN(ExpMovAvg[1]) then src*(2/(1+length))+ExpMovAvg[1]*(1-(2/(1+length))) else src*(2/(1+length));
    plot EMA = ExpMovAvg;
    EMA.HideBubble();

}# endScript AdaptiveEMA{}

#------------------------------------------------
#===================================================================================
#*** Script to measure dominant cycle length using band-pass 
#*** filter zero crossings method per Dr Ehlers
#*** Chapter 5 of "Cycle Analytics for Traders".  
Script GetCycleViaBandPassFilter{
    input source = ohlc4;
    input Period = 20;
    input Bandwidth = 0.70;

    def cosPart = Cos(0.25 * Bandwidth * 2.0 * Double.Pi / Period);
    def sinPart = Sin(0.25 * Bandwidth * 2.0 * Double.Pi / Period);

    def alpha2 = (cosPart + sinPart - 1) / cosPart;
    def HP = (1 + alpha2 / 2) * (source - source[1]) + (1 - alpha2) * HP[1];

    def beta1 = Cos(2.0 * Double.Pi / Period);
    def gamma1 = 1 / Cos(2.0 * Double.Pi * Bandwidth / Period);

    def alpha1 = gamma1 - Sqrt(gamma1 * gamma1 - 1);

    def BP = If BarNumber() == 1 or BarNumber() == 2 then 0 else 0.5 * (1 - alpha1) * (HP - HP[2]) + beta1 * (1 + alpha1) * BP[1] - alpha1 * BP[2];

    def Peak = if absValue(BP) > 0.991*Peak[1] then AbsValue(BP) else 0.991*Peak[1];

    def Real = if Peak <> 0 then BP/Peak else Double.NaN;

    def crossAbove = Real crosses above 0;
    def crossBelow = Real crosses below 0;
    def zeroCrossing = crossAbove or crossBelow;

    # Uses a recursive variable to count the bars between zero-crossings
    # If a zero-crossing happens, resets the count to 0.
    # Otherwise, increments the count by 1.
    def barsSinceCross = if zeroCrossing then 0 else barsSinceCross[1] + 1;
    def barsBetweenCrossings = barsSinceCross + 1;    
    def val = if barsBetweenCrossings < barsBetweenCrossings[1] then 2*barsBetweenCrossings[1] else val[1];

    # The following line is a port of Dr Ehlers EasyLanguage program, kept here for reference
    #def DC = If barsBetweenCrossings < 3 then 3 else If 2*(barsBetweenCrossings) > 1.25*DC[1] then 1.25*DC[1] else if 2*(barsBetweenCrossings) < 0.8*DC[1] then 0.8*DC[1] else DC[1];

    plot DC = val;
    DC.HideBubble();

} # End script GetCycleViaBandPassFilter{}

#=============================================================================
## Script to determine the length needed to adapt to market volatility
Script AdaptLengthToVolatility{
    # *** Computes the Efficiency Ratio ***
    def effRatioLength = 10;
    def fastLength = 2;
    def slowLength = 30;

    def ER = AbsValue((Close - Lowest(low, effRatioLength)) - (Highest(high, effRatioLength) - close)) / (Highest(high, effRatioLength) - Lowest(low, effRatioLength));


    def FastSF = 2 / (fastLength + 1);
    def SlowSF = 2 / (slowLength + 1);
    def ScaledSF = ER * (FastSF - SlowSF) + SlowSF;

    # *** Determines the Length ***
    # for an EMA: alpha = 1/ (L+1); where L is the lag
    # Using this expression and solving for Lag:
    # L = 2/alpha -1; let ScaledSF = alpha, and solve for the
    # value of lag, L, to get: L = 2/scaledSF - 1;
    # This Length is returned by the script 

    def cutoffLength = 2 / ScaledSF - 1; 

    plot Length = cutoffLength;
    Length.HideBubble();
}# End script AdaptLengthToVolatility{}
#===================================================================================

# *** Computes the ADX and DMI in This Section ***

input BandPassSource = ohlc4;
input BandPassPeriod = 20;
input BandPassBandwidth = 0.70;

def CycleLength = if useDC_BandPassFilter then GetCycleViaBandPassFilter(BandPassSource, BandPassPeriod, BandPassBandwidth).DC else if useVolatilityAdapter then AdaptLengthToVolatility().Length else if usePeriodogram then GetCycle().Cycle else Double.NaN;

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 to identify 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.

If you are needing cycle lengths more representative of the market dominant cycle consider using the Band-Pass Filter method which measures the market dominant cycle length by counting the bars between zero crossings of the band-pass filter waveform. The method is described in detail in Dr Ehlers book, "Cycle Analytics for Traders", chapter five. This method obtains more precise estimates of the market dominant cycle and does not bog down ThinkOrSwim with heavy duty computations. I think you will really like this one! It provided precise cycle lengths when tested against a sinewave having a fixed period length that closely matched the cycle period lengths of the sinewave. Here are a number of screenshots that capture the results:

The red line is the Dominant Cycle length measured by teh zero crossings of the band-pass filter. Zero crossings of the yellow line are watched and the number of candles between crossings are counted and multiplied by two to get the measured value of the dominant cycle length. The yellow line was made by the band-pass filter. The Cyan line is the SineWave signal of given period length = 8. As shown in the screenshot, the band-pass filter measured the period length correctly getting DC = 8.

1760317197698.png

Here are two more test cases showing the band-pass filter method gets the correct DC length for a sinewave having period = 20 and period = 40:

1760317213382.png


1760317240577.png


Because the band-pass filter method is only counting one half of the cycle then multiplying by two, it does not get the correct DC length when the sinewave has a period length that is odd. However, the values that it gets are only off by +/- 1 as shown in the test cases below.

For sinewave period = 7, the band-pass filter gets DC = 6 or DC = 8, with the correct number being the average of the two:
1760317352906.png


For sinewave period = 19, band-pass filter measures DC = 20 or DC = 18 with the correct value being the average of the two:
1760317401665.png


And finally for sinewave DC = 39, the band-pass filter measures DC = 40 or DC = 38, with the correct value being the average of the two:
1760317415756.png



Furthermore, if you are needing an ADX that adjusts to market volatility then consider using the AMA like volatility adapter method by selecting 'yes' for it and 'no' for the other two methods in the study properties dialog. The cycle length produced by this method is much shorter than the market dominant cycle value measured by the band-pass method, and I think that may be due to the current day volatility. Here is a screen shot comparing the cycle lengths produced by this volatility based method and the Band-Pass filter method, as well as the resulting ADX lines. The red ADX label in the top left corner was computed using the volatility adapter, which from the studies in the lower portion of the screen shot can be seen to have much shorter lengths leading to the higher ADX values, whereas the white ADX label was computed using the Dominant Cycle length from the Band-Pass filter method having much larger lengths, hence the lower ADX values.

1760317751218.png



In all, you now have a way to obtain dominant cycle lengths to keep in your trading arsenal that will not bog your computer down. Testing against a sinewave across a wide range of cycle lengths obtained closely matching values. This method is provided as a Script function in the code above and can readily be used to make your other indicators adaptive as desired. Happy hunting!
 

Attachments

  • 1760317506779.png
    1760317506779.png
    159.3 KB · Views: 36
Last edited:
The adaptive trend up label is that a part of the script too or is that a different script. ADX is usually just strength of trend so that label looks like a good complementary to the study?If its a different study do you mind sharing that too
 
One way is to create a new study in your ThinkOrSwim and paste a copy of the script from this page into it, give it a name and save it. Then you can simply add it to your chart as a new study. Hope this helps...
 
@Sesqui
Workspaces cannot be shared.

Grids, charts, and studies are stored on Schwab's servers and are therefore shareable.

Workspaces were created to be a personal backup of your setup that is stored on your computer.
The pointers and linkers for your custom studies are unique to you and your devices using the unique names that you have given them.

Those references do not exist on other member's devices.
This is why 'shared' workspaces come up blank when posted for other members.

@Ramesh16
Sadly no, you can't use shared workspace links.
But you can find the script for the Adaptive William %R here:
https://usethinkscript.com/threads/...-williams-r-indicators-for-thinkorswim.21497/
 
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 a three different methods so you can experiment to find the method that leaves you with no question as to whether the ADX is set to the right length. The three methods are TOS Periodogram, Dr Ehlers' Band-Pass Filter method, and an AMA like volatility adapter using the efficiency ratio.

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.

View attachment 25607

CSS:
# Adaptive ADX for ThinOrSwim by Sesqui
# [29AUG2025] - TOS periodogram used to make it adpative (not precise)
# [12OCT2025] - Added more precise DC method - Dominant Cycle measured using Band-Pass Filter zero crossings method per ch 5 of Dr Ehlers "Cycle Analytics for Traders". 
# [12OCT2025] - Added method to adapt length to volatility similar to AMA method
#===========================================================================================================================

input useDC_BandPassFilter = yes;
input useVolatilityAdapter = no;
input usePeriodogram = no;
#======================================================================================================
script GetCycle {
    # Returns variable estimate of dominant market cycle for use in adaptive indicators
    # Note, the value returned is not the detailed spectral analysis that provides the precise
    # dominant cycle period since TOS does not support matrices as needed to complete the detailed
    # and elaborate calculations required for the spectral analysis
    # As a result, this method is not recommended if you need values that are representative of the
    # market dominant cycle lengths.
    #------------------------------------------
    # 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 = if !IsNaN(ExpMovAvg[1]) then src*(2/(1+length))+ExpMovAvg[1]*(1-(2/(1+length))) else src*(2/(1+length));
    plot EMA = ExpMovAvg;
    EMA.HideBubble();

}# endScript AdaptiveEMA{}

#------------------------------------------------
#===================================================================================
#*** Script to measure dominant cycle length using band-pass
#*** filter zero crossings method per Dr Ehlers
#*** Chapter 5 of "Cycle Analytics for Traders". 
Script GetCycleViaBandPassFilter{
    input source = ohlc4;
    input Period = 20;
    input Bandwidth = 0.70;

    def cosPart = Cos(0.25 * Bandwidth * 2.0 * Double.Pi / Period);
    def sinPart = Sin(0.25 * Bandwidth * 2.0 * Double.Pi / Period);

    def alpha2 = (cosPart + sinPart - 1) / cosPart;
    def HP = (1 + alpha2 / 2) * (source - source[1]) + (1 - alpha2) * HP[1];

    def beta1 = Cos(2.0 * Double.Pi / Period);
    def gamma1 = 1 / Cos(2.0 * Double.Pi * Bandwidth / Period);

    def alpha1 = gamma1 - Sqrt(gamma1 * gamma1 - 1);

    def BP = If BarNumber() == 1 or BarNumber() == 2 then 0 else 0.5 * (1 - alpha1) * (HP - HP[2]) + beta1 * (1 + alpha1) * BP[1] - alpha1 * BP[2];

    def Peak = if absValue(BP) > 0.991*Peak[1] then AbsValue(BP) else 0.991*Peak[1];

    def Real = if Peak <> 0 then BP/Peak else Double.NaN;

    def crossAbove = Real crosses above 0;
    def crossBelow = Real crosses below 0;
    def zeroCrossing = crossAbove or crossBelow;

    # Uses a recursive variable to count the bars between zero-crossings
    # If a zero-crossing happens, resets the count to 0.
    # Otherwise, increments the count by 1.
    def barsSinceCross = if zeroCrossing then 0 else barsSinceCross[1] + 1;
    def barsBetweenCrossings = barsSinceCross + 1;   
    def val = if barsBetweenCrossings < barsBetweenCrossings[1] then 2*barsBetweenCrossings[1] else val[1];

    # The following line is a port of Dr Ehlers EasyLanguage program, kept here for reference
    #def DC = If barsBetweenCrossings < 3 then 3 else If 2*(barsBetweenCrossings) > 1.25*DC[1] then 1.25*DC[1] else if 2*(barsBetweenCrossings) < 0.8*DC[1] then 0.8*DC[1] else DC[1];

    plot DC = val;
    DC.HideBubble();

} # End script GetCycleViaBandPassFilter{}

#=============================================================================
## Script to determine the length needed to adapt to market volatility
Script AdaptLengthToVolatility{
    # *** Computes the Efficiency Ratio ***
    def effRatioLength = 10;
    def fastLength = 2;
    def slowLength = 30;

    def ER = AbsValue((Close - Lowest(low, effRatioLength)) - (Highest(high, effRatioLength) - close)) / (Highest(high, effRatioLength) - Lowest(low, effRatioLength));


    def FastSF = 2 / (fastLength + 1);
    def SlowSF = 2 / (slowLength + 1);
    def ScaledSF = ER * (FastSF - SlowSF) + SlowSF;

    # *** Determines the Length ***
    # for an EMA: alpha = 1/ (L+1); where L is the lag
    # Using this expression and solving for Lag:
    # L = 2/alpha -1; let ScaledSF = alpha, and solve for the
    # value of lag, L, to get: L = 2/scaledSF - 1;
    # This Length is returned by the script

    def cutoffLength = 2 / ScaledSF - 1;

    plot Length = cutoffLength;
    Length.HideBubble();
}# End script AdaptLengthToVolatility{}
#===================================================================================

# *** Computes the ADX and DMI in This Section ***

input BandPassSource = ohlc4;
input BandPassPeriod = 20;
input BandPassBandwidth = 0.70;

def CycleLength = if useDC_BandPassFilter then GetCycleViaBandPassFilter(BandPassSource, BandPassPeriod, BandPassBandwidth).DC else if useVolatilityAdapter then AdaptLengthToVolatility().Length else if usePeriodogram then GetCycle().Cycle else Double.NaN;

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 to identify 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.

If you are needing cycle lengths more representative of the market dominant cycle consider using the Band-Pass Filter method which measures the market dominant cycle length by counting the bars between zero crossings of the band-pass filter waveform. The method is described in detail in Dr Ehlers book, "Cycle Analytics for Traders", chapter five. This method obtains more precise estimates of the market dominant cycle and does not bog down ThinkOrSwim with heavy duty computations. I think you will really like this one! It provided precise cycle lengths when tested against a sinewave having a fixed period length that closely matched the cycle period lengths of the sinewave. Here are a number of screenshots that capture the results:

The red line is the Dominant Cycle length measured by teh zero crossings of the band-pass filter. Zero crossings of the yellow line are watched and the number of candles between crossings are counted and multiplied by two to get the measured value of the dominant cycle length. The yellow line was made by the band-pass filter. The Cyan line is the SineWave signal of given period length = 8. As shown in the screenshot, the band-pass filter measured the period length correctly getting DC = 8.

View attachment 25948
Here are two more test cases showing the band-pass filter method gets the correct DC length for a sinewave having period = 20 and period = 40:

View attachment 25949

View attachment 25950

Because the band-pass filter method is only counting one half of the cycle then multiplying by two, it does not get the correct DC length when the sinewave has a period length that is odd. However, the values that it gets are only off by +/- 1 as shown in the test cases below.

For sinewave period = 7, the band-pass filter gets DC = 6 or DC = 8, with the correct number being the average of the two:
View attachment 25951

For sinewave period = 19, band-pass filter measures DC = 20 or DC = 18 with the correct value being the average of the two:
View attachment 25952

And finally for sinewave DC = 39, the band-pass filter measures DC = 40 or DC = 38, with the correct value being the average of the two:
View attachment 25953


Furthermore, if you are needing an ADX that adjusts to market volatility then consider using the AMA like volatility adapter method by selecting 'yes' for it and 'no' for the other two methods in the study properties dialog. The cycle length produced by this method is much shorter than the market dominant cycle value measured by the band-pass method, and I think that may be due to the current day volatility. Here is a screen shot comparing the cycle lengths produced by this volatility based method and the Band-Pass filter method, as well as the resulting ADX lines. The red ADX label in the top left corner was computed using the volatility adapter, which from the studies in the lower portion of the screen shot can be seen to have much shorter lengths leading to the higher ADX values, whereas the white ADX label was computed using the Dominant Cycle length from the Band-Pass filter method having much larger lengths, hence the lower ADX values.

View attachment 25955


In all, you now have a way to obtain dominant cycle lengths to keep in your trading arsenal that will not bog your computer down. Testing against a sinewave across a wide range of cycle lengths obtained closely matching values. This method is provided as a Script function in the code above and can readily be used to make your other indicators adaptive as desired. Happy hunting!

How do I find the chart indicator of the above chart?
 
@GFTrader , are you asking about a different indicator than the adaptive ADX label? There are several indicators on the upper price chart. There is a SuperTrend that draws thick green and then red lines to mark the trend direction, Supply/Demand Zone indicator that draws horizontal red and green zones at the high and low prices to show the market structure / price channels, the dotted cured lines are the standard Bollinger bands.

Here is the script for the Supply/Demand Lines:
CSS:
#// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
#// © LuxAlgo
#study(title=" Support and Resistance Levels with Breaks",shorttitle = " Support and Resistance Levels with Breaks [LuxAlgo]", overlay = true ,  max_bars_back=1000)
# Converted and mod by Sam4Cok@Samer800   - 01/2023
# Update Added Fibo LEvel - 09/2023

input TimeFrame = 1; # Use 1 = LTF, 2 = MTF and 3= HTF
input SupplyDemandAggro = AggregationPeriod.MIN;
input zoneThickness = 0.05;
input ShowLabels = no;
input PlotSupplyDemandZones = yes;
input ShowHhLlDOTS = yes;
input RepaintingType   = {default "Off: High & Low", "On", "Off: Candle Confirmation"};# 'Repainting'
input rightBars  = 1;#, title = "Right Bars")
input leftBars  = 1;#(15, title = "Left Bars ")


###------------------------------------------------------------------------------------------
input OpenTime = 900;   #hint OpenTime: Time you want backtesting to start the session at
input CloseTime = 1600;  #hint CloseTime: Time you want backtesting to stop the session at

def Begin = SecondsFromTime(OpenTime) + 60; #Note that then +60 limits this to using 1min candles
def End = SecondsTillTime(CloseTime);
# Only use market hours when using intraday timeframe
def isIntraDay = if GetAggregationPeriod() > 14400000 or GetAggregationPeriod() == 0 then 0 else 1;
def MarketOpen = if !isIntraDay then 1 else if isIntraDay and  Begin > 0 and End > 0 then 1 else 0;
###--------------------------------------------------------------------------------------------------

script fixnan {
    input source = close;
    def fix = if !IsNaN(source) then source else fix[1];
    plot result = fix;
}
#drawBox(condition, y1, y2, color) =>
script drawBox {
    input TimeFrame = 1;
    input aggro = AggregationPeriod.MIN;
    input condition = yes;
    input y1        = high;
    input y2        = low;
    def boxHi = if condition then y1 else boxHi[1];
    def boxLo = if condition then y2 else boxLo[1];
    def extension = if TimeFrame == 1 then 5 else if TimeFrame == 2 then 1 else if TimeFrame == 3 then 1 else 1;
    plot ph = if !IsNaN(close(period = aggro)[extension]) then if !boxHi then high(period = aggro) else boxHi else Double.NaN;
    plot pl = if !IsNaN(close(period = aggro)[extension]) then if !boxLo then low(period = aggro) else boxLo else Double.NaN;

}

#repaint(c1, c2, c3) =>
script repaint {
    input type = "On";
    input c1 = no;
    input c2 = no;
    input c3 = no;
    def rTon = type == "On";
    def rTcc = type == "Off: Candle Confirmation";
    def rThv = type == "Off: High & Low";
    def repaint = if rTon then c1 else if rThv then c2 else if rTcc then c3 else Double.NaN;
    plot out = repaint;
}
script FindPivots {
    input dat = close; # default data or study being evaluated
    input HL  = 0;    # default high or low pivot designation, -1 low, +1 high
    input lbL = 5;    # default Pivot Lookback Left
    input lbR = 1;    # default Pivot Lookback Right
    ##############
    def _nan;    # used for non-number returns
    def _BN;     # the current barnumber
    def _VStop;  # confirms that the lookforward period continues the pivot trend
    def _V;      # the Value at the actual pivot point
    ##############
    _BN  = BarNumber();
    _nan = Double.NaN;
    _VStop = if !IsNaN(dat) and lbR > 0 and lbL > 0 then
                fold a = 1 to lbR + 1 with b=1 while b do
                    if HL > 0 then dat > GetValue(dat, -a) else dat < GetValue(dat, -a) else _nan;
    if (HL > 0) {
        _V = if _BN > lbL and dat == Highest(dat, lbL + 1) and _VStop
            then dat else _nan;
    } else {
        _V = if _BN > lbL and dat == Lowest(dat, lbL + 1) and _VStop
            then dat else _nan;
    }
    plot result = if !IsNaN(_V) and _VStop then _V else _nan;
}# end script FindPivots{}

#===========================================================================
# Main Supply Demand Zones Computation is In This Section

def src = close(period = SupplyDemandAggro);
def na = Double.NaN;
def last = IsNaN(src);

def ph = FindPivots(high(period =  SupplyDemandAggro), 1 , leftBars, rightBars);
def pl = FindPivots(low(period =  SupplyDemandAggro), -1, leftBars, rightBars);
def highUsePivot = fixnan(ph);
def lowUsePivot  = fixnan(pl);
#// Box Height
def s_yLoc = if low(period =  SupplyDemandAggro)[1]  > low(period =  SupplyDemandAggro)[-1]  then low(period =  SupplyDemandAggro)[-1] else low(period =  SupplyDemandAggro)[1];
def r_yLoc = if high(period =  SupplyDemandAggro)[1] > high(period =  SupplyDemandAggro)[-1] then high(period =  SupplyDemandAggro)[1] else high(period =  SupplyDemandAggro)[-1];

def r1 = if MarketOpen and PlotSupplyDemandZones then drawBox(TimeFrame,  SupplyDemandAggro, (highUsePivot - highUsePivot[1]), highUsePivot, r_yLoc).ph else na;
#def r2 = if MarketOpen then drawBox2(TimeFrame, aggro, (highUsePivot - highUsePivot[1]), highUsePivot, r_yLoc).pl else na;
def r2 = if MarketOpen and PlotSupplyDemandZones then r1 - zoneThickness else na;

AddCloud(r1, r2, if TimeFrame == 3 then Color.YELLOW else if TimeFrame == 2 then Color.DARK_RED else if TimeFrame == 1 then CreateColor(255, 51, 51) else Color.RED);

#def s1 = if MarketOpen then drawBox(aggro, (lowUsePivot - lowUsePivot[1]), s_yLoc, lowUsePivot).ph else na;

def s2 = if MarketOpen and PlotSupplyDemandZones then drawBox(TimeFrame,  SupplyDemandAggro, (lowUsePivot - lowUsePivot[1]), s_yLoc, lowUsePivot).pl else na;
def s1 = if MarketOpen and PlotSupplyDemandZones then s2 + zoneThickness else na;

AddCloud(s1, s2, if TimeFrame == 3 then Color.PLUM else if TimeFrame == 2 then Color.DARK_GREEN else if TimeFrame == 1 then CreateColor(153, 255, 153) else Color.PLUM);

#=====================================================================================
# Dots are plotted in this section to indicate Demand Zones with Red Dots Above Bars
# And Supply Zones with Green Dots Below Bars

def hh = if MarketOpen and highUsePivot > highUsePivot[1] then highUsePivot else na;
def ll = if MarketOpen and lowUsePivot  < lowUsePivot[1]  then lowUsePivot else na;
def hl = if MarketOpen and lowUsePivot  > lowUsePivot[1]  then lowUsePivot else na;
def lh = if MarketOpen and highUsePivot < highUsePivot[1] then highUsePivot else na;

plot my_LL = if MarketOpen and ShowHhLlDOTS and ll then ll else Double.NaN;
my_LL.SetPaintingStrategy(PaintingStrategy.POINTS);
my_LL.AssignValueColor(Color.GREEN);
my_LL.SetLineWeight(5);
my_LL.HideBubble();

plot my_HL = if MarketOpen and ShowHhLlDOTS and hl then hl else Double.NaN;
my_HL.SetPaintingStrategy(PaintingStrategy.POINTS);
my_HL.AssignValueColor(Color.DARK_GREEN);
my_HL.SetLineWeight(5);
my_HL.HideBubble();

plot my_HH = if MarketOpen and ShowHhLlDOTS and hh then hh else Double.NaN;
my_HH.SetPaintingStrategy(PaintingStrategy.POINTS);
my_HH.AssignValueColor(Color.RED);
my_HH.SetLineWeight(5);
my_HH.HideBubble();

plot my_LH = if MarketOpen and ShowHhLlDOTS and lh then lh else Double.NaN;
my_LH.SetPaintingStrategy(PaintingStrategy.POINTS);
my_LH.AssignValueColor(Color.DARK_RED);
my_LH.SetLineWeight(5);
my_LH.HideBubble();


#-- END of Code

Here is the script for the SuperTrend:

CSS:
# SuperTrend Yahoo Finance Replica - Modified from Mobius SuperTrend
# Modified Mobius ver. by RConner7
# Modified by Barbaros to replicate look from TradingView version
# v3.0

input AtrMult = 0.5;
input nATR = 6;
input AvgType = AverageType.HULL;
input PaintBars = no;
input ShowBubbles = no;

input Alerts = no;
input LongTrades = yes;
input ShortTrades = yes;
input showSignals = no;
input useAlerts = no;

###------------------------------------------------------------------------------------------
input OpenTime = 930;   #hint OpenTime: Time you want backtesting to start the session at
input CloseTime = 1600;  #hint CloseTime: Time you want backtesting to stop the session at

def Begin = SecondsFromTime(OpenTime);
def End = SecondsTillTime(CloseTime);
# Only use market hours when using intraday timeframe
def isIntraDay = if GetAggregationPeriod() > 14400000 or GetAggregationPeriod() == 0 then 0 else 1;
def MarketOpen = if !isIntraDay then 1 else if isIntraDay and  Begin >= 0 and End >= 0 then 1 else 0;
###--------------------------------------------------------------------------------------------------

#----------------------------------------------------------------------------------------------------
# Applies supertrend algorithm to close

def ATR = ATR("length" = nATR, "average type" = AvgType);
def UP_Band_Basic = HL2 + (AtrMult * ATR);
def LW_Band_Basic = HL2 + (-AtrMult * ATR);
def UP_Band = if ((UP_Band_Basic < UP_Band[1]) or (close[1] > UP_Band[1])) then UP_Band_Basic else UP_Band[1];
def LW_Band = if ((LW_Band_Basic > LW_Band[1]) or (close[1] < LW_Band[1])) then LW_Band_Basic else LW_Band[1];

def ST = if ((ST[1] == UP_Band[1]) and (close < UP_Band)) then UP_Band
else if ((ST[1] == UP_Band[1]) and (close > UP_Band)) then LW_Band
else if ((ST[1] == LW_Band[1]) and (close > LW_Band)) then LW_Band
else if ((ST[1] == LW_Band) and (close < LW_Band)) then UP_Band
else LW_Band;

plot Long = if MarketOpen and close > ST then ST else Double.NaN;
Long.AssignValueColor(Color.GREEN);
Long.SetLineWeight(4);
Long.HideBubble();

plot Short = if MarketOpen and close < ST then ST else Double.NaN;
Short.AssignValueColor(Color.RED);
Short.SetLineWeight(4);
Short.HideBubble();

def LongTrigger = MarketOpen and IsNaN(Long[1]) and !IsNaN(Long);
def ShortTrigger = MarketOpen and IsNaN(Short[1]) and !IsNaN(Short);

plot LongDot = if MarketOpen and LongTrigger then ST else Double.NaN;
LongDot.SetPaintingStrategy(PaintingStrategy.POINTS);
LongDot.AssignValueColor(Color.GREEN);
LongDot.SetLineWeight(5);
LongDot.HideBubble();

plot ShortDot = if MarketOpen and ShortTrigger then ST else Double.NaN;
ShortDot.SetPaintingStrategy(PaintingStrategy.POINTS);
ShortDot.AssignValueColor(Color.RED);
ShortDot.SetLineWeight(5);
ShortDot.HideBubble();

AddChartBubble(MarketOpen and ShowBubbles and LongTrigger, ST, "BUY", Color.GREEN, no);
AddChartBubble(MarketOpen and ShowBubbles and ShortTrigger, ST, "SELL", Color.RED, yes);

#AssignPriceColor(if PaintBars and close < ST
#               then Color.RED
#               else if PaintBars and close > ST
#                    then Color.GREEN
#                    else Color.CURRENT);

# End Code SuperTrend Yahoo Finance Replica

#--------------------------------------------------------------------------------------------------------------
# Market State
# Trending Up   = +1
# Trending Down = -1
# Ranging       =  0

If you were looking for a different indicator just describe it a bit to me and I will get the script for you...
 

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
500 Online
Create Post

Similar threads

Similar threads

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top