Break of Structure with Retest
A break-of-structure (BoS) trade identifies when price closes beyond a prior swing high or low by a mechanical threshold, then waits for price to retest that level before entering in the break direction. The hypothesis is that the retest filters out noise, improves entry timing, and increases the probability of a sustained move, compared to entering on the break itself.
Why this might work
Structural support and resistance mechanics. Swing highs and lows represent recent extremes in price; traders often use them as tactical levels for stops and limit orders. When price breaks beyond a swing, it signals a potential shift in short-term direction. However, breakouts are vulnerable to whipsaws: not all breaks sustain, and many reverse into the initial level. Retesting that level before re-extending can indicate conviction, price rejected the old extreme, then tested it again from the other side and held. This two-stage move is less likely to be noise than a single impulse [1].
Entry signal quality. The retest serves as a filter. By waiting for price to return to the broken level, a trader can distinguish between:
- A false break that reverses immediately (fails the retest).
- A true break that accelerates away without returning (misses the retest entirely).
- A true break that consolidates, pulls back, finds support at the broken level, and resumes (passes the retest, high probability).
The retest is observable in the price action; when price touches the retest zone and bounces, the trader sees a clear reversal candlestick and can enter with confidence [2].
Cost and risk control. In range-bound and whipsaw-prone markets, entering immediately on a break often triggers a stop loss. The retest delays entry, allowing some of the false moves to resolve before commitment. However, this benefit is offset by the latency cost: true breaks accelerate quickly, and waiting for a retest means entering at a worse price, reducing profit potential per trade [1].
The rules
Instrument and timeframe: Any liquid instrument (forex major pairs, index futures, equities with tight spreads). Default: 1-hour chart, to balance signal frequency (target ~20-50 trades per year) with stability.
Swing detection: A swing high is the highest close within a lookback window (default: 5 bars left and right of the reference bar, for a 11-bar window). A swing low is the lowest close in the same window. Swings are confirmed when they are at least 5 bars old, to avoid repainting.
Break detection: A break occurs when the close crosses the swing high or swing low by at least 1.0 × ATR (14), in the direction of the break. On the bar where this condition is first true, record the break level and direction. Do not re-trigger a new break within 20 bars (to avoid overlapping signals).
Retest definition: After a break is recorded, watch for the price to pull back toward the break level. Define the retest zone as the range from the break level to 50% of the distance between the broken swing and the prior swing in the opposite direction. For example, after a break above the swing high:
- Retest zone = [SwingHigh, 0.5 × (SwingHigh, SwingLow), SwingHigh].
For a break below the swing low:
- Retest zone = [SwingLow, SwingLow + 0.5 × (SwingHigh, SwingLow)].
A retest is confirmed when the low (for upbreak) or high (for downbreak) touches the retest zone.
Entry trigger: On the bar after retest confirmation, enter a long position (for upbreak) if the close is above the prior close. For downbreak, enter a short position if the close is below the prior close. Entry size: fixed contract quantity (input: 1 lot, adjustable).
Initial stop: Placed 2.0 × ATR (14) on the wrong side of the entry price. For long, stop = entry price, 2.0 × ATR. For short, stop = entry price + 2.0 × ATR.
Exit:: Take profit: fixed at 3.0 × ATR above entry (for long) or below entry (for short).
- Stop loss: as defined above.
- Retest signal expiry: if a retest has not occurred within 20 bars of the break, the signal expires and no trade is taken.
Position sizing: Fixed size (default: 1 contract). Risk management via fixed stop; no scaling or risk-per-account approach.
Session and time filters: None. Trade all hours the market is open and liquid.
Expected trade frequency: Approximately 20-50 trades per year on the 1H timeframe, depending on market regime and parameter tuning. This is lower than the guideline of 150+ trades/year; readers should test on shorter timeframes (15-min, 30-min) for higher frequency, at the cost of increased noise.
Code
//@version=6
strategy("Break of Structure + Retest", overlay=true,
commission_type=strategy.commission.percent, commission_value=0.001,
slippage=2, default_qty_type=strategy.fixed, default_qty_value=1.0)
// Inputs
swingLookback = input(5, "Swing Lookback (bars on each side)")
breakThreshATR = input(1.0, "Break Threshold (ATR multiplier)")
retestRangePercent = input(50, "Retest Zone (% of move)")
stopLossATR = input(2.0, "Stop Loss (ATR multiplier)")
takeProfitATR = input(3.0, "Take Profit (ATR multiplier)")
breakExpiry = input(20, "Break Signal Expiry (bars)")
confirmCloseDir = input(true, "Require Confirmation Candle for Entry")
// ATR
atrLen = input(14, "ATR Length")
atrVal = ta.atr(atrLen)
// Swing detection: highest high and lowest low in a symmetric window
swingWindow = 2 * swingLookback + 1
swingHigh = ta.highest(high, swingWindow)
swingLow = ta.lowest(low, swingWindow)
// Track break state
var breakLevel = na
var breakDirection = 0 // 1 = upbreak, -1 = downbreak
var breakBar = 0
var retestConfirmed = false
var entryPrice = na
var stopPrice = na
var tpPrice = na
// Detect break
if na(breakLevel) or breakBar + breakExpiry < bar_index
breakUp = close > swingHigh + breakThreshATR * atrVal
breakDn = close < swingLow - breakThreshATR * atrVal
if breakUp
breakLevel := swingHigh
breakDirection := 1
breakBar := bar_index
retestConfirmed := false
else if breakDn
breakLevel := swingLow
breakDirection := -1
breakBar := bar_index
retestConfirmed := false
// Retest detection
if breakDirection == 1
// Upbreak: retest is a pullback to retest zone
moveSize = breakLevel - swingLow
retestZoneBottom = breakLevel - retestRangePercent * moveSize / 100.0
if not retestConfirmed and low <= retestZoneBottom
retestConfirmed := true
else if breakDirection == -1
// Downbreak: retest is a bounce to retest zone
moveSize = swingHigh - breakLevel
retestZoneTop = breakLevel + retestRangePercent * moveSize / 100.0
if not retestConfirmed and high >= retestZoneTop
retestConfirmed := true
// Entry signal: on retest confirmation, enter on confirmation candle
entrySignal = false
if retestConfirmed and strategy.position_size == 0
if breakDirection == 1 and close > open
entrySignal := true
else if breakDirection == -1 and close < open
entrySignal := true
// Execute entry
if entrySignal
entryPrice := close
if breakDirection == 1
stopPrice := entryPrice - stopLossATR * atrVal
tpPrice := entryPrice + takeProfitATR * atrVal
strategy.entry("Long", strategy.long)
else
stopPrice := entryPrice + stopLossATR * atrVal
tpPrice := entryPrice - takeProfitATR * atrVal
strategy.entry("Short", strategy.short)
breakLevel := na
breakDirection := 0
retestConfirmed := false
// Exit on TP or SL
if strategy.position_size != 0
strategy.exit("TP/SL", stop=stopPrice, limit=tpPrice)
// Plotting
plot(swingHigh, color=color.blue, linewidth=1, title="Swing High")
plot(swingLow, color=color.red, linewidth=1, title="Swing Low")
if breakDirection == 1
moveSize = breakLevel - swingLow
retestZoneBottom = breakLevel - retestRangePercent * moveSize / 100.0
plot(breakLevel, color=color.green, linewidth=2, title="Break Level (Up)")
plot(retestZoneBottom, color=color.green, linewidth=1, style=plot.style_dashed, title="Retest Zone")
if breakDirection == -1
moveSize = swingHigh - breakLevel
retestZoneTop = breakLevel + retestRangePercent * moveSize / 100.0
plot(breakLevel, color=color.orange, linewidth=2, title="Break Level (Dn)")
plot(retestZoneTop, color=color.orange, linewidth=1, style=plot.style_dashed, title="Retest Zone")
if strategy.position_size != 0
plot(stopPrice, color=color.red, linewidth=1, style=plot.style_dotted, title="Stop")
plot(tpPrice, color=color.green, linewidth=1, style=plot.style_dotted, title="TP")
How the code works
The script maintains state variables (breakLevel, breakDirection, retestConfirmed) that track whether we are in an active break and whether a retest has occurred.
Lines 25-39 (Break Detection): On each bar, the code checks if the close has broken the swing high (by 1 ATR) or swing low (by 1 ATR) in the absence of an active break. If so, it records the break level and direction, and resets the retest flag.
Lines 41-56 (Retest Detection): If a break is active, the code monitors the low (for upbreaks) or high (for downbreaks) to see if price has pulled back to the retest zone. The retest zone is defined as 50% of the distance from the broken swing to the opposing swing, making it adaptive to volatility and move size.
Lines 58-67 (Entry Signal): Once a retest is confirmed, the code waits for a confirmation candle, a close above open for long (upbreak) or close below open for short (downbreak). When this condition is met, an entry signal is generated.
Lines 69-81 (Execution): The entry is placed at market price; stop and take-profit levels are set using ATR multiples, and the break state is reset.
Lines 83-85 (Exit): A single strategy.exit() call handles both stop loss and take-profit simultaneously.
Lines 87-104 (Plotting): Swing levels, break levels, and retest zones are drawn on the chart for visual verification.
The code includes a break expiry timer (breakExpiry, default 20 bars) to prevent stale signals from staying active indefinitely.
Testing it honestly
In-sample and out-of-sample testing: On TradingView, backtest this strategy on the 1H timeframe over a 1-year period. Split the data: first 6 months for in-sample (parameter tuning), second 6 months for out-of-sample (fresh data, no tuning). If the out-of-sample results degrade sharply compared to in-sample, the strategy is likely overfit.
Sample size: At 20-50 trades per year, the sample is at the low end of statistical significance. A 6-month test may yield only 10-25 trades. This is insufficient to draw solid conclusions about win rate, Sharpe ratio, or risk-adjusted returns. Treat all performance numbers from a single backtest as provisional; consistency across multiple 6-month periods is a better sign.
Realistic costs and slippage: Set commission to 0.1% per side (standard for retail forex) and slippage to 2-5 pips (for 1-hour bars, this is conservative). Many retail backtests ignore these costs, leading to false confidence. A strategy profitable at 0.05% commission and 1 pip slippage often fails in live trading.
Retest versus no-retest comparison: Run two versions of the backtest, one with retest confirmation, one without. Compare the net profit, win rate, and largest drawdown. If the retest version does not clearly outperform (net profit, after costs, at least 20% higher with similar or lower maximum drawdown), it is unclear whether the retest adds value or simply reduces trade frequency, making small winners harder to achieve. This is a critical diagnosis.
Parameter sensitivity: Vary the swing lookback (3, 5, 10 bars), break threshold (0.5, 1.0, 1.5 ATR), and retest range (25%, 50%, 75%). Plot the net profit and win rate for each combination. If results are highly sensitive to parameter choice, the strategy is brittle and unlikely to transfer to out-of-sample data or different market regimes.
Limitations
Hindsight bias in swing definition. Even with mechanical rules, the choice of swing lookback (5 bars) is somewhat arbitrary. A 3-bar lookback will detect earlier swings; a 10-bar lookback will miss intraday noise but lag on breakouts. Different lookbacks produce different "structures," so the strategy is sensitive to this parameter. There is no objectively correct window; this is a choice point where hindsight can creep in during backtesting.
Retest latency cost. The retest requirement delays entry, which is a double-edged sword. In strong, sustained moves, the price that executes the retest is often 0.5-1.0 ATR worse than the break price, reducing the initial risk-reward. In choppy markets, the retest confirmation never arrives, and the trader misses the move entirely. The paper provides no empirical evidence that retest entries outperform immediate breakout entries when costs are included; this requires testing on the reader's chosen market and timeframe.
Small sample and low trade frequency. At 20-50 trades per year, a typical backtest covers only a handful of trading opportunities. Statistical significance requires roughly 100+ independent trades; a 50-trade sample has a large confidence interval around any measured win rate or profit factor. A strategy that shows +20% returns over 50 trades could easily turn -10% on the next 50 trades due to random variation alone.
Regime dependence. Structure breaks work differently depending on market regime. In a strong trend, swings are steep, and breakouts are fast; the retest may not occur, and the strategy generates few signals. In a choppy, range-bound market, swings are shallow, breaks are frequent but false, and retests are common but often fail. The strategy's performance is likely to vary dramatically between trending and ranging periods; a backtest that covers only one regime gives a false picture.
Parameter overfitting risk. The break threshold (1.0 ATR), retest range (50%), stop loss (2.0 ATR), and take-profit levels (3.0 ATR) are all tunable. In a typical backtest, optimizing these parameters to past data will improve the apparent win rate and profit. However, these optimized parameters often do not generalize to new data. The strategy must be tested with fixed, reasonable parameter defaults, not tuned to the backtest period.
Cost sensitivity. Commissions and slippage are often underestimated. At 2 pips slippage and 1 pip commission per side (3 pips total per round-trip trade), a trade with a 10-pip profit target becomes breakeven or a loss. Many online backtests use unrealistic costs (0 commission, 0 slippage). This strategy must be tested with real-world costs to be credible.
Missing evidence on retest signal quality. The hypothesis that retests improve signal quality, i.e., that retest entries have higher win rates or better risk-adjusted returns than immediate breakout entries, is not validated in peer-reviewed literature. The present strategy offers no empirical support for this claim. Readers should treat the retest as a plausible but unproven filter; its value depends entirely on the market, timeframe, and cost structure in which it is applied.
No trailing stop or dynamic risk management. The fixed ATR-based stop loss does not adjust for changing volatility during the trade. In a slow market, 2 ATR stops are far away and put on excessive risk. In a volatile market, 2 ATR stops may be too tight and trigger on noise. Adaptive stops (e.g., a trailing stop, or a stop that adjusts after a certain profit) might improve risk-adjusted returns, but they are not included here.
Key definitions
Break of Structure (BoS): A price move that closes beyond a recent swing high or swing low by a mechanical threshold (e.g., 1 × ATR), signaling a potential shift in short-term trend direction.
Swing High: The highest close within a symmetric lookback window (e.g., 5 bars left and right of a reference bar), used as a level of structural resistance.
Swing Low: The lowest close within a symmetric lookback window, used as a level of structural support.
Retest: A subsequent move in price that returns to the level of a prior break, confirming the break by testing it from the new side without reversing.
ATR (Average True Range): A volatility indicator that measures the average range of price movement over a lookback period, used here to scale thresholds for entries, stops, and take-profit levels.
Retest Zone: The price range, centered at the break level, within which price must touch to confirm a retest; typically set as a percentage of the move from the broken swing to the opposing swing.
Risk-Reward Ratio: The distance from entry to take-profit divided by the distance from entry to stop loss; a ratio of 2:1 means the potential profit is twice the potential loss on a trade.
Figures
References
[1] Bulkowski, T. N., Encyclopedia of Chart Patterns, 2nd edn. John Wiley & Sons (2005). Section on breakouts and failed breakouts; technical documentation on the frequency and success rates of structure breaks and retests in equity and futures markets.
[2] CME Group, "Liquidity, Order Types, and Execution," Educational Resource (2024). URL: https://www.cmegroup.com/education. Primary source on how limit and stop orders interact with price structure in live trading; provides context for understanding retest mechanics in futures execution.
[3] Pring, M. J., Technical Analysis Explained, McGraw-Hill (2002). Classical reference on support and resistance levels, swing highs/lows, and their role in breakout trading; foundational for defining structure objectively.
[4] TradingView Help Center, "Pine Script Strategy Documentation," (2024). URL: https://www.tradingview.com/pine-script-docs/. Technical specification for strategy coding, commission, slippage, and backtesting parameters.
[5] Investopedia, "The Basics of Breakout Trading," (2023). Explanation of breakout entry methods, retest confirmation, and common pitfalls in structure-based trading.
[6] CFTC, "Futures Trading Glossary," Commodity Futures Trading Commission (2023). Primary regulatory source for definitions of support, resistance, and liquidity in derivatives markets.
Educational research on historical data only. Not investment advice, not a signal, and never a performance promise. Past results do not predict future performance. Every reference is link-verified before publication and every paper is re-audited weekly against the library's editorial standard.
Last reviewed by the PropLedger research pipeline: 2026-10-18. Educational research on historical data, not financial advice.
Keep reading
Gap-Fill Trading Based on Base-Rate Filtering
A complete, testable trading strategy: a systematic gap-fill strategy: measuring base rates first, then building rules around the cases where the base rate is actually favourable. Exact rules, full Pine Script code, and an honest reading of the evidence.
Turn-of-Month Equity Index Futures: Capturing the Monthly Flow Effect
A complete, testable trading strategy: a turn-of-month strategy in equity index futures: the documented month-end flow effect, exact entry and exit days, and how much of it survives costs. Exact rules, full Pine Script code, and an honest reading of the evidence.
Mean-Reversion Against VWAP Bands: Regime Classification and Cost of Error
A complete, testable trading strategy: a mean-reversion strategy against VWAP bands in a ranging regime: defining the regime first, and the cost of getting that classification wrong. Exact rules, full Pine Script code, and an honest reading of the evidence.