Volume Profile Indicator & POCs For ThinkOrSwim

shih90

New member
Hi @Shinthus, here is another cog indicator https://usethinkscript.com/threads/center-of-gravity-cog-indicator-for-thinkorswim.138/ I think this might be the cog indicator you're looking for if you were in bluesgirl's chatroom. (I'm in the same room :) That's similar to what she uses. From what I understand with the cog indicator is you want to play the edges and also look at the curves of the waves. So if the waves are starting to curl up price may have found a bottom and start to move up. Maybe similar to boillinger bands.

As for volume profile here is a picture of the study I use on TOS. It looks at the volume profile for every individual day, so the levels are pretty much the same across all time frames. I can post the settings I have if you're interested :)

52B6GLo.png


I like to mark off the Value area Highs/Lows (the yellow lines) and the point of control (red line). I use these lines as support/resistance and targets for the next day.

dBsFGTi.png


Oh, all of those lines are hand-drawn lol. With Volume profile, there's a concept called VPOC or virgin point of control, which means if a point of control(the red line) hasn't been tested the next day after it's been made, the price will naturally trend towards it. The "put" target level was the value area high from 8/9/19, the same day the VPOC level is from. I'm still practicing with volume profile, but I like it so far.

Hopefully this helps.
Would you please post volume profile? I'm interested it. Thank you
 

fourwinds091

New member
I was curious to see if I could scrap together an EMA that used the bar POC's. This is what I got. It doesn't seem to like my input of POC as price. Says no such function: POC at 5:15... Any idea where I went wrong?
Code:
#
def poc = reference VolumeProfile("price per row height mode" = "TICKSIZE", "on expansion" = No, "time per profile" = "BAR");

input price = poc;
input length = 9;
input displace = 0;
input showBreakoutSignals = no;

plot AvgExp = ExpAverage(price[-displace], length);
plot UpSignal = price crosses above AvgExp;
plot DownSignal = price crosses below AvgExp;

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

AvgExp.SetDefaultColor(GetColor(1));
UpSignal.SetDefaultColor(Color.UPTICK);
UpSignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
DownSignal.SetDefaultColor(Color.DOWNTICK);
DownSignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
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
 

SleepyZ

Well-known member
VIP
Lifetime
I was curious to see if I could scrap together an EMA that used the bar POC's. This is what I got. It doesn't seem to like my input of POC as price. Says no such function: POC at 5:15... Any idea where I went wrong?
Code:
#
def poc = reference VolumeProfile("price per row height mode" = "TICKSIZE", "on expansion" = No, "time per profile" = "BAR");

input price = poc;
input length = 9;
input displace = 0;
input showBreakoutSignals = no;

plot AvgExp = ExpAverage(price[-displace], length);
plot UpSignal = price crosses above AvgExp;
plot DownSignal = price crosses below AvgExp;

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

AvgExp.SetDefaultColor(GetColor(1));
UpSignal.SetDefaultColor(Color.UPTICK);
UpSignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
DownSignal.SetDefaultColor(Color.DOWNTICK);
DownSignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
Just change input price = poc; to def price = poc;
 

MerryDay

