A volume profile is a histogram on its side. Instead of asking how much traded in each bar, it asks how much traded at each price. The honest version of that histogram is built from prints. Pine Script has bars. Volume Profile Suite is the library indicator that builds the histogram anyway, by spreading each bar's volume across the prices the bar actually traded, splitting that spread into estimated buying and selling, and then keeping the prior session's busiest price around after the session is over.
Short answer
The visible profile covers the last 200 bars in 24 rows. Each bar's volume is shared across the rows its high-to-low range overlaps, in proportion to the overlap, and split by where the close sits in that range. The point of control is the row with the most volume. The value area starts there and grows toward the heavier neighboring row until it holds 70 percent of the volume. Separately, the script carries the prior session's point of control and value area forward as levels, and it keeps up to ten naked points of control: session points of control that price has not traded back through. A diamond marks the bar that trades through one. Triangles mark a close back inside the prior value area. The profile is an estimate from bars, not an exchange footprint.
Key facts
- The default window is 200 bars, drawn as 24 rows, with the histogram using 30 percent of the window's width.
- A bar that spans three rows deposits volume in all three, in proportion to how much of its range sits in each row. A zero-range bar deposits its whole volume in the one row that contains its price.
- The buying share of each deposit is (close - low) / (high - low). The rest is the selling share. This is the same estimate Delta Flow uses, and it is not bid/ask volume.
- The point of control is the single busiest row. The value area expands from that row, one row at a time, always taking the heavier neighbor, until the enclosed volume reaches the requested percent. The default is 70.
- Rows inside the value area are drawn brighter. The point-of-control row is yellow. Green is the estimated buying portion of a row. Red is the estimated selling portion.
- The profile is redrawn on the last bar only. The boxes already exist and are moved, so a new bar does not create another set of drawings.
- Auto session is the UTC day up to the 1-hour chart, the week on higher intraday charts, and the month on daily charts and above.
- The prior session's point of control and value area are plotted across the current session, with a one-bar gap at the boundary so the new level does not join the old one.
- A naked point of control is removed when a bar's range trades through it. The diamond is printed when that bar closes. Up to ten are kept.
- A triangle is a confirmed close back inside the prior value area after a close outside it. The script does not claim a success rate for what happens next.
| Object | Built from | Drawn as | Goes away when |
|---|---|---|---|
| Lookback profile | Last 200 bars, 24 rows | Boxes on the left of that window | It moves forward with the last bar |
| Point of control | The busiest row of that profile | Yellow line across the window | The window rolls |
| Value area | Rows grown from the point of control to 70 percent | Grey lines, brighter boxes | The window rolls |
| Prior session levels | The finished session's profile | Yellow step and a grey band | The next session replaces them |
| Naked point of control | A session point of control not yet revisited | Dashed yellow line, up to 10 | A bar trades through the price |
Spread the bar across the rows it actually covered
Pick a price floor and a ceiling for the window, the lowest low and the highest high, and cut that span into equal rows. The default is 24. A bar whose range sits inside one row is easy: all of its volume goes there. A bar that stretches across several rows has to be shared, or you will dump an entire impulse candle into whichever row contains the close and call that a profile. The script shares by overlap. If a third of the bar's range sits in a row, that row receives a third of the bar's volume. A bar with no range at all goes entirely into the row that contains its price.
Each deposit is then split. The buying portion is the close location, (close - low) divided by (high - low), times the deposit. The selling portion is the remainder. A close at the high of the bar paints the whole deposit green. A close at the low paints it red. This is the same estimate used in Delta Flow, and it has the same limit. It does not know which prices inside the bar were actually printed, and it does not know the bid or the ask. Turning the split off draws one color per row. The totals, the point of control, and the value area do not change, because they use the sum.
More rows look more precise and are not. Twenty-four rows on a 200-bar window is a compromise between a blocky histogram and a histogram that puts a handful of trades in each stripe and calls the noise a level. The input allows 8 to 48. If you double the rows, do it because you want to see a shelf that 24 rows were bridging, and then check that the shelf survives a smaller lookback. A level that exists only at one row setting was an artifact of the bin size.
TradingView's own volume profile is a different construction, and the two will not match. Their help page describes building the histogram from lower-timeframe bars, counting a bar as up volume when it closes at or above its open, and stopping the value area before a row that would take the enclosed volume past the target. This script uses the chart's own bars, spreads them by overlap, splits them by close location, and keeps the row that crosses the target. Same words, different measurement. Expect different lines.
The point of control is the busiest row. The value area grows from it.
Once the rows are filled, the point of control is the row whose buying plus selling volume is the largest. Ties go to the lowest index, because the scan starts at the bottom and replaces the winner only on a strictly greater total. The line is drawn through the middle of that row, not through the top or the bottom. The label on the last bar prints that price in the symbol's mintick format.
The value area is the part people implement differently without saying so. This script uses the expansion usually associated with the CBOT method. Start with the point-of-control row already included. Look at the row above the current area and the row below it. Add the heavier one. Repeat until the enclosed volume is at least the requested percent of the total, default 70. If the two neighbors are equal, the upper one is taken, because the comparison is greater-or-equal. The area can be wider on one side than the other. That is the point of growing toward the volume rather than taking a fixed number of rows each way.
The high of the value area is the top of the upper row. The low is the bottom of the lower row. Boxes inside that span are drawn brighter, and the point-of-control row is yellow regardless. Grey lines mark the high and the low across the window. Changing 70 to 80 includes more of the distribution, so the band gets taller and prices outside it get rarer. It does not make the area more correct. Pick the percent the way you pick any other threshold, and write it down.
//@version=6
indicator("Value area grown from the busiest row", overlay = false)
// rowTotal holds volume per row, already filled. n is the row count.
// This is the expansion, not the histogram.
valueArea(array<float> rowTotal, int n, float pct) =>
int poc = 0
float best = -1.0
float total = 0.0
for r = 0 to n - 1
float t = rowTotal.get(r)
total += t
if t > best
best := t
poc := r
int up = poc
int dn = poc
float acc = best
float target = total * pct / 100.0
while acc < target and (up < n - 1 or dn > 0)
float above = up < n - 1 ? rowTotal.get(up + 1) : -1.0
float below = dn > 0 ? rowTotal.get(dn - 1) : -1.0
if above >= below
up += 1
acc += above
else
dn -= 1
acc += below
[poc, up, dn]The library script stores buying and selling separately and adds them for this test, so the value area is a statement about total volume. The colors inside a row are the estimate. The boundaries are not.
The session profile is a different object from the rolling one
The boxes you see are the rolling window, recomputed on the last bar from the last 200 bars, whatever those bars are. The levels underneath are the previous finished session. Those are not the same distribution. A rolling 200-bar profile on a 15-minute chart is a bit more than two days. The prior-session level on that chart, in Auto mode, is yesterday's UTC day. Confusing the yellow line of the rolling point of control with the yellow step of the prior session is the easiest way to misread the indicator.
Auto picks the session the same way Delta Flow picks its reset, with one extra step at the top. Intraday charts at 1 hour and below use the UTC day. Higher intraday charts use the week. Daily charts and above use the month. You can force Day, Week, or Month. At the first bar of a new session the script builds a profile from the bars it collected, stores the point of control and the value-area high and low, and starts a fresh collection. Those stored prices are what get plotted through the new session.
The prior lines are set to na for one bar at the session change. That break stops the plot from drawing a vertical stroke between yesterday's point of control and today's. A vertical line there would look like a level. It would actually be the plotter connecting two unrelated prices. The grey band between the prior value-area high and low is the same series, with the same one-bar gap.
Naked means not traded through yet
Each finished session pushes its point of control onto a list, together with the bar where that session started. The list holds ten of them. An eleventh pushes the oldest off the list, even if price never went back. A naked point of control stops being naked on the first bar whose range includes the price: low at or below it, high at or above it. A wick counts. The dashed line is removed at that moment, and when the bar closes a diamond prints above it. The diamond does not mean the close held on either side. It means the bar traded the price.
Ten is a drawing choice as much as an analytical one. The script creates its line objects once, up to the maximum of ten, and moves them. It does not call line.new on every session, which is how profile scripts blow the drawing limit and start deleting old levels silently. If you need more than ten, you are also taking on the line budget and the question of whether a point of control from that far back is still the object you think it is. The input stops at ten because that is what the script pre-allocates.
Triangles are a separate rule, and they use closes. "Back in value from below" is a confirmed bar that closes above the prior value-area low, with the previous close still below that low, and with the close still under the value-area high. The mirror fires from above. The bar of a session change, and the bar after it, are excluded so the gap in the lines does not create a false cross. This is the chart event behind the Market Profile remark often called the 80 percent rule. The script marks the cross back inside. It does not count how often anything happens afterward, and it does not promise that the rest of the value area will be visited.
What to change, and what the drawing is doing
The profile is the heaviest of the five library indicators, and it is built to stay inside the drawing limits anyway. Boxes for the rows are created on the first bar, two per row, and then moved. Lines for the point of control, the value area, and the naked levels are created once. The lookback is capped at 900 bars and the script requests a thousand bars of history, because the window has to be readable with the history operator. If you raise the lookback and the profile goes empty or partial, you are asking for bars the chart has not kept. Lower it, or apply the script where more history is loaded.
Volume Profile Suite is included in every paid plan. The chart inside PineScripter runs it on crypto spot data, 308 Binance markets, up to 5,000 bars, on timeframes from 1 minute to 1 week. There is no monthly timeframe in the app, even though the script knows what a month is and will use one on a daily TradingView chart. Paste it there for markets the app does not list. Alerts exist for the two "back in value" closes and for a naked point of control being tested. They match the shapes, which means they wait for the bar to close.
Two edits are worth making before any others. The value-area percent changes the grey band and the brightness of the rows, and it changes when a "back in value" triangle can fire, because that test uses the prior area. The row count changes the bin size of every level you see. Change them one at a time in the editor. A profile that looks completely different after both edits has not discovered a new market. It is answering a different question about the same bars.
Frequently asked questions
How does this volume profile get data without a footprint?
It spreads each bar's volume across the rows that bar's high and low overlap, in proportion to the overlap. It then splits each share into estimated buying and selling by where the close sits in the range. That is an estimate from the bar. It is not a record of the prices that actually printed, and it is not bid and ask volume.
What is the point of control?
The row that received the most volume in the profile being drawn. For the rolling histogram that is the last 200 bars by default. For the yellow step line it is the point of control of the previous finished session. They are different profiles and they do not have to agree.
How is the value area chosen?
Start at the point of control and add the neighboring row with more volume, one row at a time, until the area holds the requested share of volume. The default is 70 percent. The area is not required to be symmetric.
What is a naked point of control?
A finished session's point of control that no later bar has traded through. The dashed line is removed when a bar's high and low include that price, and a diamond prints on the close of that bar. The script keeps at most ten of them.
Does the triangle mean price will travel through the value area?
No. The triangle marks a confirmed close back inside the prior value area after a close outside it. That cross is the event associated with the so-called 80 percent rule. The indicator records the cross. It does not record, and does not promise, what the next bars do.
The practical takeaway
A bar-based profile is a careful guess about where volume sat inside each bar. This one spreads volume by overlap, splits it by the close, calls the busiest row the point of control, and grows the value area toward whichever neighbor is heavier until it holds the percent you set. The rolling histogram and the prior-session levels are different windows, and the naked lines are session points of control that have not been traded since. Read them as those rules. The moment a profile is treated as a footprint, or a triangle is treated as a rate, the drawing is being asked to know something the bars never contained.
Volume Profile Suite is in the indicator library on every paid plan. The row loop and the value-area expansion are the parts to read, and PineScripter opens the script in the editor so changing the row count or the 70 percent is a diff against a profile that already compiles.
Sources
- Pine Script v6 reference: box
- TradingView: lines and boxes
- TradingView: volume profile concepts, including point of control and value area
Related reading: the same close-location estimate, as delta, anchored VWAP, a different volume-weighted level, why boxes and lines have to be reused, swing pools, the other overlay in the library.
Disclaimer: PineScripter is a coding tool for Pine Script development. It does not provide financial advice and does not guarantee trading profits. Always backtest strategies thoroughly and understand the risks before live trading.