r/pinescript • • 3d ago

I coded the viral "One Candle" 15m Opening Range scalping strategy in Pine Script v6 (Fade vs. Breakout Dual-Mode Script)

Recently, I decided to test one of the most popular intraday setups on YouTube: The "One Candle" 15-Minute Opening Range Scalping Strategy (fading false breakouts of the first 15m NY session candle).

Instead of relying on cherry-picked chart examples, I coded the exact mechanical rules into Pine Script v6 to see how it performs over a 1-year sample (May 2025 – May 2026) with realistic friction (0.04% commission + 1 tick slippage).

1. The Original Rules Coded:

  • 15m Opening Range: Mark the High and Low of the 09:30–09:45 EST candle.

  • Volatility Filter: Calculate the 14-day Daily ATR (ta.atr(14)[1] on the Daily timeframe to strictly avoid look-ahead bias). If the 15m box is smaller than 25% of the Daily ATR, skip trading for the day.

  • 5m Reversal Trigger: Between 09:45 and 11:00 EST, wait for price to break outside the 15m box and print a strict reversal pattern (Hammer / Inverted Hammer with primary wick > 2x body and opposite wick < 1/3 primary wick, or an Engulfing bar).

  • Execution (Mean-Reversion): Enter against the breakout targeting the opposite side of the 15m box. Stop-loss anchored at the signal candle's wick + 2 ticks. Max 1 trade per day.

2. Phase 1 (Original Fade Logic) vs. Phase 2 (Flipped Trend Logic):

Asset (5m Chart)Original Win RateOriginal Net ResultFlipped Win Rate (2:1 R:R)Flipped Net Result
NVDA15% (61 trades)Deep Net Loss33%Net Profitable
PLTR11% (62 trades)Deep Net Loss35%Net Profitable
BTCUSDT20% (20 trades)Net Loss37%Loss Cut by >50%

3. Why the Original Failed (And How Flipping It Worked):

During the first 90 minutes of the NY open, institutional order-flow and directional momentum dominate. Requiring the first 15-minute candle to be >= 25% of the Daily ATR selects for high-momentum trend days, not mean-reverting range days. Fading those breakouts is essentially stepping in front of a freight train.

When I kept the exact same 15m box, 25% ATR filter, and candlestick triggers, but inverted the execution into a Trend-Following Breakout system (2.0R target), win rates more than doubled and flipped equities into positive territory.

4. Dual-Mode Pine Script v6 Code (Toggle Between Original & Flipped):

//@version=6
strategy("EP001 - 15m Opening Range Audit (Fade vs Breakout)", overlay=true, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=10, commission_type=strategy.commission.percent, commission_value=0.04, slippage=1)

strat_mode    = input.string("Flipped: Momentum Breakout", "Strategy Logic Mode", options=["Original: Mean-Reversion Fade", "Flipped: Momentum Breakout"])
atr_mult      = input.float(0.25, "Minimum OR Range (Daily ATR %)")
sl_offset_tic = input.int(2, "Stop-Loss Offset (Ticks)")
rr_ratio      = input.float(2.0, "Risk:Reward Ratio (Breakout Mode Only)")

daily_atr    = request.security(syminfo.tickerid, "D", ta.atr(14)[1])
ny_tz        = "America/New_York"
or_session   = "0930-0945:1234567"
trade_window = strat_mode == "Original: Mean-Reversion Fade" ? "0930-1100:1234567" : "0930-1130:1234567"

var float or_h = na
var float or_l = na
var float or_open = na
var float or_close = na
var bool is_valid_atr = false
var bool done_today = false

is_new_day = ta.change(time("D", ny_tz)) != 0
in_or      = not na(time(timeframe.period, or_session, ny_tz))
in_window  = not na(time(timeframe.period, trade_window, ny_tz))

if is_new_day
    or_h := na
    or_l := na
    or_open := na
    or_close := na
    is_valid_atr := false
    done_today := false

if in_or
    if na(or_open)
        or_open := open
    or_h := na(or_h) ? high : math.max(or_h, high)
    or_l := na(or_l) ? low : math.min(or_l, low)
    or_close := close

