Sharp Selloffs: Mapping the Rebound Before a Short Entry

Video: 30 YEARS LATER… THIS STILL WORKS!
Creator: Oliver Velez Trading
Original Video: Watch the original video
Difficulty: Intermediate

The Big Idea

Oliver Velez focuses on a forceful selloff into a support reference, especially a 200-period moving average, followed by a partial rebound. His preferred short location is partway back through the completed decline rather than at the most extended low.

The video gives several probability estimates for rebound depths and winning trades. No supporting sample or reproducible study is supplied. Treat those figures as the creator’s claims, not measured probabilities for your market.

If You Remember Only One Thing

The rebound zone describes location; a bearish event and a tolerable structural risk are still required.

60-Second Summary

  • Measure from the start of the full completed decline.
  • Interpret thirds as fractions of that decline, measured upward from its low.
  • Separate the creator’s probability estimates from verified evidence.
  • Waiting for an event and preplacing scaled orders are different methods.
  • The automatic indicator maps completed declines and rebound events; it is not a performance backtest.

Measure the Entire Decline

The source emphasizes that the move starts at the high where the decline began, not necessarily at the first red candle. The decline may occur in one large bar or several consecutive bars.

Suppose a completed move runs from 110 to 100. A one-third rebound is near 103.33, the halfway level is 105, and a 60% rebound is 106. These describe recovery upward from the low. They are not percentages of the current share price.

The creator discusses roughly the one-third-to-60% region as an entry area, with related references to two-thirds. These are approximate discretionary zones, not interchangeable claims that every retracement endpoint is optimal.

Support Does Not Guarantee a Lasting Bounce

The creator’s hypothesis is that a violent arrival at support can precede a bounce that fails and another decline. The 200-period average supplies context rather than a guaranteed floor.

The transcript does not specify every moving-average calculation setting. Verify the actual study before attempting an exact reproduction. A slow drift into the average and a forceful multi-bar drop are different conditions and should be reviewed separately.

Location and Entry Are Separate

For developing traders, Velez recommends waiting for an event in the rebound area rather than automatically scaling into resting orders. Examples include a break below a green candle or a loss of part of a large rebound candle.

Define that event explicitly. A completed-candle color change, an intrabar low break, and a midpoint break are different entry rules. A test cannot use a candle’s final midpoint or low before those values become known.

The creator also describes an advanced starter short before the bounce and larger additions higher in the zone. That raises combined exposure. It should not be mistaken for a requirement to keep increasing a losing position.

Use Structure and Size Together

A cash-loss limit does not identify a good chart stop by itself. First determine where the setup is invalidated, then size the position so that the planned loss is tolerable. If the minimum tradable size creates too much risk, skip the trade.

For a hypothetical short at 105 with protection at 107, a $100 risk budget permits 50 shares before costs. A fill beyond 107 can lose more than $100. If several entries share that stop, calculate their total risk from their individual entry prices.

Automatic Pine Script Indicator: Selloff and Rebound Zone

Show Pine Script v6 — Automatic Selloff Rebound v2

//@version=6
// https://candlechasers.com/sharp-selloff-retracement-entry-zone/
// Original mechanical approximation; not Oliver Velez's exact rules.
indicator("CandleChasers - Automatic Selloff Rebound v2", overlay=true)
atrLen = input.int(14, "ATR length", minval=2, maxval=200)
minimumDrop = input.float(1.5, "Minimum decline in prior ATR", minval=0.2, step=0.1)
maxRun = input.int(5, "Maximum consecutive bearish bars", minval=1, maxval=20)
life = input.int(60, "Setup lifetime in chart bars", minval=5, maxval=500)
maLen = input.int(200, "Support moving-average length", minval=2, maxval=1000)
maType = input.string("SMA", "Support average type", options=["SMA", "EMA"])
requireMA = input.bool(false, "Require decline low near support average")
maTolerance = input.float(0.5, "MA proximity in prior ATR", minval=0.0, step=0.1)
if not chart.is_standard
    runtime.error("Use standard price candles.")