Administrative
Staff member
Staff
VIP
Lifetime
@shih90 @stockpsyop
Did you know that by clicking on a member's name, you can easily check when they were last seen on the uTS forum? It's a great way to keep track of who's been around recently, and who hasn't. Speaking of which, it looks like @John808 is no longer active. :(
 

TraderTheJoker

New member
Does anyone knows how to move volume profile to the right by 1 bar so i have more space between candle and volume profile on expansion?
 

fourwinds091

New member
Does anyone knows how to move volume profile to the right by 1 bar so i have more space between candle and volume profile on expansion?
Probably can change the offset in the price axis settings menu to accomplish this. Just go to settings and price axis menu. Should be able to find it from there.
 

TraderTheJoker

New member
I dont see anything on time axis that would move the expansion area to start a few bars to right of last candle rather than right after last candle, only option on there to make expansion area bigger
 

Whizz

New member
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.
Is it possible to do this with TPO?
 

SleepyZ

Well-known member
VIP
Lifetime
Does anyone knows how to move volume profile to the right by 1 bar so i have more space between candle and volume profile on expansion?

As mentioned above, there does not appear to be a way to move the volume profile when displayed on expansion.

However, the monkeybars indicator has a volume profile within it that may provide some visual assistance. It displays the volume profile right to left. I have made some modifications to the standard monkeybar indicator to highlight the volume profile usage.

Screenshot-2023-03-12-081924.png
Ruby:
#
# TD Ameritrade IP Company, Inc. (c) 2010-2023
#
# Modifications to MonkeyBars to highlight VolumeProfile Indicator within it ... 20230312 Sleepyz

input pricePerRowHeightMode = {default AUTOMATIC, TICKSIZE, CUSTOM};
input customRowHeight = 1.0;
input aggregationPeriod = {"1 min", "2 min", "3 min", "4 min", "5 min", "10 min", "15 min", "20 min", default "30 min", "1 hour", "2 hours", "4 hours", "Day", "2 Days", "3 Days", "4 Days", "Week", "Month", "Quarter", "Year"};
input timePerProfile = { CHART, MINUTE, HOUR, default DAY, WEEK, MONTH, "OPT EXP", BAR, YEAR};
input multiplier = 1;
input onExpansion = yes;
input profiles = 1;
input showMonkeyBar = no;
input showThePlayground = no;
input showProfileHighLow = no;
input thePlaygroundPercent = 70;
input opacity = 100;
input emphasizeFirstDigit = no;
input markOpenPrice = no;
input markClosePrice = no;
input volumeShowStyle = MonkeyVolumeShowStyle.last;
input showVolumeVA = yes;
input showVolumePoc = yes;
input theVolumePercent = 70;
input showInitialBalance = no;
input initialBalanceRange = 3;

def period;
def yyyymmdd = getYyyyMmDd();
def seconds = secondsFromTime(0);
def year = getYear();
def month = year * 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);
def periodMin = Floor(seconds / 60 + day_number * 24 * 60);
def periodHour = Floor(seconds / 3600 + day_number * 24);
def periodDay = countTradingDays(Min(first(yyyymmdd), yyyymmdd), yyyymmdd) - 1;
def periodWeek = Floor(day_number / 7);
def periodMonth = month - first(month);
def periodQuarter = Ceil(month / 3) - first(Ceil(month / 3));
def periodYear = year - first(year);

switch (timePerProfile) {
case CHART:
    period = 0;
case MINUTE:
    period = periodMin;
case HOUR:
    period = periodHour;
case DAY:
    period = periodDay;
case WEEK:
    period = periodWeek;
case MONTH:
    period = periodMonth;
case "OPT EXP":
    period = exp_opt - first(exp_opt);
case BAR:
    period = barNumber() - 1;
case YEAR:
    period = periodYear;
}

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

def timeInterval;
def aggMultiplier;
switch (aggregationPeriod) {
case "1 min":
    timeInterval = periodMin;
    aggMultiplier = 1;
case "2 min":
    timeInterval = periodMin;
    aggMultiplier = 2;
case "3 min":
    timeInterval = periodMin;
    aggMultiplier = 3;
case "4 min":
    timeInterval = periodMin;
    aggMultiplier = 4;
case "5 min":
    timeInterval = periodMin;
    aggMultiplier = 5;
case "10 min":
    timeInterval = periodMin;
    aggMultiplier = 10;
case "15 min":
    timeInterval = periodMin;
    aggMultiplier = 15;
case "20 min":
    timeInterval = periodMin;
    aggMultiplier = 20;
case "30 min":
    timeInterval = periodMin;
    aggMultiplier = 30;
case "1 hour":
    timeInterval = periodHour;
    aggMultiplier = 1;
case "2 hours":
    timeInterval = periodHour;
    aggMultiplier = 2;
case "4 hours":
    timeInterval = periodHour;
    aggMultiplier = 4;
case "Day":
    timeInterval = periodDay;
    aggMultiplier = 1;
case "2 Days":
    timeInterval = periodDay;
    aggMultiplier = 2;
case "3 Days":
    timeInterval = periodDay;
    aggMultiplier = 3;
case "4 Days":
    timeInterval = periodDay;
    aggMultiplier = 4;
case "Week":
    timeInterval = periodWeek;
    aggMultiplier = 1;
case "Month":
    timeInterval = periodMonth;
    aggMultiplier = 1;
case "Quarter":
    timeInterval = periodQuarter;
    aggMultiplier = 1;
case "Year":
    timeInterval = periodYear;
    aggMultiplier = 1;
}

