PipLedger
Today's forex newsNFP, CPI, FOMC and other high-impact eventsEconomic calendarCalendar →

BOS and CHoCH strategy: how to trade market structure, with a free Pine Script

Market structure is the pattern of swing highs and lows on a chart. A break of structure (BOS) says the trend is carrying on; a change of character (CHoCH) is the first sign it may be turning. This guide explains both in plain words, gives a rule-based way to trade them with an entry on the pullback, walks through a EURUSD example, and includes a free TradingView script that labels every break.

By M. A. Horaira. Updated 9 October 2026. 11 minute read.

The rules at a glance

  • Structure: swing highs and lows with five candles on each side; higher highs and higher lows make an uptrend, lower highs and lower lows a downtrend
  • BOS (break of structure): a close beyond the last swing point in the direction of the trend (continuation)
  • CHoCH (change of character): the first close beyond the last swing point against the trend (possible reversal)
  • Entry: after the break, a limit order halfway back into the leg that made it (the 50% level)
  • Stop loss and target: beyond the start of that leg plus a quarter of the ATR; target twice the risk (2R)
  • Choose: trade BOS, CHoCH or both; the order is cancelled if it hasn't filled within 20 candles

Market structure in one minute

Prices move in swings. A swing high is a peak with lower highs on both sides of it; a swing low is a dip with higher lows on both sides. In an uptrend, each swing high is higher than the last (a higher high, HH) and each swing low is higher too (a higher low, HL). In a downtrend you get lower highs (LH) and lower lows (LL). Reading this pattern is called reading market structure, and it's the base of both price action trading and smart money concepts.

To keep it objective, the script defines a swing point the same way every time: a candle whose high (or low) is beyond the five candles on each side. That means a swing is only confirmed five candles after it happens, which is a lag, but it stops you redrawing swings to suit yourself.

BOS vs CHoCH

Break of structure (BOS)Change of character (CHoCH)
What breaksThe last swing point in the trend's direction (the last high in an uptrend)The last swing point against the trend (the last higher low in an uptrend, or the last lower high in a downtrend)
What it suggestsThe trend is carrying onThe trend may be turning
How oftenOften, in a trending marketLess often; many turn out to be false
RiskTrading with the trendTrading against the trend that was in place

These are the common SMC definitions, but the terms aren't standardised: some traders call a CHoCH a market structure shift (MSS), and some keep MSS for a stronger break that follows a liquidity sweep.

Both are confirmed by a candle close beyond the swing point, not just a wick. A wick through a swing point that closes back inside is a different event, a liquidity sweep, and it often comes just before a CHoCH in the other direction.

The rules, step by step

1. Let the script track the swings

Every confirmed swing high and low is marked. The first close beyond one of them sets the trend's direction; from then on, each new break is labelled BOS (with the trend) or CHoCH (against it).

2. Choose what to trade

BOS only keeps you with the trend. CHoCH only trades reversals, which are rarer and riskier. Both takes every break. The default is both; test each mode separately before you choose.

3. Don't chase the break: wait for 50%

The candle that breaks structure is often a big one, and buying its close puts your stop a long way off. Instead, take the leg that made the break, from its start (the lowest low since the broken swing high) to the top of the breaking candle, and place a limit order halfway back. SMC traders call the halfway point equilibrium, the lower half of a range the discount zone and the upper half the premium zone, and prefer to buy at or below equilibrium.

4. Stop beyond the start of the leg

The stop goes below the leg's low, minus a quarter of the ATR. If the price goes back below the low the move started from, the break has failed. The target is twice the risk.

5. Cancel stale orders

If the pullback hasn't come within 20 candles, the order is cancelled.

Worked example: EURUSD, 1-hour chart

Swing low 1.1714Lower high 1.1748Target 1.1796Entry (50%) 1.1722Stop 1.1685BOSLower lowCHoCH2R
Illustrative chart drawn for this guide to show the rules. It isn't a real day's prices. EURUSD, 1-hour candles. The shaded box is the break leg; the entry is at its middle.

