Strategy #3 — VWAP-Retest Continuation (v3)

SPY 0DTE options · exact rules + independent backtest · prepared for the implementer · 2026-06-15

Backtest verdict: no durable edge SPY 0DTE · 3-min signal / 1-min fills real Alpaca data · strictly causal

TL;DR for the coder

These are the precise rules to implement (Section 1–2). I already built and backtested them on real SPY/option data, strictly causally (no look-ahead). Over 12 months the strategy is net-negative and shows no durable directional edge — so build it to verify/iterate, but don't fund it on these numbers. The single most promising change is the volume baseline (Section 5).

1. The setup, in one paragraph

On the 3-minute chart, after price makes a new high-of-day (long bias) or new low-of-day (short bias), wait for it to retrace back to VWAP. When price holds on the trade side of VWAP and a follow-through candle confirms, buy a same-day-expiry (0DTE) call (after a HOD) or put (after a LOD) to ride the continuation. Two gates must also pass: rising volume and 20/50 SMA trend agreement. Manage with a scale-out ladder and a breakeven stop on the runners.

2. Exact rules to code

2.1 Instrument & timeframes

2.2 Indicators

2.3 Entry state machine (this is the heart of it)

Direction is set by the extreme: a new HOD arms a CALL setup; a new LOD arms a PUT setup. Below is the CALL path; the PUT path is the exact mirror (retrace up to VWAP, hold below, bearish confirm).

  1. Arm. After 09:45, on every new HOD set armed=CALL and reset the retrace/hold flags.
  2. Retrace. Mark retraced=true once a candle's low reaches VWAP (price pulled back down to it).
  3. Candle 1 — hold. After the retrace, the first candle that closes above VWAP (beyond a ~3 bp buffer) is the hold candle.
  4. Candle 2 — confirm. The next candle must be bullish (close > open) and still close above VWAP.
  5. Enter at the OPEN of Candle 3 — i.e. fill on the first 1-min option print at/after candle 3's start — provided the gates in 2.4 and 2.5 pass.
  6. Invalidate: if, while waiting, any candle closes back below VWAP, the hold is broken → disarm and wait for the next new extreme. (A candle that stays above VWAP but isn't bullish just rolls the hold forward — keep waiting for a bullish confirm.)
  7. Re-arm on each new HOD/LOD; multiple trades per day allowed.
// CALL path (PUT = mirror). Per closed 3-min candle, in order:
if (new_HOD) { armed = CALL; retraced = false; hold = false; }
if (armed != CALL) continue;
if (low <= vwap) retraced = true;                       // pulled back to VWAP
above = (close - vwap)/vwap >  EPS;                     // EPS ~ 0.0003 (3 bp)
below = (vwap - close)/vwap >  EPS;
if (!hold) {
    if (retraced && above) hold = true;                 // candle 1: held above
} else {
    if (below)                       { disarm(); }       // broke back below -> dead
    else if (above && close > open) {                    // candle 2: bullish confirm
        enter_at_open_of_next_candle(CALL);              // candle 3 open  (if gates pass)
        disarm();
    }
    // else (above but not bullish): keep hold=true, re-check next candle
}

2.4 Momentum gate — volume

The confirm candle's volume must be ≥ 1.25× the average (target 1.25–1.30×, i.e. Roman's "25–30% above average"). In this build, "average" = the rolling mean of the prior 20 completed 3-min bars (causal — current bar excluded). If volume isn't expanding, skip the trade even if price held. See Section 5 — this baseline is the main thing worth changing.

2.5 Confluence gate — 20/50 SMA must agree

2.6 Strike, sizing, exits

3. Backtest results

Engine: a single causal Python backtest on real Alpaca 1-min SPY + 0DTE option premiums (no look-ahead; the entry uses only data available at candle-3's open). The key lever is the volume threshold, so it's swept.

3.1 Twelve months (2025-06-12 → 2026-06-12, 252 trading days) — the verdict

Volume gateTradesWin %Net P/LEx-top-5Green months
OFF (raw entry edge)13549%−$336−$2,6457/13
≥ 1.10× avg1527%−$1,301−$1,9292/13
≥ 1.25× avg (spec)1127%−$748−$1,2181/13
≥ 1.30× avg1127%−$748−$1,2181/13

Read it two ways, both negative. With the gate off (135 trades — the cleanest read of the raw entry) it's −$336 net but −$2,645 once you remove the 5 best trades: the near-breakeven headline is a top-5 mirage, not an edge. At the spec's 1.25× the sample collapses to ~11 trades/year that are also net-negative, green in only 1 of 13 months.

3.2 The six-month slice was a head-fake

On Dec 15 → Jun 12 alone, tightening the volume gate looked like it filtered out losers — net improved monotonically:

Volume gate (6-mo)TradesWin %Net P/LEx-top-5
OFF6346%−$1,234−$3,091
≥ 1.00×1233%−$758−$1,429
≥ 1.10×933%−$530−$876
≥ 1.25×540%+$23+$0

That +$23 is just 5 trades (remove them and nothing's left). Extending to 12 months reverses it to −$748 / 1-of-13 green months. Classic small-sample mirage — don't trust a config that only looks good on < ~30 trades.

3.3 Why so few trades — the funnel (30-day in-sample)

The gates are extremely selective. Tracing one month of setups:

528 new extremes armed
→ 81 actually retraced to VWAP
→ 66 held on the trade side
→ 37 got a directional confirm candle
→  3 passed the gates & traded   (volume gate killed 28 of 37; SMA killed 3)

So ~76% of otherwise-valid setups die at the volume gate. On 3-min bars a retrace-and-resume candle usually prints below the trailing-20-bar average, because that average is inflated by the high-volume impulse that made the extreme in the first place. The threshold is doing what it says — it's just punishing on this timeframe and baseline.

4. Honest read

5. The one lever worth trying

Re-baseline "volume" as time-of-day-normalized relative volume

The volume gate currently compares a candle to the trailing 20 bars of the same day. Intraday volume is U-shaped (heavy at the open/close, light midday), and VWAP retraces often happen midday — so the bar gets measured against an inflated average and almost always fails.

Try instead: relative volume = this 3-min bar's volume ÷ the average volume for that same clock-slot across the prior N days (e.g. the 09:51 bar vs the average 09:51 bar over the last 20 sessions). Then "25–30% above average" (RVOL ≥ 1.25–1.30) stops being a midday death sentence and starts meaning what a trader means by it. It won't fix a broken entry, but it's the cleanest way to get a real sample and a fair test of whether volume-confirmation has any signal.

Data: real Alpaca historical SPY 1-min underlying + 0DTE option 1-min premiums. Methodology: single causal clock, decisions use only bars at/before the moment of action (entry at candle-3 open); delta via Black-Scholes on the fill premium. "Ex-top-5" = net P/L after removing the five largest winners (a fragility check). Backtest/research only — not financial advice.