Skip to main content

Volume Weighted Average Price (VWAP) in Pine Script

· 9 min read

If you've been trading for a while, you've probably heard people mention VWAP. It's one of those indicators that sounds super technical but is actually pretty straightforward once you get it. Let me break it down for you.

Volume Weighted Average Price (VWAP) Indicator on TradingView Chart

What's VWAP All About?

VWAP stands for Volume Weighted Average Price, and it's basically the average price of a stock throughout the day, but with a twist - it gives more weight to prices where lots of trading happened.

Think of it this way: if a stock trades at $100 with only 10 shares changing hands, that's not as significant as when it trades at $101 with 10,000 shares being bought and sold. VWAP takes this into account.

The cool thing is that VWAP resets every day, so you're always looking at fresh data for the current trading session. Big institutional traders love this thing because it helps them figure out if they're getting good prices on their massive orders.

How I Use VWAP in My Trading

The Best Pine Script Generator

Here's how I actually use VWAP in real trading situations:

Checking the Overall Mood: When the price is hanging out above VWAP, it usually means buyers are in control. When it's below, sellers are calling the shots. It's like a quick mood check for the market.

Finding Support and Resistance: VWAP often acts like an invisible line in the sand. Sometimes the price bounces off it like it hit a wall, other times it breaks through and keeps going.

Timing My Entries: I like to watch how the price behaves around VWAP. If it's been below and starts pushing back up through it, that might be a good time to jump in long. Same thing in reverse for short positions.

Mean Reversion Plays: Sometimes when a stock gets too far away from VWAP, it wants to come back. I'll buy when it's way below VWAP expecting it to bounce back, or sell when it's stretched too far above.

Breakout Confirmation: When a stock breaks above VWAP with good volume, it often keeps going. Same for breaks below - they tend to continue.

Quick Background on TradingView and Pineify

If you're not familiar, TradingView is where most of us go to look at charts and analyze markets. It's got everything you need for technical analysis, plus you can chat with other traders and share ideas.

Pineify is this neat tool that makes creating custom indicators way easier. Instead of learning Pine Script from scratch, you can build indicators through a visual interface. Pretty handy if you're not into coding.

Pineify | Best Pine Script Editor

Website: Pineify

Check out what Pineify can do.

Adding VWAP to Your Charts (No Coding Required)

Getting VWAP on your TradingView charts is pretty easy. If you want to customize it without diving into code, Pineify makes it simple. You can adjust the settings and appearance through their interface without touching a single line of Pine Script.

Pineify | Best Pine Script Editor

The Pine Script Code

Here's the actual Pine Script code for a VWAP indicator if you want to see how it works under the hood:

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Pineify

//======================================================================//
// ____ _ _ __ //
// | _ \(_)_ __ ___(_)/ _|_ _ //
// | |_) | | '_ \ / _ \ | |_| | | | //
// | __/| | | | | __/ | _| |_| | //
// |_| |_|_| |_|\___|_|_| \__, | //
// |___/ //
//======================================================================//

//@version=6
indicator(title="VWAP Indicator", overlay=true, max_labels_count=500)

//#region —————————————————————————————————————————————————— Custom Code

//#endregion ————————————————————————————————————————————————————————————

//#region —————————————————————————————————————————————————— Common Dependence

p_comm_time_range_to_unix_time(string time_range, int date_time = time, string timezone = syminfo.timezone) =>
int start_unix_time = na
int end_unix_time = na
int start_time_hour = na
int start_time_minute = na
int end_time_hour = na
int end_time_minute = na
if str.length(time_range) == 11
// Format: hh:mm-hh:mm
start_time_hour := math.floor(str.tonumber(str.substring(time_range, 0, 2)))
start_time_minute := math.floor(str.tonumber(str.substring(time_range, 3, 5)))
end_time_hour := math.floor(str.tonumber(str.substring(time_range, 6, 8)))
end_time_minute := math.floor(str.tonumber(str.substring(time_range, 9, 11)))
else if str.length(time_range) == 9
// Format: hhmm-hhmm
start_time_hour := math.floor(str.tonumber(str.substring(time_range, 0, 2)))
start_time_minute := math.floor(str.tonumber(str.substring(time_range, 2, 4)))
end_time_hour := math.floor(str.tonumber(str.substring(time_range, 5, 7)))
end_time_minute := math.floor(str.tonumber(str.substring(time_range, 7, 9)))
start_unix_time := timestamp(timezone, year(date_time, timezone), month(date_time, timezone), dayofmonth(date_time, timezone), start_time_hour, start_time_minute, 0)
end_unix_time := timestamp(timezone, year(date_time, timezone), month(date_time, timezone), dayofmonth(date_time, timezone), end_time_hour, end_time_minute, 0)
[start_unix_time, end_unix_time]

p_comm_time_range_to_start_unix_time(string time_range, int date_time = time, string timezone = syminfo.timezone) =>
int start_time_hour = na
int start_time_minute = na
if str.length(time_range) == 11
// Format: hh:mm-hh:mm
start_time_hour := math.floor(str.tonumber(str.substring(time_range, 0, 2)))
start_time_minute := math.floor(str.tonumber(str.substring(time_range, 3, 5)))
else if str.length(time_range) == 9
// Format: hhmm-hhmm
start_time_hour := math.floor(str.tonumber(str.substring(time_range, 0, 2)))
start_time_minute := math.floor(str.tonumber(str.substring(time_range, 2, 4)))
timestamp(timezone, year(date_time, timezone), month(date_time, timezone), dayofmonth(date_time, timezone), start_time_hour, start_time_minute, 0)

