Indicators··7 min read

Swing Structure: BOS and CHoCH Labels

2 references, link-verifiedEditor of record: Shane CantyStandards review editorial standard · audit log

An indicator that identifies swing highs and lows, then marks when price breaks established structure (BOS) or when the character of price action changes direction (CHoCH). Price action traders use these markers to spot potential reversals and continuation points, as structure breaks often precede significant moves or mark failed reversals.

//@version=6
indicator("Swing Structure - BOS & CHoCH", overlay=true)

// Inputs
swingLen = input(5, "Swing Period", minval=1)
showSwings = input(true, "Show Swing Points")
showStructure = input(true, "Show Structure Lines")
labelOffset = input(20, "Label Offset (pips)")

// Identify swing points using pivot highs and lows
swingHigh = ta.pivothigh(high, swingLen, swingLen)
swingLow = ta.pivotlow(low, swingLen, swingLen)

// Track the two most recent swing highs and lows
var float recentSwingHigh = na
var float recentSwingLow = na
var float priorSwingHigh = na
var float priorSwingLow = na

// Update tracking when new swings form
if not na(swingHigh)
    priorSwingHigh := recentSwingHigh
    recentSwingHigh := swingHigh

if not na(swingLow)
    priorSwingLow := recentSwingLow
    recentSwingLow := swingLow

// Break of Structure (BOS): price exceeds the recent swing in the direction of the trend
bosAbove = not na(recentSwingHigh) and not na(priorSwingHigh) and 
           high > recentSwingHigh and recentSwingHigh > priorSwingHigh

bosBelow = not na(recentSwingLow) and not na(priorSwingLow) and 
           low < recentSwingLow and recentSwingLow < priorSwingLow

// Change of Character (CHoCH): swing pattern reverses
// Bullish CHoCH: lower lows pattern breaks, now making higher lows
chochBullish = not na(priorSwingLow) and not na(recentSwingLow) and 
               recentSwingLow > priorSwingLow and low > recentSwingHigh

// Bearish CHoCH: higher highs pattern breaks, now making lower highs
chochBearish = not na(priorSwingHigh) and not na(recentSwingHigh) and 
               recentSwingHigh < priorSwingHigh and high < recentSwingLow

// Visuals: plot swing points
plotchar(showSwings and not na(swingHigh), "Swing High", "▼", 
         location.abovebar, color.red, size=size.small)
plotchar(showSwings and not na(swingLow), "Swing Low", "▲", 
         location.belowbar, color.green, size=size.small)

// Plot the current structure levels
if showStructure
    plot(recentSwingHigh, "Recent High", color.new(color.red, 70), 1)
    plot(recentSwingLow, "Recent Low", color.new(color.green, 70), 1)

// Label BOS events
if bosAbove
    label.new(bar_index, high + labelOffset * syminfo.mintick, "BOS↑", 
              color=color.blue, textcolor=color.white, style=label.style_label_down, 
              size=size.small)

if bosBelow
    label.new(bar_index, low - labelOffset * syminfo.mintick, "BOS↓", 
              color=color.blue, textcolor=color.white, style=label.style_label_up, 
              size=size.small)

// Label CHoCH events
if chochBullish
    label.new(bar_index, high + labelOffset * syminfo.mintick, "CHoCH↑", 
              color=color.orange, textcolor=color.white, style=label.style_label_down, 
              size=size.small)

if chochBearish
    label.new(bar_index, low - labelOffset * syminfo.mintick, "CHoCH↓", 
              color=color.orange, textcolor=color.white, style=label.style_label_up, 
              size=size.small)

How the code works

The indicator uses ta.pivothigh() and ta.pivotlow() to identify swing points: highs where price is higher than the bars swingLen periods before and after, and lows where price is lower in the same window. These represent local extremes in price action.

Four variables track the two most recent swings in each direction. When a new swing forms, the code shifts the recent swing to prior and stores the new swing as recent, maintaining a two-bar history of structure.

Break of Structure occurs when price closes beyond the most recent swing high or low while the prior swing in that direction was still higher (for highs) or lower (for lows), confirming upward or downward momentum. This filters out false spikes by requiring the recent swing to be more extreme than the one before it, confirming a trend.

Change of Character detects when the pattern of swings reverses. A bullish CHoCH occurs when lows (which were decreasing) start increasing and price penetrates above the recent swing high, signalling a shift from downtrend structure to uptrend structure. A bearish CHoCH is the inverse: prior highs were increasing, recent highs decrease, and price penetrates below the recent swing low.

Labels appear only once per event at the bar where the condition triggers, positioned offset above or below the candle by a user-defined pip amount.

Reading it on a chart

Swing High and Swing Low markers show the local extremes. The thin structure lines connect the two most recent swings, making the breakout level visible.

A BOS↑ label (blue, above the bar) signals that price has broken above the recent swing high after a prior higher high: a bullish breakout. Watch for continuation up or use this to exit short positions. A BOS↓ label (blue, below the bar) is the bearish equivalent.

A CHoCH↑ label (orange) marks a shift from a lower-low pattern to a higher-low: the character of downtrend weakness has changed, and a reversal to an uptrend structure may be forming. Similarly, CHoCH↓ shows a shift from higher highs to lower highs, warning of trend deterioration.

Neither signal guarantees direction. BOS often presages a major move but can fail in choppy or range-bound markets. CHoCH marks a structural shift but does not automatically confirm a reversal; price must continue testing higher lows (bullish CHoCH) or lower highs (bearish CHoCH) to validate the new structure.

Limitations

Swing period lag: The indicator confirms swings only swingLen bars after they form, so labels appear late and miss quick reversals. A 5-bar period is common practice but still introduces a multi-bar delay.

Whipsaw sensitivity: In sideways or choppy markets, swing breakouts trigger frequently but fail to extend into sustained moves. Confirm BOS and CHoCH signals with volume, momentum, or level testing before acting on them alone.

CHoCH definition variance: The logic here defines CHoCH as price penetrating the opposite swing after the pattern reverses, but market participants use varying definitions. Some require only two swings of opposing polarity without penetration; others demand volume or wick confirmation. This code's definition is stricter and may miss some early reversals.

No retest logic: The indicator does not distinguish between a clean BOS and a retest of structure. In practice, retests (price returning to test the broken level) often occur and carry different implications than clean breaks.

Single timeframe: Structure identified on one timeframe may be noise on a higher one and a sub-wave on a lower one. A 5-bar swing on the 1-minute chart is noise on the daily. Always align analysis across timeframes.

No volume or context: These markers show structure alone and do not account for news, order flow, or broader market conditions that often reverse structural signals.

Key definitions

Swing High: A local peak where the high is greater than the highs n periods before and after it.

Swing Low: A local trough where the low is less than the lows n periods before and after it.

Break of Structure (BOS): When price exceeds a recent swing extreme in the direction of the prior trend, signalling the trend remains intact or has resumed.

Change of Character (CHoCH): When the pattern of swings reverses direction (e.g., from making lower lows to higher lows), indicating a potential shift in market structure.

Pivot Point: A local extreme identified by comparing a bar's high or low to a fixed number of surrounding bars.

Whipsaw: A sharp reversal that quickly invalidates a breakout signal, causing losses to traders who entered on the initial move.

References


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-09-20. Educational research on historical data, not financial advice.

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. Found an error? Email support@prop-ledger.org and the paper is corrected or withdrawn.