# Normalized Standard Indicators For ThinkOrSwim

#### stecla

##### New member
VIP
Hi Various indicators have different ranges. But this makes no sense to me. So I wanted to normalize my indicators to a standard range -100 to 100 with a zero line.

Here's the result.
I have CCI, RSI, MACD, Stochastic, raw price difference all normalized. There is also a power factor you can set so that you can expand or contract the visual of the signal without changing the crossings. So these indicators look a little different but at their core they are the standard calculation.
Find the scripts in the posts that follow.

The default numbers are pre-set for a 1 minute chart on spy.

Last edited by a moderator:
RSI Normalized to -100 to 100 and smoothed:
I left the RSI and Moving average plots there for debugging but I normally
turn them off.
Ruby:
``````#CODE START:
######################################################
# RSI Normalized to it's own moving average.
# fit into a range of -100 to 100
# a power factor allows you to make it larger or smaller
# without changing the crossings.
# secondary smoothings as well to clean up the signal.
# Adjust the lengths as you like but I like the defaults
# <NOTES>
# This software is licensed for individual use only.
# NOT FOR REDISTRIBUTION PRIVATE/CONFIDENTIAL
# Copyright (c) 2024 MtxDev/Steve Clayton
#######################################################
declare lower;

input length = 14; # Length for RSI calculation
input maLength = 14; # Length for smoothing the RSI
input powerFactor = 1.5; # Power factor for scaling
input secondarySmoothLength = 3; # Length for secondary smoothing of the RSI

# Calculate the RSI
def rsi = RSI(length);

# Calculate the moving average of the RSI
def maRsi = MovingAverage(averagetype.HULL,rsi, maLength);

# Calculate the normalized RSI by subtracting the moving average
def rawNormalizedRsi = rsi - maRsi;

# Calculate the maximum and minimum normalized RSI values over the entire dataset
def maxNormalizedRsi = HighestAll(rawNormalizedRsi);
def minNormalizedRsi = LowestAll(rawNormalizedRsi);

# Calculate the maximum absolute difference
def maxAbsNormalizedRsi = Max(AbsValue(maxNormalizedRsi), AbsValue(minNormalizedRsi));

# Use 120% of the maximum absolute difference as the normalization range
def normalizationRange = maxAbsNormalizedRsi * 1.2;

# Normalize the raw normalized RSI to the range -100 to 100
def normalizedRsi = (rawNormalizedRsi / normalizationRange) * 100;

# Ensure normalization range is non-zero to avoid division by zero
def validNormalizedRsi = if normalizationRange != 0 then normalizedRsi else 0;

# Apply power transformation to the normalized RSI
def adjustedPowerFactor = if powerFactor != 0 then 1 / powerFactor else 1;
def powerNormalizedRsi = Power(AbsValue(validNormalizedRsi), adjustedPowerFactor) * Sign(validNormalizedRsi);

# Scale the power-transformed values to -100 to 100 range
def scaledPowerNormalizedRsi = powerNormalizedRsi * (100 / maxTransformedValue);

# Apply secondary smoothing to the scaled power-normalized RSI
def smoothedPowerNormalizedRsi = MovingAverage(AverageType.hull, scaledPowerNormalizedRsi, secondarySmoothLength);

# Plot the original RSI
#plot RSIPlot = rsi;
#RSIPlot.SetDefaultColor(Color.BLUE);

# Plot the moving average of the RSI
#plot MA_RSI_Plot = maRsi;
#MA_RSI_Plot.SetDefaultColor(Color.ORANGE);

# Plot the smoothed, power-transformed, normalized RSI
plot NormalizedRSIPlot = smoothedPowerNormalizedRsi;
NormalizedRSIPlot.SetDefaultColor(Color.RED);

# Add cloud coloring above and below the zero line

Last edited by a moderator:
CCI responds a little quicker than RSI, but I have turned it into a crossing function
to simplify it. The same thing applies as the RSI, I have left the two lines I used but commented them out. I just use the red green plot.
The power factor expands for visibility but doesn't change crossings or shape.
Ruby:
``````#CODE START:
######################################################
# CCI Normalized to it's own moving average.
# fit into a range of -100 to 100
# a power factor allows you to make it larger or smaller
# without changing the crossings.
# Adjust the lengths as you like but I like the defaults
# <NOTES>
# This software is licensed for individual use only.
# NOT FOR REDISTRIBUTION PRIVATE/CONFIDENTIAL
# Copyright (c) 2024 MtxDev/Steve Clayton
#######################################################decdeclare lower;

# Input parameters
input length = 18; # Length for CCI calculation
input maLength = 19; # Length for Simple Moving Average of CCI
input powerFactor = 2.5; # Power factor for transformation

# Calculate the CCI
def cci = CCI(length);

# Calculate the Simple Moving Average (SMA) of the CCI
def maCci =MovingAverage(AverageType.HULL,cci, maLength);

# Normalize the CCI by subtracting the SMA
def normalizedCci = cci - maCci;

# Calculate the maximum and minimum normalized CCI differences across the entire dataset
def maxDiff = HighestAll(normalizedCci);
def minDiff = LowestAll(normalizedCci);

# Calculate the maximum absolute difference
def maxAbsDiff = Max(AbsValue(maxDiff), AbsValue(minDiff));

# Use 120% of the maximum absolute difference as the normalization range
def normalizationRange = maxAbsDiff * 1.2;

# Normalize the normalized CCI to the range -100 to 100
def normalizedDiff = (normalizedCci / normalizationRange) * 100;

# Ensure normalization range is non-zero to avoid division by zero
def validNormalizedDiff = if normalizationRange != 0 then normalizedDiff else 0;

# Adjust power factor for transformation
def adjustedPowerFactor = if powerFactor != 0 then 1 / powerFactor else 1;

# Apply power transformation to the normalized differences
def powerNormalizedDiff = Power(AbsValue(validNormalizedDiff), adjustedPowerFactor) * Sign(validNormalizedDiff);

# Scale the power-transformed values to -100 to 100 range
def scaledPowerNormalizedDiff = powerNormalizedDiff * (100 / maxTransformedValue);

# Plot the original CCI
#plot CCIPlot = cci;
#CCIPlot.SetDefaultColor(Color.BLUE);
# Plot the SMA of the CCI
#plot MA_CCI_Plot = maCci;
#MA_CCI_Plot.SetDefaultColor(Color.ORANGE);

# Plot the normalized and power-transformed CCI
plot NormalizedCCIPlot = scaledPowerNormalizedDiff;
NormalizedCCIPlot.SetDefaultColor(Color.Blue);

# Add cloud coloring above and below the zero line

# Add horizontal reference line at zero
plot zeroLine = 0;
zeroLine.SetDefaultColor(Color.GRAY);``````

Last edited:
Ok here's the MACD
Ruby:
``````#CODE START:
####################################################
# MACD normalized to -100 to 100 with a power factor
# for visibility.
#
#
# <NOTES>
# This software is licensed for individual use only.
# NOT FOR REDISTRIBUTION PRIVATE/CONFIDENTIAL
# Copyright (c) 2024 MtxDev/Steve Clayton
####################################################
declare lower;

# Input parameters
input fastLength = 19; # Fast EMA length
input slowLength = 20; # Slow EMA length
input signalLength = 5; # Signal line EMA length
input powerFactor = 1.5; # Power factor for transformation

# Calculate the MACD line
def fastEMA = ExpAverage(close, fastLength);
def slowEMA = ExpAverage(close, slowLength);
def macdLine = fastEMA - slowEMA;

# Calculate the Signal line
def signalLine = ExpAverage(macdLine, signalLength);

# Calculate the Histogram
def histogram = macdLine - signalLine;

# Normalize and scale the MACD line
def macdMaxDiff = HighestAll(macdLine);
def macdMinDiff = LowestAll(macdLine);
def macdMaxAbsDiff = Max(AbsValue(macdMaxDiff), AbsValue(macdMinDiff));
def macdNormalizationRange = macdMaxAbsDiff * 1.2;
def macdNormalizedDiff = (macdLine / macdNormalizationRange) * 100;
def macdValidNormalizedDiff = if macdNormalizationRange != 0 then macdNormalizedDiff else 0;
def macdPowerNormalizedDiff = Power(AbsValue(macdValidNormalizedDiff), 1 / powerFactor) * Sign(macdValidNormalizedDiff);
def macdMaxTransformedValue = Power(100, 1 / powerFactor);
def macdScaledPowerNormalizedDiff = macdPowerNormalizedDiff * (100 / macdMaxTransformedValue);

