Volume Profile Indicator & POCs For ThinkOrSwim

thanks you all for your priceless contribution. I am quite new to scripting and I spent my whole day trying to make changes to the script from @john3 to suit my need but to no avail.

Basically, I want to do a scan base off the previous daily LVA. I want to scan stock after the open, where the opening price is above or within VA, but the current price is below the VA. Can anyone help?
 
thanks you all for your priceless contribution. I am quite new to scripting and I spent my whole day trying to make changes to the script from @john3 to suit my need but to no avail.

Basically, I want to do a scan base off the previous daily LVA. I want to scan stock after the open, where the opening price is above or within VA, but the current price is below the VA. Can anyone help?

See if this helps. It plots the previous day's HVA and LVA and a label with those values to use in your scan

Capture.jpg
Ruby:
def period;
def yyyymmdd = getYyyyMmDd();
def seconds = secondsFromTime(0);
def month = getYear() * 12 + getMonth();
def day_number = daysFromDate(first(yyyymmdd)) + getDayOfWeek(first(yyyymmdd));
def dom = getDayOfMonth(yyyymmdd);
def dow = getDayOfWeek(yyyymmdd - dom + 1);
def expthismonth = (if dow > 5 then 27 else 20) - dow;
def exp_opt = month + (dom > expthismonth);

period = countTradingDays(min(first(yyyymmdd), yyyymmdd), yyyymmdd) - 1;


def count = CompoundValue(1, if period != period[1] then (count[1] + period - period[1]) % 1 else count[1], 0);
def cond = count < count[1] + period - period[1];

profile vol = VolumeProfile("startNewProfile" = cond, "numberOfProfiles" = 2, "pricePerRow" = TickSize(), "value area percent" = 70, onExpansion = no);

#Prior Day High/Low ValueAreas
def HVA = if IsNaN(vol.GetHighestValueArea()) then HVA[1] else vol.GetHighestValueArea();
def pHVA = CompoundValue(1, if cond then HVA[1] else pHVA[1], Double.NaN);
def LVA = if IsNaN(vol.GetLowestValueArea()) then LVA[1] else vol.GetLowestValueArea();
def pLVA = CompoundValue(1, if cond then LVA[1] else pLVA[1], Double.NaN);

plot PrevHVA = pHVA;
plot PrevLVA = pLVA;

addlabel(1, "Previous: HVA: " + round(PrevHVA) + " |  LVA: " + round(PLVA), color.yellow);
 
Here is something I did awhile ago that may help. It isn't the most elegant code, but hopefully does what you are requesting.
What code would I have to change to what to have the line a different style/color once touched? Instead of disappearing. I think I found the location but don't know how to code it. And how can could I go about adding H/L value lines going back for 30+ days? Previous unfilled gaps lines also going back 30+ days would make tos go head to head with ninja and sierra 🥲 btw thanks sleepyz this is one of the best codes to trade I've seen on here. Makes me compete with a big boy I know that uses a custom ninja setup he wont share.
 
Last edited:
Hey is there a post that goes into detail explaining this indicator?
Did you know that clicking on a member's name will allow you to see when a member was last seen on the uTS forum? @asianboy has not been seen in a while. :(
A search of the forum did not find any additional posts about this indicator.

It seems to be a simple Volume Standard Deviation Indicator.
It gives signals when:
  • close crosses POC
  • close crosses VAH
  • close crosses VAL
  • close crosses .5 StdDev
  • close crosses 1 StdDev
  • close crosses 2 StdDev
 
Apologies if this script is itt already. Are there any VP scripts that do timeframes like 5m, 4hr?


gTYx1e7.png


thing i'm running into is not having the vp start at the beginning of a 5m/4hr rotation. so here's a 5m vp on a 1m but it's based on a 5 candle bar count so the opens are inconsistent to a real 5m open if that makes sense cause there's no option like here -

z8IQqh8.png
 
Last edited by a moderator:
Apologies if this script is itt already. Are there any VP scripts that do timeframes like 5m, 4hr?


thing i'm running into is not having the vp start at the beginning of a 5m/4hr rotation. so here's a 5m vp on a 1m but it's based on a 5 candle bar count so the opens are inconsistent to a real 5m open if that makes sense cause there's no option like here -
No, we do not have what you are asking for here.
You would need to start a thread in the Question Forum.
Include:
  1. An annotated image showing what you are attempting to achieved.
  2. Most importantly, when asking for custom coding, provide an explanation of how this would be a profitable addition to traders' charts.
https://usethinkscript.com/threads/answers-to-commonly-asked-questions.6006/#post-58016
 
Last edited:
Hi @SleepyZ ,

I found this code by you somewhere in this thread and was wondering if you can help me make some adjustments to it. What i am looking for is a way to make the VAH and VAL display in a developing way. Basically, i want to see how the VAH & VAL changes up and down historically during the day.
And instead of just a line, i would like if possible to show it as a ribbon style similar to how this looks (see image). So one ribbon for the VAH and another for the VAL. I am guessing this ribbon is made with the addcloud function painting between a low and high price so in my example, let´s say the VAH price is 10.00, then you could use 5 cents on top of it to paint the cloud between 10.00 and 10.05. And vice versa, if VAL price is 7.00, then the addcloud can be painted between 7.00 and 6.95. Hope that makes sense and if it´s not possible to use a ribbon like this, the excisting horizontal line will work fine too.

