IBD Stock Charts Style and Scan for ThinkorSwim

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

Hi,

Please help me to convert this to an scan, I like to be able to scan for symbols that for example are above 60 or between 50 and 60
thanks for advanced

Code:
#RS_Rank - 8/28/2019 Developed by GHorschman  ([email protected])
# This is a custom quote to compute the Relative Strength percentile.
# It is calculated the same way that IV_Percentile is computed. Just
# change the length to specify the time frame of interest. The
# background color is tied to the following ranges:
#
# RS_Rank > 80 -- Dark Green
# 80 <= RS_Rank < 60 -- Light Green
# 60 <= RS_Rank < 40 -- Gray
# 40 <= RS_Rank < 20 -- Light Red
# RS_Rank <= 20 -- Dark Red
######################################################################

# Set length to period of interest.

# 1 Wk – 5 trading days
# 1 Mos – 21 Days
# 3 Mos – 63 Days
# 6 Mos – 126 Days
# 12 Mos – 252 Days

def length = 10;

#def RS = if IsNan(relativeStrength("SPX")) then 0 else relativeStrength("SPX") ;
def RS = relativeStrength("SPX");
def RSLow = Lowest(RS, length);
def RSHigh = Highest(RS, length);
def RSRank = round(100 * (RS - RSLow) / (RSHigh - RsLow),1);
addlabel (yes,RSRank);

#AddLabel (yes, if RSRank >= 1 and RSRank < 100 then "000" + astext(RSRank) else astext( RSRank) );

assignbackgroundcolor (if RSRank > 80 then color.dark_green else
if RSRank > 60 and RSRank <= 80 then createcolor(0,175,0) else
if RSRank > 40 and RSRank <= 60 then color.gray else
if RSRank > 20 and RSRank <= 40 then CreateColor(220, 0,0) else
if RSRank <= 20 then CreateColor(150, 0,0) else
color.white);
 
Last edited:
@ReyHak In your code, change def RSRank to plot RSRank. Then add the script as an indicator.

Set up your scanner to something like this:

kGW8g3T.png
 
@BenTen thank you so much, I did that but it does not like this section, it's highlighted red, what do I with it?
def RS = relativeStrength(""SPX"");
do you mind pasting the whole thing for me? not sure what I'm doing wrong
thank you
 
@ReyHak You need to edit the RSRank not the RS. It's a few lines below.
ah got it, thank you I also had to remove the labels
when I add this as a custom scan, the condition wizard tab so I can tell it look for between 50 and 60 or whatever the case is, it's grayed out, how do I get around that?
thanks you again
 
@ReyHak You didn't follow my instructions. You need to modify the script first then add it into ToS as an indicator. After that, you go to your scanner > add Study filter > add new condition and then set up a condition similar to this:

kGW8g3T.png
 
@RayHak Why do you have The symbol as ""SPY"" instead of "SPY"...??? You don't need double quotes around text anywhere in TOS...
 
@BenTen @red14733 ok worked like a charm, I need to layoff the alcohol while doing this =)
Thanks again, I didn't understand the indicator part originally
 
@ReyHak @BenTen Above in post #83, the header was stripped out. We always do our best to leave the header intact to give credit where it is due.
Please edit the post above with these two lines:
Code:
#RS_Rank - 8/28/2019 Developed by GHorschman  ([email protected])
#######################################################################
Thank you, Markos
 
Hello everyone,

I would like to know if anyone has created the similar TOS indicator as IBD Relative strength line or ranking.

Thank you
 
Instead of trying to mimic IBD RS line (for which no one has exact formula) lets do a simple construct which is easily doable in TOS platform as I have been using it for a while and works like a charm.

Steps:
1. A simple RS line using price (already exist in TOS platform by default) but if you are not satisfied then use RS ranking provided here. You can also modify the script further (require quite a bit of coding in TOS) to create RS ranking based on the date you select (e.g. create RS ranking based on 3/23/2020 to get even better results)
2. You can use the custom script under scan tab to identify stocks with RS Rank>=90 on weekly time frame.
3. Any of the following (to identify stocks which are in low volatility mode or in pullback close to MA(10) and eliminate stocks which are not in consolidation to reduce candidates)
a. Choppiness index (period = 3 on weekly) found here
b. Low within 2% of MA(10) weekly

Scan typically produces 200+ candidates, however you can sort them based on RS Rank and select top 100 as per your liking.

Till now we did not consider volume factor, but you can add to further narrow down the list using any of below: (or better just scan by eyes)
1. Volume indicator
2. AccDist (default provided by TOS)
3. Fundamental factors such as EPS growth per Qtr (same year), growth per Qtr (Prior year), earning surprise % - will require quite a bit of coding in TOS else simply go here.

