Trading Strategyv6

Build and inspect a daily VWAP reversion strategy

VWAP weights a chosen bar price by that bar’s reported volume over an anchor period. It is a reference average, not a fair-value estimate or a forecast that price will return. This intraday example enters when price crosses an outer band and exits on a return across VWAP, with optional fixed percentage brackets.

The anchor and band formula are separate choices

VWAP = Σ(source × volume) / Σ(volume), accumulated from the anchor. The default source here is hlc3 = (high + low + close) / 3, so this is a bar-based estimate, not an average of every underlying transaction.

The script resets when TradingView’s daily timeframe changes. That follows the chart’s trading calendar and available session bars; it is not a hardcoded New York 09:30 reset. Extended-hours settings and the feed’s volume definition affect the result.

Band width is a multiplier times the population standard deviation of source over the last 20 bars. It is neither volume-weighted nor reset with VWAP. These are custom rolling-price bands, not the built-in VWAP indicator’s anchored deviation bands, and crossing them does not imply a known reversal probability.

See TradingView’s VWAP calculation and anchor settings and strategy order and backtest documentation.

v6 Implementation

v6
//@version=6
strategy("Pineify Daily VWAP Reversion Example", overlay=true, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=10, pyramiding=0, commission_type=strategy.commission.percent, commission_value=0.1, slippage=1, margin_long=100, margin_short=100)

source = input.source(hlc3, "Source price")
lookback = input.int(20, "Rolling price deviation bars", minval=2)
devMultiplier = input.float(2, "Deviation multiplier", minval=0.1, step=0.1, tooltip="Rolling price standard deviation, not anchored VWAP deviation")
useStopLoss = input.bool(true, "Use fixed stop loss")
stopLossPercent = input.float(1.5, "Stop loss (%)", minval=0.1, maxval=99, step=0.1)
useTakeProfit = input.bool(true, "Use fixed take profit")
takeProfitPercent = input.float(3, "Take profit (%)", minval=0.1, maxval=99, step=0.1)

if barstate.isfirst and not timeframe.isintraday
    runtime.error("This example requires an intraday chart.")

newDay = timeframe.change("1D")
vwapValue = ta.vwap(source, newDay)
priceDeviation = ta.stdev(source, lookback)
upperBand = vwapValue + priceDeviation * devMultiplier
lowerBand = vwapValue - priceDeviation * devMultiplier
longSignal = ta.crossunder(source, lowerBand)
shortSignal = ta.crossover(source, upperBand)
longReturn = ta.crossover(source, vwapValue)
shortReturn = ta.crossunder(source, vwapValue)
validBar = source > 0 and close > 0 and not na(volume) and volume > 0 and not na(vwapValue) and not na(priceDeviation)

if barstate.isconfirmed and validBar and not newDay
    if strategy.position_size == 0
        if longSignal
            strategy.entry("VWAP Long", strategy.long)
        else if shortSignal
            strategy.entry("VWAP Short", strategy.short)
    if strategy.position_size > 0 and longReturn
        strategy.close("VWAP Long", comment="Return across VWAP")
    if strategy.position_size < 0 and shortReturn
        strategy.close("VWAP Short", comment="Return across VWAP")

// These brackets are first created at the calculation after the entry fills.
if useStopLoss or useTakeProfit
    if strategy.position_size > 0
        sl = useStopLoss ? strategy.position_avg_price * (1 - stopLossPercent / 100) : na
        tp = useTakeProfit ? strategy.position_avg_price * (1 + takeProfitPercent / 100) : na
        strategy.exit("Long bracket", from_entry="VWAP Long", stop=sl, limit=tp)
    if strategy.position_size < 0
        sl = useStopLoss ? strategy.position_avg_price * (1 + stopLossPercent / 100) : na
        tp = useTakeProfit ? strategy.position_avg_price * (1 - takeProfitPercent / 100) : na
        strategy.exit("Short bracket", from_entry="VWAP Short", stop=sl, limit=tp)

plot(vwapValue, "Daily anchored VWAP", color=color.blue, linewidth=2)
p1 = plot(upperBand, "VWAP + rolling deviation", color=color.red)
p2 = plot(lowerBand, "VWAP - rolling deviation", color=color.green)
fill(p1, p2, color=color.new(color.blue, 90))

