The demand for systematic and data-driven trading strategies has grown exponentially among professional traders in the futures and forex markets. Among the myriad of tools available to modern traders, the Volume-Weighted Average Price (VWAP) indicator has become a cornerstone for identifying trends and generating trading signals. But how do you use it to develop and test a trading strategy? This article delves into the details of backtesting a VWAP trading strategy using Python, building on key insights from a detailed walkthrough of a systematic approach.
In this step-by-step guide, we’ll break down the strategy’s core concepts, the Python implementation process, and the results of the backtesting exercise. By the end of this article, you’ll have a deeper understanding of how VWAP can be integrated into your trading toolkit, along with actionable insights to refine your own strategies.
What Is the VWAP Strategy?
The VWAP (Volume-Weighted Average Price) indicator serves as a benchmark to assess the average price of an asset, weighted by volume, over a certain time period. Traders commonly use it to identify intraday price trends and make decisions based on the relative position of the price to the VWAP.
Core Concept of the Strategy
This VWAP strategy focuses on short-term price trends using a 15-minute timeframe. The premise is simple:
- Price above VWAP: Indicates a short-term uptrend, signaling potential long entries.
- Price below VWAP: Indicates a short-term downtrend, signaling potential short entries.
The strategy combines these VWAP signals with additional filters, including:
- Candle color: Green candles (closing price above opening price) confirm bullish momentum, while red candles (closing price below opening price) confirm bearish momentum.
- Daily opening price: Trades are further validated by comparing the current price to the day’s opening price.
Furthermore, stop-losses are dynamically set based on the Average True Range (ATR), ensuring they adapt to market volatility.
Uptime
99.999% uptime. Built for 24/7 trading reliability.
Your VPS runs in Tier IV datacenters with redundant power and network, monitored 24/7 on site.
See the uptime SLAFrom $29.99/mo · Windows or Linux
Performance Highlights
The source video backtests these rules on three years of 15-minute data. Its headline numbers depend on the asset, the test period and the fees assumed, so this guide gives you the full code to run the same test on your own data.
Building the VWAP Strategy in Python: A Step-by-Step Guide

