# Cyclic RSI
# Origanlly found on Tradingview: https://www.tradingview.com/v/TmqiR1jp/
# Shout out to WentToTrade for the amazing indicator.
# Written in ThinkScript by mfox
# The cyclic smoothed RSI indicator is an enhancement of the classic RSI , adding
# additional smoothing according to the market vibration,
# adaptive upper and lower bands according to the cyclic memory and
# using the current dominant cycle length as input for the indicator.
# The cRSI is used like a standard indicator. The chart highlights trading signals where the signal line # crosses above or below the adaptive lower/upper bands. It is much more responsive to market moves than the basic RSI.
# The indicator uses the dominant cycle as input to optimize signal, smoothing and cyclic memory. To get more in-depth information on the cyclic-smoothed RSI indicator, please read Chapter 4 "Fine tuning technical indicators" of the book "Decoding the Hidden Market Rhythm, Part 1" available at your favorite book store.
declare lower;
input aggregationperiod = aggregationperiod.min;
input price = fundamentalType.CLOSE;
def src = fundamental(price, period=aggregationperiod);
input domcycle = 20;
def cyclelen = domcycle / 1.5;
def vibration = 10;
def leveling = 10.0;
def cyclicmemory = domcycle * 2;
plot h1 = 10;
h1.SetDefaultColor(Color.WHITE);
h1.SetPaintingStrategy(PaintingStrategy.DASHES);
h1.SetLineWeight(1);
plot h2 = 80;
h2.SetDefaultColor(Color.WHITE);
h2.SetPaintingStrategy(PaintingStrategy.DASHES);
h2.SetLineWeight(1);
def torque = 2.0 / (vibration + 1.0);
def phasingLag = (vibration - 1.0) / 2.0;
script nz {
input data = 0;
def ret_val = if IsNaN(data) then 0 else data;
plot return = ret_val;
}
script rma {
input src = 0;
input length = 0;
def alpha = 1 / length;
def sum = alpha * src + ( 1 - alpha) * nz(sum[1]);
plot return = sum;
}
script change {
input data = 0;
plot return = data - GetValue(data, 1);
}
def up = rma(Max(change(src), 0), cyclelen);
def down = rma(-Min(change(src), 0), cyclelen);
def rsi = if down == 0 then 100 else if up == 0 then 0 else 100 - 100 / (1 + up / down);
def crsi = torque * (2 * rsi - rsi[phasingLag]) + (1 - torque) * nz(crsi[1]);
def lm_hist = if crsi > Highest(crsi, cyclicmemory - 1) and !IsNaN(lm_hist[1])
then crsi
else if -crsi < Lowest(crsi, cyclicmemory - 1) and !IsNaN(lm_hist[1])
then -crsi
else 0;
def lmax = -Highest(lm_hist, cyclicmemory - 1);
def lmin = -Lowest(lm_hist, cyclicmemory - 1);
def mstep = (lmax - lmin) / 100;
def aperc = leveling / 100;
def db = fold dbx = 0 to 100
while (fold blx = 0 to cyclicmemory - 1
with b
do b + if crsi[blx] < lmin + mstep * dbx
then 1
else 0) / cyclicmemory >= aperc
do lmin + mstep * dbx;
def ub = fold ubx = 0 to 100
while (fold ulx = 0 to cyclicmemory - 1
with a
do a + if crsi[ulx] >= lmax - mstep * ubx
then 1
else 0) / cyclicmemory >= aperc
do lmax - mstep * ubx;
plot lowband = db;
lowband.SetDefaultColor(Color.RED);
plot highband = ub;
highband.SetDefaultColor(Color.GREEN);
plot C = crsi;
c.assignValueColor(if src>= src[4] then Color.green else Color.red);
c.assignValueColor(if src<= src[4] then Color.red else Color.green);
AddCloud(db, ub, Color.DARK_GRAY, Color.DARK_GRAY);
AddCloud(h1, if C < h1 then C else Double.NaN, Color.DARK_RED, Color.DARK_RED);
AddCloud(h2, if C > h2 then C else Double.NaN, Color.DARK_GREEN, Color.DARK_GREEN);
#assignPriceColor(if c>h2 then color.red else
# color.gray);
AssignPriceColor( if C > lowband and C < highband then Color.GRAY else if C > highband then Color.RED else if C crosses below highband then Color.YELLOW else Color. WHITE);
input showBreakoutSignals = yes;
plot signaldown = if C crosses below highband then highband else Double.NaN;
signaldown.SetHiding(!showBreakoutSignals);
signaldown.SetDefaultColor(Color.RED);
signaldown.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
signaldown.HideTitle();