Iván González

Dynamic Swing Anchored VWAP

Category: Indicators By: Iván González Created: October 27, 2026, 10:35 AM
October 27, 2026, 10:35 AM
Indicators
0 Comments
Dynamic Swing Anchored VWAP

Introduction

 

An anchored VWAP answers a precise question: what is the average price, weighted by volume, that the market has paid since a given point? Anchor it at a major low and it shows the average entry of everyone who bought from there; anchor it at a high and it shows the average entry of the sellers. The difficulty is choosing the anchor, and moving it by hand every time the market turns.

The Dynamic Swing Anchored VWAP by Zeiierman does that job automatically. It detects swing highs and lows, and every time the swing structure changes direction it anchors a new VWAP at the opposite swing point and rebuilds it from there up to the current bar. Each swing is labelled HH, LH, HL or LL, so the chart shows both the market structure and the volume-weighted path that followed each turning point.

Theory Behind the Indicator

 

Swing points. A bar is a swing high when its high is the highest of the last Swing Period bars (50 by default), and a swing low when its low is the lowest of that window. The indicator keeps the price and the bar of the latest swing high and the latest swing low.

Direction. When the latest swing high is more recent than the latest swing low the direction is up; otherwise it is down. A change of direction is the event that re-anchors the VWAP: on a turn up the new VWAP is anchored at the latest swing low, and on a turn down at the latest swing high.

Structure labels. The anchor point gets a label that compares it with the previous swing of the same kind: HL (higher low) or LL (lower low) below the lows, HH (higher high) or LH (lower high) above the highs.

An adaptive VWAP. Instead of the classic cumulative VWAP, the line is an exponentially weighted average of price times volume divided by an exponentially weighted average of volume, both seeded at the anchor with the swing price. Its speed is set by the Adaptive Price Tracking value, a half-life in bars: with 20, a bar weighs half as much as a bar 20 bars more recent. A lower value keeps the VWAP tight to price, a higher value makes it smoother.

Volatility adaptation (optional). With the adaptation switched on, the half-life is divided by the ratio between the 50-bar ATR and its own 50-bar average, raised to the Volatility Bias. In volatile phases the VWAP reacts faster; in quiet ones it becomes smoother. The value is kept between 5 and 300 bars.

Segments. At each change of direction the running segment is frozen and a new one starts at the new anchor. Since the anchor lies in the past, consecutive segments overlap for a few bars, which is where the old VWAP and the new one can be compared.

Key Features at a Glance

 

  • Automatic anchoring at the latest swing low or swing high on every change of structure.
  • HH, LH, HL and LL labels at each anchor.
  • Exponentially weighted VWAP with a half-life setting.
  • Optional ATR-based adaptation of the tracking speed.
  • The last 100 VWAP segments and the last 500 labels stay on the chart.

How to Read the Indicator

 

  • The running segment is the volume-weighted average price since the last swing. Price holding above a VWAP anchored at a swing low means the buyers from that low are, on average, in profit.
  • A close through the running VWAP after a long move is an early sign that the swing is losing strength, often before the structure itself turns.
  • The labels give the structure: a sequence of HL and HH is an uptrend, LH and LL a downtrend, and a mix of them a range.
  • The overlap between two segments shows how far the new anchor’s VWAP starts from the previous one: a large gap is a sharp change of control.

Practical Applications

 

  • Dynamic support and resistance: pullbacks towards the running VWAP in the direction of the structure.
  • Trailing reference: the VWAP can be used as a trailing level for positions opened on a structure change.
  • Trend filter: trade only in the direction of the latest label sequence.
  • Swing size: a longer Swing Period keeps only the major swings, a shorter one follows the minor structure.

Indicator Configuration

 

  • prd (default 50, minimum 2): bars used to detect swing highs and lows. Larger values find bigger, slower swings.
  • baseAPT (default 20): half-life of the VWAP in bars. Lower is tighter to price, higher is smoother.
  • useAdapt (default 0): set to 1 to adapt the half-life to the ATR ratio.
  • volBias (default 10): strength of the volatility adaptation.
  • lineW (default 2): width of the VWAP lines, from 1 to 4.
  • maxLines (default 100): number of VWAP segments kept on the chart, the running one included.
  • maxLabels (default 500): number of swing labels kept on the chart.
  • lblLoR, lblLoG, lblLoB (default 0, 230, 118): colour of the labels at swing lows.
  • lblHiR, lblHiG, lblHiB (default 242, 54, 69): colour of the labels at swing highs.
  • sR, sG, sB (default 0, 230, 118) and rR, rG, rB (default 242, 54, 69): the two VWAP colours. With the defaults, segments anchored at a swing high are drawn in the first colour (green) and segments anchored at a swing low in the second one (red). Swap them if you prefer the opposite convention.