float atr = ta.atr(atrLen)
float sma = ta.sma(close, maLen)
float ema = ta.ema(close, maLen)
float average = maType == "SMA" ? sma : ema
plot(barstate.isconfirmed ? average : average[1], "Support moving average", color=color.blue, linewidth=2)
var int run = 0
var float runHigh = na
var float runLow = na
var float baseATR = na
var float top = na
var float bottom = na
var float third = na
var float half = na
var float sixty = na
var int created = na
// 0 scanning, 1 waiting for zone, 2 zone reached, 3 rejection signalled,
// 4 invalidated, 5 expired, 6 old low revisited after zone.
var int state = 0
var int setups = 0
var int touches = 0
var int signals = 0
var float dropATR = na
bool newSetup = false
bool zoneEvent = false
bool rejection = false
if barstate.isconfirmed
    bool live = state == 1 or state == 2 or state == 3
    if live and bar_index > created
        if high >= top
            state := 4
        else if bar_index - created > life
            state := 5
        else if low < bottom and state == 1
            // Do not silently extend a frozen decline with later lows.
            state := 4
        else if low <= bottom and (state == 2 or state == 3)
            // Conservative: a zone-to-low bar cannot also earn a new signal.
            state := 6
        else
            if state == 1 and high >= third and low <= sixty
                state := 2
                zoneEvent := true
                touches += 1
            // Completed bearish candle closes below the preceding green low.
            if state == 2 and close < open and close[1] > open[1] and close < low[1]
                rejection := true
                signals += 1
                state := 3
    // Collect the incoming decline, but never act on an unfinished bar.
    if close < open
        if run == 0
            runHigh := math.max(high, high[1])
            runLow := low
            baseATR := atr[1]
        else
            runHigh := math.max(runHigh, high)
            runLow := math.min(runLow, low)
        run += 1
    else
        bool free = state == 0 or state == 4 or state == 5 or state == 6
        if run > 0 and run <= maxRun and free and not na(baseATR) and baseATR > 0
            // The first non-bearish confirmation candle may set a lower wick.
            float endpoint = math.min(runLow, low)
            float span = runHigh - endpoint
            bool sizeOK = span >= minimumDrop * baseATR
            bool maOK = not requireMA or (not na(average) and
             math.abs(endpoint - average) <= maTolerance * baseATR)
            // Do not activate after the confirmation already recovered past 60%.
            bool locationOK = high < runHigh and close <= endpoint + 0.6 * span
            if sizeOK and maOK and locationOK
                top := runHigh
                bottom := endpoint
                third := endpoint + span / 3.0
                half := endpoint + span * 0.5
                sixty := endpoint + span * 0.6
                created := bar_index
                dropATR := span / baseATR
                state := 1
                setups += 1
                newSetup := true
        run := 0
        runHigh := na
        runLow := na
        baseATR := na
bool liveNow = state == 1 or state == 2 or state == 3
color zoneColor = liveNow ? color.orange : color.gray
p1 = plot(third, "One-third rebound", color=zoneColor, style=plot.style_stepline)
plot(half, "Half rebound", color=color.gray, style=plot.style_stepline)
p2 = plot(sixty, "60 percent rebound", color=zoneColor, style=plot.style_stepline)
fill(p1, p2, color=color.new(zoneColor, liveNow ? 83 : 95))
plot(bottom, "Frozen decline low", color=color.new(color.red, 25),
 style=plot.style_stepline)
plot(top, "Frozen decline high / invalidation", color=color.new(color.red, 55),
 style=plot.style_stepline)
plotshape(newSetup, title="Selloff mapped", text="MAP",
 style=shape.diamond, location=location.belowbar, color=color.orange,
 textcolor=color.orange, size=size.tiny)
plotshape(zoneEvent, title="Rebound zone reached", text="ZONE",
 style=shape.circle, location=location.abovebar, color=color.yellow,
 textcolor=color.orange, size=size.tiny)
plotshape(rejection, title="Confirmed bearish rejection", text="SHORT?",
 style=shape.triangledown, location=location.abovebar, color=color.red,
 textcolor=color.red, size=size.small)