Implementing the VWAP strategy in Python involves a systematic approach, leveraging libraries like pandas and backtesting frameworks. Below is a breakdown of the process:
1. Load Historical Data
To begin, you’ll need historical price data for the desired asset. The example uses a 15-minute timeframe for assets such as Apple stock, Bitcoin, and Tesla.
import pandas as pd
# Load 15-minute bars with a datetime index and Open, High, Low, Close, Volume columns
data = pd.read_csv('historical_data.csv', index_col=0, parse_dates=True)
2. Calculate the VWAP
Instead of using pre-built technical analysis libraries, the VWAP function is defined by hand, so you control when it resets. The version below uses the typical price, (High + Low + Close) / 3, and starts a new running total at the first bar of each trading day.
def calculate_vwap(data):
# Typical price for each bar
typical = (data['High'] + data['Low'] + data['Close']) / 3
day = data.index.date
# Running totals that restart at the first bar of each day
data['cum_price_volume'] = (typical * data['Volume']).groupby(day).cumsum()
data['cum_volume'] = data['Volume'].groupby(day).cumsum()
data['vwap'] = data['cum_price_volume'] / data['cum_volume']
return data
3. Define Entry and Exit Rules
The strategy generates trading signals based on VWAP, candle color, and daily opening price:
- Long Entry: Price above VWAP, green candle, and price above daily open.
- Short Entry: Price below VWAP, red candle, and price below daily open.
Trailing stop-losses are based on 1.5x ATR, dynamically adjusting to market volatility.
if (close_price > vwap) and (close_price > day_open) and (candle_color == 'green'):
# Execute long trade
do_buy()
DDoS protection
Always-on DDoS protection with advanced filtering. On every plan.
Always-on mitigation filters attack traffic at the network edge. Every plan includes a dedicated IP and unmetered bandwidth for the trading environment.
See every security layerFrom $29.99/mo · Windows or Linux
4. Backtest the Strategy
The full example below uses the open-source backtesting.py package (pip install backtesting). It applies the entry rules from step 3, a 1.5x ATR trailing stop, a flat position before the session ends and a commission on every fill.
import pandas as pd
from backtesting import Backtest
from backtesting.lib import TrailingStrategy
# 15-minute bars: a datetime index plus Open, High, Low, Close and Volume columns
data = pd.read_csv('historical_data.csv', index_col=0, parse_dates=True)
def session_vwap(df):
# Typical price, reset at the start of each trading day
typical = (df['High'] + df['Low'] + df['Close']) / 3
day = df.index.date
cum_pv = (typical * df['Volume']).groupby(day).cumsum()
cum_vol = df['Volume'].groupby(day).cumsum()
return cum_pv / cum_vol
def daily_open(df):
return df['Open'].groupby(df.index.date).transform('first')
class VwapStrategy(TrailingStrategy):
atr_mult = 1.5 # trailing stop distance in ATRs
def init(self):
super().init()
self.set_atr_periods(14)
self.set_trailing_sl(self.atr_mult)
df = self.data.df
self.vwap = self.I(lambda: session_vwap(df).values, name='VWAP')
self.day_open = self.I(lambda: daily_open(df).values, name='Day open')
def next(self):
super().next()
bar_time = self.data.index[-1]
close, open_ = self.data.Close[-1], self.data.Open[-1]
# Flat before the session ends (last 15-minute bar starts at 15:45)
if bar_time.hour == 15 and bar_time.minute >= 45:
self.position.close()
return
if not self.position:
if close > self.vwap[-1] and close > self.day_open[-1] and close > open_:
self.buy()
elif close < self.vwap[-1] and close < self.day_open[-1] and close < open_:
self.sell()
# commission=0.0005 charges 0.05% of order value on every fill
bt = Backtest(data, VwapStrategy, cash=100_000, commission=0.0005,
exclusive_orders=True, finalize_trades=True)
stats = bt.run()
print(stats[['Return [%]', 'Buy & Hold Return [%]', 'Max. Drawdown [%]',
'Win Rate [%]', '# Trades']])
# Same rules with no commission, to see how much the fees cost
print(Backtest(data, VwapStrategy, cash=100_000, commission=0,
exclusive_orders=True, finalize_trades=True).run()['Return [%]'])
A few notes on the code. TrailingStrategy moves the stop loss to 1.5 ATRs behind the price on every bar, and set_atr_periods(14) uses a 14-bar ATR. The commission argument is a share of order value, and backtesting.py charges it at entry and again at exit. The 15:45 check assumes US stock hours in exchange time, so change it for futures, forex or crypto.
The stats object also reports annual return, volatility, Sharpe ratio and the full trade list in stats._trades. Call bt.plot() to see each trade on the chart.
Results and Observations
The source video reports high volatility and a substantial drawdown for this rule set, so read these numbers first when you run the code on your own data:
Key Metrics:
- Return vs buy and hold: Return [%] next to Buy & Hold Return [%] shows whether the rules beat simply holding the asset.
- Drawdown: Max. Drawdown [%] shows the deepest fall from a peak, which tells you whether you could live with the strategy.
- Win rate and trade count: Win Rate [%] and # Trades show how often the rules win and trade, which drives your total fees.
Sensitivity to Commissions
One notable finding was the strategy’s sensitivity to trading fees. For instance, at 0.05% commission per fill, each round trip costs 0.1% of the position. If the average trade earns 0.08% before costs, the same signals lose money after fees. The example code runs the backtest with and without commission so you can see this gap on your own data.
This underscores the importance of minimizing trading costs when using high-frequency strategies on lower timeframes.
Optimizing the Strategy
The strategy’s performance can be further refined by experimenting with key parameters:
- ATR Coefficient: Testing values between 0.5 and 2.5 revealed that a coefficient of 1.5 strikes the best balance between risk and reward.
- VWAP Reset Frequency: While the example used a daily VWAP, experimenting with weekly resets could improve results on higher timeframes.
- Condition Filtering: Removing the green/red candle condition yielded better backtest results, suggesting a simpler entry rule might be more effective.
Strengths and Limitations of the Strategy
Strengths:
- Clear Entry/Exit Criteria: The combination of VWAP, daily opening price, and ATR provides filters for identifying trends.
- Day Trading Focus: Closing all trades by the end of the day avoids overnight fees and reduces exposure to gapping risks.
- Customizability: The Python implementation allows for extensive parameter tweaking and experimentation.
Order flow
Built for scalpers. Heatmaps on dedicated resources.
Order-flow heatmaps and DOM ladders run on dedicated CPU, memory and NVMe, so your charts keep responding during volatility.
See the dedicated hardwareFrom $29.99/mo · Windows or Linux
Limitations:
- High Sensitivity to Fees: The reliance on intraday trades makes the strategy vulnerable to trading costs.
- Limited to Certain Markets: The strategy’s effectiveness depends on the liquidity and volatility of the chosen asset.
Key Takeaways
- VWAP as a Trend Indicator: Using VWAP alongside daily opening prices provides a reliable method for detecting intraday trends.
- Dynamic Stop-Losses: ATR-based trailing stops ensure the strategy adapts to market volatility.
- Parameter Tuning: Experimenting with ATR coefficients and VWAP reset frequencies can optimize performance.
- Cost Management: For intraday strategies, minimizing fees is critical to preserving profitability.
Conclusion
Backtesting a VWAP trading strategy in Python showcases the power of systematic, data-driven approaches in futures and forex markets. By understanding how to integrate indicators like VWAP and ATR into your trading logic, you can develop strategies for your trading style. However, always keep in mind the potential pitfalls, such as sensitivity to trading costs and the importance of rigorous backtesting.
This strategy is a starting point, offering traders a framework to build upon and refine. The key to success lies in continuous experimentation, optimization, and adaptation to ever-changing market conditions. Happy trading!
For an always-on trading workspace, QuantVPS can host the platform while your local computer is off; use only automation that your broker or prop firm permits.
Source: "A Simple VWAP Rule Beats Buy & Hold | Full Backtest In Python" - CodeTrading, YouTube, Aug 7, 2025 - https://www.youtube.com/watch?v=e9IDuLESYv8
Use: Embedded for reference. Brief quotes used for commentary/review.









