VWAP is a running ratio of two cumulative sums, as the explainer covered. The only real decision is when to reset — each session (the classic intraday VWAP) or never (anchored VWAP). Here’s both in pandas.
What you’ll need
- Python 3.9+,
pandas - Intraday OHLCV with a datetime index (for session VWAP).
Session VWAP (resets each day)
The classic intraday VWAP restarts every trading day. groupby on the date makes
that clean:
import pandas as pd
def session_vwap(df: pd.DataFrame) -> pd.Series:
typical = (df["high"] + df["low"] + df["close"]) / 3
tpv = typical * df["volume"]
day = df.index.normalize() # the calendar date per bar
cum_tpv = tpv.groupby(day).cumsum()
cum_vol = df["volume"].groupby(day).cumsum()
return (cum_tpv / cum_vol).rename("vwap")
Each day, cumsum restarts, so VWAP begins fresh at the session open and
accumulates through the day — exactly how desks and day traders use it.
Anchored VWAP (from a chosen point)
Anchored VWAP just accumulates from one starting index and never resets — this is what the chart above shows:
def anchored_vwap(df: pd.DataFrame, start) -> pd.Series:
d = df.loc[start:]
typical = (d["high"] + d["low"] + d["close"]) / 3
return (typical * d["volume"]).cumsum() / d["volume"].cumsum()
Anchor it at an earnings date, a major high, or a swing low to see the volume-weighted fair value since that event.
VWAP bands
vwap = session_vwap(df)
typical = (df["high"] + df["low"] + df["close"]) / 3
# Volume-weighted variance around VWAP, per session.
day = df.index.normalize()
var = ((typical - vwap) ** 2 * df["volume"]).groupby(day).cumsum() / df["volume"].groupby(day).cumsum()
sd = var ** 0.5
upper, lower = vwap + 2 * sd, vwap - 2 * sd
Gotchas
- Session VWAP needs a datetime index. The daily reset depends on grouping by date; on a plain integer index you can only do anchored VWAP.
- Typical price. The standard uses
(H+L+C)/3. Some use close only — pick one and be consistent. - Real volume required. Garbage volume in, garbage VWAP out. Spot forex has no central volume, so VWAP there is at best a proxy.
The lazy one-liner
import pandas_ta as ta
df["vwap"] = ta.vwap(df["high"], df["low"], df["close"], df["volume"]) # session VWAP
Same indicator elsewhere: MQL5, Pine Script, EasyLanguage, NinjaScript.
This post is educational, not financial advice. Indicators describe the past; they don’t predict the future. Backtest anything before you risk real money on it.
Sources and further reading
- GroupBy cumulative sum reference (pandas documentation)
- The Total Cost of Transactions on the NYSE (The Journal of Finance)
- Windowing operations (pandas documentation)
