// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Corbanistan
//@version=6
indicator("Anchored VWAP + Moving Average", shorttitle="AVWAP+MA", overlay=true)
// ═══════════════════════════════════════════════════════════════════════════════
// ░░░░░░░░░░░░░░░░░░░░░░░░░ ANCHORED VWAP SETTINGS ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
// ═══════════════════════════════════════════════════════════════════════════════
vwapGroup = "══════════ Anchored VWAP ══════════"
showVwap = input.bool(true, "Show VWAP", group=vwapGroup)
anchorType = input.string("Auto", "Anchor Period",
options=["Auto", "Session", "Week", "Month", "Quarter", "Year", "Highest High", "Lowest Low", "Highest Volume"],
group=vwapGroup,
tooltip="Select the anchor point for VWAP calculation.\n\n• Auto: Automatically selects best anchor based on symbol type and timeframe\n• Session: Resets each trading session\n• Week/Month/Quarter/Year: Resets on period change\n• Highest High/Lowest Low: Anchors from the highest/lowest price within lookback\n• Highest Volume: Anchors from the highest volume bar within lookback")
showAutoLabel = input.bool(true, "Show Auto-Detected Anchor Label", group=vwapGroup,
tooltip="When using Auto mode, display a label showing which anchor was selected")
lookbackLength = input.int(50, "Lookback Length", minval=1, maxval=500, group=vwapGroup,
tooltip="Number of bars to look back when searching for anchor points.\n\n⚠️ Only used when Anchor Period is set to:\n• Highest High\n• Lowest Low\n• Highest Volume\n\nThis setting is ignored for time-based anchors (Session, Week, Month, Quarter, Year, Auto).")
vwapColor = input.color(color.new(color.blue, 0), "VWAP Color", group=vwapGroup)
vwapWidth = input.int(2, "VWAP Line Width", minval=1, maxval=5, group=vwapGroup)
showAnchorMarker = input.bool(false, "Show Anchor Period Marker", group=vwapGroup,
tooltip="Display a diamond icon at the bottom of the chart marking the start of each anchor period")
anchorMarkerColor = input.color(color.new(color.fuchsia, 0), "Anchor Marker Color", group=vwapGroup)
// VWAP Band Settings
showBand1 = input.bool(false, "Show Band 1", group=vwapGroup, inline="band1")
bandMultiplier1 = input.float(1.0, "Multiplier", minval=0.1, step=0.1, group=vwapGroup, inline="band1")
band1Color = input.color(color.new(color.blue, 50), "", group=vwapGroup, inline="band1")
showBand2 = input.bool(false, "Show Band 2", group=vwapGroup, inline="band2")
bandMultiplier2 = input.float(2.0, "Multiplier", minval=0.1, step=0.1, group=vwapGroup, inline="band2")
band2Color = input.color(color.new(color.purple, 50), "", group=vwapGroup, inline="band2")
showBand3 = input.bool(false, "Show Band 3", group=vwapGroup, inline="band3")
bandMultiplier3 = input.float(3.0, "Multiplier", minval=0.1, step=0.1, group=vwapGroup, inline="band3")
band3Color = input.color(color.new(color.red, 50), "", group=vwapGroup, inline="band3")
// ═══════════════════════════════════════════════════════════════════════════════
// ░░░░░░░░░░░░░░░░░░░░░░░░░ MOVING AVERAGE SETTINGS ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
// ═══════════════════════════════════════════════════════════════════════════════
maGroup = "══════════ Moving Average ══════════"
showMa = input.bool(true, "Show Moving Average", group=maGroup)
maType = input.string("EMA", "MA Type",
options=["SMA", "EMA", "WMA", "RMA", "HMA", "VWMA", "DEMA", "TEMA"],
group=maGroup,
tooltip="Select the type of moving average:\n• SMA: Simple Moving Average\n• EMA: Exponential Moving Average\n• WMA: Weighted Moving Average\n• RMA: Running Moving Average (Wilder's)\n• HMA: Hull Moving Average\n• VWMA: Volume Weighted Moving Average\n• DEMA: Double Exponential Moving Average\n• TEMA: Triple Exponential Moving Average")
maLength = input.int(20, "MA Length", minval=1, maxval=500, group=maGroup)
maSource = input.source(close, "MA Source", group=maGroup,
tooltip="Select the price source for MA calculation (open, high, low, close, hl2, hlc3, ohlc4, hlcc4)")
maColor = input.color(color.new(color.orange, 0), "MA Color", group=maGroup)
maWidth = input.int(2, "MA Line Width", minval=1, maxval=5, group=maGroup)
// ═══════════════════════════════════════════════════════════════════════════════
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░ CROSS SIGNALS ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
// ═══════════════════════════════════════════════════════════════════════════════
signalsGroup = "══════════ Cross Signals ══════════"
showVwapCross = input.bool(false, "Show VWAP Cross Signals", group=signalsGroup,
tooltip="Display arrows when price crosses above or below the VWAP line")
vwapCrossUpColor = input.color(color.new(color.teal, 0), "VWAP Cross Up", group=signalsGroup, inline="vwapCross")
vwapCrossDownColor = input.color(color.new(color.red, 0), "Down", group=signalsGroup, inline="vwapCross")
showMaCross = input.bool(false, "Show MA Cross Signals", group=signalsGroup,
tooltip="Display arrows when price crosses above or below the Moving Average line")
maCrossUpColor = input.color(color.new(color.lime, 0), "MA Cross Up", group=signalsGroup, inline="maCross")
maCrossDownColor = input.color(color.new(color.fuchsia, 0), "Down", group=signalsGroup, inline="maCross")
showBothCross = input.bool(false, "Show Combined Cross Signals", group=signalsGroup,
tooltip="Display arrows when price crosses both VWAP and MA in the same direction on the same bar")
bothCrossUpColor = input.color(color.new(color.yellow, 0), "Both Cross Up", group=signalsGroup, inline="bothCross")
bothCrossDownColor = input.color(color.new(color.orange, 0), "Down", group=signalsGroup, inline="bothCross")
showVwapMaCross = input.bool(false, "Show VWAP/MA Cross Signals", group=signalsGroup,
tooltip="Display an X marker when VWAP crosses the Moving Average line")
vwapMaCrossColor = input.color(color.new(color.purple, 0), "VWAP/MA Cross Color", group=signalsGroup)
// ═══════════════════════════════════════════════════════════════════════════════
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ CALCULATIONS ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
// ═══════════════════════════════════════════════════════════════════════════════
// --- VWAP Anchor Detection ---
isNewPeriod(periodType) =>
switch periodType
"Session" => ta.change(time("D")) != 0
"Week" => ta.change(time("W")) != 0
"Month" => ta.change(time("M")) != 0
"Quarter" => ta.change(time("3M")) != 0
"Year" => ta.change(time("12M")) != 0
=> false
// Find highest high bar index within lookback
highestHighBar() =>
highestIdx = 0
highestVal = high[0]
for i = 1 to lookbackLength - 1
if high[i] > highestVal
highestVal := high[i]
highestIdx := i
highestIdx
// Find lowest low bar index within lookback
lowestLowBar() =>
lowestIdx = 0
lowestVal = low[0]
for i = 1 to lookbackLength - 1
if low[i] < lowestVal
lowestVal := low[i]
lowestIdx := i
lowestIdx
// Find highest volume bar index within lookback
highestVolumeBar() =>
highestIdx = 0
highestVal = volume[0]
for i = 1 to lookbackLength - 1
if volume[i] > highestVal
highestVal := volume[i]
highestIdx := i
highestIdx
// --- Auto Anchor Detection Logic ---
// Detect symbol type
isForex = syminfo.type == "forex" or syminfo.type == "cfd"
isCrypto = syminfo.type == "crypto"
isStock = syminfo.type == "stock" or syminfo.type == "dr"
isFutures = syminfo.type == "futures"
isIndex = syminfo.type == "index"
// Get timeframe in minutes for comparison
tfInMinutes = timeframe.in_seconds() / 60
// Auto-select best anchor based on symbol type and timeframe
// Logic:
// - Forex: Session (24hr markets, session reset is most relevant)
// - Crypto: Session for intraday, Week for daily+ (24/7 market)
// - Stocks: Session for intraday, Week for daily/weekly
// - Futures: Session for intraday, Week for daily+
// - Index: Session for intraday, Month for daily+
// - Higher timeframes (weekly+): Use Month or Quarter
autoAnchor = if isForex
// Forex: Use Session for intraday, Week for daily+
if tfInMinutes >= 10080 // Weekly or higher
"Month"
else if tfInMinutes >= 1440 // Daily
"Week"
else
"Session"
else if isCrypto
if tfInMinutes >= 10080 // Weekly or higher
"Month"
else if tfInMinutes >= 1440 // Daily
"Week"
else
"Session"
else if isStock or isFutures
if tfInMinutes >= 10080 // Weekly or higher
"Month"
else if tfInMinutes >= 1440 // Daily
"Week"
else
"Session"
else if isIndex
if tfInMinutes >= 10080 // Weekly or higher
"Quarter"
else if tfInMinutes >= 1440 // Daily
"Month"
else
"Session"
else
// Default fallback
if tfInMinutes >= 1440
"Week"
else
"Session"
// Resolve the effective anchor type
effectiveAnchor = anchorType == "Auto" ? autoAnchor : anchorType
// Determine if current bar is anchor point based on selected type
isAnchorPeriod = switch effectiveAnchor
"Session" => isNewPeriod("Session")
"Week" => isNewPeriod("Week")
"Month" => isNewPeriod("Month")
"Quarter" => isNewPeriod("Quarter")
"Year" => isNewPeriod("Year")
"Highest High" => bar_index >= lookbackLength and highestHighBar() == 0
"Lowest Low" => bar_index >= lookbackLength and lowestLowBar() == 0
"Highest Volume" => bar_index >= lookbackLength and highestVolumeBar() == 0
=> false
// Force anchor on first bar to ensure proper VWAP initialization
isAnchor = bar_index == 0 or isAnchorPeriod
// --- VWAP Calculation ---
var float sumPV = 0.0
var float sumV = 0.0
var float sumPV2 = 0.0
typicalPrice = hlc3
if isAnchor
sumPV := typicalPrice * volume
sumV := volume
sumPV2 := typicalPrice * typicalPrice * volume
else
sumPV := sumPV + typicalPrice * volume
sumV := sumV + volume
sumPV2 := sumPV2 + typicalPrice * typicalPrice * volume
vwapValue = sumV != 0 ? sumPV / sumV : na
// Standard deviation for bands
variance = sumV != 0 ? (sumPV2 / sumV) - (vwapValue * vwapValue) : 0
stdDev = math.sqrt(math.max(variance, 0))
upperBand1 = vwapValue + stdDev * bandMultiplier1
lowerBand1 = vwapValue - stdDev * bandMultiplier1
upperBand2 = vwapValue + stdDev * bandMultiplier2
lowerBand2 = vwapValue - stdDev * bandMultiplier2
upperBand3 = vwapValue + stdDev * bandMultiplier3
lowerBand3 = vwapValue - stdDev * bandMultiplier3
// --- Moving Average Calculation ---
// DEMA helper
dema(src, len) =>
ema1 = ta.ema(src, len)
ema2 = ta.ema(ema1, len)
2 * ema1 - ema2
// TEMA helper
tema(src, len) =>
ema1 = ta.ema(src, len)
ema2 = ta.ema(ema1, len)
ema3 = ta.ema(ema2, len)
3 * (ema1 - ema2) + ema3
maValue = switch maType
"SMA" => ta.sma(maSource, maLength)
"EMA" => ta.ema(maSource, maLength)
"WMA" => ta.wma(maSource, maLength)
"RMA" => ta.rma(maSource, maLength)
"HMA" => ta.hma(maSource, math.max(maLength, 4)) // HMA requires minimum length of 4
"VWMA" => ta.vwma(maSource, maLength)
"DEMA" => dema(maSource, maLength)
"TEMA" => tema(maSource, maLength)
=> ta.ema(maSource, maLength)
// ═══════════════════════════════════════════════════════════════════════════════
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ PLOTTING ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
// ═══════════════════════════════════════════════════════════════════════════════
// Plot VWAP
plot(showVwap ? vwapValue : na, "VWAP", color=vwapColor, linewidth=vwapWidth)
// Plot VWAP Bands
// Band 1
ub1Plot = plot(showVwap and showBand1 ? upperBand1 : na, "Upper Band 1", color=band1Color, linewidth=1)
lb1Plot = plot(showVwap and showBand1 ? lowerBand1 : na, "Lower Band 1", color=band1Color, linewidth=1)
fill(ub1Plot, lb1Plot, color=color.new(band1Color, 90), title="Band 1 Fill")
// Band 2
ub2Plot = plot(showVwap and showBand2 ? upperBand2 : na, "Upper Band 2", color=band2Color, linewidth=1)
lb2Plot = plot(showVwap and showBand2 ? lowerBand2 : na, "Lower Band 2", color=band2Color, linewidth=1)
fill(ub2Plot, lb2Plot, color=color.new(band2Color, 90), title="Band 2 Fill")
// Band 3
ub3Plot = plot(showVwap and showBand3 ? upperBand3 : na, "Upper Band 3", color=band3Color, linewidth=1)
lb3Plot = plot(showVwap and showBand3 ? lowerBand3 : na, "Lower Band 3", color=band3Color, linewidth=1)
fill(ub3Plot, lb3Plot, color=color.new(band3Color, 90), title="Band 3 Fill")
// Plot Moving Average
plot(showMa ? maValue : na, "Moving Average", color=maColor, linewidth=maWidth)
// --- Cross Signal Detection ---
// VWAP crosses (only detect if VWAP is enabled and has valid value)
vwapCrossUp = showVwap and not na(vwapValue) and ta.crossover(close, vwapValue)
vwapCrossDown = showVwap and not na(vwapValue) and ta.crossunder(close, vwapValue)
// MA crosses (only detect if MA is enabled and has valid value)
maCrossUp = showMa and not na(maValue) and ta.crossover(close, maValue)
maCrossDown = showMa and not na(maValue) and ta.crossunder(close, maValue)
// Combined crosses (both cross in same direction on same bar)
bothCrossUp = vwapCrossUp and maCrossUp
bothCrossDown = vwapCrossDown and maCrossDown
// Plot VWAP cross signals
plotshape(showVwapCross and vwapCrossUp ? low : na, "VWAP Cross Up",
style=shape.triangleup, location=location.belowbar,
color=vwapCrossUpColor, size=size.small)
plotshape(showVwapCross and vwapCrossDown ? high : na, "VWAP Cross Down",
style=shape.triangledown, location=location.abovebar,
color=vwapCrossDownColor, size=size.small)
// Plot Anchor Period Marker
plotshape(showAnchorMarker and showVwap and isAnchor, "Anchor Period Start",
style=shape.labelup, location=location.bottom,
color=anchorMarkerColor, size=size.small)
// Plot MA cross signals
plotshape(showMaCross and maCrossUp ? low : na, "MA Cross Up",
style=shape.triangleup, location=location.belowbar,
color=maCrossUpColor, size=size.small)
plotshape(showMaCross and maCrossDown ? high : na, "MA Cross Down",
style=shape.triangledown, location=location.abovebar,
color=maCrossDownColor, size=size.small)
// Plot combined cross signals
plotshape(showBothCross and bothCrossUp ? low : na, "Both Cross Up",
style=shape.triangleup, location=location.belowbar,
color=bothCrossUpColor, size=size.normal)
plotshape(showBothCross and bothCrossDown ? high : na, "Both Cross Down",
style=shape.triangledown, location=location.abovebar,
color=bothCrossDownColor, size=size.normal)
// VWAP/MA crosses (exclude anchor bars where VWAP resets cause false crosses)
vwapMaCrossUp = ta.crossover(vwapValue, maValue) and not isAnchor
vwapMaCrossDown = ta.crossunder(vwapValue, maValue) and not isAnchor
// Plot VWAP/MA cross signals (X marker at cross location)
vwapMaCross = vwapMaCrossUp or vwapMaCrossDown
plotshape(showVwapMaCross and vwapMaCross ? vwapValue : na, "VWAP/MA Cross",
style=shape.xcross, location=location.absolute,
color=vwapMaCrossColor, size=size.small)
// --- Auto Mode Info Table (tables render above chart elements) ---
var table infoTable = table.new(position.top_right, 1, 1, bgcolor=color.new(vwapColor, 85), border_width=1, border_color=color.new(vwapColor, 50))
if barstate.islast and anchorType == "Auto" and showAutoLabel and showVwap
// Create info text showing detected settings
symbolTypeText = isForex ? "Forex" : isCrypto ? "Crypto" : isStock ? "Stock" : isFutures ? "Futures" : isIndex ? "Index" : "Other"
infoText = "VWAP Anchor: " + effectiveAnchor + "\n(" + symbolTypeText + " detected)"
table.cell(infoTable, 0, 0, infoText, text_color=vwapColor, text_size=size.small)
else
table.clear(infoTable, 0, 0)
// ═══════════════════════════════════════════════════════════════════════════════
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ALERTS ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
// ═══════════════════════════════════════════════════════════════════════════════
// Price crosses VWAP
alertcondition(ta.crossover(close, vwapValue), "Price Crossed Above VWAP", "Price crossed above VWAP")
alertcondition(ta.crossunder(close, vwapValue), "Price Crossed Below VWAP", "Price crossed below VWAP")
// Price crosses MA
alertcondition(ta.crossover(close, maValue), "Price Crossed Above MA", "Price crossed above Moving Average")
alertcondition(ta.crossunder(close, maValue), "Price Crossed Below MA", "Price crossed below Moving Average")
// VWAP crosses MA (filter out anchor resets to avoid false alerts)
alertcondition(ta.crossover(vwapValue, maValue) and not isAnchor, "VWAP Crossed Above MA", "VWAP crossed above Moving Average")
alertcondition(ta.crossunder(vwapValue, maValue) and not isAnchor, "VWAP Crossed Below MA", "VWAP crossed below Moving Average")
Show all 367 lines