alertcondition(newSetup, "Selloff mapped", "A qualifying completed decline has been mapped.")
alertcondition(zoneEvent, "Rebound zone reached", "Price reached the frozen one-third to 60% zone.")
alertcondition(rejection, "Bearish rebound rejection", "After zone contact, a bearish close broke the previous green candle low.")
var table info = table.new(position.top_right, 1, 3, border_width=1)
if barstate.islast
    string message = switch state
        0 => "Scanning: no qualifying completed decline yet"
        1 => "Mapped: waiting for rebound into zone"
        2 => "Zone reached: waiting for bearish rejection"
        3 => "Rejection signalled; map remains until resolved"
        4 => "Invalidated; last map retained in gray"
        5 => "Expired; last map retained in gray"
        => "Old low revisited; last map retained in gray"
    if na(atr)
        message := "Loading ATR history"
    table.cell(info, 0, 0, "Automatic Selloff Rebound v2 | " + message,
     text_color=color.white, bgcolor=color.rgb(25, 35, 50))
    table.cell(info, 0, 1, "Maps: " + str.tostring(setups) + " | zone touches: " +
     str.tostring(touches) + " | rejection bars: " + str.tostring(signals),
     text_color=color.white, bgcolor=color.rgb(25, 35, 50))
    table.cell(info, 0, 2, "Last decline / prior ATR: " +
     (na(dropATR) ? "none" : str.tostring(dropATR, "#.##")) +
     " | MA filter: " + (requireMA ? "ON" : "OFF"),
     text_color=color.white, bgcolor=color.rgb(25, 35, 50))

Version 2 replaces the original manual price inputs with automatic detection. It plots the support moving average, maps qualifying declines, shades their one-third-to-60% rebound area, and marks zone contacts and a defined bearish rejection. These mechanical rules are original research definitions rather than a reproduction of every discretionary judgment in the video.

Default detection: one to five consecutive bearish candles followed by the first non-bearish candle, with a decline of at least 1.5 times the ATR known before the bearish run began. The high includes the candle immediately preceding the run; the low includes the confirmation candle’s lower wick. The confirmation candle must not have regained the impulse high or closed above the 60% rebound level. Longer uninterrupted runs are excluded unless you increase the maximum-run input.

The range is frozen at that confirmation close. Zone contacts and rejection signals begin on later bars, so the script does not pretend the mapped range was known during the earlier decline. The optional moving-average filter is off by default. When enabled, it requires the frozen low to be within the selected prior-ATR distance of the average on the confirmation bar. The default 200 SMA, optional EMA, and proximity threshold are our implementation choices; verify settings before comparing with the source.

What You Should See

  • Blue line: the selected support moving average once enough history is loaded.
  • MAP diamond: a qualifying decline has been identified at the completed confirmation bar.
  • Orange shaded zone: the frozen one-third-to-60% rebound area. The midpoint and impulse extremes are also drawn.
  • ZONE dot: a later bar overlaps the rebound area.
  • SHORT? triangle: after zone contact, a completed bearish candle closes below the immediately preceding green candle’s low. This is one explicit event definition, not a guaranteed trade.
  • Status table: scanning, waiting for rebound, waiting for rejection, signalled, invalidated, expired, or resolved at the old low, plus event counts.

Install the Updated Version

Remove the old manual indicator. Replace the entire Pine Editor contents with the updated code, save, and add it to a standard candlestick chart. Start with a liquid symbol and enough history for ATR and the moving average—300 or more bars is useful with the default 200-period average. No manual high, low, or date is required. Create alerts for mapping, zone contact, or rejection using Once Per Bar Close; recreate older alerts after replacing the script.

If the table says scanning, the loaded data has not produced a qualifying completed decline under the settings. As a sensitivity check, compare minimum declines of 1.0, 1.5, and 2.0 ATR, or increase the maximum run length. Do not interpret a setting that generates more markers as proof of a better trading method. With the optional average filter enabled, a missing or distant average can prevent a map.

How a Map Ends

A return to the impulse high invalidates the map. Before zone contact, a new low below the frozen bottom also invalidates it rather than silently extending the original measurement. After zone contact, revisiting the old low resolves the map. A setup also expires after its chosen lifetime, default 60 chart bars. Inactive maps stay visible in gray until replaced.

