VOL & AVG Overlay

Custom Session Volume Versus Average Volume

Description:

This indicator will create an overlay on your chart that will show you the following information:

  • Custom Session Volume
  • Average For Selected Session
  • Percentage Comparison

Options:

  • Set Custom Time Frame For Calculations
  • Set Custom Time Frame For Average Comparison
  • Set Custom Time Zone
  • Enable / Disable Each Value
  • Change Text Color
  • Change Background Color
  • Change Table location

Example:
Set indicator to 30 period average. Set custom time frame to 9:30am to 10:30am Eastern/New York.

When the time frame for the calculation is closed, the indicator will provide a comparison of the current days volume compared to the average of 30 previous days for that same time frame and display it as a percentage in the table.

In this example you could compare how the first hour of the trading day compares to the previous 30 day’s average, aiding in evaluating the potential volume for the remainder of the day.

Notes:

  • Times must be entered in 24 hour format. (1pm = 13:00 etc.)
  • This indicator is for Intra-day time frames, not > Day.

If you prefer data in this format as opposed to a plotted line, check out my other indicator: ADR & ATR Overlay

May 15

Release Notes

updated chart example only

May 15

Release Notes

updating chart only

May 15

Release Notes

Added an additional (optional) top row to the table so values aren’t covered by Trading Views buttons if placed in top right corner.

May 16

Release Notes

corrected calculation logic when changing time frame on chart


// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © abbadon9 [If you modify this script please acknowledge me.]

//@version=6
indicator("VOL & AVG Overlay", shorttitle="VOL/AVG", overlay=true)

// === INPUTS ===
selectedTz = input.string("America/New_York", "Session Timezone", options=["America/New_York", "America/Chicago", "America/Los_Angeles", "UTC", "Europe/London", "Asia/Tokyo"])
startHour = input.int(9, "Session Start Hour")
startMin = input.int(30, "Session Start Minute")
endHour = input.int(10, "Session End Hour")
endMin = input.int(30, "Session End Minute")
lookbackDays = input.int(30, "Lookback Days", minval=1)

textColor = input.color(color.white, "Text Color")
bgColor = input.color(color.new(color.black, 70), "Background Color")
showTodayVol = input.bool(true, "Show Today's Volume")
showAvgVol = input.bool(true, "Show 30-Day Average Volume")
showPercent = input.bool(true, "Show % of Avg")
addEmptyTopRow = input.bool(true, "Add Empty Top Row")

tablePositionInput = input.string("Bottom Right", "Table Position", options=["Top Left", "Top Right", "Bottom Left", "Bottom Right"])
tablePosition = tablePositionInput == "Top Left" ? position.top_left :
     tablePositionInput == "Top Right" ? position.top_right :
     tablePositionInput == "Bottom Left" ? position.bottom_left :
     position.bottom_right

// === SESSION VOLUME FUNCTION (runs on 1-minute data) ===
ff_getSessionVol() =>
    sessStart = timestamp(selectedTz, year, month, dayofmonth, startHour, startMin)
    sessEnd = timestamp(selectedTz, year, month, dayofmonth, endHour, endMin)

    var float vol = 0.0
    var bool finalized = false

    if ta.change(time("D")) != 0
        vol := 0.0
        finalized := false

    vol := (time >= sessStart and time < sessEnd) ? vol + volume : vol
    finalized := finalized or (time >= sessEnd)

    finalized ? vol : na

// === CALL SESSION LOGIC ON 1-MIN TIMEFRAME ===
sessionFinalVol = request.security(syminfo.tickerid, "1", ff_getSessionVol())

// === AVERAGE CALCULATION OUTSIDE OF request.security ===
var float[] pastVolumes = array.new_float()
if not na(sessionFinalVol) and sessionFinalVol != 0
    // Only add once per day - ensure no duplicates by checking previous volume stored
    if array.size(pastVolumes) == 0 or sessionFinalVol != array.get(pastVolumes, 0)
        array.unshift(pastVolumes, sessionFinalVol)
        if array.size(pastVolumes) > lookbackDays
            array.pop(pastVolumes)

avgVol = array.size(pastVolumes) > 0 ? array.sum(pastVolumes) / array.size(pastVolumes) : na
percentOfAvg = (not na(avgVol) and not na(sessionFinalVol)) ? (sessionFinalVol / avgVol) * 100 : na

// === DISPLAY STRINGS ===
finalVolStr = na(sessionFinalVol) ? "..." : str.tostring(sessionFinalVol, "#,###")
avgVolStr = na(avgVol) ? "..." : str.tostring(avgVol, "#,###")
percentStr = na(percentOfAvg) ? "Waiting..." : str.tostring(percentOfAvg, "#.##") + "%"

// === TABLE DISPLAY ===
visibleRows = (showTodayVol ? 1 : 0) + (showAvgVol ? 1 : 0) + (showPercent ? 1 : 0) + (addEmptyTopRow ? 1 : 0)
var table volTable = table.new(tablePosition, 1, visibleRows, border_width=1)

row = 0
if addEmptyTopRow
    table.cell(volTable, 0, row, "", text_color=textColor, bgcolor=bgColor)
    row += 1
if showTodayVol
    table.cell(volTable, 0, row, "Session Vol: " + finalVolStr, text_color=textColor, bgcolor=bgColor)
    row += 1
if showAvgVol
    table.cell(volTable, 0, row, "Avg Vol (" + str.tostring(lookbackDays) + "d): " + avgVolStr, text_color=textColor, bgcolor=bgColor)
    row += 1
if showPercent
    table.cell(volTable, 0, row, "Percent of Avg: " + percentStr, text_color=textColor, bgcolor=bgColor)