# Normalize and scale the Signal line
def signalMaxDiff = HighestAll(signalLine);
def signalMinDiff = LowestAll(signalLine);
def signalMaxAbsDiff = Max(AbsValue(signalMaxDiff), AbsValue(signalMinDiff));
def signalNormalizationRange = signalMaxAbsDiff * 1.2;
def signalNormalizedDiff = (signalLine / signalNormalizationRange) * 100;
def signalValidNormalizedDiff = if signalNormalizationRange != 0 then signalNormalizedDiff else 0;
def signalPowerNormalizedDiff = Power(AbsValue(signalValidNormalizedDiff), 1 / powerFactor) * Sign(signalValidNormalizedDiff);
def signalMaxTransformedValue = Power(100, 1 / powerFactor);
def signalScaledPowerNormalizedDiff = signalPowerNormalizedDiff * (100 / signalMaxTransformedValue);

# Normalize and scale the Histogram
def histMaxDiff = HighestAll(histogram);
def histMinDiff = LowestAll(histogram);
def histMaxAbsDiff = Max(AbsValue(histMaxDiff), AbsValue(histMinDiff));
def histNormalizationRange = histMaxAbsDiff * 1.2;
def histNormalizedDiff = (histogram / histNormalizationRange) * 100;
def histValidNormalizedDiff = if histNormalizationRange != 0 then histNormalizedDiff else 0;
def histPowerNormalizedDiff = Power(AbsValue(histValidNormalizedDiff), 1 / powerFactor) * Sign(histValidNormalizedDiff);
def histMaxTransformedValue = Power(100, 1 / powerFactor);
def histScaledPowerNormalizedDiff = histPowerNormalizedDiff * (100 / histMaxTransformedValue);

# Plot the normalized, power-transformed MACD line
plot macdPlot = macdScaledPowerNormalizedDiff;
macdPlot.SetDefaultColor(Color.CYAN);
macdPlot.SetLineWeight(1);

# Plot the normalized, power-transformed Signal line
plot signalPlot = signalScaledPowerNormalizedDiff;
signalPlot.SetDefaultColor(Color.ORANGE);
signalPlot.SetLineWeight(1);

# Plot the normalized, power-transformed Histogram
plot histPlot = histScaledPowerNormalizedDiff;
histPlot.SetDefaultColor(Color.RED);
histPlot.SetLineWeight(1);

# Add cloud coloring above and below the zero line for the Histogram

# Add horizontal reference line at zero
plot zeroLine = 0;
zeroLine.SetDefaultColor(Color.GRAY);``````

Last edited:
I use a Stochastic study to find the top of the MACD it helps with entrance and exits.
Ruby:
``````#CODE START:
##############################################
# Stochastic study normalized for -100 to 100
#
#
#
# <NOTES>
# This software is licensed for individual use only.
# NOT FOR REDISTRIBUTION PRIVATE/CONFIDENTIAL
# Copyright (c) 2024 MtxDev/Steve Clayton
#2024MtxDev/SteveClayton
##############################################
declare lower;

# Input parameters
input kPeriod = 10; # Period for %K calculation
input dPeriod = 3; # Period for %D calculation (SMA of %K)
input slowingPeriod = 3; # Smoothing period for %K
input powerFactor = 1.5; # Power factor for transformation
input overbought = 68;
input oversold = -68;
# Calculate the %K line
def highestHigh = Highest(high, kPeriod);
def lowestLow = Lowest(low, kPeriod);
def percentK = ((close - lowestLow) / (highestHigh - lowestLow)) * 100;

# Smooth the %K line
def smoothedK = SimpleMovingAvg(percentK, slowingPeriod);

# Calculate the %D line (SMA of %K)
def percentD = SimpleMovingAvg(smoothedK, dPeriod);

# Normalize and scale the %K line to -100 to 100
def kMaxDiff = HighestAll(smoothedK);
def kMinDiff = LowestAll(smoothedK);
def kMaxAbsDiff = Max(AbsValue(kMaxDiff), AbsValue(kMinDiff));
def kNormalizationRange = kMaxAbsDiff * 1.2;
def kNormalizedDiff = ((smoothedK - (kNormalizationRange / 2)) / kNormalizationRange) * 200;
def kValidNormalizedDiff = if kNormalizationRange != 0 then kNormalizedDiff else 0;
def kPowerNormalizedDiff = Power(AbsValue(kValidNormalizedDiff), 1 / powerFactor) * Sign(kValidNormalizedDiff);
def kMaxTransformedValue = Power(100, 1 / powerFactor);
def kScaledPowerNormalizedDiff = kPowerNormalizedDiff * (100 / kMaxTransformedValue);

# Normalize and scale the %D line to -100 to 100
def dMaxDiff = HighestAll(percentD);
def dMinDiff = LowestAll(percentD);
def dMaxAbsDiff = Max(AbsValue(dMaxDiff), AbsValue(dMinDiff));
def dNormalizationRange = dMaxAbsDiff * 1.2;
def dNormalizedDiff = ((percentD - (dNormalizationRange / 2)) / dNormalizationRange) * 200;
def dValidNormalizedDiff = if dNormalizationRange != 0 then dNormalizedDiff else 0;
def dPowerNormalizedDiff = Power(AbsValue(dValidNormalizedDiff), 1 / powerFactor) * Sign(dValidNormalizedDiff);
def dMaxTransformedValue = Power(100, 1 / powerFactor);
def dScaledPowerNormalizedDiff = dPowerNormalizedDiff * (100 / dMaxTransformedValue);

def smoothedKFinal = SimpleMovingAvg(kScaledPowerNormalizedDiff, smoothingLength);
def smoothedDFinal = SimpleMovingAvg(dScaledPowerNormalizedDiff, smoothingLength);

# Plot the normalized, power-transformed %K line with additional smoothing
plot kPlot = smoothedKFinal;
kPlot.SetDefaultColor(Color.CYAN);
kPlot.SetLineWeight(1);

# Plot the normalized, power-transformed %D line with additional smoothing
plot dPlot = smoothedDFinal;
dPlot.SetDefaultColor(Color.ORANGE);
dPlot.SetLineWeight(1);

# Add cloud coloring above and below the zero line

# Add horizontal reference line at zero
plot zeroLine = 0;
zeroLine.SetDefaultColor(Color.GRAY);

# Add horizontal reference lines for overbought and oversold thresholds
plot overboughtLine = overbought;
overboughtLine.SetDefaultColor(Color.RED);
overboughtLine.SetStyle(Curve.FIRM);

plot oversoldLine = oversold;
oversoldLine.SetDefaultColor(Color.GREEN);
oversoldLine.SetStyle(Curve.FIRM);``````

Last edited:
Here is a bar to bar incremental change graph. Above the line is up, below the line is moving down. If you track the crossing of the cyan line and the smoothed line it will give you a 1 bar advantage. I use this on 1 and 5 min charts but if you expand it out
for daily charts and just use the smoothed function it works really nicely to tell up and down days and see trends.

Ruby:
``````#CODE START:
#######################################
#Bar to Bar Incremental changes. Normalized to
#-100 to 100. This tells you if a price is moving
#up or down. look for the crossings between
#the unsmoothed line and the smoothed line
#to get a little advanced warning.
#
# <NOTES>
# This software is licensed for individual use only.
# NOT FOR REDISTRIBUTION PRIVATE/CONFIDENTIAL
# Copyright (c) 2024 MtxDev/Steve Clayton
#######################################
Declare Lower;
# Input parameters
input powerFactor = 1.5; # Adjust this factor for smoother transformation
input HullLength = 4; # Length for Hull Moving Average
input secondarySmoothLength = 3; # Length for secondary smoothing of the Hull MA

# Calculate the incremental (differenced) prices
def diffPrice = close - close[1];

# Calculate the maximum and minimum incremental differences across the entire dataset
def maxDiff = HighestAll(diffPrice);
def minDiff = LowestAll(diffPrice);

# Calculate the maximum absolute difference
def maxAbsDiff = Max(AbsValue(maxDiff), AbsValue(minDiff));

# Use 120% of the maximum absolute difference as the normalization range
def normalizationRange = maxAbsDiff * 1.2;

# Normalize the incremental prices to the range -100 to 100
def normalizedDiff = (diffPrice / normalizationRange) * 100;

# Ensure normalization range is non-zero to avoid division by zero
def validNormalizedDiff = if normalizationRange != 0 then normalizedDiff else 0;

# Apply power transformation to the normalized differences
def adjustedPowerFactor = if powerFactor != 0 then 1 / powerFactor else 1;
def powerNormalizedDiff = Power(AbsValue(validNormalizedDiff), adjustedPowerFactor) * Sign(validNormalizedDiff);

# Scale the power-transformed values to -100 to 100 range
def scaledPowerNormalizedDiff = powerNormalizedDiff * (100 / maxTransformedValue);

# Calculate the Hull Moving Average (HMA) of the scaled power-normalized differences
def normalizedHUL = MovingAverage(AverageType.HULL, scaledPowerNormalizedDiff, HullLength);

