TradingView strategy research

Two-bar reversal: body overlap, extremes and follow-through

A two bar reversal pairs opposite candle bodies around a similar price area: a falling body followed by a rising body for a bullish candidate, or the reverse for a bearish candidate. The name alone leaves overlap, size and entry timing undefined. This page specifies a symmetric research rule with at least 75% body overlap, nearby reversal extremes and a second close near the directional end of its range. It does not require the second body to engulf the first.

See the decision guide

A quantified version, with its own assumptions

Galen Woods describes opposite directional bars, overlap and context, then offers guidelines based on typical price. The specification below is an independent body-interval version, not his exact method or a universal definition. Its numerical thresholds are research choices. Use standard OHLC candles and keep the symbol, interval and session fixed when comparing signals.

  • The baseline uses no preceding-trend filter. It can identify a pair within a range. An optional context filter requires three strictly descending closes before bar 1 for a bullish candidate, or three strictly ascending closes for a bearish candidate.
  • The context closes are C[-3], C[-2], C[-1] when the first pattern candle is bar 1. They must all exist. An equal close fails the strict trend test. This short sequence does not establish a major market trend.

Body overlap and mirrored reversal rules

Number the older candle 1 and the newer candle 2. For each candle, body B = abs(C - O), range R = H - L, body low A = min(O, C), and body high Z = max(O, C). Shared body length I = max(0, min(Z1, Z2) - max(A1, A2)). Overlap = I / max(B1, B2). Using the larger body prevents a tiny enclosed body from scoring 100%.

  • Threshold equality passes for overlap, body fraction, extreme tolerance and close location. The follow-through close must exceed the relevant extreme by at least one tick; a touch fails.
  • A doji or zero-range candle fails before division. Touching body endpoints have zero shared length. Gaps are allowed only if the resulting pair still passes every test; there is no automatic gap exception.
  • The script converts OHLC to integer tick counts. Percentage tests use multiplication, so 75% is tested as 100 × shared length >= 75 × larger body, without rounding the displayed ratio first.
TestBullish pairBearish pair
DirectionC1 < O1 and C2 > O2C1 > O1 and C2 < O2
Size and overlapB1/R1 >= 0.50, B2/R2 >= 0.50, overlap >= 0.75Same three thresholds
Nearby extremesabs(L2 - L1) <= 0.10 × max(R1, R2)abs(H2 - H1) <= 0.10 × max(R1, R2)
Second close location(C2 - L2)/R2 >= 0.75(C2 - L2)/R2 <= 0.25
Optional next-bar follow-throughC3 > H2 and L3 > stopC3 < L2 and H3 < stop
Fixed protective stopmin(L1, L2) minus one tickmax(H1, H2) plus one tick

Complete OHLC fixtures, including a valid non-engulfing pair

Each row is an independent synthetic pair, with prices in dollars and a $0.01 tick. Tuples are (open, high, low, close). Use the default thresholds and disable the optional context filter. These fixtures test detection; they are not historical trades.

  • For the first row, body fractions are 5/7 = 71.43% and 4/5.5 = 72.73%. Both exceed 50%. Bar 2 body [100.5, 104.5] sits inside bar 1 body [100, 105], so it is not a bullish body engulfing.
  • Body engulfing asks whether the second real body contains the first, with a separately chosen equality convention. A two-bar reversal can overlap that category, but this rule also accepts partial or contained overlap. Conversely, an engulfing candle can fail the extreme-distance or closing-position tests here.
FixtureBar 1 OHLCBar 2 OHLCExpected result
Bullish, contained second body(105, 106, 99, 100)(100.5, 105, 99.5, 104.5)Pass: overlap 4/5 = 80%; low difference 0.5 <= 0.7; close location 5/5.5 = 90.91%.
Bearish mirror(100, 106, 99, 105)(104.5, 105.5, 100, 100.5)Pass: overlap 80%; high difference 0.5 <= 0.7; close location 0.5/5.5 = 9.09%.
Exact overlap boundary(105, 106, 99, 100)(100.5, 105, 99.5, 104.25)Pass: 3.75/5 = 75%.
One tick short(105, 106, 99, 100)(100.5, 105, 99.5, 104.24)Reject: 3.74/5 = 74.8%, although the other tests pass.
Extreme too distant(105, 106, 99, 100)(100.5, 105, 98.2, 104.5)Reject: low difference 0.8 > 0.7, despite 80% body overlap.
Weak close(105, 106, 99, 100)(100.5, 106.5, 99.5, 104.5)Reject: close location 5/7 = 71.43%, despite sufficient body size.
Doji(105, 106, 99, 100)(103, 105, 99.5, 103)Reject: second body is zero.
Zero range(105, 106, 99, 100)(103, 103, 103, 103)Reject before ratios are evaluated.
Upward gap with no overlap(105, 106, 99, 100)(107, 112, 106.5, 111)Reject: shared body length is zero.