Code:
#VolumeProfile break at trading zones

input pricePerRowHeightMode = {AUTOMATIC, default TICKSIZE, CUSTOM};
input customRowHeight = 1.0;
input onExpansion = no;
input profiles = 1000;
input showPointOfControl = yes;
input showValueArea = yes;
input valueAreaPercent = 70;
input opacity = 20;

def tz = if SecondsFromTime(0930) >= 0 and SecondsFromTime(1615) < 0 then 1 else if SecondsFromTime(1600) >= 0 then 2 else tz[1];

input debug = no;
plot x = if !debug then Double.NaN else tz;
x.SetPaintingStrategy(PaintingStrategy.VALUES_BELOW);

def cond = tz != tz[1];
def height;
switch (pricePerRowHeightMode) {
case AUTOMATIC:
    height = PricePerRow.AUTOMATIC;
case TICKSIZE:
    height = PricePerRow.TICKSIZE;
case CUSTOM:
    height = customRowHeight;
}

profile vol = VolumeProfile("startNewProfile" = cond, "onExpansion" = onExpansion, "numberOfProfiles" = profiles, "pricePerRow" = height, "value area percent" = valueAreaPercent);
def con = CompoundValue(1, onExpansion, no);
def pc = if IsNaN(vol.GetPointOfControl()) and con then pc[1] else vol.GetPointOfControl();
def hVA = if IsNaN(vol.GetHighestValueArea()) and con then hVA[1] else vol.GetHighestValueArea();
def lVA = if IsNaN(vol.GetLowestValueArea()) and con then lVA[1] else vol.GetLowestValueArea();

def hProfile = if IsNaN(vol.GetHighest()) and con then hProfile[1] else vol.GetHighest();
def lProfile = if IsNaN(vol.GetLowest()) and con then lProfile[1] else vol.GetLowest();
def plotsDomain = IsNaN(close) == onExpansion;

plot POC = if plotsDomain then pc else Double.NaN;
plot ProfileHigh = if plotsDomain then hProfile else Double.NaN;
plot ProfileLow = if plotsDomain then lProfile else Double.NaN;
plot VAHigh = if plotsDomain then hVA else Double.NaN;
plot VALow = if plotsDomain then lVA else Double.NaN;

DefineGlobalColor("Profile", GetColor(1));
DefineGlobalColor("Point Of Control", GetColor(5));
DefineGlobalColor("Value Area", GetColor(8));

vol.Show(GlobalColor("Profile"), if showPointOfControl then GlobalColor("Point Of Control") else Color.CURRENT, if showValueArea then GlobalColor("Value Area") else Color.CURRENT, opacity);
POC.SetDefaultColor(GlobalColor("Point Of Control"));
POC.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VALow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh.SetDefaultColor(GlobalColor("Value Area"));
VALow.SetDefaultColor(GlobalColor("Value Area"));
ProfileHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileLow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileHigh.SetDefaultColor(GetColor(3));
ProfileLow.SetDefaultColor(GetColor(3));
#ProfileHigh.Hide();
#ProfileLow.Hide();

input bubbles = yes;
input n  = 2;
def   n1 = n + 1;
AddChartBubble(bubbles and !IsNaN(close[n1]) and IsNaN(close[n]), VAHigh[n1], "VAH", color = Color.YELLOW, yes);
AddChartBubble(bubbles and !IsNaN(close[n1]) and IsNaN(close[n]), VALow[n1], "VAL", Color.YELLOW, no);
AddChartBubble(bubbles and !IsNaN(close[n1]) and IsNaN(close[n]), POC[n1], "POC", Color.RED, no);
 
Hi @SleepyZ ,

I found this code by you somewhere in this thread and was wondering if you can help me make some adjustments to it. What i am looking for is a way to make the VAH and VAL display in a developing way. Basically, i want to see how the VAH & VAL changes up and down historically during the day.
And instead of just a line, i would like if possible to show it as a ribbon style similar to how this looks (see image). So one ribbon for the VAH and another for the VAL. I am guessing this ribbon is made with the addcloud function painting between a low and high price so in my example, let´s say the VAH price is 10.00, then you could use 5 cents on top of it to paint the cloud between 10.00 and 10.05. And vice versa, if VAL price is 7.00, then the addcloud can be painted between 7.00 and 6.95. Hope that makes sense and if it´s not possible to use a ribbon like this, the excisting horizontal line will work fine too.

Code:
#VolumeProfile break at trading zones

input pricePerRowHeightMode = {AUTOMATIC, default TICKSIZE, CUSTOM};
input customRowHeight = 1.0;
input onExpansion = no;
input profiles = 1000;
input showPointOfControl = yes;
input showValueArea = yes;
input valueAreaPercent = 70;
input opacity = 20;

def tz = if SecondsFromTime(0930) >= 0 and SecondsFromTime(1615) < 0 then 1 else if SecondsFromTime(1600) >= 0 then 2 else tz[1];

input debug = no;
plot x = if !debug then Double.NaN else tz;
x.SetPaintingStrategy(PaintingStrategy.VALUES_BELOW);

