What it measures
An order block is a price zone where a strong move started. In the usual definition, a bullish order block is the last down candle before a rally that breaks a recent swing high, and a bearish order block is the last up candle before a sell-off that breaks a recent swing low. Traders who use them expect price to react if it comes back to the zone.
Order blocks come from smart money concepts, where they're described as areas of institutional orders. No chart can show who placed the orders, and definitions vary widely between educators. This page uses one simple, testable definition; see smart money concepts explained without the hype for the alternatives.
The formula in words
- Swings. A swing high is a pivot: a high with N lower highs on each side (N = 5 by default). It's confirmed only N bars after it happens.
- Break of structure. A bullish break is the first close above the latest confirmed swing high. Each swing can be broken once.
- The block. On the breaking bar, look back up to 10 bars for the most recent down candle (close below open). Its high and low form the bullish order block.
- Mitigation. The first time price trades back into the zone (the low reaches the block's top), the block counts as mitigated and stops extending.
Bearish blocks mirror this: the last up candle before the first close below the latest swing low. Other definitions use the candle's body instead of its full range, require a minimum size for the breaking move, or keep a block active until price closes through it. Each choice moves the zones.
How traders read it
- Return to the zone. The core idea is that price often revisits the origin of a strong move. Traders look for a reaction, such as a rejection candle, on the first return to a fresh block.
- Fresh versus mitigated. A block price hasn't returned to yet is called fresh or unmitigated, and is generally given more weight than one that has already been tested.
- With structure. Bullish blocks are mostly traded while structure is bullish, and bearish blocks while it's bearish; see BOS and CHoCH.
- Overlap with gaps. A block followed by a fair value gap marks an especially fast move away from the zone, which some traders treat as a stronger block.
Common settings
| Setting | Typical value | What changing it does |
|---|---|---|
| Swing strength | 3 to 10 bars | Higher means fewer, more significant swings, confirmed later. |
| Bars searched for the candle | 5 to 20 | How far back the last opposite candle may be. |
| Zone | Full candle range | Some use only the body, which gives thinner zones. |
| Active blocks kept | 3 to 10 per side | Older blocks far from price add clutter. |
Pine Script v6 code
The complete, self-contained script is below. Copy it into a new indicator in TradingView's Pine Editor, or download the .pine file.
//@version=6
indicator("Order blocks from breaks of structure", shorttitle = "Order blocks", overlay = true, max_boxes_count = 500)
swingLen = input.int(5, "Swing strength (bars on each side)", minval = 1, maxval = 50, group = "Detection")
lookback = input.int(10, "Bars searched for the last opposite candle", minval = 1, maxval = 50, group = "Detection")
maxOpen = input.int(5, "Active blocks to keep per side", minval = 1, maxval = 50, group = "Display")
keepUsed = input.bool(true, "Keep mitigated blocks on the chart", group = "Display")
showSwings = input.bool(true, "Mark confirmed swing points", group = "Display")
bullCol = input.color(color.teal, "Bullish block", group = "Display")
bearCol = input.color(color.red, "Bearish block", group = "Display")
// Swings are pivots: confirmed only swingLen bars after the high or low itself.
ph = ta.pivothigh(high, swingLen, swingLen)
pl = ta.pivotlow(low, swingLen, swingLen)
var float swingHigh = na
var float swingLow = na
var bool highUsed = true
var bool lowUsed = true
var array<box> bullBlocks = array.new<box>()
var array<box> bearBlocks = array.new<box>()
newBull = false
newBear = false
touchBull = false
touchBear = false
if barstate.isconfirmed
if not na(ph)
swingHigh := ph
highUsed := false
if not na(pl)
swingLow := pl
lowUsed := false
// A block is mitigated the first time price trades back into it; it then stops extending.
if bullBlocks.size() > 0
for i = bullBlocks.size() - 1 to 0
b = bullBlocks.get(i)
b.set_right(bar_index)
if low <= b.get_top()
touchBull := true
if keepUsed
b.set_bgcolor(color.new(color.gray, 88))
b.set_border_color(color.new(color.gray, 70))
else
b.delete()
bullBlocks.remove(i)
if bearBlocks.size() > 0
for i = bearBlocks.size() - 1 to 0
b = bearBlocks.get(i)
b.set_right(bar_index)
if high >= b.get_bottom()
touchBear := true
if keepUsed
b.set_bgcolor(color.new(color.gray, 88))
b.set_border_color(color.new(color.gray, 70))
else
b.delete()
bearBlocks.remove(i)
// Bullish break of structure: first close above the latest swing high. The block is the last down candle before it.
if not highUsed and close > swingHigh
highUsed := true
for j = 1 to lookback
if close[j] < open[j]
bullBlocks.push(box.new(bar_index - j, high[j], bar_index, low[j], border_color = bullCol, bgcolor = color.new(bullCol, 85)))
newBull := true
break
if bullBlocks.size() > maxOpen
bullBlocks.shift().delete()
// Bearish break of structure: first close below the latest swing low. The block is the last up candle before it.
if not lowUsed and close < swingLow
lowUsed := true
for j = 1 to lookback
if close[j] > open[j]
bearBlocks.push(box.new(bar_index - j, high[j], bar_index, low[j], border_color = bearCol, bgcolor = color.new(bearCol, 85)))
newBear := true
break
if bearBlocks.size() > maxOpen
bearBlocks.shift().delete()
plotshape(showSwings and not na(ph), "Swing high", shape.circle, location.abovebar, color.new(color.gray, 30), offset = -swingLen, size = size.tiny)
plotshape(showSwings and not na(pl), "Swing low", shape.circle, location.belowbar, color.new(color.gray, 30), offset = -swingLen, size = size.tiny)
alertcondition(newBull, "New bullish order block", "Close above the last swing high created a bullish order block on {{ticker}} ({{interval}})")
alertcondition(newBear, "New bearish order block", "Close below the last swing low created a bearish order block on {{ticker}} ({{interval}})")
alertcondition(touchBull, "Price returns to a bullish block", "Price traded back into a bullish order block on {{ticker}} ({{interval}})")
alertcondition(touchBear, "Price returns to a bearish block", "Price traded back into a bearish order block on {{ticker}} ({{interval}})")Swings come from ta.pivothigh() and ta.pivotlow(), so each one is confirmed N bars after the high or low, and the optional swing markers are drawn back on the bar where it happened. When a close breaks the latest swing, the script finds the last opposite candle and draws its range as a box that extends right until price returns to it.
All updates happen on closed bars, so nothing is drawn and then removed on the live bar. Alert conditions cover new blocks on both sides and the first return to a block; use Once per bar close.
Add it to your chart
- Open any chart on TradingView and open the Pine Editor.
- Create a new indicator, delete the template code and paste the script.
- Click Save, then Add to chart. Change lengths and levels from the indicator's settings.
Stuck on an error? See how to add a Pine Script indicator to TradingView.
Pitfalls
- The definition decides everything. Body or full range, which candle, what counts as a break: change one and the zones move. Fix the definition before you judge results.
- Hindsight picking. On a past chart it's easy to spot the blocks that held and skip the ones that failed. Count every block the script draws.
- Confirmation delay. Swings are known N bars late. A script that marks swings and blocks instantly is either using another definition or repainting.
- Many blocks, many reactions. With enough zones on a chart, price is always near one. Fewer, fresher blocks are easier to test honestly.
- The name isn't evidence. "Institutional orders" is an interpretation; the script only finds a candle pattern.
Related reading
- Smart money concepts explained without the hype
- 8 backtesting mistakes that make a strategy look better than it is
- Pine Script repainting: how to spot it, test for it and fix it
- Risk/Reward Calculator (free tool)
- Position Size Calculator (free tool)
The script is an educational example: test it on your own markets before relying on it. Indicators describe the past; they don't predict the future. Trading involves substantial risk of loss and is not suitable for every investor. Edgoro is a software tool, not a broker or financial adviser: nothing it produces is investment advice, and past or backtested performance does not guarantee future results.