Entry, reset and bracket behavior

  1. 1

    The example requires an intraday chart and positive prices with positive reported volume on a signal bar. Missing or zero-volume bars cannot trigger entries or VWAP-cross exits. The feed may report tick volume rather than traded volume; the code cannot establish which.

  2. 2

    Signals are computed every bar and acted on at confirmed closes. Only a flat position may enter, so the opposing signal cannot automatically reverse an open position. The first bar of each daily anchor is excluded from entries and VWAP-cross exits.

  3. 3

    A long enters on a cross below the lower band, a short on a cross above the upper band. There is no reversal confirmation. A return across VWAP requests a market close, normally executed on the next tick.

  4. 4

    Stop and target switches are independent: disabling one passes na for that bracket price. Brackets based on the average fill price are first submitted at the calculation after entry fills, normally the close of the entry bar. The position is unprotected by this bracket until then. Disabling both leaves only the VWAP-cross exit.

  5. 5

    There is no forced session-end close. A position can carry overnight; the next day’s reset changes its VWAP reference. Gap losses and short-position losses can exceed a percentage stop.

Backtest Assumptions and Metrics

This tutorial supplies rules and settings, not verified returns. No reproducible dataset supports a performance figure or a claim that a filter reduces drawdown. Record the chart symbol, venue, session, timeframe, dates and all settings before comparing results.

MetricValueInterpretation
Initial capital10,000 account-currency unitsConfirm the strategy account currency in Properties.
Order size10% of equityRequested position size, not a 10% loss cap; instrument rounding can prevent small orders.
Commission / slippage0.1% per fill / 1 tickIllustrative settings; adapt fees, spread, borrowing and funding costs.
Default bracket1.5% stop / 3% targetMeasured from average entry price once the bracket is submitted; not guaranteed fill prices.
Return and drawdownNot establishedGenerate and inspect your own Strategy Tester results.

Start with standard-price candles and check the first anchor, missing-volume bars, entry fills, the delay before bracket creation, and positions carried into the next day. Compare all four stop/target switch combinations. Bar Magnifier can add lower-timeframe fill detail where available, but does not remove execution uncertainty. Hold out a later period before choosing a band multiplier or session filter.

Review the rules and exported trades

Pineify Backtest Deep Report imports a TradingView trade-list CSV for additional trade summaries. Check that prices, quantities, currency and fees match the Strategy Tester export. Closed-trade summaries cannot reconstruct missing intrabar exposure or establish live execution quality.

The AI Coding Agent can help draft changes. Compile the resulting script and inspect its orders in TradingView before treating a change as correct.

Strategy Optimization Suggestions

1

Choose a session deliberately

Compare regular and extended-session data under a written rule. A chosen hour filter needs separate evaluation; there is no supported universally best trading window.

2

Separate a band change from an anchor change

Changing lookback alters rolling price dispersion; changing the VWAP anchor changes cumulative price-volume weighting. Test these as different hypotheses.

3

Inspect adverse moves

Include days where price keeps moving away from VWAP. Review exposure, costs and gaps rather than treating a deviation crossing as proof of an eventual return.

Frequently Asked Questions

No. This example centers a rolling, unweighted price standard deviation around daily anchored VWAP. Matching the center does not make its bands equivalent to the built-in VWAP deviation calculation.

It resets VWAP when timeframe.change("1D") is true for the chart. The trading calendar and included session bars determine that boundary. It does not hardcode 09:30 New York, and it does not close positions at the end of a session.

Only that stop or target price is submitted; the other is na. With both off, no bracket is submitted. VWAP-cross market exits still operate on eligible bars. Brackets are not present before the calculation following an entry fill.

No. It requires intraday positive-price data and usable volume; feed definitions and contract sizing vary. Syntax validation does not establish fills, profitability or suitability for a particular instrument.

Check a specific rule change

Keep the original settings, change one rule, and compare the orders and costs on a separate test period. A code draft or trade report does not establish profitability.

Disclaimer: Trading involves significant risk. The strategies and code provided are for educational purposes only and do not constitute financial advice. Past performance is not indicative of future results.