All these will be prime candidates for next breakout and works perfect.

Hope this helps :)
 
Very interesting thread to me and a lot of helpful information.

I particularly liked the scripts from @wtf_dude since it tries to follow O'Neil's descriptions. I made a updated script trying to add the comparison to a general market index and rank from 1 to 99 according to the O'Neil's web site.

I did not spend much time to test it though. Please let me know if the script makes sense if interested.

Code:
#    SMO_RsRank.ts
#    2021-01-21
#    Added comparison against a broad market index and ranks from 1 to 99
#    O'Neil price performance RS ranking
#    WTF_Dude
#    5.5.20
#    color styling codes from #WLC_RS1Yr RS_Rank by GHorschman
#     `
#    RS_Rank > 80       -- Dark Green
#    80 <= RS_Rank < 60 -- Light Green
#    60 <= RS_Rank < 40 -- Gray
#    40 <= RS_Rank < 20 -- Light Red
#    RS_Rank <= 20      -- Dark Red
######################################################################

script wtf_dude_rsrank {
# Set length to period of interest.

input len1 = 63;
input len2 = 126;
input len3 = 189;
input len4 = 252;
input cl =  close;

def year = if cl-cl[len4] is less than 0 then 0 else cl-cl[len4] ;
def nine =  if cl-cl[len3] is less than 0 then 0 else cl-cl[len3] ;
def six =  if cl-cl[len2] is less than 0 then 0 else cl-cl[len2] ;;
def three = if cl-cl[len1] is less than 0 then 0 else cl-cl[len1] ;;
def weighted = if ((2*three) + six + nine + year)/4 is less than 0 then 0 else ((2*three + six + nine + year)/4); #decimal

def h = highest(high, len4);
def l = lowest(low, len4);
def hilo = absvalue(h-l);
def calc = weighted/ hilo;

plot rsrank = round(100* calc,0);
#addlabel (yes,RSRank);
}

#  1 Wk – 5 trading days
#  1 Mos – 21 Days
#  3 Mos – 63 Days
#  6 Mos – 126 Days
#  12 Mos – 252 Days
def len1 = 63;
def len2 = 126;
def len3 = 189;
def len4 = 252;

def stock_rsrank = wtf_dude_rsrank(len1, len2, len3, len4, close);
def index_rsrank = wtf_dude_rsrank(len1, len2, len3, len4, close("SPX"));

def RS = stock_rsrank/index_rsrank;

def HHData = HighestAll(RS);
def LLData = LowestAll(RS);

plot nr = (( 98 * ( RS - LLData )) / ( HHData - LLData )) + 1;
nr.hide();
#AddLabel(yes, Concat("RS Ranking: ", nr[0]), Color.WHITE);

AddLabel(yes, Concat("RS Ranking: ", round(nr[0], 0)),
        if nr > 80 then color.dark_green else
                       if nr > 60 and nr <= 80 then createcolor(0,175,0) else
                       if nr > 40 and nr <= 60 then color.gray else
                       if nr > 20 and nr <= 40 then CreateColor(220, 0,0) else
                       if nr <= 20 then CreateColor(150, 0,0) else
                       color.white);

Edit: Sorry, I did some testing and found two issues so far in the above code.

1). the sub function should have two more inputs: priceHi and Lo.

The code below does not work for the index since it always use high/low of the current stock.

Code:
def h = highest(high, len4);
def l = lowest(low, len4);

2). the main code section should have the following changed:

Code:
def HHData = HighestAll(RS);
def LLData = LowestAll(RS);
to new code:
def HHData = Highest(RS, len4);
def LLData = Lowest(RS, len4);

It looks like I have to spend more time to debug the code.:mad:
 
Last edited by a moderator:
I did some more researches on the IBD Relative Strength Rank. There are a number of helpful sources from this thread and tradingview as well as William O'Neil/IBD and their former manager's websites. But none of them appear to provide any scripts generating a percentile rank of the RS against a group of other stocks directly.

So, I made an attempt to create a TOS script that can generate both the RS and its ranking percentile against a group of stock, without the need to actually sort through the database every time. In particular, this script can project a RS ranking score from 1 to 99 and display it on the chart for each stock. It can also display the RS curve when a user enables the relevant code.

Users can integrate this code with other stock selection criteria in their stock scan process. A typical usage is the RS Rank > 90 when selecting the top market performing CANSLIM stocks. The code is self-documented on its usage. Basically, users should get 3 calibration data to obtain a proper ranking: the RS scores of top & bottom 5th stocks, and top 50th stock when SPX is used as the general index.

