VWAP in Python
Volume-Weighted Average Price — the average price of an asset weighted by traded volume over a session, used as a primary institutional execution benchmark.
Definition
VWAP (Volume-Weighted Average Price) is the ratio of cumulative dollar value traded to cumulative volume traded over a specified period, typically the current trading session. It is the most widely used execution benchmark in institutional equity trading: a buy order executed below VWAP is considered a favorable fill; above VWAP is considered unfavorable. Beyond benchmarking, VWAP is used as a dynamic support/resistance indicator, as a signal filter (only taking long positions when price is above VWAP), and as the target for VWAP execution algorithms which spread large orders across the session proportional to expected volume.
Quantitative Formula
Where is the trade price of the -th transaction, is the volume of the -th transaction, and the summation runs from market open (or the start of the measurement window) to the current time . For bar data, is approximated by the typical price and is the bar volume. VWAP resets at the start of each session and is therefore a session-anchored, non-persistent indicator.
Why It Matters in Backtesting
In backtesting, using the closing price as the execution price for a signal generated during the session introduces lookahead bias. VWAP provides a more realistic execution assumption for intraday strategies: a strategy that generates a signal at 10:00am should be modeled as executing near the VWAP from 10:00am forward, not at the day's closing price. Institutional execution desks measure performance in basis points relative to VWAP — any backtest claiming to execute large orders at exact close prices is producing unrealistic results for orders exceeding ~0.5% of ADV.
Python Implementation
import numpy as np
import pandas as pd
def calculate_vwap(ohlcv_df: pd.DataFrame, anchored: bool = False,
anchor_date: str = None) -> pd.Series:
"""
Calculates session VWAP and optionally Anchored VWAP (AVWAP).
ohlcv_df: DataFrame with columns ['Open', 'High', 'Low', 'Close', 'Volume']
and a DatetimeIndex.
anchored: If True, computes AVWAP from the anchor_date forward.
anchor_date: Start date for anchored VWAP (e.g., '2024-01-15').
"""
df = ohlcv_df.copy()
df["typical_price"] = (df["High"] + df["Low"] + df["Close"]) / 3
df["tp_volume"] = df["typical_price"] * df["Volume"]
if anchored and anchor_date:
df = df[df.index >= anchor_date]
df["cumulative_tp_vol"] = df["tp_volume"].cumsum()
df["cumulative_vol"] = df["Volume"].cumsum()
vwap = df["cumulative_tp_vol"] / df["cumulative_vol"]
else:
# Session VWAP: reset daily
df["date"] = df.index.date
df["cumulative_tp_vol"] = df.groupby("date")["tp_volume"].cumsum()
df["cumulative_vol"] = df.groupby("date")["Volume"].cumsum()
vwap = df["cumulative_tp_vol"] / df["cumulative_vol"]
# VWAP deviation bands (±1 and ±2 standard deviations)
df["vwap"] = vwap
df["vwap_dev"] = df["typical_price"] - df["vwap"]
return pd.DataFrame({
"vwap": vwap,
"upper_1": vwap + df["vwap_dev"].rolling(20).std(),
"lower_1": vwap - df["vwap_dev"].rolling(20).std(),
"deviation": df["vwap_dev"]
})Test this in a live environment
Stop running Jupyter notebooks locally. Paste this VWAP code directly into Valetha's Strategy Lab and run a full historical backtest in seconds.
Open the Python Strategy Lab