If a bar both reaches the zone and revisits the bottom while the map is already armed, resolution takes priority over a new rejection marker. An earlier rejection signal is not erased by a later invalidation. Only one map is active at a time, so another candidate is not allowed to overwrite an active setup; this affects the sample of opportunities.

The map, markers, average display, and alerts use completed bars. There are no higher-timeframe requests or backdated signals. The script does not place orders or generate Strategy Tester trades. Offline checks covered mapping, zone contact, rejection, invalidation, expiry, threshold filtering, and event ordering. It has not been compiled or run inside TradingView here. Inspect replay examples before relying on notifications.

Do Not Expect a Fixed Number of Winners

The video uses loaded dice to discuss persistence after losses. Even if a strategy truly wins 70% over a large sample, it does not have to win seven of the next ten trades. Two early losses do not make later wins due. Losses can cluster, and the underlying edge can change.

Keep a fixed risk budget and a stopping rule. Evaluate the method over a predefined sample containing strong rebounds, full reversals, failed shorts, and moves that never offer an entry. Compare net expectancy rather than relying only on a claimed win rate.

What This Code Actually Tests

The indicator applies an original measurable definition of a sharp selloff, freezes the observed range at confirmation, and tracks later zone contact and a particular completed-candle rejection. It is a chart-study tool rather than a performance backtest. Its event counters are not trade counts or win-rate statistics.

The source supplies the selloff/rebound concept. Our definitions specify consecutive bearish candles, a prior-ATR threshold, a first non-bearish confirmation, optional average proximity, a fixed map lifetime, and a green-candle-low break. These choices deliberately make the approximation reviewable.

What This Code Does Not Test

It does not reproduce discretionary scaling, stop management, position sizing, target selection, or the creator’s claimed probabilities. It does not know whether a SHORT? marker could be filled at its displayed close, and it calculates no profit or loss. It monitors one active map and excludes uninterrupted declines longer than the maximum-run setting.

Use the charts to assess whether these definitions identify the type of decline you intended to study. Keep misses and false positives in the review. Historical levels remain fixed from their original confirmation; changing the inputs or loaded history can change which maps qualify.

Research Lab: Does the Entry Event Improve the Location?

Start with a consecutive sample of sharp declines defined before review. One possible original definition is a move of at least 1.5 times a previously available ATR over no more than three bars. This creates a measurable sample; it is not the source’s exact definition of a crash.

After each decline is frozen, compare entry on reaching the one-third-to-60% zone with entry after a completed bearish event within that zone. Keep the initial impulse, target, structural invalidation, costs, and sample dates unchanged. Log untriggered and unfilled opportunities.

Further comparisonValues or groupsInterpretation
Zone locationOne-third–one-half versus one-half–60%Compare better entry price with the possibility of no fill or a stronger reversal
Arrival strength1, 1.5, 2 prior ATRInvestigate whether more extreme declines alter the result
Support contextPremarked average contact versus no contactAsk whether the support reference contributes beyond the decline itself

Run one comparison at a time. Measure eligible impulses, trades, net expectancy, maximum adverse excursion, and drawdown. A higher win rate with larger losses can be worse; a better entry price with almost no fills can contribute less per original opportunity.

Practice the Probability Reasoning

If a model wins 70% of independent trades, the chance of three consecutive losses at a specified starting point is 0.3 cubed, or 2.7%. Over a long sequence there are many possible starting points, and real outcomes may not be independent. The example does not estimate this setup’s true probability. It illustrates why a favorable long-run rate never promises a fixed quota of wins in the next ten trades.

Final Takeaway

Map the completed decline, wait for a rebound into a defined area, and use an explicit bearish event to structure risk. The retracement zone is a location to investigate, not a promise that the next low will break.

Risk Disclosure

This article is for educational purposes only and is not financial advice or a recommendation to buy or sell any security. Trading involves substantial risk, including loss of capital. Leverage can magnify losses, and stop orders do not guarantee an execution price. Examples and historical results do not predict future performance. Account for fees, spread, slippage, and your own financial circumstances before trading.

CandleChasers is independent of the video creator. This article provides educational analysis of the source material; it does not verify the creator’s earnings or endorse paid products.

As an Amazon Associate I earn from qualifying purchases.