def agg_count = compoundvalue(1, if timeInterval != timeInterval[1] then (getValue(agg_count, 1) + timeInterval - timeInterval[1]) % aggMultiplier else getValue(agg_count, 1), 0);
def agg_cond = compoundvalue(1,  agg_count < agg_count[1] + timeInterval - timeInterval[1], yes);

def digit = compoundValue(1, if cond then 1 else agg_cond + getValue(digit, 1), 1);

profile monkey = monkeyBars(digit, "startNewProfile" = cond, "onExpansion" = onExpansion,
"numberOfProfiles" = profiles, "pricePerRow" = height, "the playground percent" = thePlaygroundPercent,
"emphasize first digit" = emphasizeFirstDigit, "volumeProfileShowStyle" = volumeShowStyle, "volumePercentVA" = theVolumePercent,
 "show initial balance" = showInitialBalance, "initial balance range" = initialBalanceRange);
def con = compoundValue(1, onExpansion, no);
def mbar = compoundvalue(1, if IsNaN(monkey.getPointOfControl()) and con then getValue(mbar, 1) else monkey.getPointOfControl(), monkey.getPointOfControl());
def hPG = compoundvalue(1, if IsNaN(monkey.getHighestValueArea()) and con then getValue(hPG, 1) else monkey.getHighestValueArea(), monkey.getHighestValueArea());
def lPG = compoundvalue(1, if IsNaN(monkey.getLowestValueArea()) and con then getValue(lPG, 1) else monkey.getLowestValueArea(), monkey.getLowestValueArea());

def hProfile = compoundvalue(1, if IsNaN(monkey.getHighest()) and con then getValue(hProfile, 1) else monkey.getHighest(), monkey.getHighest());
def lProfile = compoundvalue(1, if IsNaN(monkey.getLowest()) and con then getValue(lProfile, 1) else monkey.getLowest(), monkey.getLowest());
def plotsDomain = IsNaN(close) == onExpansion;

plot MB = if plotsDomain then mbar else Double.NaN;
plot ProfileHigh = if plotsDomain then hProfile else Double.NaN;
plot ProfileLow = if plotsDomain then lProfile else Double.NaN;
plot PGHigh = if plotsDomain then hPG else Double.NaN;
plot PGLow = if plotsDomain then lPG else Double.NaN;

DefineGlobalColor("Monkey Bar", GetColor(4));
DefineGlobalColor("The Playground", GetColor(3));
DefineGlobalColor("Open Price", GetColor(1));
DefineGlobalColor("Close Price", GetColor(1));
DefineGlobalColor("Volume", color.cyan);
DefineGlobalColor("Volume Value Area", color.yellow);
DefineGlobalColor("Volume Point of Control", GetColor(2));
DefineGlobalColor("Initial Balance", GetColor(7));

monkey.show(color.red, if showMonkeyBar then globalColor("Monkey Bar") else color.current,
 if showThePlayground then globalColor("The Playground") else color.current,
 opacity, if markOpenPrice then globalColor("Open Price") else color.current,
 if markClosePrice then globalColor("Close Price") else color.current,
 if showInitialBalance then globalColor("Initial Balance") else color.current,
 globalColor("Volume"),
 if showVolumeVA then globalColor("Volume Value Area") else color.current,
 if showVolumePOC then globalColor("Volume Point of Control") else color.current);