Confirmation, expiry and a losing follow-through trade

With follow-through disabled, the first bullish fixture creates an entry at bar 2 close for the next available tick. With follow-through enabled, it only arms a candidate. Exactly bar 3 must close above $105.00 and keep its low above the frozen $98.99 stop. If it fails, the candidate expires; later rallies cannot revive it.

  • The signal-close distance 105.50 - 98.99 = $6.51 is not the realized loss. The next open, entry slippage, stop slippage and commissions produce the $6.65 result.
  • Reflection around 205 gives a bearish follow-through bar (100.4, 105, 99, 99.5), then (99.4, 106.5, 99, 106). The short fills at 99.39, stops at 106.02 and also loses $6.65 after fees.
  • A price gap through an active stop can cause a worse exit. A gap after the entry decision does not cancel this market order. The follow-through low/high check only covers bar 3, which has already completed.
EventOHLC or calculationState / result
Bar 2 closeUse the first bullish fixture above.Arm long; reference high 105.00; stop 98.99. No order yet.
Bar 3(104.6, 106, 100, 105.5)At its close, follow-through passes. Submit one-unit buy and linked stop.
Bar 4(105.6, 106, 98.5, 99)Illustrative next-open entry 105.61; later stop fill 98.98.
Costs(98.98 - 105.61) × 1 - 2 × 0.01Net loss $6.65 for one share with $0.01 fee per side and one adverse tick per fill.
Independent failed follow-throughBar 3 = (104.6, 106, 100, 105)High breaks 105, but close only touches it. Expire without a trade.
Independent invalidationBar 3 = (104.6, 106, 98.9, 105.5)Reject despite closing above 105: low breached the prospective stop before entry.

Pine Script v6 strategy: one pending pair, one position

Paste the complete script into Pine Editor on a standard candlestick chart. Defaults enable next-bar follow-through and disable the prior-close context filter. The strategy trades one unit, freezes the pair stop and submits a time exit after three held bars if protection has not closed the trade. It has no profit target. Pattern labels include candidates that cannot be traded while another candidate or position is active.

  • One pending candidate owns its next bar. That bar cannot also arm another pair, whether follow-through passes or fails. Signals while in a position or on a bar where a trade closed are ignored. There is no pyramiding or automatic reversal.
  • For entry on bar 4, held-bar counts are 1 at bar 4 close, 2 at bar 5 close and 3 at bar 6 close. The default time exit is then submitted and normally fills at bar 7 open. The protective stop stays active in the meantime.
  • Keep the shown calculation settings for this experiment. Orders are created after a completed candle; market fills normally occur at the next open. The next available bar may follow a session break. Historical intrabar paths remain execution assumptions.
  • The one-unit size, USD account, one-cent per-unit fee and one-tick slippage are examples. Set costs, quantity and capital for the instrument, including contract point value where applicable. Borrow fees, funding and changing spreads are not modeled.
Original educational implementation of this page specification. A syntax check validates compilation, not predictive value or broker execution.pine
//@version=6
strategy("Two-bar reversal: overlap and follow-through", overlay = true,
     initial_capital = 100000, currency = currency.USD, pyramiding = 0,
     default_qty_type = strategy.fixed, default_qty_value = 1,
     commission_type = strategy.commission.cash_per_contract, commission_value = 0.01,
     slippage = 1, process_orders_on_close = false,
     calc_on_every_tick = false, calc_on_order_fills = false)

int overlapPct = input.int(75, "Minimum body overlap %", minval = 1, maxval = 100)
int extremePct = input.int(10, "Extreme tolerance % of larger range", minval = 0, maxval = 100)
bool followThrough = input.bool(true, "Require next-bar closing follow-through")
bool contextFilter = input.bool(false, "Require three prior directional closes")
int holdBars = input.int(3, "Held bars before time exit", minval = 1)
float tick = syminfo.mintick
float o = math.round(open / tick)
float h = math.round(high / tick)
float l = math.round(low / tick)
float c = math.round(close / tick)
float body = math.abs(c - o)
float span = h - l
float shared = math.max(0, math.min(math.max(o, c), math.max(o[1], c[1])) -
     math.max(math.min(o, c), math.min(o[1], c[1])))
float largeBody = math.max(body, body[1])
float largeRange = math.max(span, span[1])
bool valid = barstate.isconfirmed and bar_index >= 1 and
     span > 0 and span[1] > 0 and body > 0 and body[1] > 0
