1Copy the scriptPress Copy script above, or the copy button on the code below.
2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.
Source Code
102 lines of Pine Script v6 from volume_historical/volume_historical.pine, published under Apache-2.0. Keep the author's credit and licence lines when you reuse it.
volume_historical.pine
// Copyright 2025 Major Hayden
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//@version=6
indicator('Volume Historical Patterns', shorttitle = 'Vol Patterns', format = format.volume, overlay = false)
// User inputs
smaLength = input.int(20, 'SMA Length', minval = 1)
highVolMultiplier = input.float(3.0, 'High Volume Multiplier', minval = 1.0, step = 0.1)
lowVolPercentage = input.float(0.5, 'Low Volume Percentage', minval = 0.1, maxval = 1.0, step = 0.1)
// Time filtering inputs
enableTimeFilter = input.bool(false, 'Enable Time Filter', tooltip = 'Filter volume to specific hours (NYC time). Works on both intraday and daily timeframes.')
startHour = input.int(10, 'Start Hour (NYC)', minval = 0, maxval = 23)
startMinute = input.int(30, 'Start Minute', minval = 0, maxval = 59)
endHour = input.int(15, 'End Hour (NYC)', minval = 0, maxval = 23)
endMinute = input.int(00, 'End Minute', minval = 0, maxval = 59)
showTimeHeadband = input.bool(true, 'Show Time Filter Headband', tooltip = 'Display time filter settings at top of indicator')
// Function to check if a time is within trading hours (NYC time)
isTimeInRange(t) =>
barHour = hour(t, 'America/New_York')
barMinute = minute(t, 'America/New_York')
// Convert times to minutes for easier comparison
barTimeInMinutes = barHour * 60 + barMinute
startTimeInMinutes = startHour * 60 + startMinute
endTimeInMinutes = endHour * 60 + endMinute
// Check if bar is within the time range
barTimeInMinutes >= startTimeInMinutes and barTimeInMinutes <= endTimeInMinutes
// Calculate filtered volume based on timeframe
filteredVolume = if not enableTimeFilter
volume
else if timeframe.isintraday
// For intraday charts, just check the current bar's time
nycTime = time('', 'America/New_York')
isTimeInRange(nycTime) ? volume : 0
else
// For daily or higher timeframes, sum volume from lower timeframe bars within the time range
volArray = request.security_lower_tf(syminfo.tickerid, '5', volume)
timeArray = request.security_lower_tf(syminfo.tickerid, '5', time)
float totalVol = 0.0
if array.size(volArray) > 0
for i = 0 to array.size(volArray) - 1
barTime = array.get(timeArray, i)
if isTimeInRange(barTime)
totalVol += array.get(volArray, i)
totalVol
// Calculate volume SMA using filtered volume
volumeSMA = ta.sma(filteredVolume, smaLength)
// Track highest volume ever seen (using filtered volume)
var float highestVolume = na
highestVolume := na(highestVolume) ? filteredVolume : math.max(highestVolume, filteredVolume)
// Determine bar color and special condition flags
barColor = color.new(color.white, 75) // Regular bars: white with 25% opacity (75% transparency)
isSpecialBar = false
// Priority order for coloring (most important condition first)
if filteredVolume == highestVolume and filteredVolume > 0
barColor := color.green // Highest volume ever
isSpecialBar := true
barColor
else if filteredVolume >= volumeSMA * highVolMultiplier and volumeSMA > 0
barColor := color.yellow // High volume (configurable X times SMA)
isSpecialBar := true
barColor
else if filteredVolume < volumeSMA * lowVolPercentage and volumeSMA > 0
barColor := color.red // Low volume (less than 50% of SMA)
isSpecialBar := true
barColor
plot(filteredVolume, style = plot.style_columns, color = barColor, linewidth = 1, title = 'Volume')
plot(volumeSMA, style = plot.style_columns, color = color.new(#8b8ba7, 30), linewidth = 1, title = 'Volume SMA')
// Display time filter headband
if enableTimeFilter and showTimeHeadband
var table headband = table.new(position.bottom_center, 1, 1, bgcolor = color.new(color.blue, 10), border_width = 1, border_color = color.new(color.blue, 0))
// Format time strings with leading zeros
startTimeStr = str.format('{0,number,00}:{1,number,00}', startHour, startMinute)
endTimeStr = str.format('{0,number,00}:{1,number,00}', endHour, endMinute)
headbandText = '⏰ Time Filter (NYC): ' + startTimeStr + ' - ' + endTimeStr
table.cell(headband, 0, 0, headbandText, text_color = color.white, text_size = size.small)
Overview
Volume Historical Patterns computes an SMA of volume using optional time filtering for NYC hours and identifies the highest volume bar ever seen. Bars receive custom colors based on volume relative to this maximum or average thresholds defined by user inputs. This tool highlights volume extremes for spotting unusual activity and provides context through the SMA overlay on the price chart.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
SMA Length
int
20
smaLength
High Volume Multiplier
float
3.0
highVolMultiplier
Low Volume Percentage
float
0.5
lowVolPercentage
Enable Time Filter
bool
false
enableTimeFilter
Start Hour (NYC)
int
10
startHour
Start Minute
int
30
startMinute
End Hour (NYC)
int
15
endHour
End Minute
int
00
endMinute
Show Time Filter Headband
bool
true
showTimeHeadband
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.
Aggregate Signal (v.2) is an oscillator indicator that combines multiple technical factors into a single composite score. It scales OHLCV data using minimax normalization and evaluates indicators such as MACD, RSI, Stochastic, CCI, Momentum, On-Balance Volume,
This indicator plots a volume-weighted MACD in a separate pane. It subtracts a slow volume-weighted moving average of close from a faster one, then smooths that line with an exponential moving average to form the signal. A column histogram shows the gap betwee
PPO ATR Bands plots a percentage price oscillator in a separate pane. It compares a Hull average of typical price with a volume-weighted exponential average of Parabolic SAR, then scales three true-range bands around the slow average into matching oscillator l
This indicator calculates the Relative Strength Index using a volume-weighted moving average of the closing price as its source. It plots the resulting oscillator in a separate pane alongside configurable overbought and oversold threshold lines. The plot line
This indicator tracks and visualizes cryptocurrency net positioning across multiple derivative exchanges, including Binance, BitMEX, and Kraken. It calculates aggregated net longs, net shorts, net delta, and ratio metrics, or an optional Position RSI, renderin
This indicator plots the standard On Balance Volume (OBV) in a separate pane by accumulating volume based on the direction of price changes. It includes an optional smoothing line that can apply a Simple, Exponential, Smoothed, Weighted, or Volume-Weighted Mov