MB.SetDefaultColor(globalColor("Monkey Bar"));
MB.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
PGHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
PGLow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
PGHigh.SetDefaultColor(globalColor("The Playground"));
PGLow.SetDefaultColor(globalColor("The Playground"));
ProfileHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileLow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileHigh.SetDefaultColor(GetColor(3));
ProfileLow.SetDefaultColor(GetColor(3));
MB.sethiding(!showMonkeyBar);
PGHigh.sethiding(!showThePlayground);
PGLow.sethiding(!showThePlayground);
ProfileHigh.hide();
ProfileLow.hide();
 

toyax

New member
VIP
Tradingview volume color(up/down) on the TPOProfile indicator
tradingview indicator Like this
g7nsn93.png

Bi4Abl0.png

tradingview indicator in this video:
 
Last edited by a moderator:

SleepyZ

Well-known member
VIP
Lifetime
Tradingview volume color(up/down) on the TPOProfile indicator
tradingview indicator Like this
g7nsn93.png

Bi4Abl0.png

tradingview indicator in this video:

We do not have control over coloring the native profile indicators, nor contol over tracking up/down volume, in either case as above.

However we have made a pseudo buying selling study by BenTen to try to emulate buying/selling behavior. It is used in a relatively new function that TOS provided, dataprofile().

The DataProfile uses coloring based upon the input buyingselling method chosen. Green is 'buying' and Red is the 'selling' beyond the 'buying'. (The Red is actually the total of buying and selling with the buying overlaid on the red)

Screenshot-2023-03-12-115704.png

Code:
#DataProfile_BuyingSelling_CloseOpen
#DataProfile - Using Close based upon the input method. Green is 'buying' and Red is the 'selling' beyond the 'buying'. (The Red is actually the total of buying and selling with the buying overlaid on the red)
#20211130 Sleepyz; updated 20230312 Sleepyz

input method = {default buying_selling_pressure, buying_selling_volume};
def c = close;
def o = open;
def h = high;
def l = low;
def v = volume;

# Buying vs. Selling Power
# Assembled by BenTen at UseThinkScript.com
# Converted from https://www.tradingview.com/script/XZ3UXRvL-buy-vs-sell-power-x/

input s = 5;
input m = 9;
input len = 14;
input paintbar = yes;

def source = close;
def hilow = ((high - low) * 100);
def openclose = ((close - open) * 100);
def vol = (close / hilow);
def spreadv = (openclose * close);
def pt = spreadv + TotalSum(spreadv);

def a = ExpAverage(pt, len) - ExpAverage(pt, m);
def b = ExpAverage(pt, s) - ExpAverage(pt, m);
def p = a + b;

def blue = b;
def red = p;

def bullishRule = b >= p;
def bearishRule = b <= p;

AssignPriceColor(if paintbar and bullishRule then Color.CYAN else if paintbar and bearishRule then Color.MAGENTA else Color.CURRENT);

def test;
switch (method) {
case buying_selling_volume:
    test = if ((c - l) / (h - l) * volume) >= ((h - c) / (h - l) * volume) then close else if ((c - l) / (h - l) * volume) < ((h - c) / (h - l) * volume) then Double.NaN else test[1];
case buying_selling_pressure:
    test = if b >= p then close else if b < p then Double.NaN else test[1];
}

def buy   = test;
def Data  = close;


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

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 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 datatype = DataProfile("data" = Data, "startNewProfile" = cond, "onExpansion" = onExpansion, "numberOfProfiles" = profiles, "pricePerRow" = height, "value area percent" = valueAreaPercent);
def con = CompoundValue(1, onExpansion, no);
def pc = if IsNaN(datatype.GetPointOfControl()) and con then pc[1] else datatype.GetPointOfControl();
def hVA = if IsNaN(datatype.GetHighestValueArea()) and con then hVA[1] else datatype.GetHighestValueArea();
def lVA = if IsNaN(datatype.GetLowestValueArea()) and con then lVA[1] else datatype.GetLowestValueArea();

def hProfile = if IsNaN(datatype.GetHighest()) and con then hProfile[1] else datatype.GetHighest();
def lProfile = if IsNaN(datatype.GetLowest()) and con then lProfile[1] else datatype.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", Color.LIGHT_RED);
DefineGlobalColor("Point Of Control", Color.CYAN);
DefineGlobalColor("Value Area", Color.LIGHT_RED);

