SMC Basics · Free

Understand the boxes on your chart.

See why a price area gets marked, what happens when price returns, and when the box disappears.

Automatic chart zones. No buy/sell signals.

Pastel clay illustration of a confirmed structure break and three-candle gap forming fixed zones, marking the gap's midpoint, then tracking a zone's life.
Workflow illustration
  1. Spot the structure

    A confirmed swing break or three-candle gap.

  2. Mark the zones

    Fixed order blocks; gaps with their midpoint.

  3. Track their life

    Fresh, touched, then removed when invalidated.

See the real chart

What is SMC Basics?

SMC Basics is a free TradingView indicator for order blocks, fair value gaps and gap midpoints. It draws zones from defined candle and swing rules, fades touched zones, and removes them after a confirmed close beyond the far edge. The visual guide explains when each box becomes known and what its boundaries mean.

Why does an order block appear after its origin candle?

The script first waits for a confirmed swing and a close beyond it, then selects an earlier opposite candle. The default swing needs ten later bars to confirm. The older box origin is not its detection time. Open How an Order Block is chosen

Why can a new fair value gap already look faded?

The creation candle can satisfy this script's touch rule, so a newly drawn gap may start faded. That does not prove a later revisit. Removal still requires a confirmed close strictly beyond the zone's far edge. Open Why a box fades or disappears

Does SMC Basics include alerts or automatic higher-timeframe zones?

This version draws zones on the chart timeframe and has no alert conditions or automatic higher-timeframe zone feed. To compare timeframes, use the manual two-chart routine. It does not provide an entry ticket or setup grade. Open What this tool does not do

Why these boxes exist.

Price sometimes moves sharply, then returns to an earlier area. These ideas give you places to watch.

Candles: up ↑ · down ↓
How a price gap becomes a box: 1 closed candleStart with one candle. Its thin wick reaches $101. That is the highest price during this candle. There is no box yet.
Made-up prices · completed candles. Same default gap filter as the indicator, with 14 earlier candles supplying its volatility measure (ATR).

1 / 4

Start with one candle.

Its thin wick reaches $101. That is the highest price during this candle. There is no box yet.

SMC Basics finds these patterns for you. It also marks earlier candles as Order Blocks, explained next. “Smart Money Concepts” names these chart ideas; the boxes cannot tell you who traded or why.

New to candles? Start here.

A candle summarizes price during one time period. Its thick body joins the opening and closing prices. Its thin wicks reach the highest and lowest prices. Once the period ends, the candle closes. This tool checks its patterns at that point.

How does this help a trading plan?

Use a box to choose an area to study. Watch price there, decide what would make your idea wrong, and plan your entry and exit. Across trades, gains must cover losses and costs. A box alone does not make a trade profitable.

Watch a box form.

Start with one pattern. Follow its story one candle at a time.

Watch an Order Block form.

Press Play, or move one candle at a time.

Candles: up ↑ · down ↓Green box · upward pattern
Fictional candles · pivot length 3 to keep the lesson short (default: 10). Circle and break line are teaching guides.

Let a turning point form. Follow the candles. The tool needs a confirmed high before it can mark this upward pattern.

Latest close
$100.00
Box state
Not created
Confirmed high
Waiting
Quick check: price crosses a gap’s halfway line. Is the box removed?

No. The halfway line helps you describe price’s location. Removal requires a confirmed close beyond the far edge: below an upward zone or above a downward zone.

Find the same boxes on a real chart.

Gold · 15-minute candles · OANDA. Look for the labels first, then the box edges.

Real TradingView Gold 15-minute chart with SMC Basics: pink and green OB and FVG boxes, with dashed halfway lines inside the FVGs.
TradingView snapshot · . Guide labels 1–2 added.Open full-size chart in a new tab
  1. Order Block · OB

    The upper pink box marks an earlier candle. Its top and bottom define the area. It has no halfway line.

  2. Fair Value Gap · FVG

    The green box near the current price has a dashed halfway line. The indicator calls this the CE midline.

Color describes direction. Green marks an upward pattern; pink marks a downward pattern. Both OB and FVG can use either color. Read the label to tell them apart.

Add it to your chart.

Free and open-source. Copy, paste, and keep it.

  1. Open the editor

    On a TradingView chart, use the Pine icon to open Pine Editor.

  2. Copy and paste

    Copy the full code below. Paste it in place of the sample code.

  3. Add to chart

    Choose Add to chart, then save the script to keep it.