EURUSD is falling. After a lower high at 1.1748, it breaks its swing low at 1.1714 with a close at 1.1708: a BOS down, confirming the downtrend, and goes on to a lower low at 1.1688. (The script only labels a break once an earlier break has set the trend. This chart starts mid-trend, so assume that has already happened.) Then the buyers take over, and a candle closes at 1.1753, above the lower high. That's a change of character. The leg runs from 1.1688 to the CHoCH candle's high of 1.1756, 68 pips, so the halfway point is 1.1722.

EURUSD long after the CHoCH
Entry (buy limit at 50% of the leg)1.1722
Stop loss1.1685 (leg low 1.1688 minus a quarter of the ATR), 37 pips away
Target (2R)1.1796, 74 pips away
Account and risk$10,000, risking 1% = $100
Lot size$100 ÷ (37 pips × $10) = 0.27 lots
Loss if the stop is hit$99.90
Profit at the target$199.80

5 hours after the CHoCH, the price pulls back and fills the order. It holds, the new uptrend gets going, and 14 hours after the fill the target is reached. Buying the CHoCH candle's close at 1.1753 instead would have needed a stop about 68 pips away for the same idea, so the same $100 would have bought a much smaller position.

Why most CHoCH signals fail, and what helps

A trend doesn't usually turn on one candle. Many CHoCH breaks are just a deeper pullback inside the old trend, and the price soon carries on the old way. A few things tend to make a CHoCH more convincing; treat them as filters to test:

Risk management

Common mistakes

  1. Counting wicks as breaks. Structure breaks on a close.
  2. Redrawing swings to fit the story. Fixed swing rules, like the script's, keep the reading the same every time.
  3. Buying every CHoCH as if it were a new trend. Most reversals need confirmation, such as a BOS in the new direction.
  4. Mixing timeframes without noticing. A BOS on the 5-minute chart can be a pullback on the 1-hour chart. Know which one you're trading.

Backtest it yourself on TradingView

This page doesn't quote a win rate or a profit figure, and you should be wary of anyone who does without showing the test. Results change with the market, the dates, the data feed and the costs you put in. The honest way is to run the test yourself, and the free script below does the work in a couple of minutes.

  1. Open the chart. On TradingView, open EURUSD on the 1-hour chart.
  2. Add the script. Open the Pine Editor from the Pine icon in the panel on the right of the chart (older layouts have it as a tab under the chart), delete the code that's already there, paste this strategy's code and click "Add to chart".
  3. Put in your costs. Open the strategy's settings and go to Properties. Enter your broker's commission and a little slippage. A test without costs flatters every strategy, and short-term ones most of all.
  4. Read the Strategy Tester. The panel under the chart shows the net profit, the maximum drawdown, the profit factor, the number of trades and a list of every trade. Click a few trades and check on the chart that each one follows the rules. Trade sizes are shown in units rather than lots: 100,000 units is one lot of a forex pair, and 100 ounces is one lot of gold.
  5. Change one setting at a time. Run the three modes (BOS only, CHoCH only, both) separately first; that's the most useful comparison on this page. Then try the swing strength (3 to 8 candles), the pullback level (38% to 62%), how long the order waits and the target.

As a rough guide, don't trust a result with fewer than 100 trades, a profit factor under 1 once costs are in, or a drawdown you couldn't sit through with real money. Settings tuned to look good on one stretch of history often fail on the next, so check the same settings on dates you didn't tune them on, then demo trade the strategy for a few weeks. How much history you can test depends on your TradingView plan: the free plan loads 5,000 candles, which is a few months of 15-minute candles but years of daily ones.

The script sizes each trade from the stop loss and your risk percentage, starts with $10,000 and assumes 1:100 leverage (a 1% margin setting), so the tester doesn't flag margin calls on normal forex trade sizes. Change these under Properties to match your account. By default TradingView fills orders at the open of the candle after the signal, so the fill can differ a little from the signal candle's close. Because entries are limit orders, the fill is almost always at your limit price, or better if a candle opens beyond it.

Download the free Pine Script and PDF

The script is written in Pine Script version 6 for this guide and follows the rules above. It can't read the economic calendar, so skipping news days is up to you. It's free to use, change and share. The PDF is a one-page cheat sheet with the rules, a worked example, the lot size maths and a checklist, to keep next to your chart.