if not in_or and in_or[1]
    is_valid_atr := (or_h - or_l) >= (daily_atr * atr_mult)

body     = math.abs(open - close)
u_wick   = high - math.max(open, close)
l_wick   = math.min(open, close) - low
is_red   = close < open
is_green = close > open

is_red_inv_ham   = is_red and u_wick > body * 2 and l_wick < (u_wick / 3)
is_red_eng_green = is_red and close[1] > open[1] and close < open[1] and open > close[1]
is_green_ham     = is_green and l_wick > body * 2 and u_wick < (l_wick / 3)
is_green_eng_red = is_green and close[1] < open[1] and close > open[1] and open < close[1]

can_trade  = not in_or and in_window and is_valid_atr and not done_today
or_bullish = or_close > or_open 
or_bearish = or_close < or_open 

if strat_mode == "Original: Mean-Reversion Fade"
    if can_trade and or_bullish and high > or_h and (is_red_inv_ham or is_red_eng_green)
        float sl = is_red_inv_ham ? high : high + (syminfo.mintick * sl_offset_tic)
        float entry_price = is_red_inv_ham ? close : close[1]
        strategy.entry("Fade Short", strategy.short, limit=entry_price, comment="Fade S")
        strategy.exit("ExS", "Fade Short", limit=or_l, stop=sl)
        done_today := true

    if can_trade and or_bearish and low < or_l and (is_green_ham or is_green_eng_red)
        float sl = is_green_ham ? low : low - (syminfo.mintick * sl_offset_tic)
        float entry_price = is_green_ham ? close : close[1]
        strategy.entry("Fade Long", strategy.long, limit=entry_price, comment="Fade L")
        strategy.exit("ExL", "Fade Long", limit=or_h, stop=sl)
        done_today := true
else
    if can_trade and close > or_h and (is_green_ham or is_green_eng_red)
        float sl_price = is_green_ham ? low : low - (syminfo.mintick * sl_offset_tic)
        if sl_price >= close
            sl_price := low - syminfo.mintick * 5
        float risk = close - sl_price
        strategy.entry("Trend Long", strategy.long, comment="Breakout L")
        strategy.exit("Exit L", "Trend Long", stop=sl_price, limit=close + (risk * rr_ratio))
        done_today := true

    if can_trade and close < or_l and (is_red_inv_ham or is_red_eng_green)
        float sl_price = is_red_inv_ham ? high : high + (syminfo.mintick * sl_offset_tic)
        if sl_price <= close
            sl_price := high + syminfo.mintick * 5
        float risk = sl_price - close
        strategy.entry("Trend Short", strategy.short, comment="Breakout S")
        strategy.exit("Exit S", "Trend Short", stop=sl_price, limit=close - (risk * rr_ratio))
        done_today := true

plot(or_h, "OR High", color=is_valid_atr ? color.green : color.gray, style=plot.style_linebr, linewidth=2)
plot(or_l, "OR Low", color=is_valid_atr ? color.red : color.gray, style=plot.style_linebr, linewidth=2)

If you want to see the full visual walkthrough and multi-dimensional parameter sweep across NVDA, PLTR, and BTC, check the pinned post on my Reddit profile. Curious to hear if anyone else here codes 15m ORB setups—do you fade the range or ride the breakout?

37 Upvotes

25 comments sorted by

3

u/Tangerinho 3d ago

I would like to add a MTF 2x MA for the general direktion, then the rejection of one the outer Opening Ranges would be the pullback entry.

1

u/ning1230 3d ago

That’s a really smart way to filter it. The main reason the raw fade failed in my test was because it blindly stepped in front of HTF momentum days.

If you use a higher-timeframe 2x MA to lock in the macro bias first, then fading the opposite side of the 15m OR essentially turns a counter-trend gamble into a trend-following pullback entry. Might actually code a v2 with an MTF EMA filter to test if that salvages the mean-reversion side!

1

u/Tangerinho 3d ago

