Skip to content

We followed a popular ORB strategy guide to the letter on 10 years of NIFTY 50 data

Opening range breakout with an EMA trend filter, full-body candles and volume confirmation. 23,666 trades, ₹23.7 lakh lost after costs, and none of 8 variants made money.

As written
23,666 trades · 2016–2026−₹23.7 L
Verdict

23,666 trades, −₹23.7 lakh after costs. 0 of 8 variants profitable.

The opening range breakout (ORB) is probably the most taught intraday strategy. One widely shared guide adds three filters to the basic idea, each meant to cut out false breakouts, and quotes win rates of 42–65%. We followed it exactly on every NIFTY 50 stock from January 2016 to August 2026.

The rules, as written:

  1. Range: the high and low of the first 30 minutes (09:15–09:45).
  2. Trend: long only when the 50 EMA is above the 200 EMA and the candle closes above both (15-minute chart); short only in the mirror case.
  3. Entry: a 15-minute candle closes beyond the range, with a full body (at least 60% of its range) in the breakout direction and volume at least 1.5× the average of the previous 20 candles.
  4. Exit: stop at the far end of the breakout candle, target 2× the risk, anything open is closed at 15:15.

One trade per stock per day, ₹5 lakh per trade, entered at the next bar’s open after the candle closes.

23,666
trades
Jan 2016 – Aug 2026
41.2%
win rate
the guide quotes 42–65%
+4.5 bps
gross edge per trade
costs are ~6.5 bps
−₹23.7 L
net after costs
−₹95 L with +3 bps slippage
Cumulative P&L, rules as written (₹5 lakh per trade)Net of costsWith +3 bps slippage
−₹1Cr−₹80L−₹60L−₹40L−₹20L₹0₹20L201620182020202220242026

Weekly cumulative net P&L. Hover or tap for values.

It isn’t one bad year

Ten of the eleven years lost money, mostly ₹2–4 lakh each. The one exception was 2020, a year of unusually large daily moves, which made ₹3.5 lakh (about ₹140 per trade). Every year since has lost money again.

Net P&L by year, rules as writtenProfitLoss
−₹6L−₹4L−₹2L₹0₹2L₹4L2016: −₹4.2 L net, 2,212 trades, 42.1% winners'162017: −₹4.3 L net, 2,295 trades, 40.8% winners'172018: −₹3.9 L net, 2,369 trades, 40.7% winners'182019: −₹40,599 net, 2,353 trades, 41.3% winners'192020: ₹3.5 L net, 2,568 trades, 41.9% winners'202021: −₹3.4 L net, 2,441 trades, 41.1% winners'212022: −₹1.2 L net, 1,947 trades, 42.3% winners'222023: −₹3.4 L net, 2,164 trades, 38.9% winners'232024: −₹8,471 net, 2,205 trades, 42.7% winners'242025: −₹2.7 L net, 1,876 trades, 40.1% winners'252026: −₹3.7 L net, 1,236 trades, 40.4% winners'26
Show as table
YearTradesNetWin %
20162,212−₹4.2 L42.1
20172,295−₹4.3 L40.8
20182,369−₹3.9 L40.7
20192,353−₹40,59941.3
20202,568₹3.5 L41.9
20212,441−₹3.4 L41.1
20221,947−₹1.2 L42.3
20232,164−₹3.4 L38.9
20242,205−₹8,47142.7
20251,876−₹2.7 L40.1
20261,236−₹3.7 L40.4

The filters help, just not enough

The guide’s filters do what they claim: each one improves the average trade. Remove all three and the gross edge falls from 4.5 to 2.3 bps per trade while the number of trades grows 4.6 times, and the loss grows almost tenfold, to −₹2.27 crore. The breakouts it picks are also better than a random NIFTY 50 stock traded at the same minute in the same direction (+4.5 vs +3.0 bps).

The problem is size. A ₹5 lakh round trip costs about 6.5 bps (brokerage, STT, exchange fees, stamp duty, GST and 1 bp of slippage on each fill; see how we count costs). An edge of 4.5 bps before costs is a loss of about 2 bps after them, on every trade.

Average gross edge per trade, before costs (bps)
As written4.5 bps
No trend filter4.0 bps
No volume filter2.7 bps
No trend, no volume, no body filter2.3 bps
15-min range3.1 bps
Target 1R2.0 bps
Target 3R5.9 bps
30-min candles6.4 bps

No variant earns more before costs than a round trip costs (~6.5 bps).

Eight variants, none profitable

We changed one thing at a time: dropped each filter, used a 15-minute range, moved the target to 1R or 3R, and used 30-minute candles. These were decided before running anything. Here is every result:

VariantTradesGross / tradeWin %Net after costs+3 bps slippage2016-202021-232024-26
As written: 30-min range, 15-min candle, trend + full body + volume, 2R23,6664.5 bps41.2%−₹23.7 L−₹94.5 L−₹9.2 L−₹8.0 L−₹6.4 L
No trend filter39,6274.0 bps40.9%−₹50.0 L−₹1.69 Cr−₹16.4 L−₹19.6 L−₹14.0 L
No volume filter55,4362.7 bps38.8%−₹1.06 Cr−₹2.72 Cr−₹44.4 L−₹32.5 L−₹28.8 L
No trend, no volume, no body filter1,08,1822.3 bps38.0%−₹2.27 Cr−₹5.51 Cr−₹86.8 L−₹74.0 L−₹65.8 L
15-min range27,9403.1 bps40.6%−₹47.3 L−₹1.31 Cr−₹20.0 L−₹15.3 L−₹12.0 L
Target 1R23,6662.0 bps49.6%−₹53.0 L−₹1.24 Cr−₹25.6 L−₹16.5 L−₹10.9 L
Target 3R23,6665.9 bps39.5%−₹7.4 L−₹78.3 L₹22,345−₹2.2 L−₹5.5 L
30-min candles13,9616.4 bps44.3%−₹73,727−₹42.6 L−₹73,779₹79,841−₹79,788

₹5 lakh per trade, 5-minute bars, v2026.08 snapshot (Jan 2016 – Aug 2026), NIFTY 50 point-in-time members, discount-broker (₹20/order) and statutory charges + 1 bp slippage per fill. Generated 2026-10-07.

The closest to break-even was the 30-minute candle version: −₹74,000 over 13,961 trades, about −₹5 per trade. It made ₹0.8 lakh in 2021–23 and lost in 2016–20 and 2024–26. It’s tempting to call that “the version that works”. It isn’t. We’d be choosing it after seeing eight results, it didn’t make money over the full period, and three basis points of extra slippage per fill turn it into a ₹43 lakh loss.

What to take from this

  • A filter that improves win rate or edge is not the same as a filter that makes money. Check whether the edge per trade clears the cost of a round trip.
  • Quoted win rates mean little on their own. At 2R targets a 41% win rate loses money after costs here. What matters is the average gain per trade compared with the average cost.
  • Breakouts on NIFTY 50 stocks are close to fairly priced at this horizon. The gross edge of a well-filtered ORB is a few basis points: real, but smaller than costs.
The exact code we ranorb_pdf() in dpx_bt · 8 variants · snapshot v2026.08
def orb_pdf(or_min=30, chart=15, trend=True, full_body=True, vol=1.5, r=2.0):
    """Range = first `or_min` minutes. Signal = a `chart`-minute candle CLOSES beyond the range; optional EMA50/200
    trend filter (on chart candles), full-body candle (body >= 60% of range), volume >= vol x 20-candle average.
    Stop at the far end of the breakout candle, target r x risk, one trade per stock per day."""
    def strategy(p):
        c = p.candles(chart)
        cl = p.candle_series(c, 'close')
        cv = p.candle_series(c, 'volume')
        o, h, l, cc, v = c['open'], c['high'], c['low'], c['close'], c['volume']
        orh, orl = p.opening_range(or_min)
        long, short = cc > orh, cc < orl
        if full_body:
            body, rng = (cc - o).abs(), (h - l)
            long &= (cc > o) & (body >= 0.6 * rng)
            short &= (cc < o) & (body >= 0.6 * rng)
        if vol:
            vavg = cv.rolling(20).mean().shift(1).reindex(p.index)
            long &= v >= vol * vavg
            short &= v >= vol * vavg
        if trend:
            e50 = cl.ewm(span=50, adjust=False).mean().reindex(p.index)
            e200 = cl.ewm(span=200, adjust=False).mean().reindex(p.index)
            long &= (e50 > e200) & (cc > e50) & (cc > e200)
            short &= (e50 < e200) & (cc < e50) & (cc < e200)
        first = p.once_per_day(long | short)
        risk = ((cc - l) / cc).where(long, (h - cc) / cc).clip(lower=0.001)
        return bt.Signals(long=long & first, short=short & first, stop=risk, target=r * risk)
    return strategy

Every variant in this post is this function with different arguments, run through dpx_bt over Jan 2016 – Aug 2026.

Try a variation of this test in Ask

Have a variation in mind?

Ask runs your own idea on the same data and rules, with the same report: net after costs, +3 bps stress test, three periods.

Try Ask

Backtest on historical data (Jan 2016 – Aug 2026), net of discount-broker (₹20 per order) and statutory charges and 1 bp slippage per fill. Education and research only, not investment advice. Past results do not predict future returns. Disclaimer.