Show the code (Pine Script v6, 113 lines)
//@version=6
// BOS and CHoCH (market structure) strategy by PipLedger (https://pipledgerfx.com/bos-choch-strategy)
// Tracks swing highs and lows, labels each break as a change of character (CHoCH) or a break of structure (BOS),
// then buys or sells a pullback into the leg that made the break.
// Free to use and change. For education and backtesting only; not financial advice.
strategy("PipLedger: BOS and CHoCH", shorttitle="BOS/CHoCH", overlay=true, initial_capital=10000, pyramiding=0, default_qty_type=strategy.fixed, default_qty_value=1, margin_long=1, margin_short=1, currency=currency.USD)

// ---------- Inputs
swingLen = input.int(5, "Swing strength (bars on each side)", minval=2)
mode     = input.string("Both", "Breaks to trade", options=["Both", "CHoCH only (reversals)", "BOS only (continuation)"])
retrace  = input.float(50, "Entry: pullback into the break leg (%)", minval=10, maxval=90, step=5)
validFor = input.int(20, "Candles the order stays valid", minval=1)
stopBuf  = input.float(0.25, "Stop buffer beyond the leg (x ATR 14)", minval=0.0, step=0.05)
rr       = input.float(2.0, "Target (R multiple)", minval=0.5, step=0.25)
riskPct  = input.float(1.0, "Risk per trade (% of equity)", minval=0.1, maxval=5.0, step=0.1)

// ---------- Helpers
fx = strategy.convert_to_account(1.0)  // one unit of the chart's quote currency in account currency (1 on USD-quoted charts)
calcQty(float entry, float stop) =>
    float dist = math.abs(entry - stop)
    dist > 0 and not na(fx) ? strategy.equity * riskPct / 100 / (dist * syminfo.pointvalue * fx) : 0.0

atr = ta.atr(14)
ph  = ta.pivothigh(high, swingLen, swingLen)
pl  = ta.pivotlow(low, swingLen, swingLen)

// ---------- Swing points and trend
var float swHi = na
var float swLo = na
if not na(ph)
    swHi := ph
if not na(pl)
    swLo := pl

// the break leg starts at the lowest low (or highest high) since the swing point that was broken;
// tracked bar by bar, so the script never needs a long, changing lookback
lowSincePivot  = ta.lowest(low, swingLen + 1)
highSincePivot = ta.highest(high, swingLen + 1)
var float legLow  = na
var float legHigh = na
legLow  := not na(ph) ? lowSincePivot : math.min(legLow, low)
legHigh := not na(pl) ? highSincePivot : math.max(legHigh, high)

var int trend = 0      // 1 = up (higher highs and lows), -1 = down, 0 = not known yet
breakUp = not na(swHi) and close > swHi and close[1] <= swHi
breakDn = not na(swLo) and close < swLo and close[1] >= swLo
chochUp = breakUp and trend == -1
bosUp   = breakUp and trend == 1
chochDn = breakDn and trend == 1
bosDn   = breakDn and trend == -1
if breakUp
    trend := 1
    swHi  := na        // each swing level breaks once
if breakDn
    trend := -1
    swLo  := na

useChoch = mode != "BOS only (continuation)"
useBos   = mode != "CHoCH only (reversals)"
takeUp   = (chochUp and useChoch) or (bosUp and useBos)
takeDn   = (chochDn and useChoch) or (bosDn and useBos)

// ---------- Waiting orders
var float lvlStop = na
var int   oDir    = 0
var int   oBar    = na
flat = strategy.position_size == 0
if not flat
    oDir := 0
if oDir == 1 and (bar_index - oBar >= validFor or close < lvlStop)
    strategy.cancel("Long")
    oDir := 0
if oDir == -1 and (bar_index - oBar >= validFor or close > lvlStop)
    strategy.cancel("Short")
    oDir := 0

// ---------- Orders: a limit order part-way back into the break leg, stop beyond the start of the leg
if flat and takeUp
    strategy.cancel("Short")
    float px = high - (high - legLow) * retrace / 100
    float sl = legLow - atr * stopBuf
    float q  = calcQty(px, sl)
    lvlStop := legLow
    oDir    := 1
    oBar    := bar_index
    if q > 0 and px < close
        strategy.entry("Long", strategy.long, qty=q, limit=px)
        strategy.exit("Long exit", "Long", stop=sl, limit=px + (px - sl) * rr)
    else
        strategy.cancel("Long")
        oDir := 0
