Video: Fake Breakout or Real Move? The ONE Candle That Reveals the Difference
Creator: Jason Graystone
Original Video: Watch the original video
Difficulty: Intermediate
The Big Idea
A close beyond resistance is one observation. A following close back below it is another. Jason Graystone’s lesson is to study the change between those observations rather than assume that a breakout candle establishes lasting acceptance.
The return candle shows that the move was not sustained across those two closes. It does not reveal who traded, why they traded, or whether the market must now reverse.
If You Remember Only One Thing
The return close changes the breakout’s status; whether that change predicts a useful trade is a separate question.
60-Second Summary
- Choose resistance before the breakout.
- Separate a same-bar wick rejection from a close outside followed by a return.
- Track the breakout high, return low, and original level.
- A deeper return is measurable but not automatically more predictive.
- The supplied strategy uses rolling-range proxies, optional bullish mirror patterns, and added exits—not the creator’s exact method.
Separate the Level, Break, and Return
- Identify a meaningful resistance area before the breakout.
- Observe a candle that closes above it.
- Check whether the very next candle closes back inside the original range.
A wick through resistance followed by a same-bar rejection is a different pattern. So is a breakout followed by a small pullback that remains above resistance. Combining them all under “fake breakout” hides potentially important differences.
Keep Three Reference Points
The source marks the original resistance, the failed breakout’s high, and the return candle’s low. These create observable questions. Does price extend below the return low, regain the breakout high, or remain unresolved between them?
These levels are references, not mandatory order instructions. The video emphasizes investigation and does not supply a complete trading system with fixed sizing and exits.
Measure the Strength of the Return
A close one tick inside the old range differs from a large move back through it. Graystone suggests comparing the return distance with recent volatility and observing the following three to five candles.
For example, record the distance between resistance and the return close, divided by an ATR value available at the decision time. Then group the results using boundaries chosen before evaluating the test sample. A deeper return may produce different results, but that must be measured rather than inferred from one strong reversal.
If both the return low and breakout high are touched during one historical candle, OHLC data alone may not establish which came first. Mark the outcome ambiguous or investigate suitable intrabar data; do not automatically award the favorable sequence.
Pine Script Research Approximation — Version 2
Show Pine Script v6 — Failed Breakout Return v2
//@version=6
// https://candlechasers.com/failed-breakout-return-candle-test/
// Original rolling-range research approximation. v2 adds visible diagnostics.
// Brackets use tick distances from actual fills, not fixed structural prices.
strategy("CandleChasers - Failed Breakout Return v2", overlay=true,
initial_capital=1000000, default_qty_type=strategy.fixed, default_qty_value=1,
margin_long=100, margin_short=100, pyramiding=0,
commission_type=strategy.commission.percent, commission_value=0.01,
slippage=1, calc_on_every_tick=false, calc_on_order_fills=false)
n = input.int(20, "Pre-breakout range lookback", minval=3, maxval=500)
returnBars = input.int(1, "Maximum subsequent bars to return", minval=1, maxval=10)
direction = input.string("Both", "Research directions",
options=["Both", "Short only", "Long only"])
rr = input.float(2.0, "Target / stop-distance multiple", minval=0.1, step=0.1)
holdBars = input.int(5, "Time exit after elapsed entry bars", minval=1, maxval=100)
units = input.float(1.0, "Order quantity in instrument units", minval=0.001)
placeOrders = input.bool(true, "Submit research orders")
if not chart.is_standard
runtime.error("Use standard price candles.")
float upper = ta.highest(high, n)[1]
float lower = ta.lowest(low, n)[1]
bool ready = bar_index >= n and not na(upper) and not na(lower)
var int pending = 0
var int started = na
var float frozenLevel = na
var float extreme = na
var int candidates = 0
var int failedReturns = 0
var int submissions = 0
var int expired = 0
var float riskTicks = na
bool upStart = false
bool downStart = false
bool shortSignal = false
bool longSignal = false
float eventStop = na
if barstate.isconfirmed and ready
bool resolved = false
// Resolve only a candidate already known before this bar.
if pending != 0
if bar_index - started > returnBars
pending := 0
expired += 1
else
extreme := pending == 1 ? math.max(extreme, high) : math.min(extreme, low)
bool returned = pending == 1 ? close < frozenLevel : close > frozenLevel
if returned
shortSignal := pending == 1
longSignal := pending == -1
eventStop := pending == 1 ? extreme + syminfo.mintick : extreme - syminfo.mintick
pending := 0
resolved := true
failedReturns += 1
bool allowed = (shortSignal and direction != "Long only") or
(longSignal and direction != "Short only")
if allowed and placeOrders and strategy.position_size == 0
float distance = shortSignal ? eventStop - close : close - eventStop
if distance > 0
riskTicks := math.max(1.0, math.ceil(distance / syminfo.mintick))
float rewardTicks = math.max(1.0, math.round(riskTicks * rr))
if shortSignal
strategy.entry("Short", strategy.short, qty=units)
strategy.exit("Short bracket", "Short", loss=riskTicks, profit=rewardTicks)
else
strategy.entry("Long", strategy.long, qty=units)
strategy.exit("Long bracket", "Long", loss=riskTicks, profit=rewardTicks)
submissions += 1
if pending == 0 and not resolved
if close > upper and close[1] <= upper
pending := 1
started := bar_index
frozenLevel := upper
extreme := high
upStart := true
candidates += 1
else if close < lower and close[1] >= lower
pending := -1
started := bar_index
frozenLevel := lower
extreme := low
downStart := true
candidates += 1
if barstate.isconfirmed and strategy.position_size != 0 and strategy.opentrades > 0
int age = bar_index - strategy.opentrades.entry_bar_index(0)
if age >= holdBars
strategy.close_all(comment="Time exit")
plot(upper, "Prior rolling resistance", color=color.new(color.orange, 25))
plot(lower, "Prior rolling support", color=color.new(color.aqua, 25))
plot(pending != 0 ? frozenLevel : na, "Frozen pending level",
color=color.yellow, linewidth=3, style=plot.style_linebr)
float riskDistance = riskTicks * syminfo.mintick
float rewardDistance = math.max(1.0, math.round(riskTicks * rr)) * syminfo.mintick
float liveStop = strategy.position_size > 0 ? strategy.position_avg_price - riskDistance :
strategy.position_size < 0 ? strategy.position_avg_price + riskDistance : na
float liveTarget = strategy.position_size > 0 ? strategy.position_avg_price + rewardDistance :
strategy.position_size < 0 ? strategy.position_avg_price - rewardDistance : na
plot(liveStop, "Fill-relative bracket stop", color=color.red, style=plot.style_linebr)
plot(liveTarget, "Fill-relative bracket target", color=color.lime, style=plot.style_linebr)
plotshape(upStart, title="Close above resistance", text="BREAK",
style=shape.diamond, location=location.abovebar, color=color.blue,
textcolor=color.blue, size=size.tiny)
plotshape(downStart, title="Close below support", text="BREAK",
style=shape.diamond, location=location.belowbar, color=color.blue,
textcolor=color.blue, size=size.tiny)
plotshape(shortSignal, title="Confirmed bearish failure", text="FAIL",
style=shape.triangledown, location=location.abovebar, color=color.red,
textcolor=color.red, size=size.small)
plotshape(longSignal, title="Confirmed bullish failure", text="FAIL",
style=shape.triangleup, location=location.belowbar, color=color.lime,
textcolor=color.lime, size=size.small)
if shortSignal
alert("Bearish failed breakout confirmed: " + syminfo.ticker,
alert.freq_once_per_bar_close)
if longSignal
alert("Bullish failed breakout confirmed: " + syminfo.ticker,
alert.freq_once_per_bar_close)
var table info = table.new(position.top_right, 1, 4, border_width=1)
if barstate.islast
string status = not ready ? "Load more bars for range lookback" :
pending == 1 ? "Waiting for return below resistance" :
pending == -1 ? "Waiting for return above support" : "Scanning rolling levels"
table.cell(info, 0, 0, "Failed Breakout v2 | " + status,
text_color=color.white, bgcolor=color.rgb(25, 35, 50))
table.cell(info, 0, 1, "Breakouts: " + str.tostring(candidates) +
" | failures: " + str.tostring(failedReturns) + " | expired: " + str.tostring(expired),
text_color=color.white, bgcolor=color.rgb(25, 35, 50))
table.cell(info, 0, 2, "Order requests: " + str.tostring(submissions) +
" | open: " + str.tostring(strategy.opentrades) +
" | closed: " + str.tostring(strategy.closedtrades),
text_color=color.white, bgcolor=color.rgb(25, 35, 50))
table.cell(info, 0, 3, "Orders: " + (placeOrders ? "ON" : "OFF") +
" | unit notional approx: " +
str.tostring(math.abs(close) * syminfo.pointvalue * units, "#.##") +
" " + syminfo.currency, text_color=color.white, bgcolor=color.rgb(25, 35, 50))
Version 2 adds both rolling resistance and support, visible breakout markers, optional bullish mirror failures, and a diagnostic table. A candidate starts when a completed candle closes beyond a pre-existing rolling range. That level is then frozen while the script waits for a return. The default permits only the next candle to return, preserving the source’s immediate-return sequence.
Blue BREAK diamonds identify candidates. Red downward FAIL triangles mark closes back below frozen resistance; green upward FAIL triangles mark closes back above frozen support. These markers describe patterns independently of whether an order is permitted, affordable, or filled. Set Research directions to Short only for the bearish version, or Both to include our bullish mirror extension.
The script remains a strategy so Strategy Tester can evaluate explicitly defined research orders. Turn off Submit research orders to use only the visual study. It is an original mechanical approximation of level selection, not the creator’s discretionary identification of repeatedly tested resistance.
Install the New Version
Remove the earlier strategy, replace the entire Pine Editor contents with this code, save, and add it again. The chart title should include Failed Breakout Return v2. Use standard candles, load more history than the lookback, and check that Submit research orders is enabled if you want trades. Recreate any alerts after changing the code. In a strategy alert, select alert-function calls to receive pattern notifications; those notifications report both pattern directions independently of the order-direction filter.
Read the Diagnostics Before Changing Rules
- No rolling lines: load more chart history, confirm the script is visible, or inspect TradingView for a compile/runtime error.
- Breakouts but no failures: price did not return across the frozen level within the selected window. The original immediate-return pattern can be uncommon.
- Failure markers but no order requests: orders are disabled, the direction filter excludes the event, or a position is already open.
- Order requests but no open or closed trades: inspect Strategy Properties, capital, quantity, contract value, and any broker-emulator rejection. A request is not a fill.
- An open trade but no closed trades: the bracket or time exit may not have completed within the loaded chart history.
The default illustrative research capital is 1,000,000 with one unit and 100% margin requirements. This avoids some capital rejections from the previous 25,000 example, but does not guarantee affordability for every instrument. It is not an account-size recommendation or fixed-risk sizing rule. The displayed approximate notional is in the symbol’s currency and does not perform account-currency conversion. Quantity must respect the instrument’s minimum size. Existing saved Strategy Properties may override new defaults, so check them after re-adding.
Bracket and Fill Assumptions
At the signal close, the code measures the distance to the episode’s extreme plus one tick. It converts that distance to ticks and submits a relative stop and target bracket with the entry. The broker emulator measures those distances from the eventual fill. The target multiple therefore stays approximately consistent, subject to tick rounding, fees, slippage, and exit execution.
This is a changed experiment: a gapped fill shifts both bracket prices. The stop no longer necessarily remains beyond the original breakout extreme. It is a fixed-distance-from-fill model inspired by that extreme, not an exact structural-stop implementation. Compare that choice separately before drawing conclusions about the source’s chart-based risk management.
Market entries normally fill on the next available simulated tick, typically the next bar’s open in historical testing. Relative brackets are submitted with the entry without enabling order-fill recalculation. The time exit is submitted after the selected number of elapsed bars from entry and normally fills on a later tick. Stop and target touches in the same bar remain dependent on the broker emulator’s path assumptions. Gap-through stops can lose more than the nominal tick distance.
Offline checks covered bullish and bearish patterns, frozen levels, immediate versus delayed returns, equality cases, prefix consistency, relative bracket arithmetic, and an example of instrument notional versus available capital. The code has not been compiled or run inside TradingView here. Validate individual fills and consult TradingView’s strategy execution documentation (paid link). No trades are forced just to populate the tester.
Collect Every Qualifying Occurrence
Use one instrument and timeframe first. Include reversals, reclaimed breakouts, and sideways outcomes. Compare net results after costs, not just the size of the most attractive move. Keep a separate sample for checking any threshold developed during initial research.
What This Code Actually Tests
The source supplies a close beyond a pre-existing level followed by an immediate close back inside. Version 2 adds a rolling N-bar high/low proxy, one pending candidate at a time, optional bullish mirror patterns, next-tick market orders, fill-relative tick brackets, and a time exit. These are original experimental definitions and implementation choices.
The pending level is frozen on the breakout bar. Its extreme is tracked through the return window, and a resolved return bar cannot simultaneously create another candidate. One position can be open at a time; other pattern markers may therefore have no corresponding trade. The default one-bar window tests an immediate return. Increasing it explicitly creates a delayed-return variant.
What This Code Does Not Test
It does not recognize discretionary repeated touches, price-zone width, institutional activity, or a separate “return low before breakout high” event-order experiment. Its time exit and tick-relative bracket create a payoff model distinct from a pure pattern study.
The stop distance is derived from the signal-time extreme but applied from the actual fill. It is not an absolute stop beyond that extreme after a gap. The code does not size a fixed percentage of capital at risk or establish the creator’s profitability. Signals, order requests, fills, and closed trades are different counts and should be compared accordingly.
Backtest Lab
| Change one assumption | Values | What the comparison asks |
|---|---|---|
| Rolling reference length | 10, 20, 40 bars | Does the result depend on one narrowly chosen lookback? |
| Holding limit | 3, 5, 10 elapsed bars | Does the proposed effect occur promptly or only after extended exposure? |
| Planned reward multiple | 1, 1.5, 2 | How much does the outcome depend on the exit definition? |
Run each comparison separately on the same date interval, instrument, timeframe, cost settings, and remaining inputs. Record signal count, filled trades, net average trade, profit factor, drawdown, and the number of gaps that distort the intended bracket. Keep a later period untouched until the definitions are settled. A single standout value surrounded by weak neighbors is a reason to investigate sensitivity, not announce an optimum.
Try Measuring Return Depth
In an original numerical example, resistance is 100, the return close is 99.20, and the ATR available before the return is 2. Return depth is 0.8 divided by 2, or 0.4 ATR. Another return at 99.80 is only 0.1 ATR. Group these observations before inspecting future returns rather than choosing a threshold around the winners.
Ask: was the level fixed before the breakout? Did the return actually close inside? Was the reversal known before the entry? Did both extremes trade within one ambiguous candle? Were all qualifying returns retained? The answers determine whether the observation is usable evidence.
Final Takeaway
The candle after the breakout can change the interpretation. Define that change precisely, record what follows, and let the complete sample determine whether it is useful.
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.