bool sizeOK = body * 2 >= span and body[1] * 2 >= span[1]
bool overlapOK = 100 * shared >= overlapPct * largeBody
bool downContext = bar_index >= 4 and c[4] > c[3] and c[3] > c[2]
bool upContext = bar_index >= 4 and c[4] < c[3] and c[3] < c[2]
bool bull = valid and sizeOK and overlapOK and c[1] < o[1] and c > o and
     100 * math.abs(l - l[1]) <= extremePct * largeRange and
     100 * (c - l) >= 75 * span and (not contextFilter or downContext)
bool bear = valid and sizeOK and overlapOK and c[1] > o[1] and c < o and
     100 * math.abs(h - h[1]) <= extremePct * largeRange and
     100 * (c - l) <= 25 * span and (not contextFilter or upContext)

var int pending = 0
var int pairBar = na
var float pendingExtreme = na
var float pendingStop = na
var float activeStop = na
bool closedHere = strategy.closedtrades > nz(strategy.closedtrades[1])
int orderSide = 0
float orderStop = na

if barstate.isconfirmed
    if strategy.position_size != 0
        pending := 0
        int held = bar_index - strategy.opentrades.entry_bar_index(0) + 1
        if held >= holdBars
            strategy.close_all(comment = "Time exit")
    else
        activeStop := na
        if closedHere
            pending := 0
        else if pending != 0
            bool onNextBar = bar_index == pairBar + 1
            bool confirms = pending == 1 ? c >= pendingExtreme + 1 and l > pendingStop :
                 c <= pendingExtreme - 1 and h < pendingStop
            if onNextBar and confirms
                orderSide := pending
                orderStop := pendingStop * tick
            pending := 0
        else if bull or bear
            int side = bull ? 1 : -1
            float pairStop = bull ? math.min(l[1], l) - 1 : math.max(h[1], h) + 1
            if followThrough
                pending := side
                pairBar := bar_index
                pendingExtreme := bull ? h : l
                pendingStop := pairStop
            else
                orderSide := side
                orderStop := pairStop * tick

    if orderSide == 1
        activeStop := orderStop
        strategy.entry("Long", strategy.long)
        strategy.exit("Long stop", "Long", stop = orderStop)
    else if orderSide == -1
        activeStop := orderStop
        strategy.entry("Short", strategy.short)
        strategy.exit("Short stop", "Short", stop = orderStop)

plotshape(bull, title = "Bullish pair", text = "2BR+", style = shape.labelup,
     location = location.belowbar, color = color.green, textcolor = color.white, size = size.tiny)
plotshape(bear, title = "Bearish pair", text = "2BR-", style = shape.labeldown,
     location = location.abovebar, color = color.red, textcolor = color.white, size = size.tiny)
plot(activeStop, "Frozen trade stop", color = color.orange, style = plot.style_linebr)

Where this test can fail

Two opposite bodies can be ordinary oscillation within a range. The nearby-extreme condition can also reject a large reversal that makes a much lower low or higher high. Those exclusions are consequences of this definition, not evidence that the rejected trades would have lost.

  • Follow-through can reduce the candidate count while worsening the entry price. Compare both entry variants with identical costs and dates. Do not compare only their winning trades.
  • A very tight tolerance makes tick size influential. A larger tolerance admits less similar extremes. Changes in interval or session boundaries can split the same price move into different pairs.
  • Test signal counts, expired candidates, filled orders and net trade results separately. Record losses that pass every pattern test. A compiler pass and a correctly detected pair supply no win-rate estimate.

Use Pineify to revise and compare explicit rules

Pine Script AI Coding Agent can help edit the strategy and check Pine syntax. Supply the OHLC fixtures and request preservation of the overlap denominator, pending-candidate expiry and next-bar order timing. Inspect the resulting source and TradingView trade list before changing any threshold.

  • Strategy Optimizer compares exposed strategy inputs through its TradingView extension. A small sensitivity experiment uses overlap values 70, 75 and 80 with follow-through on or off: six combinations while all other choices stay fixed.
  • Choose parameters on a development period, then separately evaluate a frozen choice on later untouched dates. Retain trade count, costs and drawdown with the result. This page reports no measured backtest and does not establish a best market or timeframe.
Where Pineify fits

Pine Script AI Coding Agent

Turn exact overlap, tolerance and timing requirements into reviewable Pine code and check its syntax.

Also useful: Strategy Optimizer. Compare declared overlap and confirmation inputs after verifying the baseline orders and costs.

Review the two-bar rules in Pineify

Frequently asked questions

Educational research, not investment advice. The OHLC fixtures and costs are synthetic examples, not measured performance. Trading can lose money; gaps can exceed planned stop distances. Correct syntax, pattern detection and historical optimization do not guarantee future returns.

Sources and verification

Published by Pineify. Pineify is an independent product and is not affiliated with TradingView. Sources support the technical explanations; examples do not establish trading performance.