datatype.Show(GlobalColor("Profile"), if showPointOfControl then GlobalColor("Point Of Control") else Color.CURRENT, if showValueArea then GlobalColor("Value Area") else Color.CURRENT);
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"));
VAHigh.SetLineWeight(2);
VALow.SetLineWeight(2);
ProfileHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileLow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileHigh.SetDefaultColor(GetColor(3));
ProfileLow.SetDefaultColor(GetColor(3));
ProfileHigh.Hide();
ProfileLow.Hide();


profile datatype2 = DataProfile("data" = test, "startNewProfile" = cond, "onExpansion" = onExpansion, "numberOfProfiles" = profiles, "pricePerRow" = height, "value area percent" = valueAreaPercent);

def con2 = CompoundValue(1, onExpansion, no);
def pc2 = if IsNaN(datatype2.GetPointOfControl()) and con2 then pc2[1] else datatype2.GetPointOfControl();
def hVA2 = if IsNaN(datatype2.GetHighestValueArea()) and con2 then hVA2[1] else datatype2.GetHighestValueArea();
def lVA2 = if IsNaN(datatype2.GetLowestValueArea()) and con2 then lVA2[1] else datatype2.GetLowestValueArea();

def hProfile2 = if IsNaN(datatype2.GetHighest()) and con2 then hProfile2[1] else datatype2.GetHighest();
def lProfile2 = if IsNaN(datatype2.GetLowest()) and con2 then lProfile2[1] else datatype2.GetLowest();
def plotsDomain2 = IsNaN(close) == onExpansion;

plot POC2 = if plotsDomain2 then pc2 else Double.NaN;
plot ProfileHigh2 = if plotsDomain2 then hProfile2 else Double.NaN;
plot ProfileLow2 = if plotsDomain2 then lProfile2 else Double.NaN;
plot VAHigh2 = if plotsDomain2 then hVA2 else Double.NaN;
plot VALow2 = if plotsDomain2 then lVA2 else Double.NaN;

DefineGlobalColor("Profile2", Color.GREEN);
DefineGlobalColor("Point Of Control2", Color.CYAN);
DefineGlobalColor("Value Area2", Color.GREEN);

datatype2.Show(GlobalColor("Profile2"), if showPointOfControl then GlobalColor("Point Of Control") else Color.CURRENT, if showValueArea then GlobalColor("Value Area") else Color.CURRENT, opacity);

POC2.SetDefaultColor(GlobalColor("Point Of Control2"));
POC2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
POC2.SetLineWeight(2);
VAHigh2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VALow2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh2.SetDefaultColor(GlobalColor("Value Area2"));
VALow2.SetDefaultColor(GlobalColor("Value Area2"));
VAHigh2.SetLineWeight(2);
VALow2.SetLineWeight(2);
ProfileHigh2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileLow2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileHigh2.SetDefaultColor(GetColor(3));
ProfileLow2.SetDefaultColor(GetColor(3));
ProfileHigh2.Hide();
ProfileLow2.Hide();
 

SleepyZ

Well-known member
VIP
Lifetime
We do not have control over coloring the native profile indicators, nor contol over tracking up/down volume, in either case as above.

However we have made a pseudo buying selling study by BenTen to try to emulate buying/selling behavior. It is used in a relatively new function that TOS provided, dataprofile().

The DataProfile uses coloring based upon the input buyingselling method chosen. Green is 'buying' and Red is the 'selling' beyond the 'buying'. (The Red is actually the total of buying and selling with the buying overlaid on the red)

Here is a Multi_Time_Frame version of the above script with optional bubbles added
[Edit to add showbubbles]

Screenshot-2023-03-15-085654.png

Ruby:
#VolumeProfile_using_DataProfile_BuyingSelling_MTF
#DataProfile - Using Close based upon the input method. Green is 'buying' and Red is the 'selling' beyond the 'buying'. (The Red is actually the total of buying and selling with the buying overlaid on the red)
#20211130 Sleepyz; updated 20230312 Sleepyz