p_comm_time_range_to_end_unix_time(string time_range, int date_time = time, string timezone = syminfo.timezone) =>
int end_time_hour = na
int end_time_minute = na
if str.length(time_range) == 11
end_time_hour := math.floor(str.tonumber(str.substring(time_range, 6, 8)))
end_time_minute := math.floor(str.tonumber(str.substring(time_range, 9, 11)))
else if str.length(time_range) == 9
end_time_hour := math.floor(str.tonumber(str.substring(time_range, 5, 7)))
end_time_minute := math.floor(str.tonumber(str.substring(time_range, 7, 9)))
timestamp(timezone, year(date_time, timezone), month(date_time, timezone), dayofmonth(date_time, timezone), end_time_hour, end_time_minute, 0)

p_comm_timeframe_to_seconds(simple string tf) =>
float seconds = 0
tf_lower = str.lower(tf)
value = str.tonumber(str.substring(tf_lower, 0, str.length(tf_lower) - 1))
if str.endswith(tf_lower, 's')
seconds := value
else if str.endswith(tf_lower, 'd')
seconds := value * 86400
else if str.endswith(tf_lower, 'w')
seconds := value * 604800
else if str.endswith(tf_lower, 'm')
seconds := value * 2592000
else
seconds := str.tonumber(tf_lower) * 60
seconds

p_custom_sources() =>
[open, high, low, close, volume]

//#endregion —————————————————————————————————————————————————————————————————

//#region —————————————————————————————————————————————————— Ta Dependence

p_ta_vwap(series float source, simple string anchor_timeframe, series float stdev_mult) =>
anchor = timeframe.change(anchor_timeframe)
[vwap, upper, lower] = ta.vwap(source, anchor, stdev_mult)
[vwap, upper, lower]

//#endregion —————————————————————————————————————————————————————————————

//#region —————————————————————————————————————————————————— Constants

// Input Groups
string P_GP_1 = ""

//#endregion —————————————————————————————————————————————————————————

//#region —————————————————————————————————————————————————— Inputs

//#endregion ———————————————————————————————————————————————————————

//#region —————————————————————————————————————————————————— Price Data

//#endregion ———————————————————————————————————————————————————————————

//#region —————————————————————————————————————————————————— Indicators

[p_ind_1_vwap, p_ind_1_upper, p_ind_1_lower] = p_ta_vwap(hlc3, "1D", 1) // VWAP

//#endregion ———————————————————————————————————————————————————————————

//#region —————————————————————————————————————————————————— Conditions

//#endregion ———————————————————————————————————————————————————————————

//#region —————————————————————————————————————————————————— Indicator Plots

// VWAP
plot(p_ind_1_vwap, title="VWAP", color=color.rgb(41, 98, 255, 0), linewidth=1)
p_ind_1_upper_plot = plot(p_ind_1_upper, title="VWAP - Upper Band", color=color.rgb(76, 175, 80, 0), linewidth=1)
p_ind_1_lower_plot = plot(p_ind_1_lower, title="VWAP - Lower Band", color=color.rgb(76, 175, 80, 0), linewidth=1)
fill(p_ind_1_upper_plot, p_ind_1_lower_plot, color=color.rgb(76, 175, 80, 95), title="VWAP - Background")

//#endregion ————————————————————————————————————————————————————————————————

//#region —————————————————————————————————————————————————— Custom Plots

//#endregion —————————————————————————————————————————————————————————————

//#region —————————————————————————————————————————————————— Alert

//#endregion ——————————————————————————————————————————————————————

Why I Like Using VWAP

Here are the main reasons VWAP has earned a spot in my trading toolkit:

It's a Reality Check: VWAP tells me if I'm getting a good deal or not. If I'm buying below VWAP or selling above it, I know I'm doing better than the average trader that day.

It Shows Market Sentiment: Just by glancing at where the price is relative to VWAP, I can quickly gauge whether bulls or bears are winning.

Volume Matters: Unlike simple moving averages that treat every price tick the same, VWAP gives more importance to prices where actual money was moving. That makes it more realistic.

The Big Players Use It: Knowing that institutions use VWAP helps me understand where they might be looking to buy or sell. Sometimes you can ride their coattails.

How I Incorporate VWAP into My Strategies

Day Trading: VWAP is perfect for day trading because it resets every day. I use it to spot intraday trends and find good entry points.

Combining with Other Stuff: I don't use VWAP alone. I'll combine it with moving averages, RSI, or whatever else I'm looking at to get a fuller picture.

Automated Systems: If you're into algorithmic trading, VWAP works great as part of your entry and exit logic.

Anchored VWAP: This is a cool variation where you anchor the calculation to important events like earnings announcements. It helps you see how the market has reacted since that event.

The Downsides (Because Nothing's Perfect)

Let me be honest about VWAP's limitations:

It's Always Playing Catch-Up: Since VWAP is based on what already happened, it can be slow to react to sudden market moves. By the time it catches up, you might have missed the boat.

Daily Reset Problem: Since it resets every day, VWAP isn't great for longer-term analysis. If you're swing trading or position trading, you might need something else.

Thin Markets Can Mess It Up: In stocks that don't trade much, VWAP can get weird because there's not enough volume to make it meaningful.

Big Trades Can Skew It: Sometimes a huge institutional order can throw off the VWAP calculation, making it less reliable for a while.

Wrapping Up

VWAP is one of those indicators that's genuinely useful once you understand what it's telling you. It's not magic, but it gives you a solid reference point for understanding market dynamics and making better trading decisions.

The key is not to rely on it alone. Use it as part of your overall analysis, combine it with other tools, and always remember that no indicator is right 100% of the time.

If you want to start experimenting with VWAP, fire up TradingView and add it to your charts. Play around with it on different timeframes and markets. See how it behaves during different market conditions. The best way to learn any indicator is to watch it in action and see how it performs in real market situations.

Happy trading!