# Apply secondary smoothing to the Hull MA
def smoothedHUL = MovingAverage(AverageType.Hull, normalizedHUL, secondarySmoothLength);

# Plot the power-transformed normalized incremental prices
plot powerNormalizedDiffPlot = scaledPowerNormalizedDiff;
powerNormalizedDiffPlot.SetDefaultColor(Color.CYAN);

# Plot the Hull MA with secondary smoothing
plot pNormalizedHul = smoothedHUL;
pNormalizedHul.SetDefaultColor(Color.MAGENTA);

# Add horizontal reference line at zero
plot zeroLine = 0;
zeroLine.SetDefaultColor(Color.GRAY);
# Add cloud coloring above and below the zero line

Last edited by a moderator:
Here is a version of your Normalized RSI in a binary indicator
Code:
``````Declare Lower;
input powerFactor = 1.5; # Power factor for scaling
input secondarySmoothLength = 3; # Length for secondary smoothing of the RSI
# GLOBAL DEFINITIONS

DefineGlobalColor("TrendUp", Color.Cyan);
DefineGlobalColor("TrendDown", Color.Magenta);
DefineGlobalColor("TrendUp2", Color.Blue);
DefineGlobalColor("TrendDown2", Color.Red);
input DotSize = 2;
INPUT APC = 0;

