Volume Weighted Average Price (VWAP)
I. What is VWAP
Volume Weighted Average Price (VWAP) is a technical indicator that calculates the average price weighted by volume over a given trading session. It reflects the true average transaction cost of market participants and is one of the most commonly used benchmark prices by institutional investors.
Historical Background
The concept of VWAP originated in the 1980s within institutional trading on Wall Street. As electronic trading and algorithmic trading gained traction, large funds and investment banks needed a benchmark price to measure execution quality. VWAP was widely adopted to meet this need. Early algorithmic trading pioneers such as James Elkins promoted VWAP as a core trading benchmark, making it the standard tool for evaluating institutional trade execution performance.
Today, VWAP serves not only as an institutional trading benchmark but is also widely used by day traders to identify intraday support/resistance levels and trend direction.
Indicator Classification
- Type: Overlay indicator, plotted directly on the price chart
- Category: Other Overlay / Volume-Weighted Indicator
- Default Parameters: No fixed period parameter; resets at the open of each trading day and accumulates until the close
- Data Requirements: Requires price and volume data (OHLCV)
VWAP is not a traditional trend indicator but rather a fair price benchmark. Institutional investors use it to evaluate whether their orders were executed at a “reasonable price” — if the buy price is below VWAP, execution is considered better than the market average.
II. Mathematical Principles and Calculation
Core Formula
VWAP is the volume-weighted average of the typical price over a trading session:
Where:
- is the Typical Price of the -th bar:
- is the volume of the -th bar
- is the number of bars generated so far in the current trading session
Step-by-Step Calculation
- Calculate Typical Price: For each bar, compute .
- Compute TP x Volume: Multiply the typical price by the corresponding volume to approximate the turnover.
- Cumulative Summation: Accumulate and separately from the start of the trading day.
- Divide to Get VWAP: At each point in time, VWAP = Cumulative Turnover / Cumulative Volume.
- Daily Reset: At the start of the next trading day, all cumulative values reset to zero.
Cumulative Nature
An important property of VWAP is that it is cumulative:
This means:
- As the trading day progresses, VWAP changes become increasingly smooth (the denominator keeps growing)
- Early session data has a greater influence on VWAP
- VWAP cannot be “crossed” and quickly reverse — its changes are gradual
In practice, 1-2 standard deviation bands are often added above and below VWAP to form VWAP Bands, similar in concept to Bollinger Bands: Where is the standard deviation of the typical price from VWAP.
III. Python Implementation
import numpy as np
import pandas as pd
def vwap(high: pd.Series, low: pd.Series, close: pd.Series,
volume: pd.Series, session: pd.Series = None) -> pd.Series:
"""
Calculate Volume Weighted Average Price (VWAP)
Parameters
----------
high : pd.Series
High price series
low : pd.Series
Low price series
close : pd.Series
Close price series
volume : pd.Series
Volume series
session : pd.Series, optional
Trading session identifier series (for daily reset).
If not provided, all data is assumed to belong to a single session.
Returns
-------
pd.Series
VWAP value series
"""
# Calculate typical price
tp = (high + low + close) / 3.0
# Calculate TP * Volume
tp_vol = tp * volume
if session is not None:
# Group by trading day and compute cumulative sums
cum_tp_vol = tp_vol.groupby(session).cumsum()
cum_vol = volume.groupby(session).cumsum()
else:
cum_tp_vol = tp_vol.cumsum()
cum_vol = volume.cumsum()
result = cum_tp_vol / cum_vol
result.name = "VWAP"
return result
def vwap_with_bands(high: pd.Series, low: pd.Series, close: pd.Series,
volume: pd.Series, session: pd.Series = None,
num_std: float = 1.0) -> pd.DataFrame:
"""
Calculate VWAP with standard deviation bands
Returns
-------
pd.DataFrame
DataFrame with VWAP, Upper Band, and Lower Band columns
"""
tp = (high + low + close) / 3.0
tp_vol = tp * volume
if session is not None:
cum_tp_vol = tp_vol.groupby(session).cumsum()
cum_vol = volume.groupby(session).cumsum()
cum_count = volume.groupby(session).cumcount() + 1
else:
cum_tp_vol = tp_vol.cumsum()
cum_vol = volume.cumsum()
cum_count = pd.Series(range(1, len(tp) + 1), index=tp.index)
vwap_line = cum_tp_vol / cum_vol
# Calculate cumulative variance (volume-weighted)
tp_sq_vol = (tp ** 2) * volume
if session is not None:
cum_tp_sq_vol = tp_sq_vol.groupby(session).cumsum()
else:
cum_tp_sq_vol = tp_sq_vol.cumsum()
variance = (cum_tp_sq_vol / cum_vol) - vwap_line ** 2
variance = variance.clip(lower=0) # Avoid negative values from floating-point errors
std = np.sqrt(variance)
return pd.DataFrame({
"VWAP": vwap_line,
"Upper": vwap_line + num_std * std,
"Lower": vwap_line - num_std * std,
})
# ========== Usage Example ==========
if __name__ == "__main__":
np.random.seed(42)
# Simulate 3 trading days of 5-minute bar data (approx. 48 bars per day)
n_bars_per_day = 48
n_days = 3
n_total = n_bars_per_day * n_days
dates = []
sessions = []
for d in range(n_days):
day = pd.Timestamp(f"2024-01-{d+2:02d} 09:30:00")
for i in range(n_bars_per_day):
dates.append(day + pd.Timedelta(minutes=5 * i))
sessions.append(day.date())
price = 100 + np.cumsum(np.random.randn(n_total) * 0.3)
df = pd.DataFrame({
"datetime": dates,
"session": sessions,
"open": price + np.random.randn(n_total) * 0.1,
"high": price + np.abs(np.random.randn(n_total) * 0.4),
"low": price - np.abs(np.random.randn(n_total) * 0.4),
"close": price,
"volume": np.random.randint(500, 5000, size=n_total),
})
df.set_index("datetime", inplace=True)
# Calculate VWAP (reset daily)
df["VWAP"] = vwap(df["high"], df["low"], df["close"],
df["volume"], session=df["session"])
# Calculate VWAP with standard deviation bands
bands = vwap_with_bands(df["high"], df["low"], df["close"],
df["volume"], session=df["session"], num_std=1.5)
df = pd.concat([df, bands[["Upper", "Lower"]]], axis=1)
# Print last 5 bars for each day
for day in sorted(df["session"].unique()):
subset = df[df["session"] == day]
print(f"\n=== {day} End of Session ===")
print(subset[["close", "volume", "VWAP", "Upper", "Lower"]].tail(5))
# Signal example: price breaks above VWAP -> bullish
df["above_vwap"] = (df["close"] > df["VWAP"]).astype(int)
print("\nProportion of time price is above VWAP:",
f"{df['above_vwap'].mean():.1%}")
IV. Problems the Indicator Solves
1. Institutional Trade Execution Benchmark
The most critical use of VWAP is as a measure of institutional order execution quality:
- Buy side: Average execution price < VWAP indicates superior execution
- Sell side: Average execution price > VWAP indicates superior execution
- Many VWAP algorithms split large orders into smaller ones to keep the overall execution price close to VWAP
2. Intraday Trend Assessment
| Price Position | Interpretation |
|---|---|
| Price consistently above VWAP | Intraday bullish dominance, buyers in control |
| Price consistently below VWAP | Intraday bearish dominance, sellers in control |
| Price oscillating around VWAP | Market divergence, direction unclear |
3. Dynamic Support and Resistance
VWAP itself acts as a powerful dynamic intraday support/resistance line. When price pulls back to VWAP from above, buying support often appears; when price bounces up to VWAP from below, selling pressure often emerges.
4. Overbought/Oversold with VWAP Bands
- Price reaching the Upper Band suggests short-term overbought conditions, with a potential pullback toward VWAP
- Price reaching the Lower Band suggests short-term oversold conditions, with a potential bounce toward VWAP
VWAP is an intraday indicator that resets daily. It should not be extended across multiple days on a daily chart — a multi-day VWAP loses its meaning as a “fair price for the current day.” Some platforms offer “Anchored VWAP” for multi-day analysis, but its logic differs from standard VWAP.
V. Advantages, Disadvantages, and Use Cases
Advantages
| Advantage | Description |
|---|---|
| Incorporates volume | Reflects the true average cost of market participants more accurately than simple moving averages |
| High institutional recognition | A globally accepted trading benchmark with self-reinforcing effects |
| No parameter tuning | No need to choose a period, avoiding parameter optimization issues |
| Smooth and reliable | Cumulative calculation makes VWAP increasingly stable over time |
Disadvantages
| Disadvantage | Description |
|---|---|
| Intraday only | Standard VWAP resets daily and is not suitable for multi-day trend analysis |
| Late-day insensitivity | VWAP barely changes in the final hours before close, reducing signal value |
| Requires volume | Less effective in markets with unreliable volume (e.g., forex tick volume) |
| Not for low-liquidity instruments | Sparse volume can cause VWAP to be distorted by a few large orders |
Use Cases
- Day trading: Identify intraday direction and entry timing; VWAP is the day trader’s “anchor”
- Algorithmic trading: The VWAP algorithm is one of the most classic institutional execution algorithms
- Stocks and futures: Works best in markets with real volume data
- High-liquidity instruments: Blue-chip stocks, active contracts, and other high-volume instruments
Comparison with Related Indicators
| Comparison | VWAP | SMA | TWAP |
|---|---|---|---|
| Weighting | Volume-weighted | Equal weight | Time-weighted |
| Reset mechanism | Daily reset | Rolling window | Customizable |
| Best timeframe | Intraday | Daily and above | Intraday |
| Number of parameters | 0 | 1 (period) | 1 (period) |
- VWAP tends to fluctuate significantly in the first 30 minutes after market open; wait for it to stabilize before using it as a reference.
- Combining VWAP with Volume Profile allows for more precise identification of key price levels.
- In trending days, when price holds above VWAP and successfully retests it, this is a classic intraday long entry setup.
- Be aware of the distinction between “standard VWAP” (daily reset) and “Anchored VWAP” (custom start point) — they serve different purposes.