Indicators··7 min read

Swing Structure: BOS & CHoCH Marker

3 references, link-verified · 1 primaryEditor of record: Shane CantyStandards review editorial standard · audit log

A Pine Script v6 indicator that identifies pivot points (swing highs and lows) and marks significant structural breaks: Break of Structure (BOS) signals trend continuation, while Change of Character (CHoCH) signals reversal potential. Useful for traders tracking institutional order flow patterns, supply-demand shifts, and structural market events.

//@version=6
indicator("Swing Structure: BOS & CHoCH Marker", overlay=true, max_labels_count=500)

// Inputs
lookbackLength = input.int(5, "Lookback Bars for Swings", minval=2, maxval=20)
offsetATR = input.float(1.0, "Label Offset (ATR Multiples)", minval=0.5, maxval=3)
plotSwings = input.bool(true, "Plot Swing Points")
plotStructure = input.bool(true, "Plot BOS/CHoCH Labels")

// Detect swing highs and lows using lookback period
periodHigh = ta.highest(high, lookbackLength)
periodLow = ta.lowest(low, lookbackLength)

isSwingHigh = high == periodHigh
isSwingLow = low == periodLow

// Track the most recent swing levels and direction
var float lastSwingHigh = na
var float lastSwingLow = na
var bool lastWasHigh = na  // true = uptrend (last swing was high), false = downtrend

// Update swings when detected
if isSwingHigh
    lastSwingHigh := high
    lastWasHigh := true

if isSwingLow
    lastSwingLow := low
    lastWasHigh := false

// Break of Structure (BOS): directional break confirming trend
// BOS-High: uptrend confirmed by breaking above prior swing high
// BOS-Low: downtrend confirmed by breaking below prior swing low
bosHigh = lastWasHigh == true and high > lastSwingHigh
bosLow = lastWasHigh == false and low < lastSwingLow

// Change of Character (CHoCH): counter-trend break signaling reversal
// CHoCH-High: lower-trend reverses, breaking above prior swing high
// CHoCH-Low: uptrend reverses, breaking below prior swing low
chocHigh = lastWasHigh == false and high > lastSwingHigh
chocLow = lastWasHigh == true and low < lastSwingLow

// ATR-based offset for label placement
offset = ta.atr(14) * offsetATR

// Plot swing pivot points as triangles
if plotSwings
    plotshape(isSwingHigh, style=shape.triangledown, location=location.abovebar, 
             color=color.red, size=size.small)
    plotshape(isSwingLow, style=shape.triangleup, location=location.belowbar, 
             color=color.green, size=size.small)

// Label BOS events (orange)
if plotStructure
    if bosHigh
        label.new(bar_index, high + offset, "BOS ↑", color=color.orange, 
                 textcolor=color.white, style=label.style_label_down, size=size.small)
    if bosLow
        label.new(bar_index, low - offset, "BOS ↓", color=color.orange, 
                 textcolor=color.white, style=label.style_label_up, size=size.small)
    
    // Label CHoCH events (purple)
    if chocHigh
        label.new(bar_index, high + offset, "CHoCH ↑", color=color.purple, 
                 textcolor=color.white, style=label.style_label_down, size=size.small)
    if chocLow
        label.new(bar_index, low - offset, "CHoCH ↓", color=color.purple, 
                 textcolor=color.white, style=label.style_label_up, size=size.small)

How the code works

Swing detection: The indicator uses ta.highest(high, lookbackLength) and ta.lowest(low, lookbackLength) to find the highest and lowest prices within a rolling window. When the current bar's high or low matches these extremes, a swing is detected. The var keyword persists the last swing high, low, and direction across bars without repainting.

Tracking direction: A boolean flag lastWasHigh toggles between true (uptrend: last swing was high) and false (downtrend: last swing was low). This establishes the structural context for the next break.

BOS logic: Break of Structure occurs when price extends in the direction of the established trend. If lastWasHigh == true (uptrend), breaking above the prior swing high (high > lastSwingHigh) confirms trend strength. If lastWasHigh == false (downtrend), breaking below the prior swing low confirms downtrend continuation.

CHoCH logic: Change of Character reverses the condition: it fires when price breaks a swing level in the opposite direction from the current trend. An uptrend that breaks below the prior low, or a downtrend that breaks above the prior high, suggests the market character is shifting.

Label placement: ATR-derived offset ensures labels scale with volatility and do not overlap price bars. Triangles mark the actual swing points; colored labels identify BOS (orange) and CHoCH (purple) events.

Reading it on a chart

Swing triangles appear at local extremes: red triangles above swing highs, green triangles below swing lows. These mark pivot points where price direction historically reversed.

BOS labels (orange) confirm trend continuation: when an uptrend breaks above the prior high, the uptrend has structure; when a downtrend breaks below the prior low, the downtrend is intact. BOS often precedes further directional moves.

CHoCH labels (purple) signal reversal potential: when a downtrend breaks above a prior high, or an uptrend breaks below a prior low, the market is showing a change in character. CHoCH often marks the start of trend reversals or at minimum a pause in the established direction.

Trader workflow: Use swing triangles to identify key support and resistance levels. Watch for BOS to confirm trend strength (often entry signals in breakout strategies). Monitor CHoCH events as early warning signs of reversal; a CHoCH followed by a new swing in the opposite direction confirms a trend change has begun.

Limitations

Lagging identification: Swings are only confirmed after lookbackLength bars have passed. A 5-bar lookback means each swing is identified 5 bars after its actual occurrence. This delay is structural and unavoidable; intrabar reversals or false swings cannot be seen until confirmation bars arrive.

Lookback period sensitivity: A short lookback (2-3 bars) generates excessive micro-swings and noise; too long a period (20+ bars) misses structure on smaller timeframes. The optimal value depends on asset volatility and trading timeframe; backtesting is required to find appropriate settings.

False breakouts: A BOS or CHoCH label indicates price touched a level; it does not guarantee follow-through or reversal. A breakout can be stopped by order flow, news, or broader market moves. CHoCH signals reversal potential, not certainty.

Multi-timeframe disconnect: Swings identified on one timeframe may be noise on a larger timeframe. A CHoCH on a 15-minute chart might resolve as a continuation on the hourly chart. No timeframe hierarchy is built into the indicator.

Volume and context ignored: The indicator marks structural breaks but does not consider volume, bid-ask spreads, open interest, or macro events. A swing break with low volume carries different weight than one on heavy volume; the indicator treats both identically.

Labels can clutter: With high volatility or short lookback periods, many labels appear on crowded charts. The max_labels_count=500 limit prevents memory overflow, but older labels are deleted first as new ones arrive, potentially losing historical context.

Key definitions

Swing High: A local maximum where price is higher than the bars on either side within a defined lookback window.

Swing Low: A local minimum where price is lower than the bars on either side within a defined lookback window.

Break of Structure (BOS): Price crossing above the previous swing high (in an uptrend) or below the previous swing low (in a downtrend), confirming trend continuation.

Change of Character (CHoCH): Price breaking above a prior swing high while in a downtrend, or below a prior swing low while in an uptrend, signaling a potential shift in market direction or character.

Pivot: A turning point in price where direction reverses; synonymous with swing high or swing low.

Lookback Period: The number of bars examined to determine the highest high or lowest low; controls sensitivity and lag.

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-10-04. 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.