If you use RSI on your chart, your trading will dramatically improve with visualizing the RSI on the upper chart and viewing RSI as candles on the lower chart. Notice the standard RSI at the bottom of the picture. It doesn't compare to seeing the candles hit the zones.
In both charts, there are gray shaded areas that are considered support and resistance zones. These areas are circled in the picture. The single colored lines represent the 70 and 30 levels. The colored shaded areas are extremes.
Original page: https://www.tradingview.com/script/ZgFgK9df-RSI-chart-overlay/
The upper chart code for Adaptive RSI Overlay:
Lower chart Adaptive RSI Zones code:
The actual RSI Line can be turned on in the settings. Note that the candle wicks are not always accurate. I'm still trying to find a way to perfect the candle wicks.
Original page: https://www.tradingview.com/script/CMBt48lk-RSI-adaptive-zones-AdaptiveRSI/
In both charts, there are gray shaded areas that are considered support and resistance zones. These areas are circled in the picture. The single colored lines represent the 70 and 30 levels. The colored shaded areas are extremes.
Original page: https://www.tradingview.com/script/ZgFgK9df-RSI-chart-overlay/
The upper chart code for Adaptive RSI Overlay:
Code:
# Adaptive RSI Overlay
# Converted by Chewie 11/30/2025
# Original page: https://www.tradingview.com/script/ZgFgK9df-RSI-chart-overlay/
declare upper;
input Length = 14;
input UpperLevel = 70;
input LowerLevel = 30;
input show_EMA = yes;
input show_fill = no;
# Wilder RMA inline
def alpha = 1.0 / Length;
def myEMA = CompoundValue(1, alpha * close + (1 - alpha) * myEMA[1], close);
def absChange = AbsValue(close - close[1]);
def CC_vol = CompoundValue(1, alpha * absChange + (1 - alpha) * CC_vol[1], absChange);
def normalization_factor = Length - 1;
def max_width = CC_vol * normalization_factor;
def up_b = myEMA + (UpperLevel - 50) / 50 * max_width;
def down_b = myEMA - (50 - LowerLevel) / 50 * max_width;
def uz1 = myEMA + (59.9 - 50) / 50 * max_width;
def uz2 = myEMA + (63.5 - 50) / 50 * max_width;
def dz1 = myEMA - (50 - 40.9) / 50 * max_width;
def dz2 = myEMA - (50 - 36.5) / 50 * max_width;
def uz3 = myEMA + (72.33 - 50) / 50 * max_width;
def uz4 = myEMA + (76.58 - 50) / 50 * max_width;
def dz3 = myEMA - (50 - 27.7) / 50 * max_width;
def dz4 = myEMA - (50 - 23.4) / 50 * max_width;
AddCloud(uz2, uz1, color.gray, color.gray);
AddCloud(dz1, dz2, color.gray, color.gray);
AddCloud(uz4, uz3, color.red, color.red);
AddCloud(dz3, dz4, color.green, color.green);
plot EMAline = if show_EMA then myEMA else Double.NaN;
EMAline.SetDefaultColor(color.yellow);
EMAline.SetLineWeight(2);
plot Upper = up_b;
Upper.SetDefaultColor(color.red);
Upper.SetLineWeight(2);
plot Lower = down_b;
Lower.SetDefaultColor(color.green);
Lower.SetLineWeight(2);
# Overbought cloud:
def obTop = if show_fill and close > up_b then close else Double.NaN;
def obBot = up_b;
AddCloud(obTop, obBot, color.red, color.red);
# Oversold cloud:
def osTop = down_b;
def osBot = if show_fill and close < down_b then close else Double.NaN;
AddCloud(osTop, osBot, color.green, color.green);
Lower chart Adaptive RSI Zones code:
The actual RSI Line can be turned on in the settings. Note that the candle wicks are not always accurate. I'm still trying to find a way to perfect the candle wicks.
Original page: https://www.tradingview.com/script/CMBt48lk-RSI-adaptive-zones-AdaptiveRSI/
Code:
# RSI_Adaptive_Zones
# Converted by Chewie 11/29/2025
# Original page https://www.tradingview.com/script/CMBt48lk-RSI-adaptive-zones-AdaptiveRSI/
declare lower;
input Length = 14;
input showAVGLine = yes;
input showRSILine = no;
input showZones = yes;
# Common numeric constants
def SF = 1.0 / Length;
def power_exponent = 0.5;
def inv_sqrt_lenm1 = 1.0 / Power(Length - 1.0, power_exponent);
def eps = 0.00000001;
# -- Recursive (RMA-like) smoothing using CompoundValue
def middle = CompoundValue(1, (1 - SF) * middle[1] + SF * close, close);
# intrabar middles
def middle_O = CompoundValue(1, (1 - SF) * middle_O[1] + SF * open, open);
def middle_H = CompoundValue(1, (1 - SF) * middle_H[1] + SF * high, high);
def middle_L = CompoundValue(1, (1 - SF) * middle_L[1] + SF * low, low);
# CC_vol (rma of absolute changes)
def CC_vol = CompoundValue(1, (1 - SF) * CC_vol[1] + SF * AbsValue(close - close[1]), AbsValue(close - close[1]));
def CC_vol_O = CompoundValue(1, (1 - SF) * CC_vol_O[1] + SF * AbsValue(open - close[1]), AbsValue(open - close[1]));
def CC_vol_H = CompoundValue(1, (1 - SF) * CC_vol_H[1] + SF * AbsValue(high - close[1]), AbsValue(high - close[1]));
def CC_vol_L = CompoundValue(1, (1 - SF) * CC_vol_L[1] + SF * AbsValue(low - close[1]), AbsValue(low - close[1]));
# denominators
def den_C = Max(CC_vol, eps) * (Length - 1.0);
def den_O = Max(CC_vol_O, eps) * (Length - 1.0);
def den_H = Max(CC_vol_H, eps) * (Length - 1.0);
def den_L = Max(CC_vol_L, eps) * (Length - 1.0);
plot half_range = 50.0;
half_range.setdefaultColor(color.yellow);
half_range.Hidebubble();
plot OB = 70.0;
OB.setlineWeight(2);
OB.setdefaultColor(color.red);
OB.Hidebubble();
plot OS = 30.0;
OS.setlineWeight(2);
OS.setdefaultColor(color.green);
OS.Hidebubble();
# --- compute raw RSI-like values ---
def raw_myRSI = half_range + half_range * ((close - middle) / den_C);
def raw_RSI_O = half_range + half_range * ((open - middle_O) / den_O);
def raw_RSI_H = half_range + half_range * ((high - middle_H) / den_H);
def raw_RSI_L = half_range + half_range * ((low - middle_L) / den_L);
# --- clamp to 0..100 to keep values on standard RSI scale ---
def myRSI = if IsNaN(raw_myRSI) then Double.NaN else Min(100, Max(0, raw_myRSI));
def RSI_O = if IsNaN(raw_RSI_O) then Double.NaN else Min(100, Max(0, raw_RSI_O));
def RSI_H = if IsNaN(raw_RSI_H) then Double.NaN else Min(100, Max(0, raw_RSI_H));
def RSI_L = if IsNaN(raw_RSI_L) then Double.NaN else Min(100, Max(0, raw_RSI_L));
# thresholds (z → RSI distance mapping)
def body_threshold = Sqrt((5.0 - Sqrt(17.0)) / 2.0); # ≈0.658
def tail_threshold = Sqrt((5.0 + Sqrt(17.0)) / 2.0); # ≈2.135
def breakout_threshold = 1.0;
def reversal_threshold = Sqrt(3.0);
# tanh script
script TANH {
input x = 0.0;
plot tanh = (Exp(2.0 * x) - 1.0) / (Exp(2.0 * x) + 1.0);
}
# RSI distance script
script RSI_distance_from50 {
input z = 0.0;
input invsqrt = 1.0;
plot out = 50 * TANH(x = z * invsqrt).tanh;
}
def Z_ins = RSI_distance_from50(z = body_threshold, invsqrt = inv_sqrt_lenm1).out;
def Z_out = RSI_distance_from50(z = breakout_threshold, invsqrt = inv_sqrt_lenm1).out;
def OO_ins = RSI_distance_from50(z = reversal_threshold, invsqrt = inv_sqrt_lenm1).out;
def OO_out = RSI_distance_from50(z = tail_threshold, invsqrt = inv_sqrt_lenm1).out;
plot RSI_Line = if showRSILine then myRSI else Double.NaN;
RSI_Line.SetDefaultColor(Color.white);
RSI_Line.SetLineWeight(1);
RSI_Line.SetPaintingStrategy(PaintingStrategy.LINE);
# Middle line at 50
plot RSI_Mid = if showRSILine then 50 else Double.NaN;
RSI_Mid.SetDefaultColor(Color.DARK_GRAY);
RSI_Mid.SetLineWeight(1);
RSI_Mid.SetPaintingStrategy(PaintingStrategy.LINE);
# Zone clouds: make levels NaN when showZones is false
def topOB = if showZones then 50 + OO_out else Double.NaN;
def botOB = if showZones then 50 + OO_ins else Double.NaN;
def topOS = if showZones then 50 - OO_ins else Double.NaN;
def botOS = if showZones then 50 - OO_out else Double.NaN;
def topRes = if showZones then 50 + Z_out else Double.NaN;
def botRes = if showZones then 50 + Z_ins else Double.NaN;
def topSup = if showZones then 50 - Z_ins else Double.NaN;
def botSup = if showZones then 50 - Z_out else Double.NaN;
# AddCloud calls (NaN levels are ignored)
AddCloud(topOB, botOB, Color.RED, Color.RED);
AddCloud(topOS, botOS, Color.GREEN, Color.GREEN);
AddCloud(topRes, botRes, Color.LIGHT_GRAY, Color.GRAY);
AddCloud(topSup, botSup, Color.LIGHT_GRAY, Color.GRAY);
input fillBodies = yes;
def rsiO_raw = myRSI[1];
def rsiC_raw = myRSI;
def rsiH_raw = RSI_H;
def rsiL_raw = RSI_L;
def rsiO_pre = if IsNaN(rsiO_raw) then rsiC_raw else rsiO_raw;
def rsiH_unclamped = Max(rsiH_raw, Max(rsiO_pre, rsiC_raw));
def rsiL_unclamped = Min(rsiL_raw, Min(rsiO_pre, rsiC_raw));
def rsiO = Min(100, Max(0, rsiO_pre));
def rsiC = Min(100, Max(0, rsiC_raw));
def rsiH = Min(100, Max(0, rsiH_unclamped));
def rsiL = Min(100, Max(0, rsiL_unclamped));
def tiny = 0.0001;
def rsiH_final = if rsiH == rsiL then rsiH + tiny else rsiH;
def rsiL_final = if rsiH == rsiL then rsiL - tiny else rsiL;
#==========================#
# Up Candle
#==========================#
def UpO = if rsiO <= rsiC then (if fillBodies then rsiC else rsiO) else Double.NaN;
#def UpH = if rsiO <= rsiC then rsiH_final else Double.NaN;
#def UpL = if rsiO <= rsiC then rsiL_final else Double.NaN;
def UpH = if rsiO <= rsiC then rsi_h else Double.NaN;
def UpL = if rsiO <= rsiC then rsi_l else Double.NaN;
def UpC = if rsiO <= rsiC then (if fillBodies then rsiO else rsiC) else Double.NaN;
#==========================#
# Down Candle
#==========================#
def DnO = if rsiO >= rsiC then (if fillBodies then rsiO else rsiC) else Double.NaN;
#def DnH = if rsiO >= rsiC then rsiH_final else Double.NaN;
#def DnL = if rsiO >= rsiC then rsiL_final else Double.NaN;
def DnH = if rsiO >= rsiC then rsi_H else Double.NaN;
def DnL = if rsiO >= rsiC then rsi_L else Double.NaN;
def DnC = if rsiO >= rsiC then (if fillBodies then rsiC else rsiO) else Double.NaN;
#==========================#
# Doji Candle (O == C)
#==========================#
def DojiO = if rsiO == rsiC then rsiO else Double.NaN;
#def DojiH = if rsiO == rsiC then rsiH_final else Double.NaN;
#def DojiL = if rsiO == rsiC then rsiL_final else Double.NaN;
def DojiH = if rsiO == rsiC then rsi_H else Double.NaN;
def DojiL = if rsiO == rsiC then rsi_L else Double.NaN;
def DojiC = if rsiO == rsiC then rsiC else Double.NaN;
#==========================#
# Paint RSI Candles
#==========================#
# Define Global Colors
DefineGlobalColor("RSIMagenta", Color.MAGENTA);
DefineGlobalColor("RSICyan", Color.CYAN);
DefineGlobalColor("RSIUp", Color.UPTICK);
DefineGlobalColor("RSIDown", Color.DOWNTICK);
DefineGlobalColor("RSIDoji", Color.WHITE);
# Conditions
def isMagenta = rsiH > OB;
def isCyan = rsiL < OS;
def isUp = rsiC > rsiO;
def isDown = rsiC < rsiO;
def isDoji = rsiC == rsiO;
# Up candle
AddChart(
high = if isup then UpH else Double.NaN,
low = if isup then UpL else Double.NaN,
open = if isup then UpO else Double.NaN,
close= if isup then UpC else Double.NaN,
type = ChartType.CANDLE,
GlobalColor("RSIup")
);
# Down candle
AddChart(
high = DnH,
low = DnL,
open = DnO,
close= DnC,
type = ChartType.CANDLE,
GlobalColor("RSIDown")
);
# Doji
AddChart(
high = DojiH,
low = DojiL,
open = DojiO,
close= DojiC,
type = ChartType.CANDLE,
GlobalColor("RSIDoji")
);
# Magenta
AddChart(
high = if isMagenta then rsiH else Double.NaN,
low = if isMagenta then rsiL else Double.NaN,
open = if isMagenta then rsiO else Double.NaN, # swap
close= if isMagenta then rsiC else Double.NaN, # swap
type = ChartType.CANDLE,
GlobalColor("RSIMagenta")
);
# Cyan
AddChart(
high = if isCyan then rsiH else Double.NaN,
low = if isCyan then rsiL else Double.NaN,
open = if isCyan then rsiC else Double.NaN, # swap
close= if isCyan then rsiO else Double.NaN, # swap
type = ChartType.CANDLE,
GlobalColor("RSICyan")
);
input AvgLength = 14;
def price = close;
def averageType = AverageType.WILDERS;
# Short Length
def NetChgAvg = MovingAverage(averageType, price - price[1], AvgLength);
def TotChgAvg = MovingAverage(averageType, AbsValue(price - price[1]), AvgLength);
def ChgRatio = if TotChgAvg != 0 then NetChgAvg / TotChgAvg else 0;
def RSI = 50 * (ChgRatio + 1);
DEF price2 = rsi;
DEF displace = 0;
plot AvgExp = if showAVGLine then ExpAverage(price2[-displace], AvgLength) else double.nan;
AVGEXP.setdefaultColor(color.cyan);
avgexp.setlineWeight(2);
Last edited: