Dominant Cycle + RSI = Cyclic RSI for ThinkOrSwim

mfox

Member
Author states:
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.

I originally found this little beauty on TradingView, written by WhenToTrade. It combines the dominant cycle length to create adaptive RSI overbought/oversold bands for more responsive signals.
I've found it works perfectly fine on any time frame, for general stocks as well as crypto. I have been combining it with the Volatility Box and a simple MACD. Today I used this combination and pulled a 20 minute, 80% profit from EGOC.

mod note: This script is too complicated to scan the Universe of stocks.
Some members have had some success when limiting scans to a small subset such as the S&P100
u0LrE2z.png

Code:
# 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;

def src = close;
input domcycle = 20;
def cyclelen = domcycle / 2;
def vibration = 10;
def leveling = 10.0;
def cyclicmemory = domcycle * 2;

input RSIOversold = 30;
input RSIOverbought = 70;

plot h1 = RSIOversold;
h1.SetDefaultColor(Color.WHITE);
h1.SetPaintingStrategy(PaintingStrategy.DASHES);
h1.SetLineWeight(1);

plot h2 = RSIOverbought;
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.GREEN);

plot highband = ub;
highband.SetDefaultColor(Color.RED);

plot C = crsi;
C.SetDefaultColor(Color.PLUM);

plot Oversold = C < lowband;
Oversold.Hide();

plot Overbought = C > highband;
Overbought.Hide();

plot SuperOversold = lowband < RSIOversold and Oversold;
SuperOversold.Hide();

plot SuperOverbought = highband > RSIOverbought and Overbought;
SuperOverbought.Hide();

AddCloud(db, ub, Color.DARK_GRAY, Color.DARK_GRAY);
AddCloud(0, if SuperOversold then 100 else Double.NaN, Color.GREEN, Color.GREEN);
AddCloud(0, if SuperOverbought then 100 else Double.NaN, Color.RED, Color.RED);

Enjoy.
 
Last edited by a moderator:

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

It's really nice - thanks - very helpful to see on charts - however, I don't seem to be able to get it to scan, though, with system timeouts - maybe it's too complex as is?
 
I originally found this little beauty on TradingView, written by WhenToTrade. It combines the dominant cycle length to create adaptive RSI overbought/oversold bands for more responsive signals.

Code:
# 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;

def src = close;
input domcycle = 20;
def cyclelen = domcycle / 2;
def vibration = 10;
def leveling = 10.0;
def cyclicmemory = domcycle * 2;

plot h1 = 30;
h1.SetDefaultColor(Color.White);
h1.SetPaintingStrategy(PaintingStrategy.DASHES);
h1.SetlineWeight(1);

plot h2 = 70;
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.SetDefaultColor(Color.PLUM);

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);

AmiEvyR.png


The image was taken from WhenToTrade's own listing here. However, I've found it works perfectly fine on any time frame, for general stocks as well as crypto. I have been combining it with the Volatility Box and a simple MACD. Today I used this combination and pulled a 20 minute, 80% profit from EGOC.

For my next trick, I'll be attempting to convert one of WhenToTrade's other indicators, the Detrended Rhythm Oscillator, which gives insight into the proper dominant cycle to use, accounting for time frame.

Enjoy.
Thanks a lot , it can easily find the bottoms when combined with other indicators.
 
Sorry - I see that it does work if you search on S&P 500 or a smaller subset of symbols
You are right. When I first posted it I hadn't wrote a scan for it, and after writing it I thought it was broken! In fact I was writing a question in another thread about optimizing it further. The nested Fold's are crushing the processing time, so if you can limit your search prior to scanning
Code:
CyclicRSI().C < CyclicRSI().lowband
the faster it will be. I'm hoping to revisit it soon and see if I can optimize it.
 
Last edited by a moderator:
@Rojo Grande
It will work in the scanner, but on a limited basis. It really helps to narrow down your search results as much as possible to running the scanner on it. However, as I see no way of optimizing the folds in the code further, I believe you'd be better off narrowing your search results and checking the CRSI individually.

Likewise, it appears that, historically speaking, there is a limit to amount of data the indicator can process. I've noticed that more than 1-2 days in a 5-minute time frame will cause an error about not being enough data to render, and the indicator will simply cutoff.

Sorry for any conveniences with it. While I'm confident in the logic being spot on with WhenToTrade's code, I am far from an expert in ThinkScript.
 