def cond = tz != tz[1];
def height;
switch (pricePerRowHeightMode) {
case AUTOMATIC:
    height = PricePerRow.AUTOMATIC;
case TICKSIZE:
    height = PricePerRow.TICKSIZE;
case CUSTOM:
    height = customRowHeight;
}

profile vol = VolumeProfile("startNewProfile" = cond, "onExpansion" = onExpansion, "numberOfProfiles" = profiles, "pricePerRow" = height, "value area percent" = valueAreaPercent);
def con = CompoundValue(1, onExpansion, no);
def pc = if IsNaN(vol.GetPointOfControl()) and con then pc[1] else vol.GetPointOfControl();
def hVA = if IsNaN(vol.GetHighestValueArea()) and con then hVA[1] else vol.GetHighestValueArea();
def lVA = if IsNaN(vol.GetLowestValueArea()) and con then lVA[1] else vol.GetLowestValueArea();

def hProfile = if IsNaN(vol.GetHighest()) and con then hProfile[1] else vol.GetHighest();
def lProfile = if IsNaN(vol.GetLowest()) and con then lProfile[1] else vol.GetLowest();
def plotsDomain = IsNaN(close) == onExpansion;

plot POC = if plotsDomain then pc else Double.NaN;
plot ProfileHigh = if plotsDomain then hProfile else Double.NaN;
plot ProfileLow = if plotsDomain then lProfile else Double.NaN;
plot VAHigh = if plotsDomain then hVA else Double.NaN;
plot VALow = if plotsDomain then lVA else Double.NaN;

DefineGlobalColor("Profile", GetColor(1));
DefineGlobalColor("Point Of Control", GetColor(5));
DefineGlobalColor("Value Area", GetColor(8));

vol.Show(GlobalColor("Profile"), if showPointOfControl then GlobalColor("Point Of Control") else Color.CURRENT, if showValueArea then GlobalColor("Value Area") else Color.CURRENT, opacity);
POC.SetDefaultColor(GlobalColor("Point Of Control"));
POC.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VALow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh.SetDefaultColor(GlobalColor("Value Area"));
VALow.SetDefaultColor(GlobalColor("Value Area"));
ProfileHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileLow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileHigh.SetDefaultColor(GetColor(3));
ProfileLow.SetDefaultColor(GetColor(3));
#ProfileHigh.Hide();
#ProfileLow.Hide();

input bubbles = yes;
input n  = 2;
def   n1 = n + 1;
AddChartBubble(bubbles and !IsNaN(close[n1]) and IsNaN(close[n]), VAHigh[n1], "VAH", color = Color.YELLOW, yes);
AddChartBubble(bubbles and !IsNaN(close[n1]) and IsNaN(close[n]), VALow[n1], "VAL", Color.YELLOW, no);
AddChartBubble(bubbles and !IsNaN(close[n1]) and IsNaN(close[n]), POC[n1], "POC", Color.RED, no);
Sorry, but this script will not show developing profiles, but new profiles for each period. These new profiles are independent of the previous ones.
 
