← Back to Algorithmic Glossary

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

VWAPt=i=1tPiVii=1tViVWAP_t = \frac{\sum_{i=1}^{t} P_i \cdot V_i}{\sum_{i=1}^{t} V_i}

Where PiP_i is the trade price of the ii-th transaction, ViV_i is the volume of the ii-th transaction, and the summation runs from market open (or the start of the measurement window) to the current time tt. For bar data, PiP_i is approximated by the typical price Highi+Lowi+Closei3\frac{High_i + Low_i + Close_i}{3} and ViV_i 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

Ready to find your edge ?

Start for Free