Volume Profile Indicator & POCs For ThinkOrSwim

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();
 
SleepyZ, can this be made in a way to also show previous day Volume profile (not including today) , lines extended in to today, with different colors?
 
SleepyZ, can this be made in a way to also show previous day Volume profile (not including today) , lines extended in to today, with different colors?

This may be what you are looking for that I did in post #93 https://usethinkscript.com/threads/volume-profile-indicator-pocs-for-thinkorswim.8153/post-69037

Here it is with profiles set to 2 and a volumeprofile study included to show that just the lines (poc/vah/val) from the previous day's were extended onto today. http://tos.mx/QVFO8mB

Screenshot-2022-11-11-032814.png
 
This is the one I'm using.

Code:
# Profile TPO & Volume
input profileType = {default Time, Volume};
input pricePerRowHeightMode = {default Ticksize, Automatic, Custom};
input customRowHeight = 1.0;
input timePerProfile = {default Day, Week, Month, Year, Hour, Chart, "Opt Exp"};
input multiplier = 1;
input OnExpansionProfile = No;
input OnExpansionValueArea = No;
input profiles = 2;
input showPointOfControl = Yes;
input showValueArea = Yes;
input showValueAreaCloud = Yes;
input ValueAreaPercent = 70;
input ShowHighLow = Yes;
input opacity = 5;
input PaintBars = No;
input ShowExtensions = No;
input DynamicHideExtensions = Yes;
input ShowLabel = No;
def FibExt1 = 1.618;
def FibExt2 = 2.618;
def FibExt3 = 4.236;
def SE = ShowExtensions;
def ShowProfileValueAreaCloud = no;

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);
switch (timePerProfile) {
case Chart:
    period = 0;
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 Year:
    period = Floor(year - First(year));
case "Opt Exp":
    period = exp_opt - First(exp_opt);
}

def CloseByPeriod = close(Period = timePerProfile)[-1];
def Openbyperiod  = open(Period = timePerProfile)[-1];
def NewDay = if !IsNaN(CloseByPeriod) then 0 else 1;

rec Count = if period != period[1] then (Count[1] + period - period[1]) % 1 else Count[1];
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 = if profileType == profileType.Volume then VolumeProfile("startNewProfile" = Cond, "onExpansion" = onExpansionProfile, "NumberOfProfiles" = profiles, "PricePerRow" = height, "Value Area Percent" = ValueAreaPercent) else TimeProfile("startNewProfile" = Cond, "OnExpansion" = onExpansionProfile, "NumberOfProfiles" = profiles, "PricePerRow" = height, "Value Area Percent" = ValueAreaPercent);

def con = CompoundValue(1, onExpansionProfile, no);
rec pc = if IsNaN(VOL.GetPointOfControl()) and con then pc[1] else VOL.GetPointOfControl();
rec hVA = if IsNaN(VOL.GetHighestValueArea()) and con then hVA[1] else VOL.GetHighestValueArea();
rec lVA = if IsNaN(VOL.GetLowestValueArea()) and con then lVA[1] else VOL.GetLowestValueArea();
rec HVA_Last = if period == period[1] then HVA_Last[1] else hVA[1];
rec PC_Last  = if period == period[1] then PC_Last[1]  else pc[1];
rec LVA_Last = if period == period[1] then LVA_Last[1] else lVA[1];
rec hProfile = if IsNaN(VOL.GetHighest()) and con then hProfile[1] else VOL.GetHighest();
rec lProfile = if IsNaN(VOL.GetLowest()) and con then lProfile[1] else VOL.GetLowest();
def plotsDomain = IsNaN(close) == onExpansionProfile;

rec hP_Last = if period == period[1] then hP_Last[1] else hProfile[1];
rec lP_Last = if period == period[1] then lP_Last[1] else lProfile[1];

plot VAH  = if !showValueArea then Double.NaN else if IsNaN(close[0]) then HVA_Last[0] else if !OnExpansionValueArea then HVA_Last[0] else Double.NaN;
plot POC  = if IsNaN(close[0]) then PC_Last[0] else if !OnExpansionValueArea then PC_Last[0] else Double.NaN;
plot VAL  = if !showValueArea then Double.NaN else if IsNaN(close[0]) then LVA_Last[0] else if !OnExpansionValueArea then LVA_Last[0] else Double.NaN;
plot High = if !ShowHighLow then Double.NaN else if IsNaN(close[0]) then hP_Last[0] else if !OnExpansionValueArea then hP_Last[0] else Double.NaN;
plot Low = if !ShowHighLow then Double.NaN else if IsNaN(close[0]) then lP_Last[0] else if !OnExpansionValueArea then lP_Last[0] else Double.NaN;