The VWAP needs volume: on instruments without volume data the line is not drawn, while the swing labels still are.

The Code

 

//---------------------------------------------------------------
// PRC_Dynamic Swing VWAP
// version = 0
// 26.10.2026
// Iván González @ www.prorealcode.com
// Author: Zeiierman
// Sharing ProRealTime knowledge
//--------------------------------------------------------------------//
DEFPARAM DRAWONLASTBARONLY = true

// ===================== INPUTS =====================
// Swing points
prd = 50               // Swing Period (min 2): bars used to detect swing highs and lows
baseAPT = 20           // Adaptive Price Tracking (min 1): VWAP half-life in bars
useAdapt = 0           // 1 = adapt the tracking speed with the ATR ratio
volBias = 10           // Volatility Bias (min 0.1): strength of the ATR adaptation

// Style
lineW = 2              // VWAP line width (1 to 4)
maxLines = 100         // VWAP segments kept on the chart (the live one included)
maxLabels = 500        // Swing labels kept on the chart

// Colours: swing labels (low, high) and VWAP lines (S, R)
lblLoR = 0
lblLoG = 230
lblLoB = 118
lblHiR = 242
lblHiG = 54
lblHiB = 69
sR = 0
sG = 230
sB = 118
rR = 242
rG = 54
rB = 69

// ===================== SWING POINTS =====================
pPrd = max(2, round(prd))
hlc3V = (high + low + close) / 3

IF barindex = 0 THEN
   phL = 0
   plL = 0
   hasPh = 0
   hasPl = 0
   hasPrev = 0
   nEv = 0
   // segment 0: the VWAP that runs from the first bar until the first swing change
   $eB[0] = 0
   $eX[0] = 0
   $eY[0] = hlc3V
   $eD[0] = -1
   $eOk[0] = 1
   $eT[0] = 0
ENDIF

// A bar is a swing high / low when it is the extreme of the last prd bars
IF barindex >= pPrd - 1 THEN
   IF high >= highest[pPrd](high) THEN
      ph = high
      phL = barindex
      hasPh = 1
   ENDIF
   IF low <= lowest[pPrd](low) THEN
      pl = low
      plL = barindex
      hasPl = 1
   ENDIF
ENDIF

IF phL > plL THEN
   dir = 1
ELSE
   dir = -1
ENDIF

// ===================== ADAPTIVE TRACKING =====================
atrV = averagetruerange[50](close)
IF barindex < 98 THEN
   atrAvg = 0
ELSIF barindex = 98 THEN
   atrAvg = average[50](atrV)
ELSE
   atrAvg = (atrV + 49 * atrAvg[1]) / 50
ENDIF
IF atrAvg > 0 THEN
   ratio = atrV / atrAvg
ELSE
   ratio = 1
ENDIF
IF useAdapt = 1 THEN
   aptRaw = baseAPT / pow(ratio, volBias)
ELSE
   aptRaw = baseAPT
ENDIF
aptS = round(max(5, min(300, aptRaw)))
atr14 = averagetruerange[14](close)

// ===================== SWING CHANGE EVENTS =====================
// Every change of direction anchors a new VWAP at the opposite swing point
IF barindex > 0 AND dir <> dir[1] THEN
   nEv = nEv + 1
   txtCode = 0
   IF dir > 0 THEN
      xAnc = plL
      yAnc = pl
      okAnc = hasPl
      IF hasPl = 1 AND hasPrev = 1 THEN
         IF pl < prev THEN
            txtCode = 1
         ELSIF pl > prev THEN
            txtCode = 2
         ENDIF
      ENDIF
      prev = ph[1]
      hasPrev = hasPh[1]
   ELSE
      xAnc = phL
      yAnc = ph
      okAnc = hasPh
      IF hasPh = 1 AND hasPrev = 1 THEN
         IF ph < prev THEN
            txtCode = 3
         ELSIF ph > prev THEN
            txtCode = 4
         ENDIF
      ENDIF
      prev = pl[1]
      hasPrev = hasPl[1]
   ENDIF
   $eB[nEv] = barindex
   $eX[nEv] = xAnc
   $eY[nEv] = yAnc
   $eD[nEv] = dir
   $eOk[nEv] = okAnc
   $eT[nEv] = txtCode