input agg = AggregationPeriod.FIVE_MIN;
input method = {default buying_selling_pressure, buying_selling_volume};
def c = close(period = agg);
def o = open(period = agg);
def h = high(period = agg);
def l = low(period = agg);
def v = volume(period = agg);

# Buying vs. Selling Power
# Assembled by BenTen at UseThinkScript.com
# Converted from https://www.tradingview.com/script/XZ3UXRvL-buy-vs-sell-power-x/

input s = 2;#5;
input m = 4;#9;
input len = 6;#14;
input paintbar = no;

def source = c;
def hilow = ((h - l) * 100);
def openclose = ((c - o) * 100);
def vol = (c / hilow);
def spreadv = (openclose * c);
def pt = spreadv + TotalSum(spreadv);

def a = ExpAverage(pt, len) - ExpAverage(pt, m);
def b = ExpAverage(pt, s) - ExpAverage(pt, m);
def p = a + b;

def blue = b;
def red = p;

def bullishRule = b >= p;
def bearishRule = b <= p;

AssignPriceColor(if paintbar and bullishRule then Color.CYAN else if paintbar and bearishRule then Color.MAGENTA else Color.CURRENT);

def test;
switch (method) {
case buying_selling_volume:
    test = if ((c - l) / (h - l) * v) >= ((h - c) / (h - l) * v) then c else if ((c - l) / (h - l) * v) < ((h - c) / (h - l) * v) then Double.NaN else test[1];
case buying_selling_pressure:
    test = if b >= p then c else if b < p then Double.NaN else test[1];
}

def buy   = Round(test, 2);
def Data  = Round(c, 2);


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

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 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 datatype = DataProfile("data" = Data, "startNewProfile" = cond, "onExpansion" = onExpansion, "numberOfProfiles" = profiles, "pricePerRow" = height, "value area percent" = valueAreaPercent);
def con = CompoundValue(1, onExpansion, no);
def pc = if IsNaN(datatype.GetPointOfControl()) and con then pc[1] else datatype.GetPointOfControl();
def hVA = if IsNaN(datatype.GetHighestValueArea()) and con then hVA[1] else datatype.GetHighestValueArea();
def lVA = if IsNaN(datatype.GetLowestValueArea()) and con then lVA[1] else datatype.GetLowestValueArea();

def hProfile = if IsNaN(datatype.GetHighest()) and con then hProfile[1] else datatype.GetHighest();
def lProfile = if IsNaN(datatype.GetLowest()) and con then lProfile[1] else datatype.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", Color.RED);
DefineGlobalColor("Point Of Control", Color.CYAN);
DefineGlobalColor("Value Area", Color.RED);

datatype.Show(GlobalColor("Profile"), if showPointOfControl then GlobalColor("Point Of Control") else Color.CURRENT, if showValueArea then GlobalColor("Value Area") else Color.CURRENT);
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"));
VAHigh.SetLineWeight(2);
VALow.SetLineWeight(2);
ProfileHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileLow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileHigh.SetDefaultColor(GetColor(3));
ProfileLow.SetDefaultColor(GetColor(3));
ProfileHigh.Hide();
ProfileLow.Hide();


profile datatype2 = DataProfile("data" = test, "startNewProfile" = cond, "onExpansion" = onExpansion, "numberOfProfiles" = profiles, "pricePerRow" = height, "value area percent" = valueAreaPercent);

def con2 = CompoundValue(1, onExpansion, no);
def pc2 = if IsNaN(datatype2.GetPointOfControl()) and con2 then pc2[1] else datatype2.GetPointOfControl();
def hVA2 = if IsNaN(datatype2.GetHighestValueArea()) and con2 then hVA2[1] else datatype2.GetHighestValueArea();
def lVA2 = if IsNaN(datatype2.GetLowestValueArea()) and con2 then lVA2[1] else datatype2.GetLowestValueArea();

def hProfile2 = if IsNaN(datatype2.GetHighest()) and con2 then hProfile2[1] else datatype2.GetHighest();
def lProfile2 = if IsNaN(datatype2.GetLowest()) and con2 then lProfile2[1] else datatype2.GetLowest();
def plotsDomain2 = IsNaN(close) == onExpansion;