Will you share what you're using to scan for this please?
My entire scan is just volume, close, and then one of the following based on what you are looking for:
Code:
CyclicRSI().OverSold
Code:
CyclicRSI().OverBought
Code:
CyclicRSI().SuperOverSold
Code:
CyclicRSI().SuperOverBought

But I'm narrowing my results down a LOT by setting a very tight range of close that I search for (sub-penny to 0.01 or 0.02), and a moderately high volume that I've customized based on what I typically find in the market. That alone doesn't usually return more than 100 or 200 stocks, which allows the CyclicRSI() to still be scanned without timing out.

Edit: I just scanned with it and was able to retrieve 6 stocks which satisfy my scan. Hope that helps.
 
I took some time during the weekend and today live on /NQ 3 mins, the dominating cycle 20 seems to work best. I tried everything from 1 to 90. Still, the Detrended Rhythm Oscillator might be useful to fine-tune it in a longer time frame.
 
I took some time during the weekend and today live on /NQ 3 mins, the dominating cycle 20 seems to work best. I tried everything from 1 to 90. Still, the Detrended Rhythm Oscillator might be useful to fine-tune it in a longer time frame.
I was unaware that TOS had that built in, but unfortunately it doesn't satisfy what I was planning to do. Seeing the limitations of the processing for scans I'm not sure it's possible now, even if it's just to place a label on the chart that says "Use ## Dominant Cycle". You'd have to find a way to look up a handful of both previous highs and lows, then calculate the intercept of the line of best fit for the highs/lows plotted with their bar-number equivalent. Traditionally, you'd manually inspect the values for repeating fibs or common ranges (20s, 40s, 80s, or multiples of these), but I found that y = mx+b lands very close. I found pairing it with a MACD where the fast is half the cycle and the slow equals the cycle generally removes a lot of noise in-between Cyclic RSI dips below the low-band.
 
I have experimented with this indicator. here is my thought on it.

These are 2 indicators working together. One is Cyclic RSI and the other is Bollinger band.

https://tos.mx/CQZciro

After the green bar on Cyclic RSI wait until the price goes above the upper Bollinger band and exit when the price drops back under the upper Bollinger band. I have also shown how to short sell can be done on the chart. Let me know your thoughts on it.

here is the image link.

https://ibb.co/hMsR9cb
 
I have experimented with this indicator. here is my thought on it.

These are 2 indicators working together. One is Cyclic RSI and the other is Bollinger band.

https://tos.mx/CQZciro

After the green bar on Cyclic RSI wait until the price goes above the upper Bollinger band and exit when the price drops back under the upper Bollinger band. I have also shown how to short sell can be done on the chart. Let me know your thoughts on it.

here is the image link.

https://ibb.co/hMsR9cb
Assuming the price is represented by the purple line? Also, looking at your image, it shows an exit after the first buy but when do you buy again? If you exit on the first exit, how can you sell on the two sells if you already edited? Sell when purple drops below green?
 
Assuming the price is represented by the purple line? Also, looking at your image, it shows an exit after the first buy but when do you buy again? If you exit on the first exit, how can you sell on the two sells if you already edited? Sell when purple drops below green?
Hi, I was just showing what could be better bought after the green bar on cyclic RSI. I am not looking at the purple line but the green and red bar on the indicator. It will be buying again when the green bar hit and after that, the blue candle appears. exit when red candle hit or take part profit when gray candle appears.
 
@mfox thanks for posting, this seems fantastic. especially on daily 10 min it does a good job of identifying tops and bottoms. majority of the time stocks don't trend a straight direction throughout the day so this looks to identify tops/bottoms pretty well
 
@mfox thanks for posting, this seems fantastic. especially on daily 10 min it does a good job of identifying tops and bottoms. majority of the time stocks don't trend a straight direction throughout the day so this looks to identify tops/bottoms pretty well
I'm glad to hear it works for you. I mostly look at it to confirm opening-bell reversals and play short morning flips. I would still like to circle back to this in the future and make it faster, if that's even possible, but unfortunately I still work aside from day trading and my time is currently too limited to dive into it again. Best of luck with it in the future.
 
anyone please?
Since everything seems to be based off of 'src' then modify the 'src' code with

Ruby:
input aggregationperiod = aggregationperiod.min;
input price = fundamentalType.CLOSE;
def src     = fundamental(price, period=aggregationperiod);
 
trying to get the assignvalue color on this any help. i got somewhat close but not entirely

Ruby:
# 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();
 

Attachments

  • 7-10-2022 6-30-06 PM.jpg
    7-10-2022 6-30-06 PM.jpg
    30 KB · Views: 471
Last edited by a moderator:

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
376 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