else if flat and takeDn
    strategy.cancel("Long")
    float px = low + (legHigh - low) * retrace / 100
    float sl = legHigh + atr * stopBuf
    float q  = calcQty(px, sl)
    lvlStop := legHigh
    oDir    := -1
    oBar    := bar_index
    if q > 0 and px > close
        strategy.entry("Short", strategy.short, qty=q, limit=px)
        strategy.exit("Short exit", "Short", stop=sl, limit=px - (sl - px) * rr)
    else
        strategy.cancel("Short")
        oDir := 0

// ---------- Chart
plot(swHi, "Last swing high", color=color.new(color.gray, 30), style=plot.style_linebr)
plot(swLo, "Last swing low", color=color.new(color.gray, 30), style=plot.style_linebr)
plotshape(chochUp, "CHoCH up", shape.labelup, location.belowbar, color.teal, text="CHoCH", textcolor=color.white, size=size.tiny)
plotshape(bosUp, "BOS up", shape.labelup, location.belowbar, color.new(color.teal, 40), text="BOS", textcolor=color.white, size=size.tiny)
plotshape(chochDn, "CHoCH down", shape.labeldown, location.abovebar, color.red, text="CHoCH", textcolor=color.white, size=size.tiny)
plotshape(bosDn, "BOS down", shape.labeldown, location.abovebar, color.new(color.red, 40), text="BOS", textcolor=color.white, size=size.tiny)

Trading this from India

Residents can trade EURUSD, GBPUSD and USDJPY futures and options on NSE and BSE through a SEBI-registered broker. The contracts are quoted the same way as the spot pair, one lot is 1,000 units of the base currency, and they're cash-settled in rupees. They trade only from 9 a.m. to 7:30 p.m. IST, volumes are thin and not every broker offers them, so check the hours and the spread first. Trading forex or CFDs with offshore online platforms isn't allowed for residents under FEMA, even if the app is easy to download. Details are in is forex trading legal in India.

Related strategies: liquidity sweep, fair value gap, order block, ICT kill zones, XAUUSD FVG + order block. All 34 strategies are compared on one page in forex trading strategies.

Quick answers

What is the difference between BOS and CHoCH?

A break of structure (BOS) is a close beyond the last swing point in the direction of the trend, so it suggests the trend is carrying on. A change of character (CHoCH) is the first close beyond a swing point against the trend, so it's an early sign that the trend may be turning.

What is a CHoCH in trading?

It stands for change of character. In a downtrend, it's the first candle that closes above the last lower high; in an uptrend, the first that closes below the last higher low. On its own it's an early warning, not a confirmed reversal.

Is BOS bullish or bearish?

Either. A BOS up is a close above the last swing high in an uptrend, which is bullish; a BOS down is a close below the last swing low in a downtrend, which is bearish.

What timeframe is best for market structure?

Structure exists on every timeframe. Many traders read the trend on the 4-hour or 1-hour chart and look for BOS and CHoCH entries on the 15-minute chart. Whatever you choose, use the same swing rules every time.

Should I enter on the break or wait for a pullback?

Entering on the break gets you into every move but with a wide stop. Waiting for a pullback, such as the 50% level of the break leg in these rules, gives a tighter stop but misses the moves that don't pull back. The script lets you test the pullback depth.

What do HH, HL, LH and LL mean?

Higher high, higher low, lower high and lower low. A run of HH and HL is an uptrend; a run of LH and LL is a downtrend.

More guides

All 75 guides →

हिंदी में पढ़ें: Lot size kaise nikale?, Prop firm challenge kaise pass kare?, Gold trading kaise kare?, Forex trading kya hai, और India में यह legal है या नहीं?

Trading psychology

The habits that decide whether a good strategy makes money.

All 14 trading psychology guides

8 popular prop firms

Well-known firms for forex, gold and index traders that were still operating in 2026. Compare their rules before you buy a challenge.

If a link in this list is a referral link, PipLedger may earn a commission if you sign up, at no extra cost to you. This list is not a recommendation. Programs, prices and rules change often, so check each firm's own site, including its margin and drawdown rules, before you buy a challenge.