I expect the changes of these RS scores are limited each day and so is the impact on the RS rank. So the calibration can probably be done weekly or monthly.

I tested the script with a few high-flying IBD stocks and it appears to generate somewhat higher scores than those from IBD. I suspect if we choose NASDAQ composite, which has higher performance than SPX, as the general market index, the percentile rank will then reduce a bit. The script needs updating to support recent IPO's.

Hope this script is useful and can get improved from user's feedback and code updates.

Code:
#==============================================================================
# SMO_RsRank.ts:  TOS script mimicking IBD Relative Strength Rank
# Version 1: 2021-01-24
# Calculated according to the following principles:
#   The Relative Strength Rating is the result of calculating a stock’s
#   percentage change of prices over the last 4 quarters:
#   A 40% weight is assigned to the latest quarter period;
#   the remaining three quarters each has 20% weight.
#   The stock's price performance is compared w/ a general market index
#   (e.g.SPX) to generate relative strength.
#   It's intended to rate stocks in order of greatest price performance
#   and assigned a percentile rank from 99 (highest) to 1 (lowest). A 50% rank
#   indicates same price performance as the general market index.
#
# Two step usage procedure:
#   1). Get calibrated data first
#       Create a custom scan by copying the code from the beginning to the
#       the section marked as "End of Scan Code Section"
#       Need to add a custom quote named as "IBD_RS" for sorting top and
#       bottom scores
#   2). Input calibrated data
#       Put the obtained data to the variables defined below the section
#       named "Multipoint Calibration"
#       There are 3 data points for this version and may be updated weekly
#       or monthly, depending on your trading time frame.
#   The prices used here are close prices and the quarter may be calendar
#   quarter or other number of days if shorter term ranking is desired.
#==============================================================================

script my_rsrank {
# Set length to period of interest.
# Only total length of days is input and other periods are derived
input len4 = 252;
input cl =  close;

def len1 = round(len4/4, 0);   #63;
def len2 = len1 * 2; #126;
def len3 = len1 * 3; #189

# Calculate price change percentages per quarter
def p4q = (cl[len3]-cl[len4]) / cl[len4];
def p3q = (cl[len2]-cl[len3]) / cl[len3];
def p2q = (cl[len1]-cl[len2]) / cl[len2];
def p1q = (cl-cl[len1]) / cl[len1];
def weighted = ((2*p1q) + p2q + p3q + p4q) / 5;

plot rsrank = 100 * weighted;
}

#  1 Wk – 5 trading days
#  1 Mos – 21 Days
#  3 Mos – 63 Days
#  6 Mos – 126 Days
#  12 Mos – 252 Days
def len4 = 252;
# Use the following for 6 month period ranking
#def len4 = 126;

def stockCl = close;
def indexCl = close("SPX");

def stock_rsrank = my_rsrank(len4, stockCl);
#plot stockdbg = stock_rsrank;

def index_rsrank = my_rsrank(len4, indexCl);
#plot indexdbg = index_rsrank;

def index_rsrank1 = if (index_rsrank == 0, index_rsrank[1], index_rsrank);
def RS = stock_rsrank/index_rsrank1;

#------------------- Code required for Custom Quote in Scan Tab----------------
# Selectively uncomment the following code in scan tab
# The following RS scores as of today need to be adjusted in each periodical
# calibrations
# Possible RS scores for bottom 1%
#input rs_score = -1;
# Possible RS scores for top 1%
#input rs_score = 4.5;
# Possible RS scores for top 10%
#input rs_score = 2.8;
#plot scan = if rs_score <= 0 then rs < rs_score else
#            rs > rs_score;
#---------------- End of Scan Code Section ------------------------------------

# Uncomment the following if display of relative strength is required
# Please select the option of left axis for this indicator
#plot rsCurve = rs;

#-------------------- Multipoint Calibration ----------------------------------
# Get the max & min values of RS for the reference index_rsrank (e.g. SPX)
# by using the TOS scan /w customized quote IBD_RS and sorting the results
# Max value is the min rs value of the top 5 (1%) stocks in the SP 500
# Min value is the max rs value of the bottom 5 (1%) stocks in the SP 500
# The calibration should be done weekly or at other time as necessary
# Replace the values below with the values obtained from custom quote

# RS score corresponding to 99 percentile
def HHData = 6.1;
# RS score corresponding to 1 percentile
def LLData = -1.1;
# Add a 90% calibration point since we are very interested at this percentile
# The RS score should be the score of top n'th stock,
# where n is the Total number of Index Stocks (e.g. 505 for SPX) x (100% - 90%)
# (e.g. 51 for SPX)
def d90    = 2.91;