Indicator code

Copy the code as it is. No coding needed.

View the full code
//@version=6
// ============================================================================
//  SMC Basics — ProEA Lab
// ----------------------------------------------------------------------------
//  Free, open-source Smart-Money-Concepts starter: auto-detected Order Blocks
//  and Fair Value Gaps with honest, non-repainting mechanics.
//
//  What it draws
//    · Order Blocks  — on a confirmed swing break (BOS), the last opposite
//      candle before the impulse. Geometry frozen at creation.
//    · Fair Value Gaps — 3-candle imbalances larger than an ATR-scaled minimum.
//    · Basic mitigation — zones fade once price trades into them and are
//      removed (or ghosted) once price CLOSES through the far edge.
//
//  Honest notes
//    · Swing points confirm `pivotLen` bars late by construction — that is what
//      makes them non-repainting. Nothing here predicts anything.
//    · This is the free sibling of the SMC AI-Scored Toolkit (scoring, sweeps,
//      regime, verdict, trade-plan ticket live there). This one stays simple
//      on purpose: the freshest zones only, drawn cleanly.
// ============================================================================
indicator("SMC Basics — ProEA Lab", "SMC Basics", overlay = true, max_boxes_count = 60, max_labels_count = 30, max_lines_count = 40)

// ===== 1 · INPUTS ===========================================================
G1 = "Structure"
pivotLen  = input.int(10, "Swing pivot length", minval = 3, maxval = 50, group = G1, tooltip = "Swing highs/lows confirm this many bars after they form — later, but honest.", display = display.none)

G2 = "Order Blocks"
showOB    = input.bool(true,  "Show Order Blocks", group = G2, display = display.none)
obUseWick = input.bool(false, "Use full wick (off = candle body)", group = G2, display = display.none)
obMax     = input.int(3, "Keep last … per side", minval = 1, maxval = 5, group = G2, display = display.none)

G3 = "Fair Value Gaps"
showFVG   = input.bool(true, "Show Fair Value Gaps", group = G3, display = display.none)
fvgMinAtr = input.float(0.3, "Min gap size (× ATR)", minval = 0.0, maxval = 2.0, step = 0.1, group = G3, display = display.none)
fvgMax    = input.int(3, "Keep last … per side", minval = 1, maxval = 5, group = G3, display = display.none)
showCE    = input.bool(true, "CE midline (50% of the gap)", group = G3, tooltip = "Consequent encroachment — the half-way line of an FVG. Pros judge a gap by how price behaves at this line.", display = display.none)

G4 = "Display"
showTags  = input.bool(true, "Zone tags (OB / FVG)", group = G4, display = display.none)
keepGhost = input.bool(false, "Keep mitigated zones as ghost outlines", group = G4, display = display.none)
showChip  = input.bool(true, "Header chip", group = G4, display = display.none)

