#// Indicator for TOS
#// © upslidedown
#// One of the first indicators I ever used was %R, and I realized that with crypto strategies a period of 112
#// provided very interesting results in trend following strategies. This indicator intends to mix standard %R
#// with the longer period %R and show key areas of interest. Using classic overbought/oversold logic, the
#// indicator highlights a key trend and a subsequent break in that trend. When this condition is detected it
#// will print a reversal arrow down. This is one of my odder ideas that appears to have some merit, so I'm
#// publicly publishing for the community to find. If you find this useful please reach out and let me know.
#Hint ExhaustionThreshold: Sets the overbought/oversold zone size and offset. Lower values will produce less results, higher values towards 50 will produce many results.
#Hint showCrossovers: Experimental idea for plotting crossovers with attempted bull/bear coloring. This needs to be combined with other TA but typically crossover condition results in interesting price action during or after.
#indicator("%R Trend Exhaustion [upslidedown]", format=format.price, precision=2, explicit_plot_zorder=true)
# Converted by Sam4Cok@Samer800 - 03/2025
declare lower;
input formula = {default "Standard (2 Period)", "Average"}; # "Formula"
input Source = close; #, "Source", group=groupSettings)
input ExhaustionThreshold = 20; #itle="Exhaustion Threshold", minval=1, maxval=50, group=groupSettings,
input smoothType = AverageType.EXPONENTIAL; #('ema', title="Smoothing Type"
input average_ma = 3; #, "Average Formula MA", group=groupSettings)
input showCloud = yes; #="Fill Gradients in OB/OS Zone"
input showCrossovers = no; #tle="Highlight Crossovers"
input plot_zero_crosses = no; # title="Plot Zero Line Crosses"
input fastLength = 21; #(title="fast Length", defval=21, group=lookbackGroupName)
input fastSmoothingLength = 7; #, title="Fast Smoothing Length", group=lookbackGroupName)
input slowLength = 112; #, title="Slow Length", minval=1, group=lookbackGroupName)
input slowSmoothingLength = 3; #, title="Slow Smoothing Length", group=lookbackGroupName)
def na = Double.NaN;
def last = IsNaN(close);
def use_average = formula == formula."Average";
#// functions
Script _pr {
input src = close;
input length = 112;
def max = highest(high, length);
def min = lowest(low, length);
def pr = 100 * (src - max) / (max - min);
plot out = pr;
}
def s_percentR1 = _pr(Source, fastLength);
def l_percentR1 = _pr(Source, slowLength);
def avg_percentR1 = (s_percentR1 + l_percentR1) / 2;
def s_percentR = if fastSmoothingLength>1 then MovingAverage(smoothType,s_percentR1,fastSmoothingLength) else s_percentR1;
def l_percentR = if slowSmoothingLength>1 then MovingAverage(smoothType,l_percentR1,slowSmoothingLength) else l_percentR1;
def avg_percentR = if average_ma>1 then MovingAverage(smoothType,avg_percentR1,average_ma) else avg_percentR1;
def overbought; def oversold; def ob_reversal;
def os_reversal; def ob_trend_start; def os_trend_start;
Switch (formula) {
Case "Average":
overbought = avg_percentR >= -ExhaustionThreshold;
oversold = avg_percentR <= -100+ExhaustionThreshold;
ob_reversal = !overbought and overbought[1];
os_reversal = !oversold and oversold[1];
ob_trend_start = overbought and !overbought[1];
os_trend_start = oversold and !oversold[1];
Default:
overbought = s_percentR >= -ExhaustionThreshold and l_percentR >= -ExhaustionThreshold;
oversold = s_percentR <= -100+ExhaustionThreshold and l_percentR <= -100+ExhaustionThreshold;
ob_reversal = !overbought and overbought[1];
os_reversal = !oversold and oversold[1];
ob_trend_start = overbought and !overbought[1];
os_trend_start = oversold and !oversold[1];
}
def bool_cross_long1 = (s_percentR Crosses Above -50);
def bool_cross_long2 = (l_percentR Crosses Above -50);
def cross_zero_long = bool_cross_long1 or bool_cross_long2;
def bool_cross_short1 = (s_percentR Crosses Below -50);
def bool_cross_short2 = (l_percentR Crosses Below -50);
def cross_zero_short = bool_cross_short1 or bool_cross_short2;
def zero_long = (s_percentR > -50 and l_percentR > -50) and cross_zero_long;
def zero_short = (s_percentR < -50 and l_percentR < -50) and cross_zero_short;
#// detect crossovers for potential "in between" signals
def cross_bear = (l_percentR Crosses Above s_percentR);
def cross_bull = (l_percentR Crosses Below s_percentR);
#-- crosses
plot obRev = if ob_reversal then 0 else na; # "Overbought Trend Reversal ▼"
plot osRev = if os_reversal then -100 else na; # "Oversold Trend Reversal ▲"
plot obSig = if overbought then 5 else na; # "Overbought Trend Warning ■"
plot osSig = if oversold then -105 else na; # "Oversold Trend Warning ■"
plot zeroLong = if zero_long and plot_zero_crosses then 5 else na; # "Zero Cross Long",
plot zeroShort = if zero_short and plot_zero_crosses then -105 else na; # "Zero Cross Short"
plot cross = if showCrossovers and (cross_bull or cross_bear) then l_percentR else na; #, "Crossover Dot (small)"
plot obStart = if ob_trend_start then 5 else na; # char="◡", color=bearcol
plot osStart = if os_trend_start then -105 else na; # char="◠", color=bullcol,
obRev.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
osRev.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
obSig.SetPaintingStrategy(PaintingStrategy.SQUARES);
osSig.SetPaintingStrategy(PaintingStrategy.SQUARES);
zeroLong.SetStyle(Curve.POINTS);
zeroShort.SetStyle(Curve.POINTS);
cross.SetPaintingStrategy(PaintingStrategy.LINE_VS_POINTS);
obStart.SetPaintingStrategy(PaintingStrategy.LINE_VS_SQUARES);
osStart.SetPaintingStrategy(PaintingStrategy.LINE_VS_SQUARES);
obRev.SetDefaultColor(Color.MAGENTA);
osRev.SetDefaultColor(Color.CYAN);
obSig.SetDefaultColor(Color.MAGENTA);
osSig.SetDefaultColor(Color.CYAN);
zeroLong.SetDefaultColor(Color.YELLOW);
zeroShort.SetDefaultColor(Color.YELLOW);
cross.SetDefaultColor(Color.WHITE);
obStart.SetDefaultColor(Color.GRAY);
osStart.SetDefaultColor(Color.GRAY);
#// plot %R
plot p_fastr = if !last and !use_average then s_percentR else na; # "Fast Period %R"
plot p_slowr = if !last and !use_average then l_percentR else na; # "Slow Period %R"
plot p_avgr = if !last and use_average then avg_percentR else na; # "Average Formula %R"
p_avgr.SetLineWeight(2);
p_fastr.SetDefaultColor(Color.WHITE);
p_slowr.SetDefaultColor(Color.VIOLET);
p_avgr.SetDefaultColor(Color.WHITE);
#// Print lines for stuff
plot top = if !last then 0 else na; #, 'Top'
plot band1 = if !last then -ExhaustionThreshold else na; #, 'Top Threshold'
plot middle = if !last then -50 else na; #, 'Middle Line'
plot band0 = if !last then -100+ExhaustionThreshold else na; #, 'Bottom Threshold'
plot bottom = if !last then -100 else na; #, 'Bottom'
top.SetPaintingStrategy(PaintingStrategy.DASHES);
band1.SetPaintingStrategy(PaintingStrategy.DASHES);
middle.SetPaintingStrategy(PaintingStrategy.DASHES);
band0.SetPaintingStrategy(PaintingStrategy.DASHES);
bottom.SetPaintingStrategy(PaintingStrategy.DASHES);
top.SetDefaultColor(Color.RED);
band1.SetDefaultColor(Color.DARK_RED);
middle.SetDefaultColor(Color.DARK_GRAY);
band0.SetDefaultColor(Color.DARK_GREEN);
bottom.SetDefaultColor(Color.GREEN);
#-- Cloud
def maxCol = if showCloud then Max(p_slowr, p_fastr) else na;
def minCol = if showCloud then Min(p_slowr, p_fastr) else na;
AddCloud(maxCol, Max(Min(p_fastr, p_slowr), -20), Color.RED, Color.CURRENT); #"Overbought Gradient Fill")
AddCloud(min(Max(p_fastr, p_slowr), -80), minCol, Color.GREEN, Color.CURRENT); # "Oversold Gradient Fill")
#-- END of CODE