plot POC2 = if plotsDomain2 then pc2 else Double.NaN;
plot ProfileHigh2 = if plotsDomain2 then hProfile2 else Double.NaN;
plot ProfileLow2 = if plotsDomain2 then lProfile2 else Double.NaN;
plot VAHigh2 = if plotsDomain2 then hVA2 else Double.NaN;
plot VALow2 = if plotsDomain2 then lVA2 else Double.NaN;

DefineGlobalColor("Profile2", Color.GREEN);
DefineGlobalColor("Point Of Control2", Color.CYAN);
DefineGlobalColor("Value Area2", Color.GREEN);

datatype2.Show(GlobalColor("Profile2"), if showPointOfControl then GlobalColor("Point Of Control") else Color.CURRENT, if showValueArea then GlobalColor("Value Area") else Color.CURRENT, opacity);

POC2.SetDefaultColor(GlobalColor("Point Of Control2"));
POC2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
POC2.SetLineWeight(2);
VAHigh2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VALow2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh2.SetDefaultColor(GlobalColor("Value Area2"));
VALow2.SetDefaultColor(GlobalColor("Value Area2"));
VAHigh2.SetLineWeight(2);
VALow2.SetLineWeight(2);
ProfileHigh2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileLow2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
ProfileHigh2.SetDefaultColor(GetColor(3));
ProfileLow2.SetDefaultColor(GetColor(3));
ProfileHigh2.Hide();
ProfileLow2.Hide();

input showbubbles = yes;
input bubblemover = 2;
def bm  = bubblemover;
def bm1 = bm + 1;
def mover = showbubbles and IsNaN(close[bm]) and !IsNaN(close[bm1]);

AddChartBubble(mover, POC[bm1], "APOC", POC.TakeValueColor());#All POC
AddChartBubble(mover, POC2[bm1], "UPOC", POC.TakeValueColor());#Up POC
AddChartBubble(mover, VAHigh[bm1], "AVAH", VAHigh.TakeValueColor());
AddChartBubble(mover, VAHigh2[bm1], "UVAH", VAHigh2.TakeValueColor());
AddChartBubble(mover, VALow[bm1], "AVAL", VALow.TakeValueColor());
AddChartBubble(mover, VALow2[bm1], "UVAL", VALow2.TakeValueColor());
 
Last edited:

Point of controller

New member
Plus
Does anyone know how to scan for stocks where the current day volume profile is inside the previous day volume profile?

Such that the current day VAH is equal to or lower than previous day VAH and the current day VAL is equal to or higher than previous day VAL.

Like an inside bar scan, but for the volume profile study
 

BenTen

Administrative
Staff member
Staff
VIP
Lifetime
@Point of controller Try this:

Code:
#Courtesy of Pete Hahn
#visit link below on how to use
# https://www.hahn-tech.com/thinkorswim-scan-volume-profile/


input scanUpperVaLimit = 100.0;
input scanUpperVaRange = 20.0;
input scanLowerVaLimit = 0.0;
input scanLowerVaRange = 20.00;
input scanLookbackBars = 3;
input pricePerRowHeightMode = {default AUTOMATIC, TICKSIZE, CUSTOM};
input customRowHeight = 1.0;
input timePerProfile = { MINUTE, HOUR, DAY,default WEEK, MONTH, "OPT EXP", BAR};
input multiplier = 1;
input onExpansion = no;
input profiles = 50;
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 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 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 "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;

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

rec priorPOC = if period != period[1] then pc[1] else priorPOC[1] ;
rec priorVAHigh = if period!= period[1] then VAHigh[1] else priorVAHigh[1];
rec priorVALow = if period != period[1] then VALow[1] else priorVALow[1];

def aboveVaHigh = lowest(low[1], scanLookbackBars) > priorVAHigh;
def belowVaLow = highest(high[1], scanLookbackBars) < priorVALow;
def insideVA = highest(high[1], scanLookbackBars) < priorVAHigh and lowest(low[1], scanLookbackBars) > priorVALow;