def rsiA = RSI(3); def maRsiA = MovingAverage(averagetype.HULL,rsiA, 3);
def rsiB = RSI(6); def maRsiB = MovingAverage(averagetype.HULL,rsiB, 6);
def rsiC = RSI(9); def maRsiC = MovingAverage(averagetype.HULL,rsiC, 9);
def rsiD = RSI(12); def maRsiD = MovingAverage(averagetype.HULL,rsiD, 12);
def rsiE = RSI(15); def maRsiE = MovingAverage(averagetype.HULL,rsiE, 15);
def rsiF = RSI(18); def maRsiF = MovingAverage(averagetype.HULL,rsiF, 18);
def rsiG = RSI(21); def maRsiG = MovingAverage(averagetype.HULL,rsiG, 21);
def rsiH = RSI(24); def maRsiH = MovingAverage(averagetype.HULL,rsiH, 24);
def rsiI = RSI(27); def maRsiI = MovingAverage(averagetype.HULL,rsiI, 27);
def rsiJ = RSI(30); def maRsiJ = MovingAverage(averagetype.HULL,rsiJ, 30);
def rawNormalizedRsiA = rsiA - maRsiA;
def rawNormalizedRsiB = rsiB - maRsiB;
def rawNormalizedRsiC = rsiC - maRsiC;
def rawNormalizedRsiD = rsiD - maRsiD;
def rawNormalizedRsiE = rsiE - maRsiE;
def rawNormalizedRsiF = rsiF - maRsiF;
def rawNormalizedRsiG = rsiG - maRsiG;
def rawNormalizedRsiH = rsiH - maRsiH;
def rawNormalizedRsiI = rsiI - maRsiI;
def rawNormalizedRsiJ = rsiJ - maRsiJ;
def maxNormalizedRsiA = HighestAll(rawNormalizedRsiA);
def minNormalizedRsiA = LowestAll(rawNormalizedRsiA);
def maxNormalizedRsiB = HighestAll(rawNormalizedRsiB);
def minNormalizedRsiB = LowestAll(rawNormalizedRsiB);
def maxNormalizedRsiC = HighestAll(rawNormalizedRsiC);
def minNormalizedRsiC = LowestAll(rawNormalizedRsiC);
def maxNormalizedRsiD = HighestAll(rawNormalizedRsiD);
def minNormalizedRsiD = LowestAll(rawNormalizedRsiD);
def maxNormalizedRsiE = HighestAll(rawNormalizedRsiE);
def minNormalizedRsiE = LowestAll(rawNormalizedRsiE);
def maxNormalizedRsiF = HighestAll(rawNormalizedRsiF);
def minNormalizedRsiF = LowestAll(rawNormalizedRsiF);
def maxNormalizedRsiG = HighestAll(rawNormalizedRsiG);
def minNormalizedRsiG = LowestAll(rawNormalizedRsiG);
def maxNormalizedRsiH = HighestAll(rawNormalizedRsiH);
def minNormalizedRsiH = LowestAll(rawNormalizedRsiH);
def maxNormalizedRsiI = HighestAll(rawNormalizedRsiI);
def minNormalizedRsiI = LowestAll(rawNormalizedRsiI);
def maxNormalizedRsiJ = HighestAll(rawNormalizedRsiJ);
def minNormalizedRsiJ = LowestAll(rawNormalizedRsiJ);
def maxAbsNormalizedRsiA = Max(AbsValue(maxNormalizedRsiA), AbsValue(minNormalizedRsiA));
def maxAbsNormalizedRsiB = Max(AbsValue(maxNormalizedRsiB), AbsValue(minNormalizedRsiB));
def maxAbsNormalizedRsiC = Max(AbsValue(maxNormalizedRsiC), AbsValue(minNormalizedRsiC));
def maxAbsNormalizedRsiD = Max(AbsValue(maxNormalizedRsiD), AbsValue(minNormalizedRsiD));
def maxAbsNormalizedRsiE = Max(AbsValue(maxNormalizedRsiE), AbsValue(minNormalizedRsiE));
def maxAbsNormalizedRsiF = Max(AbsValue(maxNormalizedRsiF), AbsValue(minNormalizedRsiF));
def maxAbsNormalizedRsiG = Max(AbsValue(maxNormalizedRsiG), AbsValue(minNormalizedRsiG));
def maxAbsNormalizedRsiH = Max(AbsValue(maxNormalizedRsiH), AbsValue(minNormalizedRsiH));
def maxAbsNormalizedRsiI = Max(AbsValue(maxNormalizedRsiI), AbsValue(minNormalizedRsiI));
def maxAbsNormalizedRsiJ = Max(AbsValue(maxNormalizedRsiJ), AbsValue(minNormalizedRsiJ));
def normalizationRangeA = maxAbsNormalizedRsiA * 1.2;
def normalizationRangeB = maxAbsNormalizedRsiB * 1.2;
def normalizationRangeC = maxAbsNormalizedRsiC * 1.2;
def normalizationRangeD = maxAbsNormalizedRsiD * 1.2;
def normalizationRangeE = maxAbsNormalizedRsiE * 1.2;
def normalizationRangeF = maxAbsNormalizedRsiF * 1.2;
def normalizationRangeG = maxAbsNormalizedRsiG * 1.2;
def normalizationRangeH = maxAbsNormalizedRsiH * 1.2;
def normalizationRangeI = maxAbsNormalizedRsiI * 1.2;
def normalizationRangeJ = maxAbsNormalizedRsiJ * 1.2;
def normalizedRsiA = (rawNormalizedRsiA / normalizationRangeA) * 100;
def normalizedRsiB = (rawNormalizedRsiB / normalizationRangeB) * 100;
def normalizedRsiC = (rawNormalizedRsiC / normalizationRangeC) * 100;
def normalizedRsiD = (rawNormalizedRsiD / normalizationRangeD) * 100;
def normalizedRsiE = (rawNormalizedRsiE / normalizationRangeE) * 100;
def normalizedRsiF = (rawNormalizedRsiF / normalizationRangeF) * 100;
def normalizedRsiG = (rawNormalizedRsiG / normalizationRangeG) * 100;
def normalizedRsiH = (rawNormalizedRsiH / normalizationRangeH) * 100;
def normalizedRsiI = (rawNormalizedRsiI / normalizationRangeI) * 100;
def normalizedRsiJ = (rawNormalizedRsiJ / normalizationRangeJ) * 100;
def validNormalizedRsiA = if normalizationRangeA != 0 then normalizedRsiA else 0;
def validNormalizedRsiB = if normalizationRangeB != 0 then normalizedRsiB else 0;
def validNormalizedRsiC = if normalizationRangeC != 0 then normalizedRsiC else 0;
def validNormalizedRsiD = if normalizationRangeD != 0 then normalizedRsiD else 0;
def validNormalizedRsiE = if normalizationRangeE != 0 then normalizedRsiE else 0;
def validNormalizedRsiF = if normalizationRangeF != 0 then normalizedRsiF else 0;
def validNormalizedRsiG = if normalizationRangeG != 0 then normalizedRsiG else 0;
def validNormalizedRsiH = if normalizationRangeH != 0 then normalizedRsiH else 0;
def validNormalizedRsiI = if normalizationRangeI != 0 then normalizedRsiI else 0;
def validNormalizedRsiJ = if normalizationRangeJ != 0 then normalizedRsiJ else 0;
def adjustedPowerFactor = if powerFactor != 0 then 1 / powerFactor else 1;
def powerNormalizedRsiA = Power(AbsValue(validNormalizedRsiA), adjustedPowerFactor) * Sign(validNormalizedRsiA);
def powerNormalizedRsiB = Power(AbsValue(validNormalizedRsiB), adjustedPowerFactor) * Sign(validNormalizedRsiB);
def powerNormalizedRsiC = Power(AbsValue(validNormalizedRsiC), adjustedPowerFactor) * Sign(validNormalizedRsiC);
def powerNormalizedRsiD = Power(AbsValue(validNormalizedRsiD), adjustedPowerFactor) * Sign(validNormalizedRsiD);
def powerNormalizedRsiE = Power(AbsValue(validNormalizedRsiE), adjustedPowerFactor) * Sign(validNormalizedRsiE);
def powerNormalizedRsiF = Power(AbsValue(validNormalizedRsiF), adjustedPowerFactor) * Sign(validNormalizedRsiF);
def powerNormalizedRsiG = Power(AbsValue(validNormalizedRsiG), adjustedPowerFactor) * Sign(validNormalizedRsiG);
def powerNormalizedRsiH = Power(AbsValue(validNormalizedRsiH), adjustedPowerFactor) * Sign(validNormalizedRsiH);
def powerNormalizedRsiI = Power(AbsValue(validNormalizedRsiI), adjustedPowerFactor) * Sign(validNormalizedRsiI);
def powerNormalizedRsiJ = Power(AbsValue(validNormalizedRsiJ), adjustedPowerFactor) * Sign(validNormalizedRsiJ);
def scaledPowerNormalizedRsiA = powerNormalizedRsiA * (100 / maxTransformedValue);
def scaledPowerNormalizedRsiB = powerNormalizedRsiB * (100 / maxTransformedValue);
def scaledPowerNormalizedRsiC = powerNormalizedRsiC * (100 / maxTransformedValue);
def scaledPowerNormalizedRsiD = powerNormalizedRsiD * (100 / maxTransformedValue);
def scaledPowerNormalizedRsiE = powerNormalizedRsiE * (100 / maxTransformedValue);
def scaledPowerNormalizedRsiF = powerNormalizedRsiF * (100 / maxTransformedValue);
def scaledPowerNormalizedRsiG = powerNormalizedRsiG * (100 / maxTransformedValue);
def scaledPowerNormalizedRsiH = powerNormalizedRsiH * (100 / maxTransformedValue);
def scaledPowerNormalizedRsiI = powerNormalizedRsiI * (100 / maxTransformedValue);
def scaledPowerNormalizedRsiJ = powerNormalizedRsiJ * (100 / maxTransformedValue);
def smoothedPowerNormalizedRsiA = MovingAverage(AverageType.hull, scaledPowerNormalizedRsiA, secondarySmoothLength);
def smoothedPowerNormalizedRsiB = MovingAverage(AverageType.hull, scaledPowerNormalizedRsiB, secondarySmoothLength);
def smoothedPowerNormalizedRsiC = MovingAverage(AverageType.hull, scaledPowerNormalizedRsiC, secondarySmoothLength);
def smoothedPowerNormalizedRsiD = MovingAverage(AverageType.hull, scaledPowerNormalizedRsiD, secondarySmoothLength);
def smoothedPowerNormalizedRsiE = MovingAverage(AverageType.hull, scaledPowerNormalizedRsiE, secondarySmoothLength);
def smoothedPowerNormalizedRsiF = MovingAverage(AverageType.hull, scaledPowerNormalizedRsiF, secondarySmoothLength);
def smoothedPowerNormalizedRsiG = MovingAverage(AverageType.hull, scaledPowerNormalizedRsiG, secondarySmoothLength);
def smoothedPowerNormalizedRsiH = MovingAverage(AverageType.hull, scaledPowerNormalizedRsiH, secondarySmoothLength);
def smoothedPowerNormalizedRsiI = MovingAverage(AverageType.hull, scaledPowerNormalizedRsiI, secondarySmoothLength);
def smoothedPowerNormalizedRsiJ = MovingAverage(AverageType.hull, scaledPowerNormalizedRsiJ, secondarySmoothLength);
plot R1_Dot = if IsNaN(close) then Double.NaN else 1;
R1_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R1_Dot.SetLineWeight(DotSize);
R1_Dot.AssignValueColor(if smoothedPowerNormalizedRsiA < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp"));
R1_Dot.HideBubble();
plot R2_Dot = if IsNaN(close) then Double.NaN else 2;
R2_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R2_Dot.SetLineWeight(DotSize);
R2_Dot.AssignValueColor(if smoothedPowerNormalizedRsiB < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp"));
R2_Dot.HideBubble();
plot R3_Dot = if IsNaN(close) then Double.NaN else 3;
R3_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R3_Dot.SetLineWeight(DotSize);
R3_Dot.AssignValueColor(if smoothedPowerNormalizedRsiC < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp"));
R3_Dot.HideBubble();
plot R4_Dot = if IsNaN(close) then Double.NaN else 4;
R4_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R4_Dot.SetLineWeight(DotSize);
R4_Dot.AssignValueColor(if smoothedPowerNormalizedRsiD  < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp"));
R4_Dot.HideBubble();
plot R5_Dot = if IsNaN(close) then Double.NaN else 5;
R5_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R5_Dot.SetLineWeight(DotSize);
R5_Dot.AssignValueColor(if smoothedPowerNormalizedRsiE < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp"));
R5_Dot.HideBubble();
plot R6_Dot = if IsNaN(close) then Double.NaN else 6;
R6_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R6_Dot.SetLineWeight(DotSize);
R6_Dot.AssignValueColor(if smoothedPowerNormalizedRsiF < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2"));
R6_Dot.HideBubble();
plot R7_Dot = if IsNaN(close) then Double.NaN else 7;
R7_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R7_Dot.SetLineWeight(DotSize);
R7_Dot.AssignValueColor(if smoothedPowerNormalizedRsiG < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2"));
R7_Dot.HideBubble();
plot R8_Dot = if IsNaN(close) then Double.NaN else 8;
R8_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R8_Dot.SetLineWeight(DotSize);
R8_Dot.AssignValueColor(if smoothedPowerNormalizedRsiH < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2"));
R8_Dot.HideBubble();
plot R9_Dot = if IsNaN(close) then Double.NaN else 9;
R9_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R9_Dot.SetLineWeight(DotSize);
R9_Dot.AssignValueColor(if smoothedPowerNormalizedRsiI  < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2"));
R9_Dot.HideBubble();
plot R10_Dot = if IsNaN(close) then Double.NaN else 10;
R10_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R10_Dot.SetLineWeight(DotSize);
R10_Dot.AssignValueColor(if smoothedPowerNormalizedRsiJ < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2"));
R10_Dot.HideBubble();
#assignPriceColor
assignPriceColor( if apc == 1 then if smoothedPowerNormalizedRsiA < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp") else
if apc == 2 then if smoothedPowerNormalizedRsiB < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp") else
if apc == 3 then if smoothedPowerNormalizedRsiC < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp") else
if apc == 4 then if smoothedPowerNormalizedRsiD < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp") else
if apc == 5 then if smoothedPowerNormalizedRsiE < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp") else
if apc == 6 then if smoothedPowerNormalizedRsiF < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2") else
if APC == 7 THEN IF smoothedPowerNormalizedRsiG < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2") else
if APC == 8 THEN IF smoothedPowerNormalizedRsiH < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2") else
if APC == 9 THEN IF smoothedPowerNormalizedRsiI < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2") else
if APC == 10 THEN IF smoothedPowerNormalizedRsiJ < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2") else Color.current);``````

It tracks the RSI in lengths from 3 thru 30, with the fastest RSI on the lowest line going to longer lengths as you go up

You can also color the price bars by changing the APC to reflect the line you choose

Last edited by a moderator:
Here is a version of Normalized CCI in a binary indicator
Code:
``````#CODE START:
######################################################
# CCI Normalized to it's own moving average.
# fit into a range of -100 to 100
# a power factor allows you to make it larger or smaller
# without changing the crossings.
# Adjust the lengths as you like but I like the defaults
# <NOTES>
# This software is licensed for individual use only.
# NOT FOR REDISTRIBUTION PRIVATE/CONFIDENTIAL
# Copyright (c) 2024 MtxDev/Steve Clayton
#Converted to  a binary indicator by Henry Kaczmarczyk 05 20 2024
#######################################################
Declare Lower;
input powerFactor = 1.5; # Power factor for scaling
# GLOBAL DEFINITIONS

DefineGlobalColor("TrendUp", Color.Cyan);
DefineGlobalColor("TrendDown", Color.Magenta);
DefineGlobalColor("TrendUp2", Color.Blue);
DefineGlobalColor("TrendDown2", Color.Red);
input DotSize = 2;
INPUT APC = 0;
def CCIA = CCI(3); def maCCIA = MovingAverage(averagetype.HULL,CCIA, 3);
def CCIB = CCI(6); def maCCIB = MovingAverage(averagetype.HULL,CCIB, 6);
def CCIC = CCI(9); def maCCIC = MovingAverage(averagetype.HULL,CCIC, 9);
def CCID = CCI(12); def maCCID = MovingAverage(averagetype.HULL,CCID, 12);
def CCIE = CCI(15); def maCCIE = MovingAverage(averagetype.HULL,CCIE, 15);
def CCIF = CCI(18); def maCCIF = MovingAverage(averagetype.HULL,CCIF, 18);
def CCIG = CCI(21); def maCCIG = MovingAverage(averagetype.HULL,CCIG, 21);
def CCIH = CCI(24); def maCCIH = MovingAverage(averagetype.HULL,CCIH, 24);
def CCII = CCI(27); def maCCII = MovingAverage(averagetype.HULL,CCII, 27);
def CCIJ = CCI(30); def maCCIJ = MovingAverage(averagetype.HULL,CCIJ, 30);
def NormalizedCCIA = CCIA - maCCIA;
def NormalizedCCIB = CCIB - maCCIB;
def NormalizedCCIC = CCIC - maCCIC;
def NormalizedCCID = CCID - maCCID;
def NormalizedCCIE = CCIE - maCCIE;
def NormalizedCCIF = CCIF - maCCIF;
def NormalizedCCIG = CCIG - maCCIG;
def NormalizedCCIH = CCIH - maCCIH;
def NormalizedCCII = CCII - maCCII;
def NormalizedCCIJ = CCIJ - maCCIJ;
def maxDiffA = HighestAll(normalizedCciA);
def minDiffA = LowestAll(normalizedCciA);
def maxDiffB = HighestAll(normalizedCciB);
def minDiffB = LowestAll(normalizedCciB);
def maxDiffC = HighestAll(normalizedCciC);
def minDiffC = LowestAll(normalizedCciC);
def maxDiffD = HighestAll(normalizedCciD);
def minDiffD = LowestAll(normalizedCciD);
def maxDiffE = HighestAll(normalizedCciE);
def minDiffE = LowestAll(normalizedCciE);
def maxDiffF = HighestAll(normalizedCciF);
def minDiffF = LowestAll(normalizedCciF);
def maxDiffG = HighestAll(normalizedCciG);
def minDiffG = LowestAll(normalizedCciG);
def maxDiffH = HighestAll(normalizedCciH);
def minDiffH = LowestAll(normalizedCciH);
def maxDiffI = HighestAll(normalizedCciI);
def minDiffI = LowestAll(normalizedCciI);
def maxDiffJ = HighestAll(normalizedCciJ);
def minDiffJ = LowestAll(normalizedCciJ);
def maxAbsDiffA = Max(AbsValue(maxDiffA), AbsValue(minDiffA));
def maxAbsDiffB = Max(AbsValue(maxDiffB), AbsValue(minDiffB));
def maxAbsDiffC = Max(AbsValue(maxDiffC), AbsValue(minDiffC));
def maxAbsDiffD = Max(AbsValue(maxDiffD), AbsValue(minDiffD));
def maxAbsDiffE = Max(AbsValue(maxDiffE), AbsValue(minDiffE));
def maxAbsDiffF = Max(AbsValue(maxDiffF), AbsValue(minDiffF));
def maxAbsDiffG = Max(AbsValue(maxDiffG), AbsValue(minDiffG));

def maxAbsDiffH = Max(AbsValue(maxDiffH), AbsValue(minDiffH));
def maxAbsDiffI = Max(AbsValue(maxDiffI), AbsValue(minDiffI));
def maxAbsDiffJ = Max(AbsValue(maxDiffJ), AbsValue(minDiffJ));
def normalizationRangeA = maxAbsDiffA * 1.2;
def normalizationRangeB = maxAbsDiffB * 1.2;
def normalizationRangeC = maxAbsDiffC * 1.2;
def normalizationRangeD = maxAbsDiffD * 1.2;
def normalizationRangeE = maxAbsDiffE * 1.2;
def normalizationRangeF = maxAbsDiffF * 1.2;
def normalizationRangeG = maxAbsDiffG * 1.2;
def normalizationRangeH = maxAbsDiffH * 1.2;
def normalizationRangeI = maxAbsDiffI * 1.2;
def normalizationRangeJ = maxAbsDiffJ * 1.2;
def normalizedDiffA = (normalizedCciA / normalizationRangeA) * 100;
def normalizedDiffB = (normalizedCciB / normalizationRangeB) * 100;
def normalizedDiffC = (normalizedCciC / normalizationRangeC) * 100;
def normalizedDiffD = (normalizedCciD / normalizationRangeD) * 100;
def normalizedDiffE = (normalizedCciE / normalizationRangeE) * 100;
def normalizedDiffF = (normalizedCciF / normalizationRangeF) * 100;
def normalizedDiffG = (normalizedCciG / normalizationRangeG) * 100;
def normalizedDiffH = (normalizedCciH / normalizationRangeH) * 100;
def normalizedDiffI = (normalizedCciI / normalizationRangeI) * 100;
def normalizedDiffJ = (normalizedCciJ / normalizationRangeJ) * 100;
def validNormalizedDiffA = if normalizationRangeA != 0 then normalizedDiffA else 0;
def validNormalizedDiffB = if normalizationRangeB != 0 then normalizedDiffB else 0;
def validNormalizedDiffC = if normalizationRangeC != 0 then normalizedDiffC else 0;
def validNormalizedDiffD = if normalizationRangeD != 0 then normalizedDiffD else 0;
def validNormalizedDiffE = if normalizationRangeE != 0 then normalizedDiffE else 0;
def validNormalizedDiffF = if normalizationRangeF != 0 then normalizedDiffF else 0;
def validNormalizedDiffG = if normalizationRangeG != 0 then normalizedDiffG else 0;
def validNormalizedDiffH = if normalizationRangeH != 0 then normalizedDiffH else 0;
def validNormalizedDiffI = if normalizationRangeI != 0 then normalizedDiffI else 0;
def validNormalizedDiffJ = if normalizationRangeJ != 0 then normalizedDiffJ else 0;
def adjustedPowerFactor = if powerFactor != 0 then 1 / powerFactor else 1;
def powerNormalizedDiffA = Power(AbsValue(validNormalizedDiffA), adjustedPowerFactor) * Sign(validNormalizedDiffA);
def powerNormalizedDiffB = Power(AbsValue(validNormalizedDiffB), adjustedPowerFactor) * Sign(validNormalizedDiffB);
def powerNormalizedDiffC = Power(AbsValue(validNormalizedDiffC), adjustedPowerFactor) * Sign(validNormalizedDiffC);
def powerNormalizedDiffD = Power(AbsValue(validNormalizedDiffD), adjustedPowerFactor) * Sign(validNormalizedDiffD);
def powerNormalizedDiffE = Power(AbsValue(validNormalizedDiffE), adjustedPowerFactor) * Sign(validNormalizedDiffE);
def powerNormalizedDiffF = Power(AbsValue(validNormalizedDiffF), adjustedPowerFactor) * Sign(validNormalizedDiffF);
def powerNormalizedDiffG = Power(AbsValue(validNormalizedDiffG), adjustedPowerFactor) * Sign(validNormalizedDiffG);
def powerNormalizedDiffH = Power(AbsValue(validNormalizedDiffH), adjustedPowerFactor) * Sign(validNormalizedDiffH);
def powerNormalizedDiffI = Power(AbsValue(validNormalizedDiffI), adjustedPowerFactor) * Sign(validNormalizedDiffI);
def powerNormalizedDiffJ = Power(AbsValue(validNormalizedDiffJ), adjustedPowerFactor) * Sign(validNormalizedDiffJ);
def scaledPowerNormalizedDiffA = powerNormalizedDiffA * (100 / maxTransformedValue);
def scaledPowerNormalizedDiffB = powerNormalizedDiffB * (100 / maxTransformedValue);
def scaledPowerNormalizedDiffC = powerNormalizedDiffC * (100 / maxTransformedValue);
def scaledPowerNormalizedDiffD = powerNormalizedDiffD * (100 / maxTransformedValue);
def scaledPowerNormalizedDiffE = powerNormalizedDiffE * (100 / maxTransformedValue);
def scaledPowerNormalizedDiffF = powerNormalizedDiffF * (100 / maxTransformedValue);
def scaledPowerNormalizedDiffG = powerNormalizedDiffG * (100 / maxTransformedValue);
def scaledPowerNormalizedDiffH = powerNormalizedDiffH * (100 / maxTransformedValue);
def scaledPowerNormalizedDiffI = powerNormalizedDiffI * (100 / maxTransformedValue);
def scaledPowerNormalizedDiffJ = powerNormalizedDiffJ * (100 / maxTransformedValue);
plot R1_Dot = if IsNaN(close) then Double.NaN else 1;
R1_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R1_Dot.SetLineWeight(DotSize);
R1_Dot.AssignValueColor(if scaledPowerNormalizedDiffA < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp"));
R1_Dot.HideBubble();
plot R2_Dot = if IsNaN(close) then Double.NaN else 2;
R2_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R2_Dot.SetLineWeight(DotSize);
R2_Dot.AssignValueColor(if scaledPowerNormalizedDiffB < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp"));
R2_Dot.HideBubble();
plot R3_Dot = if IsNaN(close) then Double.NaN else 3;
R3_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R3_Dot.SetLineWeight(DotSize);
R3_Dot.AssignValueColor(if scaledPowerNormalizedDiffC < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp"));
R3_Dot.HideBubble();
plot R4_Dot = if IsNaN(close) then Double.NaN else 4;
R4_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R4_Dot.SetLineWeight(DotSize);
R4_Dot.AssignValueColor(if scaledPowerNormalizedDiffD  < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp"));
R4_Dot.HideBubble();
plot R5_Dot = if IsNaN(close) then Double.NaN else 5;
R5_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R5_Dot.SetLineWeight(DotSize);
R5_Dot.AssignValueColor(if scaledPowerNormalizedDiffE < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp"));
R5_Dot.HideBubble();
plot R6_Dot = if IsNaN(close) then Double.NaN else 6;
R6_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R6_Dot.SetLineWeight(DotSize);
R6_Dot.AssignValueColor(if scaledPowerNormalizedDiffF < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2"));
R6_Dot.HideBubble();
plot R7_Dot = if IsNaN(close) then Double.NaN else 7;
R7_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R7_Dot.SetLineWeight(DotSize);
R7_Dot.AssignValueColor(if scaledPowerNormalizedDiffG < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2"));
R7_Dot.HideBubble();
plot R8_Dot = if IsNaN(close) then Double.NaN else 8;
R8_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R8_Dot.SetLineWeight(DotSize);
R8_Dot.AssignValueColor(if scaledPowerNormalizedDiffH < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2"));
R8_Dot.HideBubble();
plot R9_Dot = if IsNaN(close) then Double.NaN else 9;
R9_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R9_Dot.SetLineWeight(DotSize);
R9_Dot.AssignValueColor(if scaledPowerNormalizedDiffI  < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2"));
R9_Dot.HideBubble();
plot R10_Dot = if IsNaN(close) then Double.NaN else 10;
R10_Dot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
R10_Dot.SetLineWeight(DotSize);
R10_Dot.AssignValueColor(if scaledPowerNormalizedDiffJ < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2"));
R10_Dot.HideBubble();
#assignPriceColor
assignPriceColor( if apc == 1 then if scaledPowerNormalizedDiffA < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp") else
if apc == 2 then if scaledPowerNormalizedDiffB < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp") else
if apc == 3 then if scaledPowerNormalizedDiffC < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp") else
if apc == 4 then if scaledPowerNormalizedDiffD < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp") else
if apc == 5 then if scaledPowerNormalizedDiffE < 0 then GlobalColor("TrendDown") else GlobalColor("TrendUp") else
if apc == 6 then if scaledPowerNormalizedDiffF < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2") else
if APC == 7 THEN IF scaledPowerNormalizedDiffG < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2") else
if APC == 8 THEN IF scaledPowerNormalizedDiffH < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2") else
if APC == 9 THEN IF scaledPowerNormalizedDiffI < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2") else
if APC == 10 THEN IF scaledPowerNormalizedDiffJ < 0 then GlobalColor("TrendDown2") else GlobalColor("TrendUp2") else Color.current);``````
This is the CCI in lengths from 3 thru 30 with the fastest CCI on the lowest line going to longer lengths as you go up

You can also color the price bars by changing the APC to reflect the line you choose

Here's a composite scoring system using all the indicators above.
it's a crossing system. Sell crossing zero going down, Buy crossing zero going up.

Ruby:
``````###########################################
#Stochastic, CCI, RSI, MACD composite score
#This is a buy sell composite system
#that combines these indicators into
#a crossing function. Buy when crossing
# zero going up and sell when crossing down
#2024MtxDev/SteveClayton
###########################################

declare lower;

# Input parameters for each study
input fastLength = 10;
input slowLength = 20;
input signalLength = 5;
input macdPowerFactor = 1.5;
input cciLength = 18;
input cciMaLength = 19;
input cciPowerFactor = 1.8;
input rsiLength = 14;
input rsiMaLength = 14;
input rsiPowerFactor = 1.1;
input rsiSecondarySmoothLength = 3;
input kPeriod = 14;
input dPeriod = 3;
input slowingPeriod = 3;
input stochasticPowerFactor = 1.5;
input stochasticSmoothingLength = 3;
input overbought = 68;
input oversold = -68;

# Weights for each study
input macdWeight = 0.25;
input histogramWeight = 0.25;
input cciWeight = 0.25;
input rsiWeight = 0.25;
input stochasticWeight = 0.25;

# Optional smoothing average
input smoothingLength = 3;
input smoothingType = AverageType.HULL;
input useSmoothing = yes;

# Stochastic thresholds
input upperThreshold = 50;
input lowerThreshold = -50;

# MACD
def fastEMA = ExpAverage(close, fastLength);
def slowEMA = ExpAverage(close, slowLength);
def macdLine = fastEMA - slowEMA;
def signalLine = ExpAverage(macdLine, signalLength);
def histogram = macdLine - signalLine;

# Slope of MACD and Histogram
def macdSlope = macdLine - macdLine[1];
def histogramSlope = histogram - histogram[1];

# Normalize MACD
def macdMaxDiff = HighestAll(macdLine);
def macdMinDiff = LowestAll(macdLine);
def macdMaxAbsDiff = Max(AbsValue(macdMaxDiff), AbsValue(macdMinDiff));
def macdNormalizationRange = macdMaxAbsDiff * 1.2;
def macdNormalizedDiff = (macdLine / macdNormalizationRange) * 100;
def macdValidNormalizedDiff = if macdNormalizationRange != 0 then macdNormalizedDiff else 0;
def macdPowerNormalizedDiff = Power(AbsValue(macdValidNormalizedDiff), 1 / macdPowerFactor) * Sign(macdValidNormalizedDiff);
def macdMaxTransformedValue = Power(100, 1 / macdPowerFactor);
def macdScaledPowerNormalizedDiff = macdPowerNormalizedDiff * (100 / macdMaxTransformedValue);

# Normalize Histogram
def histMaxDiff = HighestAll(histogram);
def histMinDiff = LowestAll(histogram);
def histMaxAbsDiff = Max(AbsValue(histMaxDiff), AbsValue(histMinDiff));
def histNormalizationRange = histMaxAbsDiff * 1.2;
def histNormalizedDiff = (histogram / histNormalizationRange) * 100;
def histValidNormalizedDiff = if histNormalizationRange != 0 then histNormalizedDiff else 0;
def histPowerNormalizedDiff = Power(AbsValue(histValidNormalizedDiff), 1 / macdPowerFactor) * Sign(histValidNormalizedDiff);
def histMaxTransformedValue = Power(100, 1 / macdPowerFactor);
def histScaledPowerNormalizedDiff = histPowerNormalizedDiff * (100 / histMaxTransformedValue);

# CCI
def cci = CCI(cciLength);
def maCci = MovingAverage(AverageType.HULL, cci, cciMaLength);
def normalizedCci = cci - maCci;
def cciMaxDiff = HighestAll(normalizedCci);
def cciMinDiff = LowestAll(normalizedCci);
def cciMaxAbsDiff = Max(AbsValue(cciMaxDiff), AbsValue(cciMinDiff));
def cciNormalizationRange = cciMaxAbsDiff * 1.2;
def cciNormalizedDiff = (normalizedCci / cciNormalizationRange) * 100;
def cciValidNormalizedDiff = if cciNormalizationRange != 0 then cciNormalizedDiff else 0;
def cciPowerNormalizedDiff = Power(AbsValue(cciValidNormalizedDiff), 1 / cciPowerFactor) * Sign(cciValidNormalizedDiff);
def cciMaxTransformedValue = Power(100, 1 / cciPowerFactor);
def cciScaledPowerNormalizedDiff = cciPowerNormalizedDiff * (100 / cciMaxTransformedValue);

# Slope of CCI
def cciSlope = cciScaledPowerNormalizedDiff - cciScaledPowerNormalizedDiff[1];

# RSI
def rsi = RSI(rsiLength);
def maRsi = MovingAverage(AverageType.HULL, rsi, rsiMaLength);
def rawNormalizedRsi = rsi - maRsi;
def maxNormalizedRsi = HighestAll(rawNormalizedRsi);
def minNormalizedRsi = LowestAll(rawNormalizedRsi);
def maxAbsNormalizedRsi = Max(AbsValue(maxNormalizedRsi), AbsValue(minNormalizedRsi));
def rsiNormalizationRange = maxAbsNormalizedRsi * 1.1;
def normalizedRsi = (rawNormalizedRsi / rsiNormalizationRange) * 100;
def validNormalizedRsi = if rsiNormalizationRange != 0 then normalizedRsi else 0;
def rsiAdjustedPowerFactor = if rsiPowerFactor != 0 then 1 / rsiPowerFactor else 1;
def powerNormalizedRsi = Power(AbsValue(validNormalizedRsi), rsiAdjustedPowerFactor) * Sign(validNormalizedRsi);
def scaledPowerNormalizedRsi = powerNormalizedRsi * (100 / rsiMaxTransformedValue);
def smoothedPowerNormalizedRsi = MovingAverage(AverageType.HULL, scaledPowerNormalizedRsi, rsiSecondarySmoothLength);

# Slope of RSI
def rsiSlope = smoothedPowerNormalizedRsi - smoothedPowerNormalizedRsi[1];

# Stochastic
def highestHigh = Highest(high, kPeriod);
def lowestLow = Lowest(low, kPeriod);
def percentK = ((close - lowestLow) / (highestHigh - lowestLow)) * 100;
def smoothedK = SimpleMovingAvg(percentK, slowingPeriod);
def percentD = SimpleMovingAvg(smoothedK, dPeriod);

# Slope of Stochastic %K
def stochasticKSlope = smoothedK - smoothedK[1];

# Distance Calculation
def distanceFromBottom = AbsValue(smoothedK) - AbsValue(lowestLow);
def distanceFromTop = AbsValue(highestHigh) - AbsValue(smoothedK);
def normalizedDistance = if stochasticKSlope > 0 then (distanceFromBottom / 100) else (distanceFromTop / 100);
def signedNormalizedDistance = if stochasticKSlope > 0 then normalizedDistance else -normalizedDistance;

# Stochastic Scoring
def stochasticCrossScore = if smoothedK crosses above percentD then 2 else if smoothedK crosses below percentD then -2 else 0;
def stochasticThresholdScore = if smoothedK < lowerThreshold then 1 else if smoothedK > upperThreshold then -1 else 0;
def stochasticScore = -(stochasticCrossScore + stochasticThresholdScore + normalizedDistance) * stochasticWeight;

# Calculate scores for other studies
def macdCrossScore = if macdLine crosses above signalLine then 1 else if macdLine crosses below signalLine then -1 else 0;
def macdZeroCrossScore = if macdLine crosses above 0 then 2 else if macdLine crosses below 0 then -2 else 0;
def macdSlopeScore = if macdSlope > 0 then 1 else -1;
def macdScore = (macdCrossScore + macdZeroCrossScore + macdSlopeScore) * macdWeight;

def histogramZeroCrossScore = if histogram crosses above 0 then 2 else if histogram crosses below 0 then -2 else 0;
def histogramSlopeScore = if histogramSlope > 0 then 1 else -1;
def histogramNormalizedScore = (histogram / 50) * 2;
def histogramScore = (histogramNormalizedScore + histogramZeroCrossScore + histogramSlopeScore) * histogramWeight;

def cciZeroCrossScore = if cciScaledPowerNormalizedDiff crosses above 0 then 2 else if cciScaledPowerNormalizedDiff crosses below 0 then -2 else 0;
def cciSlopeScore = if cciSlope > 0 then 1 else -1;
def cciNormalizedScore = (cciScaledPowerNormalizedDiff / 50) * 2;
def cciScore = (cciNormalizedScore + cciZeroCrossScore + cciSlopeScore) * cciWeight;

def rsiZeroCrossScore = if smoothedPowerNormalizedRsi crosses above 0 then 2 else if smoothedPowerNormalizedRsi crosses below 0 then -2 else 0;
def rsiSlopeScore = if rsiSlope > 0 then 1 else -1;
def rsiNormalizedScore = (smoothedPowerNormalizedRsi / 50) * 2;
def rsiScore = (rsiNormalizedScore + rsiZeroCrossScore + rsiSlopeScore) * rsiWeight;

# Total combined score
def rawTotalScore = macdScore + histogramScore + cciScore + rsiScore + stochasticScore;

# Apply optional smoothing
def totalScore = if useSmoothing then MovingAverage(smoothingType, rawTotalScore, smoothingLength) else rawTotalScore;

# Plot the combined score
plot combinedScore = totalScore;
combinedScore.SetLineWeight(1);

# Add cloud coloring above and below the zero line
AddCloud(if combinedScore >= 0 then combinedScore else Double.NaN, 0, Color.GREEN);
AddCloud(if combinedScore < 0 then combinedScore else Double.NaN, 0, Color.RED);

# Add horizontal reference lines for zero, overbought, and oversold
plot zeroLine = 0;
zeroLine.SetDefaultColor(Color.GRAY);
#plot overboughtLine = overbought;
#overboughtLine.SetDefaultColor(Color.RED);
#plot oversoldLine = oversold;
#oversoldLine.SetDefaultColor(Color.GREEN);``````

Last edited by a moderator:
Here's a composite scoring system using all the indicators above.
it's a crossing system. Sell crossing zero going down, Buy crossing zero going up.
declare lower;

###########################################
#Stochastic, CCI, RSI, MACD composite score
#This is a buy sell composite system
#that combines these indicators into
#a crossing function. Buy when crossing
# zero going up and sell when crossing down
#2024MtxDev/SteveClayton
###########################################

declare lower;

# Input parameters for each study
input fastLength = 10;
input slowLength = 20;
input signalLength = 5;
input macdPowerFactor = 1.5;
input cciLength = 18;
input cciMaLength = 19;
input cciPowerFactor = 1.8;
input rsiLength = 14;
input rsiMaLength = 14;
input rsiPowerFactor = 1.1;
input rsiSecondarySmoothLength = 3;
input kPeriod = 14;
input dPeriod = 3;
input slowingPeriod = 3;
input stochasticPowerFactor = 1.5;
input stochasticSmoothingLength = 3;
input overbought = 68;
input oversold = -68;

# Weights for each study
input macdWeight = 0.25;
input histogramWeight = 0.25;
input cciWeight = 0.25;
input rsiWeight = 0.25;
input stochasticWeight = 0.25;

# Optional smoothing average
input smoothingLength = 3;
input smoothingType = AverageType.HULL;
input useSmoothing = yes;

# Stochastic thresholds
input upperThreshold = 50;
input lowerThreshold = -50;

# MACD
def fastEMA = ExpAverage(close, fastLength);
def slowEMA = ExpAverage(close, slowLength);
def macdLine = fastEMA - slowEMA;
def signalLine = ExpAverage(macdLine, signalLength);
def histogram = macdLine - signalLine;

# Slope of MACD and Histogram
def macdSlope = macdLine - macdLine[1];
def histogramSlope = histogram - histogram[1];

# Normalize MACD
def macdMaxDiff = HighestAll(macdLine);
def macdMinDiff = LowestAll(macdLine);
def macdMaxAbsDiff = Max(AbsValue(macdMaxDiff), AbsValue(macdMinDiff));
def macdNormalizationRange = macdMaxAbsDiff * 1.2;
def macdNormalizedDiff = (macdLine / macdNormalizationRange) * 100;
def macdValidNormalizedDiff = if macdNormalizationRange != 0 then macdNormalizedDiff else 0;
def macdPowerNormalizedDiff = Power(AbsValue(macdValidNormalizedDiff), 1 / macdPowerFactor) * Sign(macdValidNormalizedDiff);
def macdMaxTransformedValue = Power(100, 1 / macdPowerFactor);
def macdScaledPowerNormalizedDiff = macdPowerNormalizedDiff * (100 / macdMaxTransformedValue);

# Normalize Histogram
def histMaxDiff = HighestAll(histogram);
def histMinDiff = LowestAll(histogram);
def histMaxAbsDiff = Max(AbsValue(histMaxDiff), AbsValue(histMinDiff));
def histNormalizationRange = histMaxAbsDiff * 1.2;
def histNormalizedDiff = (histogram / histNormalizationRange) * 100;
def histValidNormalizedDiff = if histNormalizationRange != 0 then histNormalizedDiff else 0;
def histPowerNormalizedDiff = Power(AbsValue(histValidNormalizedDiff), 1 / macdPowerFactor) * Sign(histValidNormalizedDiff);
def histMaxTransformedValue = Power(100, 1 / macdPowerFactor);
def histScaledPowerNormalizedDiff = histPowerNormalizedDiff * (100 / histMaxTransformedValue);

# CCI
def cci = CCI(cciLength);
def maCci = MovingAverage(AverageType.HULL, cci, cciMaLength);
def normalizedCci = cci - maCci;
def cciMaxDiff = HighestAll(normalizedCci);
def cciMinDiff = LowestAll(normalizedCci);
def cciMaxAbsDiff = Max(AbsValue(cciMaxDiff), AbsValue(cciMinDiff));
def cciNormalizationRange = cciMaxAbsDiff * 1.2;
def cciNormalizedDiff = (normalizedCci / cciNormalizationRange) * 100;
def cciValidNormalizedDiff = if cciNormalizationRange != 0 then cciNormalizedDiff else 0;
def cciPowerNormalizedDiff = Power(AbsValue(cciValidNormalizedDiff), 1 / cciPowerFactor) * Sign(cciValidNormalizedDiff);
def cciMaxTransformedValue = Power(100, 1 / cciPowerFactor);
def cciScaledPowerNormalizedDiff = cciPowerNormalizedDiff * (100 / cciMaxTransformedValue);

# Slope of CCI
def cciSlope = cciScaledPowerNormalizedDiff - cciScaledPowerNormalizedDiff[1];

# RSI
def rsi = RSI(rsiLength);
def maRsi = MovingAverage(AverageType.HULL, rsi, rsiMaLength);
def rawNormalizedRsi = rsi - maRsi;
def maxNormalizedRsi = HighestAll(rawNormalizedRsi);
def minNormalizedRsi = LowestAll(rawNormalizedRsi);
def maxAbsNormalizedRsi = Max(AbsValue(maxNormalizedRsi), AbsValue(minNormalizedRsi));
def rsiNormalizationRange = maxAbsNormalizedRsi * 1.1;
def normalizedRsi = (rawNormalizedRsi / rsiNormalizationRange) * 100;
def validNormalizedRsi = if rsiNormalizationRange != 0 then normalizedRsi else 0;
def rsiAdjustedPowerFactor = if rsiPowerFactor != 0 then 1 / rsiPowerFactor else 1;
def powerNormalizedRsi = Power(AbsValue(validNormalizedRsi), rsiAdjustedPowerFactor) * Sign(validNormalizedRsi);
def scaledPowerNormalizedRsi = powerNormalizedRsi * (100 / rsiMaxTransformedValue);
def smoothedPowerNormalizedRsi = MovingAverage(AverageType.HULL, scaledPowerNormalizedRsi, rsiSecondarySmoothLength);

# Slope of RSI
def rsiSlope = smoothedPowerNormalizedRsi - smoothedPowerNormalizedRsi[1];

# Stochastic
def highestHigh = Highest(high, kPeriod);
def lowestLow = Lowest(low, kPeriod);
def percentK = ((close - lowestLow) / (highestHigh - lowestLow)) * 100;
def smoothedK = SimpleMovingAvg(percentK, slowingPeriod);
def percentD = SimpleMovingAvg(smoothedK, dPeriod);

# Slope of Stochastic %K
def stochasticKSlope = smoothedK - smoothedK[1];

# Distance Calculation
def distanceFromBottom = AbsValue(smoothedK) - AbsValue(lowestLow);
def distanceFromTop = AbsValue(highestHigh) - AbsValue(smoothedK);
def normalizedDistance = if stochasticKSlope > 0 then (distanceFromBottom / 100) else (distanceFromTop / 100);
def signedNormalizedDistance = if stochasticKSlope > 0 then normalizedDistance else -normalizedDistance;

# Stochastic Scoring
def stochasticCrossScore = if smoothedK crosses above percentD then 2 else if smoothedK crosses below percentD then -2 else 0;
def stochasticThresholdScore = if smoothedK < lowerThreshold then 1 else if smoothedK > upperThreshold then -1 else 0;
def stochasticScore = -(stochasticCrossScore + stochasticThresholdScore + normalizedDistance) * stochasticWeight;

# Calculate scores for other studies
def macdCrossScore = if macdLine crosses above signalLine then 1 else if macdLine crosses below signalLine then -1 else 0;
def macdZeroCrossScore = if macdLine crosses above 0 then 2 else if macdLine crosses below 0 then -2 else 0;
def macdSlopeScore = if macdSlope > 0 then 1 else -1;
def macdScore = (macdCrossScore + macdZeroCrossScore + macdSlopeScore) * macdWeight;

def histogramZeroCrossScore = if histogram crosses above 0 then 2 else if histogram crosses below 0 then -2 else 0;
def histogramSlopeScore = if histogramSlope > 0 then 1 else -1;
def histogramNormalizedScore = (histogram / 50) * 2;
def histogramScore = (histogramNormalizedScore + histogramZeroCrossScore + histogramSlopeScore) * histogramWeight;

def cciZeroCrossScore = if cciScaledPowerNormalizedDiff crosses above 0 then 2 else if cciScaledPowerNormalizedDiff crosses below 0 then -2 else 0;
def cciSlopeScore = if cciSlope > 0 then 1 else -1;
def cciNormalizedScore = (cciScaledPowerNormalizedDiff / 50) * 2;
def cciScore = (cciNormalizedScore + cciZeroCrossScore + cciSlopeScore) * cciWeight;

def rsiZeroCrossScore = if smoothedPowerNormalizedRsi crosses above 0 then 2 else if smoothedPowerNormalizedRsi crosses below 0 then -2 else 0;
def rsiSlopeScore = if rsiSlope > 0 then 1 else -1;
def rsiNormalizedScore = (smoothedPowerNormalizedRsi / 50) * 2;
def rsiScore = (rsiNormalizedScore + rsiZeroCrossScore + rsiSlopeScore) * rsiWeight;

# Total combined score
def rawTotalScore = macdScore + histogramScore + cciScore + rsiScore + stochasticScore;

# Apply optional smoothing
def totalScore = if useSmoothing then MovingAverage(smoothingType, rawTotalScore, smoothingLength) else rawTotalScore;

# Plot the combined score
plot combinedScore = totalScore;
combinedScore.SetLineWeight(1);

# Add cloud coloring above and below the zero line
AddCloud(if combinedScore >= 0 then combinedScore else Double.NaN, 0, Color.GREEN);
AddCloud(if combinedScore < 0 then combinedScore else Double.NaN, 0, Color.RED);

# Add horizontal reference lines for zero, overbought, and oversold
plot zeroLine = 0;
zeroLine.SetDefaultColor(Color.GRAY);
#plot overboughtLine = overbought;
#overboughtLine.SetDefaultColor(Color.RED);
#plot oversoldLine = oversold;
#oversoldLine.SetDefaultColor(Color.GREEN);
Are you saying that you have all of you indicators normalized to say the same thing? If so, why have multiple indicators?

Are you saying that you have all of you indicators normalized to say the same thing? If so, why have multiple indicators?

No, the oscillators are not "normalized" to say the same thing.
Oscillators oscillate on different scales.
Some range, 0-to-100
Some range -10-to +10
etc.. etc..
These oscillators are normalized to the same scale.

All that said, you are still correct.
Oscillators when optimized with the correct settings can be collinear.

Yes, they are telling you the same thing.
It is like putting 5 fuel gauges on your car.
While it is psychologically reassuring that all the fuel gauges read full.
It is not providing any additional value.

However, these particular scripts are not optimized to provide exactly the same information.
Some are looking more at momentum data, some looking more at price data.
Some are providing closer to trend analysis, while some are providing price action.

But unless you are purposefully creating the difference and understand how to analyze the difference.
No, putting many fuel gauges on your chart, will eat resources and not provide significant insights.

Here are two indicators that measures different types of information and provides a ranking:

Last edited:
No, the oscillators are not "normalized" to say the same thing.
Oscillators oscillate on different scales.
Some range, 0-to-100
Some range -10-to +10
etc.. etc..
These oscillators are normalized to the same scale.

All that said, you are still correct.
Oscillators when optimized with the correct settings can be collinear.

Yes, they are telling you the same thing.
It is like putting 5 fuel gauges on your car.
While it is psychologically reassuring that all the fuel gauges read full.
It is not providing any additional value.

However, these particular scripts are not optimized to provide exactly the same information.
Some are looking more at momentum data, some looking more at price data.
Some are providing closer to trend analysis, while some are providing price action.

But unless you are purposefully creating the difference and understand how to analyze the difference.
No, putting many fuel gauges on your chart, will eat resources and not provide significant insights.

Here are two indicator that measures different types of information and provides a ranking:
Now I'm gonna' go out and get a couple more fuel gauges for my car!

I should have been kinder with my answer!

Since the market is mathematical in nature, it is helpful to have each indicator (oscillator) look at the market from a slightly different mathematical perspective.

It better for 3 different indicators to point a change in direction, than have the same indicator (oscillator) say the same thing 3 times?

Last edited by a moderator:

87k+ Posts
354 Online

## The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
• Exclusive indicators
• Proven strategies & setups
• Private Discord community
• Exclusive members-only content
• 1 full year of unlimited support

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?