DefineGlobalColor("Profile", GetColor(7));
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 ShowProfileValueAreaCloud then GlobalColor("Value Area") else Color.CURRENT, opacity);

POC.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
POC.SetDefaultColor(Color.DARK_GRAY);
#POC.SetDefaultColor(CreateColor(32,49,57));
POC.SetLineWeight(1);
POC.HideTitle();

VAH.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAH.SetDefaultColor(Color.DARK_GREEN);
VAH.SetLineWeight(1);
VAH.HideBubble();
VAH.HideTitle();

VAL.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAL.SetDefaultColor(Color.DARK_RED);
VAL.SetLineWeight(1);
VAL.HideBubble();
VAL.HideTitle();

High.SetPaintingStrategy(PaintingStrategy.DASHES);
High.SetDefaultColor(CreateColor(38, 38, 8));
High.SetLineWeight(1);
High.HideBubble();
High.HideTitle();

Low.SetPaintingStrategy(PaintingStrategy.DASHES);
Low.SetDefaultColor(CreateColor(38, 38, 8));
Low.SetLineWeight(1);
Low.HideBubble();
Low.HideTitle();
#Paint Bars

#AssignPriceColor(if !PaintBars then Color.CURRENT else if open >= VAH and close >= VAH then CreateColor(0, 204, 0) else if open <= VAL and close <= VAL then CreateColor(204, 0, 0) else Color.Light_GRAY);
AssignPriceColor(if !PaintBars then Color.CURRENT else if open >= VAH and close >= VAH then Color.Green else if open <= VAL and close <= VAL then Color.Red else Color.Light_GRAY);
#Value Area Cloud

#DefineGlobalColor("Value Area Cloud", (CreateColor(20, 20, 20)));
DefineGlobalColor("Value Area Cloud", Color.DARK_GRAY);
def cloudhigh = if showValueAreaCloud and IsNaN(close[0]) then HVA_Last else if !OnExpansionValueArea then HVA_Last else Double.NaN;
def cloudlow  = if showValueAreaCloud and IsNaN(close[0]) then LVA_Last else if !OnExpansionValueArea then LVA_Last else Double.NaN;
AddCloud (cloudhigh, cloudlow, GlobalColor("Value Area Cloud"));
#Chart Label

def InsideValueArea = close < HVA_Last and close > LVA_Last;
def BelowValue = close < LVA_Last;

AddLabel(ShowLabel, close, if InsideValueArea then Color.GRAY else if BelowValue then Color.RED else Color.GREEN);
#Fibonacci Extensions

def VAWidth = VAH - VAL;

plot E1H = if SE < 1 then Double.NaN else VAH + VAWidth * (FibExt1 - 1);
E1H.SetHiding(DynamicHideExtensions and close < VAH);
E1H.SetDefaultColor(CreateColor(0, 51, 0));
E1H.SetPaintingStrategy(PaintingStrategy.DASHES);
E1H.SetLineWeight(1);
E1H.HideBubble();
E1H.HideTitle();
plot E1L = if SE < 1 then Double.NaN else VAL - VAWidth * (FibExt1 - 1);
E1L.SetHiding(DynamicHideExtensions and close > VAL);
E1L.SetDefaultColor(CreateColor(51, 0, 0));
E1L.SetPaintingStrategy(PaintingStrategy.DASHES);
E1L.SetLineWeight(1);
E1L.HideBubble();
E1L.HideTitle();

plot E2H = if SE < 1 then Double.NaN else VAH + VAWidth * (FibExt2 - 1);
E2H.SetHiding(DynamicHideExtensions and close < E1H);
E2H.SetDefaultColor(CreateColor(0, 51, 0));
E2H.SetPaintingStrategy(PaintingStrategy.DASHES);
E2H.SetLineWeight(1);
E2H.HideBubble();
E2H.HideTitle();
plot E2L = if SE < 1 then Double.NaN else VAL - VAWidth * (FibExt2 - 1);
E2L.SetHiding(DynamicHideExtensions and close > E1L);
E2L.SetDefaultColor(CreateColor(51, 0, 0));
E2L.SetPaintingStrategy(PaintingStrategy.DASHES);
E2L.SetLineWeight(1);
E2L.HideBubble();
E2L.HideTitle();