#------------------- End of Calibration Data -----------------------------------

# For SPX & SPY, the RS score should be 1 and correlate to a 50 percentile rank
def d50    = 1;

def rsCalibrated = if rs > HHData then HHData else
                   if rs < LLData then LLData else
                   RS;
#plot dbgCal = rsCalibrated;

# Create final RS rank /w multiple point calibrated segments
# Formula for each segment:
# Segment RS Rank = [(End RS Rank - Start RS Rank) * (RScalibrated - Start RS)) /
#                   (End RS - Start RS)] + Start RS Rank
plot nr = # Segment:  Start Rank: 1, End Rank: 50
          if rsCalibrated <= 1 then
            (( 49 * ( RScalibrated - LLData )) / ( d50 - LLData )) + 1
          else
          # Segment: Start Rank: 51, End Rank: 90
          if rsCalibrated <= d90 then
            (( 39 * ( RScalibrated - d50 )) / ( d90 - d50 )) + 51
          # Segment: Start Rank: 91, End Rank: 99
          else
            (( 8 * ( RScalibrated - d90 )) / ( HHData - d90 )) + 91;
nr.hide();

# Color coding from top to bottom ranks:
# Bright Green -> Dark Green -> Grey -> Dark Red -> Bright Red
AddLabel(yes, Concat("RS Ranking: ", round(nr, 0)),
        if nr > 80 then color.green else
                       if nr > 60 and nr <= 80 then color.dark_green else
                       if nr > 40 and nr <= 60 then color.gray else
                       if nr > 20 and nr <= 40 then color.red else
                       color.red) ;
# End of Code
 
This looks VERY neat, especially for those of us who have been pining for an IBD RS rank. But I am SO confused based on the provided directions...
 
This looks VERY neat, especially for those of us who have been pining for an IBD RS rank. But I am SO confused based on the provided directions...
Yes, this one is a bit more complicated, because of the need to find the 3 RS scores from the scan tab, in order to calculate the RS rank.

Here's some more instructions on how to use the code. I think It's still necessary to read the descriptions in the script though.

The key part to obtain the RS Rank is to obtain 3 critical calibration points of IBD_RS scores in a database. Let's use TOS scan for SP500 index as an example and assume there are 500 stocks for easy calculation.

1). RS score corresponding to 99 percentile

This 99% outperforming percentile means 500 x 1% = 5, i.e. the 5th top RS score is equivalent to 99% rank. To make it easy to count a limited number of stocks, use the code that you've already put into the scan study:
# Possible RS scores for top 1%
input rs_score = 4.5;
You can reduce the value of 4.5 when the scan could not produce 5 stocks and increase the value when the scan produces too many number of stocks (e.g. over 50) for you to find the 5th one. Now sort the TOS scan results by IBD_RS (a custom quote added for this script) in a decreasing order, you can find the 5th stock is someone like DISA. Its IBD_RS score is 4.65.

Then, put this value in the variable below:
def HHData = 4.65; # was 6.1;
2). RS score corresponding to 1 percentile
For the same reason, select code in the scan study script to find the bottom 1% underperforming RS score, which is the 5th lowest score.
# Possible RS scores for bottom 1%
input rs_score = -1;
The 5th lowest RS score may be NI or other stocks. If you find its IBD_RS score is -1.17. then, put this value into the variable below:
def LLData = -1.17; #-1.1;
3). Add a 90% calibration point since we are very interested at this percentile
We'll be looking for the RS score of the top 50th stock in this case. Select the code in the scan study below:
# Possible RS scores for top 10%
input rs_score = 2.8;
Make sure your scan results show all stocks satisfying the scan criteria by showing 100 or more stocks. Say you find the stock of the 50th (or 51th) highest RS value is NVDA and it has RS value of 3.07. Then, change the value of the following variable to 3.07 as shown below:
# The RS score should be the score of top n'th stock,
# where n is the Total number of Index Stocks (e.g. 505 for SPX) x (100% - 90%)
# (e.g. 51 for SPX)
def d90 = 3.07; #2.91;
 
What I use is the IBD 50 list from Here and run a TMO scan for OS and look for an entry. If you join IBD Digital(for $35 a month I believe) You get High RS, Stock Spotlight, Large Caps 20, New 52 Week High and other lists. I just update my IBD 50 once or twice a week. Hope this helps someone

I also use 20 day average volume above 1Million and price above 200EMA. Works for me for Swing trades.
 

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

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