//@version=6 indicator("DIY Volume Profile", overlay = true, max_bars_back = 500) lookback = input.int(150, "Bars in the profile", minval = 20, maxval = 400) rows = input.int(24, "Price rows", minval = 6, maxval = 40) vaPct = input.float(70, "Value area %", minval = 10, maxval = 95) maxW = input.int(24, "Widest row, in blocks", minval = 4, maxval = 40) var array bins = array.new_float(rows, 0) float poc = na float vah = na float val = na int pocRow = na int vaLo = na int vaHi = na hiP = ta.highest(high, lookback) loP = ta.lowest(low, lookback) step = (hiP - loP) / rows inWindow = bar_index >= last_bar_index - lookback + 1 ready = inWindow and step > 0 if ready array.fill(bins, 0) for i = 0 to lookback - 1 h = high[i] l = low[i] v = nz(volume[i]) a = math.min(rows - 1, math.max(0, math.floor((l - loP) / step))) b = math.min(rows - 1, math.max(0, math.floor((h - loP) / step))) for r = a to b rLo = loP + r * step part = math.min(h, rLo + step) - math.max(l, rLo) share = h > l ? math.max(0, part) / (h - l) : 1.0 array.set(bins, r, array.get(bins, r) + v * share) if ready pocRow := array.indexof(bins, array.max(bins)) poc := loP + (pocRow + 0.5) * step if ready target = array.sum(bins) * vaPct / 100 acc = array.get(bins, pocRow) vaLo := pocRow vaHi := pocRow while acc < target and (vaLo > 0 or vaHi < rows - 1) up = vaHi < rows - 1 ? array.get(bins, vaHi + 1) : -1.0 dn = vaLo > 0 ? array.get(bins, vaLo - 1) : -1.0 if up >= dn vaHi += 1 acc += up else vaLo -= 1 acc += dn vah := loP + (vaHi + 1) * step val := loP + vaLo * step pH = plot(vah, "Value area high", color.new(color.teal, 0), 1, plot.style_linebr) pL = plot(val, "Value area low", color.new(color.teal, 0), 1, plot.style_linebr) fill(pH, pL, color.new(color.teal, 90), "Value area") plot(poc, "POC", color.new(color.orange, 0), 3, plot.style_linebr) var table prof = table.new(position.top_right, 2, 40, frame_width = 1, frame_color = color.gray) if barstate.islast and ready top = array.max(bins) for r = 0 to rows - 1 w = top > 0 ? math.round(array.get(bins, r) / top * maxW) : 0 blocks = str.repeat("█", w) inVA = r >= vaLo and r <= vaHi c = r == pocRow ? color.orange : inVA ? color.teal : color.gray px = str.tostring(loP + (r + 0.5) * step, format.mintick) row = rows - 1 - r table.cell(prof, 0, row, px, text_color = c, text_size = size.tiny) table.cell(prof, 1, row, blocks, text_color = c, text_size = size.tiny, text_halign = text.align_left)