// ===== 2 · PALETTE (fixed Aurora — matches the ProEA Lab family) ============
C_BULL  = color.new(#22c68c, 0)
C_BEAR  = color.new(#f06292, 0)
C_BULLF = color.new(#22c68c, 82)
C_BEARF = color.new(#f06292, 82)
C_BULLT = color.new(#22c68c, 90)   // touched (faded) fill
C_BEART = color.new(#f06292, 90)
C_GHOST = color.new(#8a93a6, 78)
C_CHIP  = color.new(#0e1430, 8)
C_TXT   = color.new(#e8ecf8, 0)

// ===== 3 · SHARED SERIES (all ta.* global) ==================================
atr14   = ta.atr(14)
phPrice = ta.pivothigh(high, pivotLen, pivotLen)
plPrice = ta.pivotlow(low,  pivotLen, pivotLen)
// the OB scan reads candles at a dynamic offset — size the buffers explicitly
max_bars_back(open, 60)
max_bars_back(high, 60)
max_bars_back(low, 60)
max_bars_back(close, 60)

// ===== 4 · TYPES + STATE ====================================================
// state: 0 = fresh · 1 = touched · 2 = mitigated
type Zone
    box    bx
    label  tg
    line   ce                // FVG only: the 50% (consequent encroachment) midline
    int    kind   = 0        // 0 = OB, 1 = FVG
    int    side   = 1        // 1 = bull, -1 = bear
    float  top    = na
    float  bottom = na
    int    state  = 0

var array<Zone> zones = array.new<Zone>()

// swing structure memory (committed on confirmed bars only)
var float lastSwingHi  = na
var float lastSwingLo  = na
var int   lastHiBar    = na
var int   lastLoBar    = na
var bool  brokeUpOnce  = false
var bool  brokeDnOnce  = false

// ===== 5 · HELPERS ==========================================================
zoneFill(int side, int state) =>
    state == 1 ? (side == 1 ? C_BULLT : C_BEART) : (side == 1 ? C_BULLF : C_BEARF)

// removes the oldest zones of one (kind, side) beyond the cap — keeps freshest
enforceCap(array<Zone> pool, int kind, int side, int cap) =>
    if array.size(pool) > 0
        count = 0
        for i = array.size(pool) - 1 to 0
            z = array.get(pool, i)
            if z.kind == kind and z.side == side and z.state != 2
                count += 1
                if count > cap
                    box.delete(z.bx)
                    label.delete(z.tg)
                    line.delete(z.ce)
                    zDrop = array.remove(pool, i)
                    true

// hard ceiling on the whole pool (ghosts included) so nothing grows unbounded
prunePool(array<Zone> pool) =>
    if array.size(pool) > 36
        z = array.get(pool, 0)
        box.delete(z.bx)
        label.delete(z.tg)
        line.delete(z.ce)
        zDrop = array.remove(pool, 0)
        true

registerZone(array<Zone> pool, int kind, int side, float zTop, float zBot, int leftBar, int cap) =>
    kindTxt = kind == 0 ? "OB" : "FVG"
    bx = box.new(leftBar, zTop, bar_index, zBot,
         border_color = side == 1 ? C_BULL : C_BEAR, border_width = 1,
         bgcolor = side == 1 ? C_BULLF : C_BEARF, extend = extend.right)
    label tg = na
    if showTags
        tg := label.new(leftBar, zTop, kindTxt,
             style = side == 1 ? label.style_label_lower_right : label.style_label_upper_right,
             color = color.new(color.black, 100), textcolor = side == 1 ? C_BULL : C_BEAR,
             size = size.tiny)
    line ceLn = na
    if kind == 1 and showCE
        mid = (zTop + zBot) / 2
        ceLn := line.new(leftBar, mid, bar_index, mid, extend = extend.right,
             color = side == 1 ? color.new(#22c68c, 45) : color.new(#f06292, 45),
             style = line.style_dashed, width = 1)
    z = Zone.new(bx, tg, ceLn, kind, side, zTop, zBot, 0)
    array.push(pool, z)
    enforceCap(pool, kind, side, cap)
    prunePool(pool)

// mitigation pass — runs on confirmed bars only; geometry never changes
updateZones(array<Zone> pool, float hi, float lo, float cl, bool ghost) =>
    if array.size(pool) > 0
        for i = array.size(pool) - 1 to 0
            z = array.get(pool, i)
            if z.state == 2
                continue
            mitigated = z.side == 1 ? cl < z.bottom : cl > z.top
            touched   = z.side == 1 ? lo <= z.top   : hi >= z.bottom
            if mitigated
                z.state := 2
                line.delete(z.ce)
                if ghost
                    box.set_bgcolor(z.bx, color.new(color.gray, 100))
                    box.set_border_color(z.bx, C_GHOST)
                    box.set_extend(z.bx, extend.none)
                    box.set_right(z.bx, bar_index)
                    label.delete(z.tg)
                    true
                else
                    box.delete(z.bx)
                    label.delete(z.tg)
                    zGone = array.remove(pool, i)
                    true
            else if touched and z.state == 0
                z.state := 1
                box.set_bgcolor(z.bx, zoneFill(z.side, 1))
                true

// ===== 6 · COMMIT (barstate.isconfirmed — nothing here repaints) ============
if barstate.isconfirmed
    // -- remember confirmed swings ------------------------------------------
    if not na(phPrice)
        lastSwingHi := phPrice
        lastHiBar   := bar_index - pivotLen
        brokeUpOnce := false
    if not na(plPrice)
        lastSwingLo := plPrice
        lastLoBar   := bar_index - pivotLen
        brokeDnOnce := false

    // -- Order Blocks: first close through a confirmed swing = the break ----
    if showOB and not na(lastSwingHi) and not brokeUpOnce and close > lastSwingHi
        brokeUpOnce := true
        // last bearish candle before the impulse = bullish OB
        obBar = -1
        for k = 1 to 20
            if close[k] < open[k]
                obBar := k
                break
        if obBar > 0
            zTop = obUseWick ? high[obBar] : math.max(open[obBar], close[obBar])
            zBot = obUseWick ? low[obBar]  : math.min(open[obBar], close[obBar])
            registerZone(zones, 0, 1, zTop, zBot, bar_index - obBar, obMax)
    if showOB and not na(lastSwingLo) and not brokeDnOnce and close < lastSwingLo
        brokeDnOnce := true
        obBar = -1
        for k = 1 to 20
            if close[k] > open[k]
                obBar := k
                break
        if obBar > 0
            zTop = obUseWick ? high[obBar] : math.max(open[obBar], close[obBar])
            zBot = obUseWick ? low[obBar]  : math.min(open[obBar], close[obBar])
            registerZone(zones, 0, -1, zTop, zBot, bar_index - obBar, obMax)

    // -- Fair Value Gaps: 3-candle imbalance ≥ ATR minimum ------------------
    if showFVG
        bullGap = low > high[2] and (low - high[2]) >= fvgMinAtr * atr14
        bearGap = high < low[2] and (low[2] - high) >= fvgMinAtr * atr14
        if bullGap
            registerZone(zones, 1, 1, low, high[2], bar_index - 2, fvgMax)
        if bearGap
            registerZone(zones, 1, -1, low[2], high, bar_index - 2, fvgMax)

    // -- basic mitigation ---------------------------------------------------
    updateZones(zones, high, low, close, keepGhost)

// ===== 7 · RENDER (barstate.islast — display only) ==========================
var label chip = na
if barstate.islast
    label.delete(chip)
    chip := na
    if showChip
        chip := label.new(bar_index, high + atr14 * 3, "◆ SMC Basics | ProEA Lab",
             style = label.style_label_down, color = C_CHIP, textcolor = C_TXT, size = size.small)
First time? Keep the default settings.

Pivot length 10 · 3 zones of each type per direction · halfway lines on. Give the chart enough candles to confirm its turning points.

Explore more when you need it.

Open the topic that answers your next question.

How an Order Block is chosen

A swing high or low is a turning point with enough candles on both sides. With the default pivot length of 10, it is only confirmed 10 candles later.

The first closed candle beyond that confirmed high or low is the break. For an upward break, the tool searches the previous 20 candles for the nearest down candle. For a downward break, it looks for the nearest up candle. If none exists, it draws no Order Block.

The box uses that candle’s body by default; you can include its wicks. It appears after the break, even though its left edge points to an older candle. A doji, with equal open and close, does not count as an opposite candle.

This is a chart pattern rule. It does not prove institutional orders or that buying or selling was absorbed there. The simulator’s circle and break line are teaching guides; the indicator draws the zone and tag.

How a gap and its halfway line are chosen

For an upward gap, candle 3’s low is above candle 1’s high. For a downward gap, candle 3’s high is below candle 1’s low. The space between those prices becomes the box. No swing break is required.

Candle 2 can trade through that space. A gap between the first and third wicks does not mean no trades happened there.

The default size filter is 0.3 × ATR(14). ATR measures recent price movement; this filter leaves out gaps smaller than that threshold. The lesson includes 14 earlier candles for this calculation.

CE means consequent encroachment. It is simply the halfway price: (top + bottom) ÷ 2. Crossing it does not automatically break a zone, change its state, or produce an alert.

Why a box fades or disappears

Fresh: a new zone has not met the script’s touch rule. Touched: price reaches its near edge and the fill fades. Its price boundaries stay fixed.

Removed: a confirmed close passes the far edge—below the bottom of an upward zone, or above the top of a downward zone. A wick beyond that edge, or a close exactly on it, does not trigger removal.

The script checks touching on the same candle that creates a box. A new FVG already meets that rule, so it starts faded. The shade alone does not prove a later visit.

With ghost outlines enabled, a removed zone leaves a gray outline ending at that candle. Its label and halfway line disappear. Older active zones can also be removed by the per-side cap. A total pool limit of 36 includes ghosts, so this is not permanent history.

Five ways to study zones in a trading plan

These are observation exercises. Use your own rules for entry, exit, trade size, and loss limits.

1. The OB retest

Mark a confirmed Order Block, then watch whether price returns. Describe what happens inside it and whether a close passes the far edge. A visit alone is not an entry.

2. A gap’s halfway line

Compare price with the middle and the edges. Record whether price moves away or continues through. The middle helps describe the move; it does not decide whether it will succeed.

3. Overlapping boxes · the stack

An OB and FVG may overlap. That gives two pattern references near the same price, but does not establish a higher chance of profit.

4. Read the surrounding trend

Compare recent confirmed highs and lows with the zone. A box is only one part of the chart. Decide in advance what would make your trade idea wrong.

5. Wait for a useful location

Let your plan decide which areas matter. An empty chart may reflect settings, confirmation delay, or the zone cap. It does not tell you to trade or stay out.

Choose what the indicator shows

Start with the defaults. Change one setting at a time and compare the result.

Swing pivot length
Default: 10 · range 3–50
How many candles are needed on each side of a turning point. A larger number increases the confirmation delay.
Show Order Blocks
Default: On
Show or hide the Order Block patterns.
Use full wick
Default: Off · candle body
Include the chosen candle’s full high–low range instead of only its body.
Keep last OBs per side
Default: 3 · range 1–5
Keep this many active upward OBs and this many downward OBs.
Show Fair Value Gaps
Default: On
Show or hide the three-candle gap patterns.
Min gap size (× ATR)
Default: 0.3 · range 0–2, steps of 0.1
Raise it to leave out smaller gaps relative to recent price movement.
Keep last FVGs per side
Default: 3 · range 1–5
A separate cap for upward and downward FVGs.
CE midline (50% of the gap)
Default: On
Show a dashed halfway line inside each active FVG.
Zone tags (OB / FVG)
Default: On
Keep these labels visible while learning to tell the boxes apart.
Keep mitigated zones as ghost outlines
Default: Off
Keep a temporary gray outline after a close breaks a zone.
Header chip
Default: On
Show the small SMC Basics name on the chart.

The default caps allow up to 12 active zones: 3 in each type-and-direction group. More boxes or a larger pivot setting do not automatically mean better trades. There is no session filter.

A simple routine with two timeframes
  1. Look at your wider timeframe first. Note recent highs, lows and nearby zones.
  2. Open your trading timeframe. Each chart calculates its own zones from its own candles.
  3. Choose an area to observe and wait for price to reach it.
  4. Compare the touch, the close, and the far edge with your entry and exit rules.
  5. Record the result, including losses and costs. Review several trades before changing your plan.

Comparing timeframes is a manual workflow. This free tool does not automatically combine their zones or provide an entry plan.

What this tool does not do

It marks chart patterns—never what price will do next. There is no zone score, liquidity sweep detector, regime filter, trade ticket, or alert.

New zones and state changes are committed when candles close. Pivot confirmation takes time. Once a zone exists, its price boundaries stay fixed, but it may fade or be removed.

This is a chart-reading tool, not financial advice. Practise with virtual money and check whether your complete plan works after losses and costs.

  • IFVG Desk

    Continue from identifying a fair value gap to studying an inversion-based entry setup.

  • Supply & Demand Desk

    Compare these candle-defined zones with a separate departure-and-return zone model.

Built by ProEA Lab. Compare all free indicators.

05 · THE LOG

Every change, dated

What shipped and what changed in SMC Basics, newest first. Ask for the next change below; what gets built lands here with a date, and on the lab queue on the front page.

  1. SMC Basics Shipped

    Tracks price zones left by a move until they break.

BUILT WITH TRADERS

Something to change in SMC Basics?

A small friction or a big idea. Tell us what would make this tool work better for you.

What would help?

Describe your rules and what you want the tool to help you see.

Add chart details Optional

For a question about your idea or an update if it ships.

Guides & new tools Optional

Add an email above to choose this.

Show us on your chart Optional

Crop out any account details you don't want to share.

No account needed. Sent privately to the lab.
  1. We read it
  2. We choose what to build
  3. Shipped changes get a date

Requests for a new tool go on the same queue: see what is asked for and what is being built.

© 2026 ProEA · All rights reservedBuilt for MT5 · Not affiliated with MetaQuotes