plot E3H = if SE < 1 then Double.NaN else VAH + VAWidth * (FibExt3 - 1);
E3H.SetHiding(DynamicHideExtensions and close < E2H);
E3H.SetDefaultColor(CreateColor(0, 51, 0));
E3H.SetPaintingStrategy(PaintingStrategy.DASHES);
E3H.SetLineWeight(1);
E3H.HideBubble();
E3H.HideTitle();
plot E3L = if SE < 1 then Double.NaN else VAL - VAWidth * (FibExt3 - 1);
E3L.SetHiding(DynamicHideExtensions and close > E2L);
E3L.SetDefaultColor(CreateColor(51, 0, 0));
E3L.SetPaintingStrategy(PaintingStrategy.DASHES);
E3L.SetLineWeight(1);
E3L.HideBubble();
E3L.HideTitle();
View attachment 1020
If this have the option to change the profile to time shouldn't it work for forex pairs?
 
Hi all,

I'm having a concerning little anomaly with thinkorswim's standard volume profile indicator:

if i use it on a "1Year , Week" chart
and also on a "1Year , Day" chart of the same security

the levels will be different ... not the same ...

( i'm using it in chart mode to show the levels for the entire chart )

is this normal ?? i would think that no matter the candle timelength, the volume profile ought to be the same ...
 
Last edited:
Here is the script you provided with 5 poc extensions to the right added at the bottom of the code. You can create more using the logic in the code. It is a very manual process.

Question on SleepyZ post - he shared a pic of AAL that provides cumulative volume at that price level, with exact amount of Volume Traded at that price. (Volume Profile doesn't always show this volume, so need to play around with custom row height)

Is there anyway to quantify this and pull those numbers in order to use them?

Example1 : SPY today on 5m Chart, todays VPOC is 396.15 with 1,869,090 Volume traded at that range.
Goal is to have Volume at VPOC in label similar to the VPOC label in this pic.
 
Question on SleepyZ post - he shared a pic of AAL that provides cumulative volume at that price level, with exact amount of Volume Traded at that price. (Volume Profile doesn't always show this volume, so need to play around with custom row height)

Is there anyway to quantify this and pull those numbers in order to use them?

Example1 : SPY today on 5m Chart, todays VPOC is 396.15 with 1,869,090 Volume traded at that range.
Goal is to have Volume at VPOC in label similar to the VPOC label in this pic.

Sorry, but we do not have access to those volume numbers.
 
hi, im looking to add a 3 year profile time frame to this script. Ive added a quartly time frame, but this one is confusing me. Anyone know the code for a 3 year profile?
 
hi, im looking to add a 3 year profile time frame to this script. Ive added a quartly time frame, but this one is confusing me. Anyone know the code for a 3 year profile?

Here is a modification of TOS VolumeProfile to include TimePerProfile options of custom Dates range, Quarter and Year. The difference between the custom Dates and Year options is that custom Dates will include the current year's trading if selected as part of a multi-year range, whereas the Year option set to a multiple generally will not include it.

Screenshot-2023-01-02-074613.png
Ruby:
# VolumeProfile_CustomDate
# Modification of TOS Indicator to use Custom Dates input and Quarter and Year TimeperProfiles
#

input begindate  = 20200101;
input enddate    = 20230131;

input pricePerRowHeightMode = {default AUTOMATIC, TICKSIZE, CUSTOM};
input customRowHeight = 1.0;
input timePerProfile = {default DATES, CHART, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER , YEAR, "OPT EXP", BAR};
input multiplier = 1;
input onExpansion = no;
input profiles = 100;
input showPointOfControl = yes;
input showValueArea = yes;
input valueAreaPercent = 70;
input opacity = 50;

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);
def qtr = (GetMonth() - 1 ) % 3;
switch (timePerProfile) {
case DATES:
    period = GetYYYYMMDD() >= (begindate)  and GetYYYYMMDD() <= enddate;
case CHART:
    period = 0;
case MINUTE:
    period = Floor(seconds / 60 + day_number * 24 * 60);
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 QUARTER:
    period = Floor(qtr == 0 and qtr[1] != 0);
case YEAR:
    period = Floor(year - First(year));
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  = if timeperprofile == timeperprofile.dates
            then period!=period[1]
            else 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();

input bubbles = yes;
input n  = 2;
def   n1 = n + 1;
AddChartBubble(bubbles and !IsNaN(close[n1]) and IsNaN(close[n]), VAHigh[n1], "V-VAH", color = Color.YELLOW, yes);
AddChartBubble(bubbles and !IsNaN(close[n1]) and IsNaN(close[n]), VALow[n1], "V-VAL", Color.YELLOW, no);
AddChartBubble(bubbles and !IsNaN(close[n1]) and IsNaN(close[n]), POC[n1], "V-POC", Color.RED, no);
 
Last edited:
I have POC's for bars turned enabled on my intraday charts. Does anyone think it would be possible to modify the existing TOS RSI code to calculate RSI based off of those intraday bar POC's instead of close price? My VP settings are (TICKSIZE, 1.0, BAR, 1, no, 1000, yes, no, 70, 0). I'm basically displaying only the POC on each intraday chart, no VA's. I've done a few examples manually in excel and the results seem promising. I don't know Thinkscript (plan to get started learning asap) and its pretty time consuming doing it manually.
 
Here is a modification of TOS VolumeProfile to include TimePerProfile options of custom Dates range, Quarter and Year. The difference between the custom Dates and Year options is that custom Dates will include the current year's trading if selected as part of a multi-year range, whereas the Year option set to a multiple generally will not include it.
How do you move the VP graph to left side of screen? this code puts the graph on Right side.
 
I have POC's for bars turned enabled on my intraday charts. Does anyone think it would be possible to modify the existing TOS RSI code to calculate RSI based off of those intraday bar POC's instead of close price? My VP settings are (TICKSIZE, 1.0, BAR, 1, no, 1000, yes, no, 70, 0). I'm basically displaying only the POC on each intraday chart, no VA's. I've done a few examples manually in excel and the results seem promising. I don't know Thinkscript (plan to get started learning asap) and its pretty time consuming doing it manually.

The following code should display a RSI based upon a VolumeProfile BAR setting's POC within a RSI indicator .

The image shows the VolumeProfile in the upper panel, a standard RSI based upon Close in the uppermost lower panel and then the RSI based upon the VolumeProfile POC set at BAR. http://tos.mx/916Lc00

Screenshot-2023-01-02-105703.png
Ruby:
#RSI_using_POC_set_at_Bar_basis
def poc = reference VolumeProfile("price per row height mode" = "TICKSIZE", "on expansion" = No, "time per profile" = "BAR");
#
# TD Ameritrade IP Company, Inc. (c) 2007-2022
#

declare lower;

input length = 14;
input over_Bought = 70;
input over_Sold = 30;
def price = poc;
input averageType = AverageType.WILDERS;
input showBreakoutSignals = no;

def NetChgAvg = MovingAverage(averageType, price - price[1], length);
def TotChgAvg = MovingAverage(averageType, AbsValue(price - price[1]), length);
def ChgRatio = if TotChgAvg != 0 then NetChgAvg / TotChgAvg else 0;

plot RSI = 50 * (ChgRatio + 1);
plot OverSold = over_Sold;
plot OverBought = over_Bought;
plot UpSignal = if RSI crosses above OverSold then OverSold else Double.NaN;
plot DownSignal = if RSI crosses below OverBought then OverBought else Double.NaN;

UpSignal.SetHiding(!showBreakoutSignals);
DownSignal.SetHiding(!showBreakoutSignals);

RSI.DefineColor("OverBought", GetColor(5));
RSI.DefineColor("Normal", GetColor(7));
RSI.DefineColor("OverSold", GetColor(1));
RSI.AssignValueColor(if RSI > over_Bought then RSI.color("OverBought") else if RSI < over_Sold then RSI.color("OverSold") else RSI.color("Normal"));
OverSold.SetDefaultColor(GetColor(8));
OverBought.SetDefaultColor(GetColor(8));
UpSignal.SetDefaultColor(Color.UPTICK);
UpSignal.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
DownSignal.SetDefaultColor(Color.DOWNTICK);
DownSignal.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
 
The following code should display a RSI based upon a VolumeProfile BAR setting's POC within a RSI indicator .

The image shows the VolumeProfile in the upper panel, a standard RSI based upon Close in the uppermost lower panel and then the RSI based upon the VolumeProfile POC set at BAR. http://tos.mx/916Lc00
Thanks! I primarily trade futures. I noticed when looking at AAL, the scaling of the indicator seems correct. However, when I go futures, or other equities, the scale seems to get wonky. Like on /ES it is showing a potential value up to 4,000 RSI, which makes it impossible to see the RSI graph.


YrYoTTL.png
 
Last edited:
Thanks! I primarily trade futures. I noticed when looking at AAL, the scaling of the indicator seems correct. However, when I go futures, or other equities, the scale seems to get wonky. Like on /ES it is showing a potential value up to 4,000 RSI, which makes it impossible to see the RSI graph.


YrYoTTL.png

You can try this which multiplies the components of the modified RSI with POC by 100. TOS uses the VolumeProfile indicators scaling even though it is just referenced. https://tos.mx/ABJ4JRA

Here is image with standard RSI and modified RSI with POC scaled by 100

 

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
254 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