---
title: Anchored VWAP
description: >-
  Weekly and daily VWAP that reset on real UTC session boundaries, with bands
  and a live stretch readout for mean-reversion context.
---

<div class="flex gap-3 mb-6">
  <span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-green-50 text-green-600 text-sm font-medium">
    Beginner
  </span>
  <span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-gray-100 text-gray-600 text-sm font-medium">
    5 min read
  </span>
</div>

VWAP is the volume-weighted average price, the level large players benchmark fills against. A plain cumulative VWAP drifts: it averages from wherever the chart happened to start loading, so the line you see depends on how much history your browser fetched. This recipe pins VWAP to real calendar sessions instead. The weekly line resets every Monday at 00:00 UTC and the daily line resets every midnight, so two traders looking at the same symbol see the same level. It adds percentage bands and a "stretch" number that tells you how far price has pulled from fair value.

```javascript title="scripts/probes/cookbook/anchored_vwap.ks" lines wrap
//@version=2
// ============================================================================
//  WEEKLY ANCHORED VWAP + DAILY SESSIONS  (v3.2 only)
//  v2's vwap was a single cumulative line from wherever the chart happened to
//  start loading: it drifted as more history loaded. v3 anchors to real UTC
//  sessions: the weekly VWAP resets every Monday 00:00 UTC and the daily one
//  every midnight, regardless of how much data the browser fetched.
// ============================================================================
define(title="Anchored VWAP (week + day)", position="onchart", axis=false);

var weekCol = input(name="weekCol", type="color", defaultValue="#f5a623", label="Weekly VWAP");
var dayCol  = input(name="dayCol",  type="color", defaultValue="#4a90d9", label="Daily VWAP");
var bandPct = input(name="bandPct", type="slider", defaultValue=0.5, label="Band %", constraints={min: 0.1, max: 3, step: 0.1});

timeseries d = ohlcv(symbol=currentSymbol, exchange=currentExchange);

// Session-anchored: na before the first complete session, exact after.
timeseries wVwap = vwap(anchor="week", source=d);
timeseries dVwap = vwap(anchor="day", source=d);

timeseries wUpper = wVwap * (1 + bandPct / 100);
timeseries wLower = wVwap * (1 - bandPct / 100);

plotLine(wVwap, colors=[weekCol], width=2, label=["Weekly VWAP"], desc=["Volume weighted average price anchored to the UTC week"]);
plotLine(dVwap, colors=[dayCol], width=1, label=["Daily VWAP"], desc=["Volume weighted average price anchored to the UTC day"]);
plotLine(wUpper, colors=[opacity(weekCol, 30)], width=1, label=["Week Upper"], desc=["Weekly VWAP plus band percent"]);
plotLine(wLower, colors=[opacity(weekCol, 30)], width=1, label=["Week Lower"], desc=["Weekly VWAP minus band percent"]);
fillBetween(wUpper, wLower, weekCol, 8);

// Price stretched from the weekly anchor = mean-reversion context.
var stretch = isnum(wVwap[0]) && wVwap[0] > 0 ? (d.close[0] - wVwap[0]) / wVwap[0] * 100 : 0;
if (isLastBar) {
  plotTable(
    data=[["Anchored VWAP", ""], ["Weekly", isnum(wVwap[0]) ? "".concat(math.round(wVwap[0] * 100) / 100) : "warming"], ["Stretch %", "".concat(math.round(stretch * 100) / 100)]],
    position="bottom_right", headerRow=true, backgroundColor="#0d1117", textColor="#e6edf3", fontSize=11
  );
}
```


## How it works

**The anchor is the whole trick.** `vwap(anchor="week", source=d)` accumulates price-times-volume from the start of the current UTC week and resets the moment a new week begins. The daily line does the same on a midnight boundary. The reset is tied to the calendar, not to your scroll position or how much history loaded, which is exactly why the level is stable and shared.

**Warm-up is honest.** An anchored VWAP is `na` until its session actually starts on screen. The daily line fills in within the first day of loaded data, the weekly line needs roughly a week. Every place the script reads the VWAP it checks `isnum(...)` first, so nothing breaks during warm-up. The table even prints `"warming"` instead of a fake number while it waits.

**The bands frame the move.** `wUpper` and `wLower` are just the weekly VWAP scaled by a percentage. `fillBetween` shades the channel between them. When price rides the upper band it is stretched rich versus the week's fair value, when it sags to the lower band it is cheap. The bands are drawn faint with `opacity()` so the VWAP line itself stays the star.

**The stretch readout.** The most actionable number is how far price has pulled from the anchor, expressed as a percent: `(close - wVwap) / wVwap * 100`. A large positive stretch is an overextension signal for mean-reversion traders. It is printed once, on the last bar, in a small `plotTable` so you get a live readout without cluttering history.

## Customize it

- **Band width.** The `bandPct` slider sets how far the bands sit from VWAP. Tighten it toward `0.2` on calm majors, widen it toward `2` on volatile names so the bands actually contain the noise.
- **Anchor period.** Swap `"week"` for `"month"` to track a longer-horizon fair value, or `"day"` for an intraday anchor. Monthly needs about a month of loaded history before it shows anything, so load enough bars. See [special indicators](/kscript/functions/special-indicators#vwap) for the full anchor rules.
- **Band the daily line too.** The bands here wrap the weekly VWAP. Duplicate the `wUpper` / `wLower` / `fillBetween` block against `dVwap` if you trade the intraday session instead.
- **Stretch as a signal.** Right now stretch is just displayed. Add a `plotShape` when `stretch` exceeds a threshold to mark genuine overextensions, or wire it into an [`alert()`](/kscript/functions/alerts).
- **Colors.** `weekCol` and `dayCol` are inputs. The `opacity()` calls derive the faint band tints from them automatically, so changing the base color restyles the whole set.

## Concepts used

- [Special indicators](/kscript/functions/special-indicators#vwap) for anchored `vwap` and its session-reset behavior
- [Plotting](/kscript/functions/plotting) for `plotLine`, `fillBetween`, `hline`, and `plotTable`
- [Color functions](/kscript/functions/color-functions) for `opacity` band tints
- [na and scalar types](/kscript/core-concepts/na-and-scalar-types) for the warm-up guards