ENDIF

// ===================== DRAWING =====================
IF islastbarupdate THEN
   lw = max(1, min(4, round(lineW)))
   ln2 = log(2)

   // ---- VWAP segments: the last maxLines ones ----
   firstSeg = max(0, nEv - max(1, round(maxLines)) + 1)
   FOR k = firstSeg TO nEv DO
      sx = $eX[k]
      IF k < nEv THEN
         ex = $eB[k + 1] - 1
         segDir = $eD[k + 1]
         IF segDir < 0 THEN
            cR = rR
            cG = rG
            cB = rB
         ELSE
            cR = sR
            cG = sG
            cB = sB
         ENDIF
      ELSE
         ex = barindex
         // live segment: on the change bar itself the colour rule is the opposite one
         IF k > 0 AND $eB[k] = barindex THEN
            IF dir < 0 THEN
               cR = rR
               cG = rG
               cB = rB
            ELSE
               cR = sR
               cG = sG
               cB = sB
            ENDIF
         ELSE
            IF dir > 0 THEN
               cR = rR
               cG = rG
               cB = rB
            ELSE
               cR = sR
               cG = sG
               cB = sB
            ENDIF
         ENDIF
      ENDIF

      IF $eOk[k] = 1 THEN
         off0 = barindex - sx
         pAcc = $eY[k] * volume[off0]
         vAcc = volume[off0]
         havePt = 0
         FOR t = sx TO ex DO
            off = barindex - t
            al = 1 - exp(0 - ln2 / max(1, aptS[off]))
            pAcc = (1 - al) * pAcc + al * hlc3V[off] * volume[off]
            vAcc = (1 - al) * vAcc + al * volume[off]
            IF vAcc > 0 THEN
               vwapV = pAcc / vAcc
               IF havePt = 1 THEN
                  IF lw = 1 THEN
                     DRAWSEGMENT(t - 1, lastV, t, vwapV) COLOURED(cR, cG, cB, 255) STYLE(line, 1)
                  ELSIF lw = 2 THEN
                     DRAWSEGMENT(t - 1, lastV, t, vwapV) COLOURED(cR, cG, cB, 255) STYLE(line, 2)
                  ELSIF lw = 3 THEN
                     DRAWSEGMENT(t - 1, lastV, t, vwapV) COLOURED(cR, cG, cB, 255) STYLE(line, 3)
                  ELSE
                     DRAWSEGMENT(t - 1, lastV, t, vwapV) COLOURED(cR, cG, cB, 255) STYLE(line, 4)
                  ENDIF
               ENDIF
               lastV = vwapV
               havePt = 1
            ELSE
               havePt = 0
            ENDIF
         NEXT
      ENDIF
   NEXT

   // ---- Swing labels: the last maxLabels ones ----
   firstLbl = max(1, nEv - max(1, round(maxLabels)) + 1)
   FOR k = firstLbl TO nEv DO
      IF $eOk[k] = 1 AND $eT[k] > 0 THEN
         lx = $eX[k]
         lOff = atr14[barindex - lx]
         IF $eD[k] > 0 THEN
            ly = $eY[k] - lOff * 0.6
            IF $eT[k] = 1 THEN
               DRAWTEXT("LL", lx, ly, sansserif, bold, 11) COLOURED(lblLoR, lblLoG, lblLoB, 204)
            ELSE
               DRAWTEXT("HL", lx, ly, sansserif, bold, 11) COLOURED(lblLoR, lblLoG, lblLoB, 204)
            ENDIF
         ELSE
            ly = $eY[k] + lOff * 0.6
            IF $eT[k] = 3 THEN
               DRAWTEXT("LH", lx, ly, sansserif, bold, 11) COLOURED(lblHiR, lblHiG, lblHiB, 204)
            ELSE
               DRAWTEXT("HH", lx, ly, sansserif, bold, 11) COLOURED(lblHiR, lblHiG, lblHiB, 204)
            ENDIF
         ENDIF
      ENDIF
   NEXT
ENDIF

RETURN

Download
Filename: PRC_Dynamic-Swing-VWAP.itf
Downloads: 16
Iván González
Iván González Legend
I usually let my code do the talking, which explains why my bio is as empty as a newly created file. Bio to be initialized...
Author’s Profile

Comments

ProRealCode ProRealCode
Loading...