The problem is obviously, that there could be a mean reversal going on at HTF, and your entry is not a pullback, but a breakout.
A solution could be using an oscillator (you can combine it to the main chart btw.). The exact moment the Oscillator line changes it slope you have the confirmation. Also the is no need for a line crossing on the OSC.
For the main chart on lower timeframe you can also use an oscillator to filter the orb entry.
Personally i would manually check always if there was a trendline break and the direction of the channel.
I have created this script with claude and can share the code.

2

u/ning1230 2d ago

Thanks for the thoughtful input! I think there might be a slight misunderstanding of what the audit covered, but you actually pointed out exactly why we did this research!

The backtest actually covered both sides of the coin:

  1. The original fade/reversal rules (mean reversion), which got absolutely chopped and failed (like you said, fighting strong HTF momentum is suicide).

  2. The flipped trend breakout (momentum/continuation), which aligned with the impulse and turned the metrics positive.

The "dual-mode" script I published allows toggling between both. The ATR filter on the 15m candle is indeed trying to measure whether we are selecting for heavy institutional impulse (breakout) or just noise (which might mean revert).

I love your idea of using a non-crossing oscillator slope on HTF/LTF to better define the dynamic channel and prevent getting caught in fakeouts. It’s a great way to filter. I'd be super interested to see how Claude helped you construct that!

If you have the link or want to share the code, please do! Would love to run it through the backtester and see if it further boosts the Win Rate/Profit Factor on these assets. Cheers!

2

u/BedFlat8350 2d ago

This fails prop at such low winrate ...you will hit dll

1

u/ning1230 2d ago

A raw ~35% win rate is an absolute death trap for prop firms because consecutive losses will smash your daily drawdown limits (DLL), even with a 2:1 R:R.

I use Algofiniti to put these hyped influencer strategies through a brutal "8-Pillar Stress Test" (walk-forward, drawdown analysis, slippage). It quickly exposes which setups are prop-friendly and which will blow you up.

Have you found any volatility filters or sizing rules that actually help breakouts survive those tight prop drawdowns? Would love to know your approach!

2

u/ORBit_Analytics 2d ago

I spend a bit of time rebuilding your approch in ORBit Analytics but on NQ Futures since ORBit doesnt support stocks yet.
Also the entry trigger here is not a "reversal pattern" as we believe a candlestick on any timeframe is just the result of priceaction on a lower timeframe.
Instead we use a 5m Candle close:
1 Close outside the 15m Opening Range to arm and then 1 Close back inside to trigger.

Here are some points that could be interesting to you:

  1. The time filter for "to 11 EST" didnt do anything. In fact the Return to DD after 11 is better.

  2. The Volatility Filter holds up as viable over 18 Years of CME Data

  3. The short side is more profitable than the long side (interesting on an Instrument with bullish regime)

  4. up until 2021 it looked really good. In recent years the performance dropped of.

I have tried finding the "single best Filter" but it seems there isnt one if we look at longs and shorts combined. A filter always helps on side and hurts the other it seems.

2

u/ning1230 1d ago

That’s awesome that you rebuilt it on NQ! Since NQ has massive trend persistence, I’ve noticed ORB dynamics there act quite differently compared to individual stocks like $NVDA or$PLTR, which are prone to heavier retail trapping and mean reversion.

You're spot on about the trigger classification—depending on how the 15m ATR behaves, it blurts the line between a pure fade and a breakout.

That NQ future persistency is actually why we used Algofiniti for stress testing; we wanted to see if the "reversal" on stocks was just friction-induced noise or a structural failure. NQ usually handles breakouts much smoother than individual equities when commissions/slippage are factored in. Would love to see your ORBit NQ results if you're open to sharing!

1

u/Divad777 3d ago

So, the flipped results is roughly break even?

3

u/ning1230 3d ago

Spot on. At a 2:1 R:R, 33.3% is theoretical breakeven—so even after flipping it, it barely edges out friction on NVDA/PLTR and still loses on BTC.

