Skip to content

Pivot points: 85,701 trades show they are coin flips

Textbook floor-pivot breakouts and bounces on every NIFTY 50 stock since 2016. Before costs, the breakout earns +1.3 bps and the bounce at the same level loses 1.3 bps. After costs, both lose crores.

Breakout
85,701 trades · 2016–2026−₹2.21 Cr
Verdict

Breakout −₹2.21 Cr, bounce −₹3.36 Cr. The two are mirror images, and both lose every year.

Floor pivots are on almost every Indian trading chart. From yesterday’s high (H), low (L) and close (C):

  • P = (H + L + C) / 3
  • R1 = 2P − L, S1 = 2P − H
  • R2 = P + (H − L), S2 = P − (H − L)

Textbooks give two ways to trade them, and we tested both exactly:

  • Breakout: buy when price breaks above R1 (stop at P, target R2); sell when it breaks below S1 (stop at P, target S2).
  • Bounce: buy the first touch of S1 (stop at S2, target P); sell the first touch of R1 (stop at R2, target P).

The order rests at the level and fills there (or at the open if price gaps through). Only the first touch counts, and the day must have opened on the other side of the level. One trade per stock per day, ₹5 lakh per trade, every NIFTY 50 stock, January 2016 to August 2026.

85,701
level touches traded
each strategy
+1.3 bps
breakout, gross edge per trade
costs ~6.5 bps
−1.3 bps
bounce, gross edge per trade
losing before costs
−₹5.6 Cr
both, after costs
₹5 lakh per trade

The breakout and the bounce are the same trade, reversed

Look at what each strategy does at R1. The breakout buys when price touches R1 from below. The bounce sells when price touches R1 from below. Same level, same moment, opposite direction. The same holds at S1. So both strategies trade exactly the same 85,701 touches, and their gross results are almost exact mirror images: +1.32 bps for the breakout, −1.35 bps for the bounce. (They aren’t exact opposites because the stops and targets sit at different levels.)

That mirror is the finding. If pivot levels carried real information, one side would earn a meaningful edge and the other would lose it. Instead the price after a touch is close to a coin flip: a basis point or so either way, against a round-trip cost of about 6.5 bps.

Cumulative P&L after costs (₹5 lakh per trade)Breakout (R1/S1 → R2/S2)Bounce (S1/R1 → P)
−₹4Cr−₹3Cr−₹2Cr−₹1Cr₹0₹1Cr201620182020202220242026

Both lose steadily in every period. Hover or tap for values.

Every year, both ways

Neither strategy had a single profitable year, and neither turned profitable in 2024–26.

Breakout: net P&L by yearProfitLoss
−₹40L−₹30L−₹20L−₹10L₹02016: −₹19.7 L net, 7,958 trades, 50% winners'162017: −₹32.3 L net, 8,148 trades, 47.6% winners'172018: −₹26.3 L net, 8,144 trades, 50.3% winners'182019: −₹18.4 L net, 8,173 trades, 50.2% winners'192020: −₹16.1 L net, 7,927 trades, 51.2% winners'202021: −₹16.8 L net, 8,063 trades, 50.9% winners'212022: −₹16.9 L net, 7,789 trades, 50.4% winners'222023: −₹25.4 L net, 8,077 trades, 48.6% winners'232024: −₹21.3 L net, 8,104 trades, 49.4% winners'242025: −₹19.7 L net, 8,233 trades, 49.3% winners'252026: −₹8.5 L net, 5,085 trades, 48.8% winners'26
Show as table
YearTradesNetWin %
20167,958−₹19.7 L50
20178,148−₹32.3 L47.6
20188,144−₹26.3 L50.3
20198,173−₹18.4 L50.2
20207,927−₹16.1 L51.2
20218,063−₹16.8 L50.9
20227,789−₹16.9 L50.4
20238,077−₹25.4 L48.6
20248,104−₹21.3 L49.4
20258,233−₹19.7 L49.3
20265,085−₹8.5 L48.8
VariantTradesGross / tradeWin %Net after costs+3 bps slippage2016-202021-232024-26
Breakout: R1/S1, stop P, target R2/S285,7011.3 bps49.7%−₹2.21 Cr−₹4.78 Cr−₹1.13 Cr−₹59.1 L−₹49.6 L
Bounce: S1/R1, stop S2/R2, target P85,701−1.4 bps47.1%−₹3.36 Cr−₹5.92 Cr−₹1.50 Cr−₹96.3 L−₹89.3 L

₹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.

Why pivots feel like they work

Pivots are drawn from yesterday’s range, and most days trade inside a range of a similar size, so prices really do reach R1 and S1 often and frequently turn near them. On a chart that looks like the levels “hold”. But a level that price often turns at is not the same as a level where turning is more likely than continuing. Across 85,701 touches, it isn’t.

Win rates sit near 50% for the breakout (49.7%) and the bounce (47.1%), close to what you’d expect from noise once the stop and target distances are taken into account.

What to take from this

  • Test both directions at a level. If a breakout and the fade at the same level both look weak, the level is probably noise.
  • On liquid large caps, chart levels are fairly priced. An edge of ±1 bps is invisible next to a round trip of about 6.5 bps.
  • “It held again” is how a coin flip feels. You remember the turns at R1 and forget the breakouts through it.
The exact code we ranpivot() in dpx_bt · 2 variants · snapshot v2026.08
def pivot(setup='breakout'):
    """breakout: resting buy stop at R1 (sell stop at S1), stop at P, target R2 (S2).
    bounce:   resting buy limit at S1 (sell limit at R1), stop S2 (R2), target P.
    Only the first touch counts and the day must have opened on the other side of the level."""
    def strategy(p):
        lv = _pivots(p)
        o = p.day_open
        if setup == 'breakout':
            up, dn = lv['R1'], lv['S1']
            long = (p.high >= up) & (o < up)
            short = (p.low <= dn) & (o > dn)
            ep_l, ep_s = np.maximum(up, p.open), np.minimum(dn, p.open)
            stop_l, stop_s = (ep_l - lv['P']) / ep_l, (lv['P'] - ep_s) / ep_s
            tgt_l, tgt_s = (lv['R2'] - ep_l) / ep_l, (ep_s - lv['S2']) / ep_s
        else:
            up, dn = lv['R1'], lv['S1']
            long = (p.low <= dn) & (o > dn)
            short = (p.high >= up) & (o < up)
            ep_l, ep_s = np.minimum(dn, p.open), np.maximum(up, p.open)
            stop_l, stop_s = (ep_l - lv['S2']) / ep_l, (lv['R2'] - ep_s) / ep_s
            tgt_l, tgt_s = (lv['P'] - ep_l) / ep_l, (ep_s - lv['P']) / ep_s
        first = p.once_per_day(long | short)
        long, short = long & first, short & first
        ep = ep_l.where(long, ep_s)
        stop = stop_l.where(long, stop_s).clip(lower=0.0005)
        tgt = tgt_l.where(long, tgt_s).clip(lower=0.0005)
        return bt.Signals(long=long, short=short, entry_price=ep, stop=stop, target=tgt)
    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.