Volume Weighted Average Price (VWAP)

Haiyue
12min

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)
Core Role of VWAP

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:

VWAP=i=1NTPi×Vii=1NViVWAP = \frac{\sum_{i=1}^{N} TP_i \times V_i}{\sum_{i=1}^{N} V_i}

Where:

  • TPiTP_i is the Typical Price of the ii-th bar: TPi=Hi+Li+Ci3TP_i = \frac{H_i + L_i + C_i}{3}
  • ViV_i is the volume of the ii-th bar
  • NN is the number of bars generated so far in the current trading session

Step-by-Step Calculation

  1. Calculate Typical Price: For each bar, compute TP=(High+Low+Close)/3TP = (High + Low + Close) / 3.
  2. Compute TP x Volume: Multiply the typical price by the corresponding volume to approximate the turnover.
  3. Cumulative Summation: Accumulate TP×VTP \times V and VV separately from the start of the trading day.
  4. Divide to Get VWAP: At each point in time, VWAP = Cumulative Turnover / Cumulative Volume.
  5. 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:

VWAPt=i=1tTPiVii=1tViVWAP_t = \frac{\sum_{i=1}^{t} TP_i \cdot V_i}{\sum_{i=1}^{t} V_i}

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
About VWAP Bands

In practice, 1-2 standard deviation bands are often added above and below VWAP to form VWAP Bands, similar in concept to Bollinger Bands: Upper=VWAP+n×σUpper = VWAP + n \times \sigma Lower=VWAPn×σLower = VWAP - n \times \sigma Where σ\sigma 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 PositionInterpretation
Price consistently above VWAPIntraday bullish dominance, buyers in control
Price consistently below VWAPIntraday bearish dominance, sellers in control
Price oscillating around VWAPMarket 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
Note

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

AdvantageDescription
Incorporates volumeReflects the true average cost of market participants more accurately than simple moving averages
High institutional recognitionA globally accepted trading benchmark with self-reinforcing effects
No parameter tuningNo need to choose a period, avoiding parameter optimization issues
Smooth and reliableCumulative calculation makes VWAP increasingly stable over time

Disadvantages

DisadvantageDescription
Intraday onlyStandard VWAP resets daily and is not suitable for multi-day trend analysis
Late-day insensitivityVWAP barely changes in the final hours before close, reducing signal value
Requires volumeLess effective in markets with unreliable volume (e.g., forex tick volume)
Not for low-liquidity instrumentsSparse 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
ComparisonVWAPSMATWAP
WeightingVolume-weightedEqual weightTime-weighted
Reset mechanismDaily resetRolling windowCustomizable
Best timeframeIntradayDaily and aboveIntraday
Number of parameters01 (period)1 (period)
Practical Tips
  1. VWAP tends to fluctuate significantly in the first 30 minutes after market open; wait for it to stabilize before using it as a reference.
  2. Combining VWAP with Volume Profile allows for more precise identification of key price levels.
  3. In trending days, when price holds above VWAP and successfully retests it, this is a classic intraday long entry setup.
  4. Be aware of the distinction between “standard VWAP” (daily reset) and “Anchored VWAP” (custom start point) — they serve different purposes.