This uses the script function to create the 3 profilles
Hi SleepyZ, this script for showing the day, week, and month period profile lines on the same chart is excellent, thank you for sharing this! One question, I think I already know that the answer is no but want to make sure: is it possible to use a "bars back" type of method to enable the study to correctly calculate the week and month POCs etc. while nonetheless having the chart settings configured to go back only one or two days? I want to use this with /ES but for some reason, /ES loads too slowly when more than a few days are displayed (this is not a problem with SPY, only /ES, so maybe it's an issue with futures charts being too resource intensive).

I also had another question, really a request if it's not very difficult to make the modification:

I see that this script plots a separate volume profile for extended hours and another for RTH, whereas this script plots the previous day's profile POC, VALH, etc. forward onto the current day. Can these scripts be easily combined in such a way that instead of the previous day's profile lines being plotted forward onto the current day, it is the extended hours profile lines that are plotted forward onto the current day?
 
Has anybody been able to successfully replicate the Trader Dale's Volume Profile Study for flexible intervals within the chart in TOS ?

Here is some minor tweaking to the ToS VolumeProfile study to add 5, 15, and 30 min options. It's not as cool as Trader Dale's but it allows for more fine grained profiles to be set. Here's the code, which you'll have to create a new study and paste it into:

# Paste this code into a new study

input pricePerRowHeightMode = {default TICKSIZE, AUTOMATIC, CUSTOM};
input customRowHeight = 1.0;
input timePerProfile = {CHART, MINUTE, FIVEMINUTE, QUARTERHOUR, default HALFHOUR, HOUR, DAY, WEEK, MONTH, "OPT EXP", BAR};
input multiplier = 1;
input onExpansion = no;
input profiles = 1000;
input showPointOfControl = yes;
input showValueArea = yes;
input valueAreaPercent = 70;
input opacity = 25;

def period;
def yyyymmdd = getYyyyMmDd();
def seconds = secondsFromTime(0);
def month = getYear() * 12 + getMonth();
def day_number = daysFromDate(first(yyyymmdd)) + getDayOfWeek(first(yyyymmdd));
def dom = getDayOfMonth(yyyymmdd);
def dow = getDayOfWeek(yyyymmdd - dom + 1);
def expthismonth = (if dow > 5 then 27 else 20) - dow;
def exp_opt = month + (dom > expthismonth);
switch (timePerProfile) {
case CHART:
period = 0;
case MINUTE:
period = floor(seconds / 60 + day_number * 24 * 60);
case FIVEMINUTE:
period = floor(seconds / 300 + day_number * 24 * 12);
case QUARTERHOUR:
period = floor(seconds / 900 + day_number * 24 * 4);
case HALFHOUR:
period = floor(seconds / 1800 + day_number * 24 * 2);
case HOUR:
period = floor(seconds / 3600 + day_number * 24);
case DAY:
period = countTradingDays(min(first(yyyymmdd), yyyymmdd), yyyymmdd) - 1;
case WEEK:
period = floor(day_number / 7);
case MONTH:
period = floor(month - first(month));
case "OPT EXP":
period = exp_opt - first(exp_opt);
case BAR:
period = barNumber() - 1;
}

def count = CompoundValue(1, if period != period[1] then (count[1] + period - period[1]) % multiplier else count[1], 0);
def cond = count < count[1] + period - period[1];
def height;
switch (pricePerRowHeightMode) {
case AUTOMATIC:
height = PricePerRow.AUTOMATIC;
case TICKSIZE:
height = PricePerRow.TICKSIZE;
case CUSTOM:
height = customRowHeight;
}

profile vol = volumeProfile("startNewProfile" = cond, "onExpansion" = onExpansion, "numberOfProfiles" = profiles, "pricePerRow" = height, "value area percent" = valueAreaPercent);
def con = compoundValue(1, onExpansion, no);
def pc = if IsNaN(vol.getPointOfControl()) and con then pc[1] else vol.getPointOfControl();
def hVA = if IsNaN(vol.getHighestValueArea()) and con then hVA[1] else vol.getHighestValueArea();
def lVA = if IsNaN(vol.getLowestValueArea()) and con then lVA[1] else vol.getLowestValueArea();

def hProfile = if IsNaN(vol.getHighest()) and con then hProfile[1] else vol.getHighest();
def lProfile = if IsNaN(vol.getLowest()) and con then lProfile[1] else vol.getLowest();
def plotsDomain = IsNaN(close) == onExpansion;

plot POC = if plotsDomain then pc else Double.NaN;
plot ProfileHigh = if plotsDomain then hProfile else Double.NaN;
plot ProfileLow = if plotsDomain then lProfile else Double.NaN;
plot VAHigh = if plotsDomain then hVA else Double.NaN;
plot VALow = if plotsDomain then lVA else Double.NaN;

DefineGlobalColor("Profile", GetColor(1));
DefineGlobalColor("Point Of Control", GetColor(5));
DefineGlobalColor("Value Area", GetColor(8));

vol.show(globalColor("Profile"), if showPointOfControl then globalColor("Point Of Control") else color.current, if showValueArea then globalColor("Value Area") else color.current, opacity);
POC.SetDefaultColor(globalColor("Point Of Control"));
POC.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VALow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh.SetDefaultColor(globalColor("Value Area"));
VALow.SetDefaultColor(globalColor("Value Area"));
ProfileHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileLow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileHigh.SetDefaultColor(GetColor(3));
ProfileLow.SetDefaultColor(GetColor(3));
ProfileHigh.hide();
ProfileLow.hide();
#END

One way to get closer to a flexible volume profile would be to add a parameter that allowed the user to set a start and end date. I have seen some anchored VWaps that allow the user to set the anchor date. But, that is beyond me

Here is a chart with 30 minute intervals,

Has anybody been able to successfully replicate the Trader Dale's Volume Profile Study for flexible intervals within the chart in TOS ?

https://www.trader-dale.com/flexible-volume-profile-forex-indicator/
 
Last edited:
@ssmike123
I am not familiar with TraderDale and was not able to see what his profile setup is. If you could describe in a bit more detail, I'm sure the TOS tools can be adjusted to work that way. There is another thread on Candle Aggregation which uses the volume profile at custom time-based intervals which is probably along the right track.
 
Last edited by a moderator:
@ssmike123
I am not familiar with TraderDale and was not able to see what his profile setup is. If you could describe in a bit more detail, I'm sure the TOS tools can be adjusted to work that way. There is another thread on Candle Aggregation which uses the volume profile at custom time-based intervals which is probably along the right track.
@FutureTony.
Take a look at this Video Dale put out yesterday. It should be very clear.
https://www.trader-dale.com/nzd-chf-long-term-analysis-with-volume-profile/
 
This might work on most symbols and timeframes that match the periods you requested. The way this works is to assign different values to each period, which remain the same until the next period. The variable cond then prints a new volume profile when the values change.
Hey @SleepyZ, Thanks for all you do . I'm trying to keep the period consistent in my profiles (either a day, week, or month), but only compute the volume profile based on regular market hours. I don't want a separate profile for RTH and one for ETH, I just want a single profile that was generated only using data from RTHs. Is this possible? If so, would you be willing to show me or explain to me how that's done? Hopefully this makes sense.
 
Last edited:
Hey @SleepyZ, Thanks for all you do . I'm trying to keep the period consistent in my profiles (either a day, week, or month), but only compute the volume profile based on regular market hours. I don't want a separate profile for RTH and one for ETH, I just want a single profile that was generated only using data from RTHs. Is this possible? If so, would you be willing to show me or explain to me how that's done? Hopefully this makes sense.

See if this helps. There is some value area shading that lingers outside the RTHs that can be reduced at opacity, but it affects the RTH's opacity as well.

Screenshot-2022-10-20-094313.png
Ruby:
#VolumeProfile break at trading zones

input pricePerRowHeightMode = {AUTOMATIC, default TICKSIZE, CUSTOM};
input customRowHeight = 1.0;
input onExpansion = no;
input profiles = 1000;
input showPointOfControl = yes;
input showValueArea = yes;
input valueAreaPercent = 70;
input opacity = 10;

def tz = if SecondsFromTime(0400) >= 0 and SecondsFromTime(0930) < 0 then 0 else if SecondsFromTime(0930) >= 0 and SecondsFromTime(1600) < 0 then 1 else if SecondsFromTime(1600) >= 0 then 0 else tz[1];

input debug = no;
plot x = if !debug then Double.NaN else tz;
x.SetPaintingStrategy(PaintingStrategy.VALUES_BELOW);

def cond = if tz==0 then 1 else double.nan;
def height;
switch (pricePerRowHeightMode) {
case AUTOMATIC:
    height = PricePerRow.AUTOMATIC;
case TICKSIZE:
    height = PricePerRow.TICKSIZE;
case CUSTOM:
    height = customRowHeight;
}

profile vol = VolumeProfile("startNewProfile" = cond, "onExpansion" = onExpansion, "numberOfProfiles" = profiles, "pricePerRow" = height, "value area percent" = valueAreaPercent);
def con = CompoundValue(1, onExpansion, no);
def pc = if IsNaN(vol.GetPointOfControl()) and con then pc[1] else vol.GetPointOfControl();
def hVA = if IsNaN(vol.GetHighestValueArea()) and con then hVA[1] else vol.GetHighestValueArea();
def lVA = if IsNaN(vol.GetLowestValueArea()) and con then lVA[1] else vol.GetLowestValueArea();

def hProfile = if IsNaN(vol.GetHighest()) and con then hProfile[1] else vol.GetHighest();
def lProfile = if IsNaN(vol.GetLowest()) and con then lProfile[1] else vol.GetLowest();
def plotsDomain = IsNaN(close) == onExpansion and tz==1;

plot POC = if plotsDomain then pc else Double.NaN;
plot ProfileHigh = if plotsDomain then hProfile else Double.NaN;
plot ProfileLow = if plotsDomain then lProfile else Double.NaN;
plot VAHigh = if plotsDomain then hVA else Double.NaN;
plot VALow = if plotsDomain then lVA else Double.NaN;

DefineGlobalColor("Profile", GetColor(1));
DefineGlobalColor("Point Of Control", GetColor(5));
DefineGlobalColor("Value Area", GetColor(8));

vol.Show(GlobalColor("Profile"), if showPointOfControl then GlobalColor("Point Of Control") else Color.CURRENT, if showValueArea then GlobalColor("Value Area") else Color.CURRENT, opacity);
POC.SetDefaultColor(GlobalColor("Point Of Control"));
POC.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VALow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh.SetDefaultColor(GlobalColor("Value Area"));
VALow.SetDefaultColor(GlobalColor("Value Area"));
ProfileHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileLow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileHigh.SetDefaultColor(GetColor(3));
ProfileLow.SetDefaultColor(GetColor(3));
#ProfileHigh.Hide();
#ProfileLow.Hide();

input bubbles = yes;
input n  = 2;
def   n1 = n + 1;
AddChartBubble(bubbles and !IsNaN(close[n1]) and IsNaN(close[n]), VAHigh[n1], "VAH", color = Color.YELLOW, yes);
AddChartBubble(bubbles and !IsNaN(close[n1]) and IsNaN(close[n]), VALow[n1], "VAL", Color.YELLOW, no);
AddChartBubble(bubbles and !IsNaN(close[n1]) and IsNaN(close[n]), POC[n1], "POC", Color.RED, no);
 
See if this helps. There is some value area shading that lingers outside the RTHs that can be reduced at opacity, but it affects the RTH's opacity as well.
Thanks again for all the assistance. Maybe the solution you provided is only for intraday because it does some very strange things on the Daily timeframe. Here is what I'm using with modifications to automatically configure the period based on the Aggregation Period. On a Daily timeframe, the volume profile is based a Monthly period and on the 1h timeframe the volume profile is based on a weekly period, and minute timeframes are based on Daily period. What I was hoping for was a combination of these solutions, but maybe I'm way off base.

Ruby:
#
# Quant Trading App Volume Profile
# Created: September 15, 2021
#
# Credit: Bryant Littrean, Thinkorswim
# Contact: [email protected]
# Trading Litt Youtube: https://bit.ly/trading-litt-yt
# Quant Trading App Discord: https://quanttradingdiscord.com
# 20220427 Sleepyz added timeperprofile for Day, Week, Month options
#

def multiplier = 1;
def onExpansion = no;
def profiles = 1000;
input profileSession = {default Day, Week, Month};
input showPointOfControl = yes;
input showValueArea = yes;
input valueAreaPercent = 68;
input opacity = 60;
input showBubbles = no;
input pricePerRowHeightMode = {default AUTOMATIC, TICKSIZE, CUSTOM};
input customRowHeight = 1.0;

def period;
def yyyymmdd = GetYYYYMMDD();
def seconds = SecondsFromTime(0);
def month = GetYear() * 12 + GetMonth();
def year = GetYear();
def day_number = DaysFromDate(First(yyyymmdd)) + GetDayOfWeek(First(yyyymmdd));
def dom = GetDayOfMonth(yyyymmdd);
def dow = GetDayOfWeek(yyyymmdd - dom + 1);
def expthismonth = (if dow > 5 then 27 else 20) - dow;
def exp_opt = month + (dom > expthismonth);
################################################################
##########  Set time period based on aggPeriod           #######
################################################################
def aggPeriod = GetAggregationPeriod();
if aggPeriod == AggregationPeriod.WEEK {
    period = Floor(year - First(year));
} else if aggPeriod == AggregationPeriod.DAY {
    period = Floor(month - First(month));
} else if aggPeriod == AggregationPeriod.HOUR {
    period = Floor(day_number / 7);
} else if (aggPeriod == AggregationPeriod.THIRTY_MIN or aggPeriod == AggregationPeriod.FIFTEEN_MIN or aggPeriod == AggregationPeriod.FIVE_MIN or aggPeriod == AggregationPeriod.THREE_MIN or aggPeriod == AggregationPeriod.MIN) {
    period = CountTradingDays(Min(First(yyyymmdd), yyyymmdd), yyyymmdd) - 1;
#} else if aggPeriod == AggregationPeriod.MIN or aggPeriod == AggregationPeriod.THREE_MIN {
#    period = Floor(seconds / 3600 + day_number * 24);
} else {
    period = 0;
}

def height;
switch (pricePerRowHeightMode) {
case AUTOMATIC:
    height = PricePerRow.AUTOMATIC;
case TICKSIZE:
    height = PricePerRow.TICKSIZE;
case CUSTOM:
    height = customRowHeight;
}
def count = CompoundValue(1, if period != period[1] then (count[1] + period - period[1]) % multiplier else count[1], 0);
def cond = count < count[1] + period - period[1];
profile vol = VolumeProfile("startNewProfile" = cond, "onExpansion" = onExpansion, "numberOfProfiles" = profiles, "pricePerRow" = height, "value area percent" = valueAreaPercent);
def con = CompoundValue(1, onExpansion, no);
def pc = if IsNaN(vol.GetPointOfControl()) and con then pc[1] else vol.GetPointOfControl();
def hVA = if IsNaN(vol.GetHighestValueArea()) and con then hVA[1] else vol.GetHighestValueArea();
def lVA = if IsNaN(vol.GetLowestValueArea()) and con then lVA[1] else vol.GetLowestValueArea();
def hProfile = if IsNaN(vol.GetHighest()) and con then hProfile[1] else vol.GetHighest();
def lProfile = if IsNaN(vol.GetLowest()) and con then lProfile[1] else vol.GetLowest();
def plotsDomain = IsNaN(close) == onExpansion;
plot POC = if plotsDomain then pc else Double.NaN;
plot ProfileHigh = if plotsDomain then hProfile else Double.NaN;
plot ProfileLow = if plotsDomain then lProfile else Double.NaN;
plot VAHigh = if plotsDomain then hVA else Double.NaN;
plot VALow = if plotsDomain then lVA else Double.NaN;
DefineGlobalColor("Profile", CreateColor(70, 70, 70));
DefineGlobalColor("Point Of Control", CreateColor(255, 215, 0));
DefineGlobalColor("Value Area", CreateColor(95, 140, 230));
vol.Show(GlobalColor("Profile"), if showPointOfControl then GlobalColor("Point Of Control") else Color.CURRENT, if showValueArea then GlobalColor("Value Area") else Color.CURRENT, opacity);
POC.SetDefaultColor(GlobalColor("Point Of Control"));
POC.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
POC.SetLineWeight(2);
VAHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VALow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh.SetDefaultColor(GlobalColor("Value Area"));
VALow.SetDefaultColor(GlobalColor("Value Area"));
ProfileHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileLow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileHigh.SetDefaultColor(GetColor(3));
ProfileLow.SetDefaultColor(GetColor(3));
ProfileHigh.Hide();
ProfileLow.Hide();

#20171027 - Additional Code for Limited Extended POC plot request by Tb8
input debug = no;
#plot xx = if !debug then Double.NaN else period;
def ldd = GetLastDay();
#plot xx = if debug then GetYear() else Double.NaN;
plot xx = if !debug then Double.NaN else period;
xx.SetPaintingStrategy(PaintingStrategy.VALUES_BELOW);
 
Last edited:
Thanks again for all the assistance. Maybe the solution you provided is only for intraday because it does some very strange things on the Daily timeframe. Here is what I'm using with modifications to automatically configure the period based on the Aggregation Period. On a Daily timeframe, the volume profile is based a Monthly period and on the 1h timeframe the volume profile is based on a weekly period, and minute timeframes are based on Daily period. What I was hoping for was a combination of these solutions, but maybe I'm way off base.

Ruby:
#
# Quant Trading App Volume Profile
# Created: September 15, 2021
#
# Credit: Bryant Littrean, Thinkorswim
# Contact: [email protected]
# Trading Litt Youtube: https://bit.ly/trading-litt-yt
# Quant Trading App Discord: https://quanttradingdiscord.com
# 20220427 Sleepyz added timeperprofile for Day, Week, Month options
#

def multiplier = 1;
def onExpansion = no;
def profiles = 1000;
input profileSession = {default Day, Week, Month};
input showPointOfControl = yes;
input showValueArea = yes;
input valueAreaPercent = 68;
input opacity = 60;
input showBubbles = no;
input pricePerRowHeightMode = {default AUTOMATIC, TICKSIZE, CUSTOM};
input customRowHeight = 1.0;

def period;
def yyyymmdd = GetYYYYMMDD();
def seconds = SecondsFromTime(0);
def month = GetYear() * 12 + GetMonth();
def year = GetYear();
def day_number = DaysFromDate(First(yyyymmdd)) + GetDayOfWeek(First(yyyymmdd));
def dom = GetDayOfMonth(yyyymmdd);
def dow = GetDayOfWeek(yyyymmdd - dom + 1);
def expthismonth = (if dow > 5 then 27 else 20) - dow;
def exp_opt = month + (dom > expthismonth);
################################################################
##########  Set time period based on aggPeriod           #######
################################################################
def aggPeriod = GetAggregationPeriod();
if aggPeriod == AggregationPeriod.WEEK {
    period = Floor(year - First(year));
} else if aggPeriod == AggregationPeriod.DAY {
    period = Floor(month - First(month));
} else if aggPeriod == AggregationPeriod.HOUR {
    period = Floor(day_number / 7);
} else if (aggPeriod == AggregationPeriod.THIRTY_MIN or aggPeriod == AggregationPeriod.FIFTEEN_MIN or aggPeriod == AggregationPeriod.FIVE_MIN or aggPeriod == AggregationPeriod.THREE_MIN or aggPeriod == AggregationPeriod.MIN) {
    period = CountTradingDays(Min(First(yyyymmdd), yyyymmdd), yyyymmdd) - 1;
#} else if aggPeriod == AggregationPeriod.MIN or aggPeriod == AggregationPeriod.THREE_MIN {
#    period = Floor(seconds / 3600 + day_number * 24);
} else {
    period = 0;
}

def height;
switch (pricePerRowHeightMode) {
case AUTOMATIC:
    height = PricePerRow.AUTOMATIC;
case TICKSIZE:
    height = PricePerRow.TICKSIZE;
case CUSTOM:
    height = customRowHeight;
}
def count = CompoundValue(1, if period != period[1] then (count[1] + period - period[1]) % multiplier else count[1], 0);
def cond = count < count[1] + period - period[1];
profile vol = VolumeProfile("startNewProfile" = cond, "onExpansion" = onExpansion, "numberOfProfiles" = profiles, "pricePerRow" = height, "value area percent" = valueAreaPercent);
def con = CompoundValue(1, onExpansion, no);
def pc = if IsNaN(vol.GetPointOfControl()) and con then pc[1] else vol.GetPointOfControl();
def hVA = if IsNaN(vol.GetHighestValueArea()) and con then hVA[1] else vol.GetHighestValueArea();
def lVA = if IsNaN(vol.GetLowestValueArea()) and con then lVA[1] else vol.GetLowestValueArea();
def hProfile = if IsNaN(vol.GetHighest()) and con then hProfile[1] else vol.GetHighest();
def lProfile = if IsNaN(vol.GetLowest()) and con then lProfile[1] else vol.GetLowest();
def plotsDomain = IsNaN(close) == onExpansion;
plot POC = if plotsDomain then pc else Double.NaN;
plot ProfileHigh = if plotsDomain then hProfile else Double.NaN;
plot ProfileLow = if plotsDomain then lProfile else Double.NaN;
plot VAHigh = if plotsDomain then hVA else Double.NaN;
plot VALow = if plotsDomain then lVA else Double.NaN;
DefineGlobalColor("Profile", CreateColor(70, 70, 70));
DefineGlobalColor("Point Of Control", CreateColor(255, 215, 0));
DefineGlobalColor("Value Area", CreateColor(95, 140, 230));
vol.Show(GlobalColor("Profile"), if showPointOfControl then GlobalColor("Point Of Control") else Color.CURRENT, if showValueArea then GlobalColor("Value Area") else Color.CURRENT, opacity);
POC.SetDefaultColor(GlobalColor("Point Of Control"));
POC.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
POC.SetLineWeight(2);
VAHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VALow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh.SetDefaultColor(GlobalColor("Value Area"));
VALow.SetDefaultColor(GlobalColor("Value Area"));
ProfileHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileLow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileHigh.SetDefaultColor(GetColor(3));
ProfileLow.SetDefaultColor(GetColor(3));
ProfileHigh.Hide();
ProfileLow.Hide();

#20171027 - Additional Code for Limited Extended POC plot request by Tb8
input debug = no;
#plot xx = if !debug then Double.NaN else period;
def ldd = GetLastDay();
#plot xx = if debug then GetYear() else Double.NaN;
plot xx = if !debug then Double.NaN else period;
xx.SetPaintingStrategy(PaintingStrategy.VALUES_BELOW);
. I made these modifications so I didn't need to adjust manually each time I changed timeframe.
There are only RTH intraday, so that is what the script I did does.
 
Understand, thanks again.

Tron, this may be the combination that you wanted. It will do Daily RTHrs for chart timeframes less than 1hr, Monthly for chart timeframes of Day and Week and Yearly for chart timeframes of Monthly

Ruby:
#Thanks again for all the assistance. Maybe the solution you provided is only for intraday because it does some very strange things on the Daily timeframe. Here is what I'm using with modifications to automatically configure the period based on the Aggregation Period. On a Daily timeframe, the volume profile is based a Monthly period and on the 1h timeframe the volume profile is based on a weekly period, and minute timeframes are based on Daily period. What I was hoping for was a combination of these solutions, but maybe I'm way off base.
#
#VolumeProfile break at trading zones

input pricePerRowHeightMode = {AUTOMATIC, default TICKSIZE, CUSTOM};
input customRowHeight = 1.0;
input onExpansion = no;
input profiles = 1000;
input showPointOfControl = yes;
input showValueArea = yes;
input valueAreaPercent = 70;
input opacity = 10;
def multiplier = 1;

def period;
def yyyymmdd = GetYYYYMMDD();
def seconds = SecondsFromTime(0);
def month = GetYear() * 12 + GetMonth();
def year = GetYear();
def day_number = DaysFromDate(First(yyyymmdd)) + GetDayOfWeek(First(yyyymmdd));
def dom = GetDayOfMonth(yyyymmdd);
def dow = GetDayOfWeek(yyyymmdd - dom + 1);
def expthismonth = (if dow > 5 then 27 else 20) - dow;
def exp_opt = month + (dom > expthismonth);
################################################################
##########  Set time period based on aggPeriod           #######
################################################################
def aggPeriod = GetAggregationPeriod();
if aggPeriod == AggregationPeriod.month {
    period = Floor(year - First(year));
} else if aggPeriod == AggregationPeriod.week {
    period = Floor(month - First(month));
} else if aggPeriod == AggregationPeriod.DAY {
    period = Floor(month - First(month));
} else if aggPeriod == AggregationPeriod.hour {
    period = Floor(day_number / 7);
} else {
    period = 0;
}

def height;
switch (pricePerRowHeightMode) {
case AUTOMATIC:
    height = PricePerRow.AUTOMATIC;
case TICKSIZE:
    height = PricePerRow.TICKSIZE;
case CUSTOM:
    height = customRowHeight;
}
def count = CompoundValue(1, if period != period[1] then (count[1] + period - period[1]) % multiplier else count[1], 0);

def tz = if SecondsFromTime(0400) >= 0 and SecondsFromTime(0930) < 0 then 0 else if SecondsFromTime(0930) >= 0 and SecondsFromTime(1600) < 0 then 1 else if SecondsFromTime(1600) >= 0 then 0 else tz[1];

input debug = no;
plot x = if !debug then Double.NaN else tz;
x.SetPaintingStrategy(PaintingStrategy.VALUES_BELOW);

def cond = if GetAggregationPeriod() < AggregationPeriod.hour and tz == 0 then 1 else count < count[1] + period - period[1];


profile vol = VolumeProfile("startNewProfile" = cond, "onExpansion" = onExpansion, "numberOfProfiles" = profiles, "pricePerRow" = height, "value area percent" = valueAreaPercent);

def con = CompoundValue(1, onExpansion, no);
def pc = if IsNaN(vol.GetPointOfControl()) and con then pc[1] else vol.GetPointOfControl();
def hVA = if IsNaN(vol.GetHighestValueArea()) and con then hVA[1] else vol.GetHighestValueArea();
def lVA = if IsNaN(vol.GetLowestValueArea()) and con then lVA[1] else vol.GetLowestValueArea();
def hProfile = if IsNaN(vol.GetHighest()) and con then hProfile[1] else vol.GetHighest();
def lProfile = if IsNaN(vol.GetLowest()) and con then lProfile[1] else vol.GetLowest();
def plotsDomain = IsNaN(close) == onExpansion;
plot POC = if plotsDomain then pc else Double.NaN;
plot ProfileHigh = if plotsDomain then hProfile else Double.NaN;
plot ProfileLow = if plotsDomain then lProfile else Double.NaN;
plot VAHigh = if plotsDomain then hVA else Double.NaN;
plot VALow = if plotsDomain then lVA else Double.NaN;
DefineGlobalColor("Profile", CreateColor(70, 70, 70));
DefineGlobalColor("Point Of Control", CreateColor(255, 215, 0));
DefineGlobalColor("Value Area", CreateColor(95, 140, 230));
vol.Show(GlobalColor("Profile"), if showPointOfControl then GlobalColor("Point Of Control") else Color.CURRENT, if showValueArea then GlobalColor("Value Area") else Color.CURRENT, opacity);
POC.SetDefaultColor(GlobalColor("Point Of Control"));
POC.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
POC.SetLineWeight(2);
VAHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VALow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh.SetDefaultColor(GlobalColor("Value Area"));
VALow.SetDefaultColor(GlobalColor("Value Area"));
ProfileHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileLow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileHigh.SetDefaultColor(GetColor(3));
ProfileLow.SetDefaultColor(GetColor(3));
ProfileHigh.Hide();
ProfileLow.Hide();
 

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

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
340 Online
Create Post

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