RVOL (Relative Volume) Scan Label Watchlist for ThinkorSwim

Thanks for this great script, very useful.

One question:

Can you or someone else explain what the following line does? (It is a question that has more to do with thinkScript basics, but wasn't able to find a similar example in TOS thinkscript pages to understand it)

# average of cumulative volume at this time of day for the last 10 trading days
def avgCumVolume = (cumVolume[(bpd*1)] + cumVolume[(bpd*2)] + cumVolume[(bpd*3)] + cumVolume[(bpd*4)] + cumVolume[(bpd*5)] + cumVolume[(bpd*6)] + cumVolume[(bpd*7)] + cumVolume[(bpd*8)] + cumVolume[(bpd*9)] + cumVolume[(bpd*10)]) / 10;

I understand -thanks to the comment- what it is supposed to do. But I don't get where is the cumVolume coming from.
Because when the cumVolume was declared a couple of lines above, it was storing the cumulative volume for the current day.
But in this line you can access the previous days' volume? How come? (no pun intended :p)

The index at the end of cumVolume, between the brackets [], defines how many candles back we are looking. In this case we use the bpd variable, which tells us how many bars there are in a day, and we're multiplying that by the number of days to look back. cumVolume with no index is equivalent to [0] and represents now. cumVolume[1] is the previous candle. cumVolume[bpd] is the candle at this time on the previous trading day.

That line retrieves the volume at that time of day for each of the previous 10 trading days and divides by 10 to get the average. That tells us what is "normal" volume by this time of day. Then we calculate today's volume so far as a % of that "normal".
 
Last edited:

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

How rvol is supposed to be calculated is well known to some of us but I guess it's good you got confirmation for others. There's code already in this thread that has the right intent in how to calculate rvol but it's buggy. I posted comments on how to fix it recently. I'll post my code which is specifically for a watchlist column and you guys can modify for other purposes.

Whoever posted the original code had concerns about it dragging down overall TOS performance which is why I made it handle multiple timeframes. The lower the timeframe the more the performance impact. Though, I'm not sure I ever ran it below 5m so I'm not sure if the concern is warranted. The only real benefit of using a low timeframe is that the data is meaningless until the first period closes and a small period will close earlier. After that it matters less on each subsequent period. Though, you also don't want to set this higher than needed because it compares current volume to the average volume at the start of the period. If you set to 1H then at 11:15 it's comparing current volume to the average at 10:30. Better to narrow that window. After I switched to swing trading I changed mine to 10m. Before that I was using 5m.

This data is meaningless in pre-market. Having accurate pre-market rvol on TOS isn't possible because TOS doesn't have data for periods with no volume and it skews trying to look at the same time of day on previous days. Don't use Extended Hours with this code.

RVOL Watchlist Column Don't use Extended Hours with this code.
Ruby:
input greenLevel = 1.5;

def period = GetAggregationPeriod();
def minutesPerBar = period / 60000;
def minutesPerDay = 60 * 6.5; # 6.5 hours of standard trading session
def bpd = minutesPerDay / minutesPerBar; # bars per day

# This is the cumulative volume for the current day
def day = GetDay();
def cumVolume =
  if day != day[1] then volume
  else cumVolume[1] + volume
;

# average of cumulative volume at this time of day for the last 10 trading days
def avgCumVolume = (cumVolume[(bpd*1)] + cumVolume[(bpd*2)] + cumVolume[(bpd*3)] + cumVolume[(bpd*4)] + cumVolume[(bpd*5)] + cumVolume[(bpd*6)] + cumVolume[(bpd*7)] + cumVolume[(bpd*8)] + cumVolume[(bpd*9)] + cumVolume[(bpd*10)]) / 10;

plot RVol = Round(if IsNaN(cumVolume) then 0 else cumVolume / avgCumVolume, 2);
RVol.AssignValueColor(if RVol >= 1 and RVol < greenLevel then Color.YELLOW else if RVol >= greenLevel then Color.LIGHT_GREEN else Color.PINK);
thanks this is a really good code closer to the real rvol! 2 questions:
1. i made it a label and understand that the time frame matters as you explained in the comments, if its 1 hour candles and the candle didnt complete yet, its using cumvolume end of last candle. What about on daily graph, is it calculating from yesterday?
2. follow up question, if i use it as a column in watchlist or scanner it seems to be calculating as if on the daily candle time frame, is there a way to change this to 15 min to be more accurate in the column?
 
thanks this is a really good code closer to the real rvol! 2 questions:
1. i made it a label and understand that the time frame matters as you explained in the comments, if its 1 hour candles and the candle didnt complete yet, its using cumvolume end of last candle. What about on daily graph, is it calculating from yesterday?
2. follow up question, if i use it as a column in watchlist or scanner it seems to be calculating as if on the daily candle time frame, is there a way to change this to 15 min to be more accurate in the column?

1. If you only need % of average total daily volume this code isn't ideal for that. It should work correctly but it excludes premarket volume due the issues with finding the correct time of day candles on prior days when extended hours is enabled. It also does a lot of math that just isn't necessary for the daily timeframe. On daily and higher timeframes, the much simpler solution of volume / Average(volume, 10) is more accurate and less work for your cpu.

2. When you're looking at the code for the column in TOS and it has a Column Name text field at the top of the window, change the D next to the text field to whatever timeframe you want.
 
Do you have a relative volume watchlist column that is also color-coded? These are game-changers.
 
Last edited by a moderator:
Here is the written code from the link @zeek provided:

Short version:

Code:
def rVol = volume / Average(volume, 21)[1];

AddLabel(yes, round(rVol,2));
#AddLabel(yes, asPercent(rVol));

AssignPriceColor(if rVol >= 1 then color.dark_red else if rVol <=.5 then Color.black else color.Gray);

Long version:

Code:
input length = 21;
input offset = 1;

def ADV = Average(volume, length)[offset];
def rVol = volume /ADV;

# remove "#" infront of Addlabels to select prefer choice

AddLabel(yes, round(rVol,2));
#AddLabel(yes, asPercent(rVol));

AssignPriceColor(if rVol >= 1 then color.dark_red else if rVol <=.5 then Color.black else color.Gray);
@BenTen Looking into other indicators and wanted to find a Relative Volume indicator like the Zanger indicator. Is there a recent version you would recommend?
 
I created an Rvol label for on your chart, it has options to change between percentage/decimal as well as the timeframe. Red is .5 or below, light green is 1.5-2, green is 2.0+. It can go in the volume or price section.

3yvnJ36.png



Shared Link: http://tos.mx/S4sHUMq (or use code below). Click here for --> Easiest way to load shared links

Code:
#Relative Volume on Chart by Wiinii: https://usethinkscript.com/threads/unusual-volume-moving-average-scan.1014/page-9#post-77659
declare upper;
input Timeframe = 30;
input AsPercent = yes;
def x = Average(volume(period = AggregationPeriod.DAY), Timeframe)[1];
def v = volume(period = AggregationPeriod.DAY);
def r = Round((v / x), (1));
AddLabel(yes, "RVol: " + (if AsPercent then Round((r * 100), (0)) else Round(r)) + (if AsPercent then "%" else ""), if r >= 2 then Color.GREEN else if r >= 1 then Color.LIGHT_GREEN else Color.RED);

This is set on the 30-day timeframe which is what Trade-Ideas uses, but you can change that in the code too (Benzinga uses 90-day intraday adjusted).

Here is also an RVOL Watchlist Column: http://tos.mx/mQabM5j

RVOL Scanner: http://tos.mx/4cDNqLc

Or just put this the above code as a custom scan filter (1.0 is average so changing the >1.0 to whatever you're looking for like >2.0 for twice-average):

Code:
RelativeVolume(30) > 1.0

And here's my Premarket RVOL scanner and watchlist column.
 
Last edited:
For intraday trading, I opt for the idea that comparing the volume in the same period of time in the past few days should be much more meaningful than comparing the current bar volume with the volumes in the immediately previous few bars.

Also, to compare relative volumes across different products, there is a need to standardize the relative volume, instead of just using multiples. For example, low priced stocks like Ford tend to give higher multiples than high priced stocks like Adobe. Therefore, I generated the code that calculate the standard deviation of relative volumes.

A great deal of this code should be attributed to Slippage and Mobius. I only did very little work by modifying the calculation logic to show the relative volume standard deviation during the same period in the last 20 days and changing the color scheme.

With this code, I can quickly find out what products have drawn the highest / lowest market attention in my watchlist and make a decision if I want to trade them.

WLC Version:

Code:
## Relative Volume StDev by Emrys (WLC version).
## Modified from the following coders’ work:
## (1) Relative Volume by Slippage:
## https://usethinkscript.com/threads/rvol-relative-volume-indicator-watchlist-for-thinkorswim.1014/page-7#post-58295
## (2) Partially based on Mobius code:
##https://usethinkscript.com/threads/looking-for-relative-volume-indicator-in-thinkorswim.241/
## Finally, the color scheme has been modified to reflect the idea of standard deviation.
## Green: above one StDev
## Yellow: below one StDev and above zero
## Pink: below zero and above minus one StDev
## Red: below minus one StDev

def period = GetAggregationPeriod();
def minutesPerBar = period / 60000;
def minutesPerDay = 60 * 6.5; # 6.5 hours of standard trading session
def bpd = minutesPerDay / minutesPerBar; # bars per day

# This is the cumulative volume for the current day
def day = GetDay();
def cumVolume =
  if day != day[1] then volume
  else cumVolume[1] + volume
;

# St Dev of cumulative volume at this time of day for the last 20 trading days
def avgCumVolume = (cumVolume[(bpd*1)] + cumVolume[(bpd*2)] + cumVolume[(bpd*3)] + cumVolume[(bpd*4)] + cumVolume[(bpd*5)] + cumVolume[(bpd*6)] + cumVolume[(bpd*7)] + cumVolume[(bpd*8)] + cumVolume[(bpd*9)] + cumVolume[(bpd*10)] + cumVolume[(bpd*11)] + cumVolume[(bpd*12)] + cumVolume[(bpd*13)] + cumVolume[(bpd*14)] + cumVolume[(bpd*15)] + cumVolume[(bpd*16)] + cumVolume[(bpd*17)] + cumVolume[(bpd*18)] + cumVolume[(bpd*19)] + cumVolume[(bpd*20)]) / 20;

def Variance = (Power((cumVolume[(bpd*1)]- avgCumVolume), 2) + Power((cumVolume[(bpd*2)]- avgCumVolume), 2) + Power((cumVolume[(bpd*3)]- avgCumVolume), 2) + Power((cumVolume[(bpd*4)]- avgCumVolume), 2) + Power((cumVolume[(bpd*5)]- avgCumVolume), 2) + Power((cumVolume[(bpd*6)]- avgCumVolume), 2) + Power((cumVolume[(bpd*7)]- avgCumVolume), 2) + Power((cumVolume[(bpd*8)]- avgCumVolume), 2) + Power((cumVolume[(bpd*9)]- avgCumVolume), 2) + Power((cumVolume[(bpd*10)]- avgCumVolume), 2) + Power((cumVolume[(bpd*11)]- avgCumVolume), 2) + Power((cumVolume[(bpd*12)]- avgCumVolume), 2) + Power((cumVolume[(bpd*13)]- avgCumVolume), 2) + Power((cumVolume[(bpd*14)]- avgCumVolume), 2) + Power((cumVolume[(bpd*15)]- avgCumVolume), 2) + Power((cumVolume[(bpd*16)]- avgCumVolume), 2) + Power((cumVolume[(bpd*17)]- avgCumVolume), 2) + Power((cumVolume[(bpd*18)]- avgCumVolume), 2) + Power((cumVolume[(bpd*19)]- avgCumVolume), 2) + Power((cumVolume[(bpd*20)]- avgCumVolume), 2)) / 20;

def SD = Sqrt(Variance);

def Diff = Round(if IsNaN(cumVolume) then 0 else cumVolume - avgCumVolume, 2);

plot R = Round(if volume == 0 then 0 else Diff / SD, 2);
       R.AssignValueColor(if R >= 1 then color.green
                   else if R>= 0 then color.yellow
else if R >= - 1 then color.pink
else color.red);
 
Last edited:
For intraday trading, I opt for the idea that comparing the volume in the same period of time in the past few days should be much more meaningful than comparing the current bar volume with the volumes in the immediately previous few bars.

Also, to compare relative volumes across different products, there is a need to standardize the relative volume, instead of just using multiples. For example, low priced stocks like Ford tend to give higher multiples than high priced stocks like Adobe. Therefore, I generated the code that calculate the standard deviation of relative volumes.

A great deal of this code should be attributed to Slippage and Mobius. I only did very little work by modifying the calculation logic to show the relative volume standard deviation during the same period in the last 20 days and changing the color scheme.

With this code, I can quickly find out what products have drawn the highest / lowest market attention in my watchlist and make a decision if I want to trade them.

WLC Version:

Code:
## Relative Volume StDev by Emrys (WLC version).
## Modified from the following coders’ work:
## (1) Relative Volume by Slippage:
## https://usethinkscript.com/threads/rvol-relative-volume-indicator-watchlist-for-thinkorswim.1014/page-7#post-58295
## (2) Partially based on Mobius code:
##https://usethinkscript.com/threads/looking-for-relative-volume-indicator-in-thinkorswim.241/
## Finally, the color scheme has been modified to reflect the idea of standard deviation.
## Green: above one StDev
## Yellow: below one StDev and above zero
## Pink: below zero and above minus one StDev
## Red: below minus one StDev

def period = GetAggregationPeriod();
def minutesPerBar = period / 60000;
def minutesPerDay = 60 * 6.5; # 6.5 hours of standard trading session
def bpd = minutesPerDay / minutesPerBar; # bars per day

# This is the cumulative volume for the current day
def day = GetDay();
def cumVolume =
  if day != day[1] then volume
  else cumVolume[1] + volume
;

# St Dev of cumulative volume at this time of day for the last 20 trading days
def avgCumVolume = (cumVolume[(bpd*1)] + cumVolume[(bpd*2)] + cumVolume[(bpd*3)] + cumVolume[(bpd*4)] + cumVolume[(bpd*5)] + cumVolume[(bpd*6)] + cumVolume[(bpd*7)] + cumVolume[(bpd*8)] + cumVolume[(bpd*9)] + cumVolume[(bpd*10)] + cumVolume[(bpd*11)] + cumVolume[(bpd*12)] + cumVolume[(bpd*13)] + cumVolume[(bpd*14)] + cumVolume[(bpd*15)] + cumVolume[(bpd*16)] + cumVolume[(bpd*17)] + cumVolume[(bpd*18)] + cumVolume[(bpd*19)] + cumVolume[(bpd*20)]) / 20;

def Variance = (Power((cumVolume[(bpd*1)]- avgCumVolume), 2) + Power((cumVolume[(bpd*2)]- avgCumVolume), 2) + Power((cumVolume[(bpd*3)]- avgCumVolume), 2) + Power((cumVolume[(bpd*4)]- avgCumVolume), 2) + Power((cumVolume[(bpd*5)]- avgCumVolume), 2) + Power((cumVolume[(bpd*6)]- avgCumVolume), 2) + Power((cumVolume[(bpd*7)]- avgCumVolume), 2) + Power((cumVolume[(bpd*8)]- avgCumVolume), 2) + Power((cumVolume[(bpd*9)]- avgCumVolume), 2) + Power((cumVolume[(bpd*10)]- avgCumVolume), 2) + Power((cumVolume[(bpd*11)]- avgCumVolume), 2) + Power((cumVolume[(bpd*12)]- avgCumVolume), 2) + Power((cumVolume[(bpd*13)]- avgCumVolume), 2) + Power((cumVolume[(bpd*14)]- avgCumVolume), 2) + Power((cumVolume[(bpd*15)]- avgCumVolume), 2) + Power((cumVolume[(bpd*16)]- avgCumVolume), 2) + Power((cumVolume[(bpd*17)]- avgCumVolume), 2) + Power((cumVolume[(bpd*18)]- avgCumVolume), 2) + Power((cumVolume[(bpd*19)]- avgCumVolume), 2) + Power((cumVolume[(bpd*20)]- avgCumVolume), 2)) / 20;

def SD = Sqrt(Variance);

def Diff = Round(if IsNaN(cumVolume) then 0 else cumVolume - avgCumVolume, 2);

plot R = Round(if volume == 0 then 0 else Diff / SD, 2);
       R.AssignValueColor(if R >= 1 then color.green
                   else if R>= 0 then color.yellow
else if R >= - 1 then color.pink
else color.red);
What's the use of SD and Variance... You seem to have it and not use it.

TIA
MN
 
What's the use of SD and Variance... You seem to have it and not use it.

TIA
MN

Thanks for the question.
SD (Standard Deviation) has been used as the denominator to generate R (Ratio), meaning how many standard deviations the current volume is compared to the historical 20 days in the same period of time.
Variance has been used to generate SD.

Please do let me know if you have found any problems or inaccuracy, especially the mathematical aspect.
 
Last edited:
Ruby:
Code:
input greenLevel = 1.5;

def period = GetAggregationPeriod();
def minutesPerBar = period / 60000;
def minutesPerDay = 60 * 6.5; # 6.5 hours of standard trading session
def bpd = minutesPerDay / minutesPerBar; # bars per day

# This is the cumulative volume for the current day
def day = GetDay();
def cumVolume =
  if day != day[1] then volume
  else cumVolume[1] + volume
;

# average of cumulative volume at this time of day for the last 10 trading days
def avgCumVolume = (cumVolume[(bpd*1)] + cumVolume[(bpd*2)] + cumVolume[(bpd*3)] + cumVolume[(bpd*4)] + cumVolume[(bpd*5)] + cumVolume[(bpd*6)] + cumVolume[(bpd*7)] + cumVolume[(bpd*8)] + cumVolume[(bpd*9)] + cumVolume[(bpd*10)]) / 10;

plot RVol = Round(if IsNaN(cumVolume) then 0 else cumVolume / avgCumVolume, 2);
RVol.AssignValueColor(if RVol >= 1 and RVol < greenLevel then Color.YELLOW else if RVol >= greenLevel then Color.LIGHT_GREEN else Color.PINK);

Correct me if I'm wrong but the GetDay(); function returns the current day of the year from 1 to 365. It doesn't count back bars from the current day with the current day holding [0].

Therefore RVol isn't correct.

Has anyone actually posted a functional and properly calculated RVol?
 
@crackedtrading While there isn't anything exactly like what you are asking on the forum. I moved your post to this thread because there are similar snippets sprinkled throughout these eight pages. Perhaps you will be able to glean enough to hobble something together.
 
The more I use rVol the more I realize it misses a lot of plays because a lot of stocks don't meet the criteria if they've already spiked a few days back, rest for a few days and go again.
 

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

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