# now we need to define a percentile value expressing the relative
# position of the close as compared to the value area
def prctOfVA = ((close - priorVALow) / (priorVAHigh - priorVALow)) * 100;

def upperVaRange = prctOfVA < scanUpperVaLimit and prctOfVA > (scanUpperVaLimit - scanUpperVaRange);
def lowerVaRange = prctOfVa > scanLowerVaLimit and prctOfVA < (scanLowerVaLimit + scanLowerVaRange);

def condition1 = VAHigh <= VAHIGH[1];
def condition2 = VALOW >= VALOW[1];
plot scan = condition1 and condition2;
 

Point of controller

New member
Plus
@Point of controller Try this:

Code:
#Courtesy of Pete Hahn
#visit link below on how to use
# https://www.hahn-tech.com/thinkorswim-scan-volume-profile/


input scanUpperVaLimit = 100.0;
input scanUpperVaRange = 20.0;
input scanLowerVaLimit = 0.0;
input scanLowerVaRange = 20.00;
input scanLookbackBars = 3;
input pricePerRowHeightMode = {default AUTOMATIC, TICKSIZE, CUSTOM};
input customRowHeight = 1.0;
input timePerProfile = { MINUTE, HOUR, DAY,default WEEK, MONTH, "OPT EXP", BAR};
input multiplier = 1;
input onExpansion = no;
input profiles = 50;
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 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 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 "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;

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

rec priorPOC = if period != period[1] then pc[1] else priorPOC[1] ;
rec priorVAHigh = if period!= period[1] then VAHigh[1] else priorVAHigh[1];
rec priorVALow = if period != period[1] then VALow[1] else priorVALow[1];

def aboveVaHigh = lowest(low[1], scanLookbackBars) > priorVAHigh;
def belowVaLow = highest(high[1], scanLookbackBars) < priorVALow;
def insideVA = highest(high[1], scanLookbackBars) < priorVAHigh and lowest(low[1], scanLookbackBars) > priorVALow;

# now we need to define a percentile value expressing the relative
# position of the close as compared to the value area
def prctOfVA = ((close - priorVALow) / (priorVAHigh - priorVALow)) * 100;

def upperVaRange = prctOfVA < scanUpperVaLimit and prctOfVA > (scanUpperVaLimit - scanUpperVaRange);
def lowerVaRange = prctOfVa > scanLowerVaLimit and prctOfVA < (scanLowerVaLimit + scanLowerVaRange);

def condition1 = VAHigh <= VAHIGH[1];
def condition2 = VALOW >= VALOW[1];
plot scan = condition1 and condition2;

Thank you for the response. I have pasted that code into the TOS stock hacker with the 'is true' designation and received 1800+ results. When I cross-checked a few of the results they did not meet the criteria of the inside previous day volume profile that I was hoping for. I know AAPL, OXY, ABNB have a volume profile that is completely inside yesterday's profile, for example, to show what I am looking for.

Maybe my inputs have to be adjusted or I am missing something -- any recommendations?
 
Last edited:

Point of controller

New member
Plus
Thank you for the response. I have pasted that code into the TOS stock hacker with the 'is true' designation and received 1800+ results. When I cross-checked a few of the results they did not meet the criteria of the inside previous day volume profile that I was hoping for. I know AAPL has a volume profile that is completely inside yesterday's profile, for example.

Maybe my inputs have to be adjusted or I am missing something -- any recommendations?
@Point of controller The code I gave you is already the scan code itself. Don't create any additional conditions for it.
I cleared all filters and started a new scan with just the code you posted into the thinkscript editor and received no results, just 'script execution timeout error' messages.

When I added two filters, Market Cap 1,000M and 900,000 volume, (I did this thinking if I narrow the list of stocks to search maybe it will help the execution of the code) -- I did receive 1700 results. However, after checking the volume profile on a few of the stocks in the results list, it was not the result I was hoping for.

Many of the stocks on the list did not have a volume profile inside the previous day volume profile.
 

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

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
304 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.
Top