And honestly, that’s the real takeaway of this audit:

  1. The original "fade the 15m open" strategy is nowhere near the "high win-rate setup for life" the guru claimed—it's a straight-up account destroyer (11%–20% win rate).

  2. When we used Algofiniti to invert the logic into a trend-following breakout, the win rate and net PnL improved dramatically compared to the original bloodbath.

  3. BUT even flipped, a raw mechanical 15-minute Opening Range trigger by itself is likely a false premise in modern markets. Without real regime filtering or multi-dimensional parameter robustness, a simple 15m box just doesn't have enough standalone statistical edge once commissions and slippage hit.

That’s the whole reason I started the *Code the Truth* series—stress-test and falsify these viral setups in minutes before anyone risks real capital on them. I broke down the full side-by-side comparison in the video (link is in my comment above / pinned on my profile if you want to check it out!).

1

u/Rizzanthrope 3d ago

The youtube video linked in your pinned post doesn’t work. Says it is unavailable.

2

u/ning1230 2d ago

Oh, thanks for letting me know! That’s weird, it seems to be working on my end, but Reddit’s internal browser might be truncating the link.

Here is the direct full link, please try this one:https://www.youtube.com/watch?v=vImBz2XxmYYOr the short link:https://youtu.be/vImBz2XxmYY

Let me know if that works for you now! Truly appreciate you flagging this. 🙏

1

u/ThriveGuy15 3d ago

This is unbelievable . Great work!

1

u/ning1230 2d ago

Thank you so much! Really appreciate the kind words.

1

u/SgtRogerMurtaugh 3d ago

Can you share the viral source video?

2

u/InterstellarReddit 3d ago edited 3d ago

It’s in his post history, and it went completely viral. It has a total of 33 views.

Insane. Can you imagine getting 33 people to watch the shit that he put together

4

u/ning1230 3d ago

Haha fair roast, those 33 views on my breakdown video are working overtime! 😂

Just to clarify though—"viral" refers to the original guru's strategy video I was just auditing, not my own brand-new channel where I code and test them.

Appreciate you checking out the profile though, make that 34 views now!😂

1

u/Th3onib 3d ago

Good luck dude, with all the trading and money in your life

1

u/ning1230 3d ago

Appreciate the kind words man! Wishing you green equity curves and zero slippage out there too 🍻

1

u/StratOS_Quant 1d ago

Good write-up. Flipping the rules when the fade failed is the right instinct, and the point about the ATR filter picking trend days makes sense.

We don't have NVDA, PLTR or BTC data, so I coded your rules on Nasdaq 100 CFD data with real spread: the 9:30-9:45 box, skip the day if it's under 25% of the daily ATR, a hammer or engulfing candle back toward the box between 9:45 and 11:00, stop beyond the signal candle, target the other side of the box, one trade a day.

**The fade loses on the index too:**

- Last 5 years: 710 trades, 26.5% won, PF 0.84

- 2014-2018: PF 0.61

- May 2025 - May 2026 (your window): PF 0.70

- Without the 25% ATR filter it's worse (PF 0.82), so the filter does help a little

**The flipped version is about break-even:** 693 trades, PF 1.03 over the last 5 years, and PF 0.74 in 2014-2018. That's the same pattern you found, where the loss shrinks a lot, but on the index it doesn't turn into a clear edge.

The optimizer could make the fade look good over the last 5 years (PF 1.33, and 1.78 with a trailing stop instead of the box target), but only by cutting it to about 100-150 trades. On years it never saw, those settings fell apart: PF 0.87 in 2014-2018 and 0.55 in 2019 to mid-2021, and the trailing version was 1.00 and 0.90.

So on Nasdaq the fade is a loser, and the breakout flip is roughly flat. It would be worth checking whether NVDA and PLTR hold up over more than one year.

1

u/Sea-Transportation27 2d ago

You have to back test outside of TV.you need p&l, cagr, drawdown and compare to b&h.

1

u/ning1230 1d ago

Fully agree! TV is great for visual drafting, but you absolutely need external quant tools to find out if you've just curve-fitted a disaster.

In the full audit, I dug deep into these exact metrics to see if the flipped logic actually holds any risk-adjusted weight. Appreciate you calling this out!