Indicator · Pine Script v6 · On the chart

SMC Exit Signal

by skipp-dev· code credited to preuss_steffen

SMC Exit Signal is an overlay companion indicator that manages position lifecycle states driven by external Smart Money Concepts engine outputs.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code213
Settings16inputs
LicenceNone statedfile: MPL-2.0
Last update4 days ago26 Oct 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

213 lines of Pine Script v6 from SMC_Exit_Signal.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

SMC_Exit_Signal.pine
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © preuss_steffen

//@version=6

// Product role: Beginner-facing EXIT companion for SMC Mobile_Dashboard.
// Source of truth: linked SMC Core Engine BUS v2 outputs.
// What it adds: a local position-lifecycle state machine + alertconditions for
//   STOP / TP1 / TP2 / DEFENSIVE EXIT — the missing piece so a manual trader
//   can rely on TradingView phone alerts instead of staring at the chart.
// Trigger, invalidation, stop and both targets are consumed directly from the
// producer. Schema mismatch or an incomplete/incoherent plan fails closed.
// No library imports — fully BUS-driven and self-contained.

indicator("SMC Exit Signal", overlay = true)

// ───────────────────────── Inputs ─────────────────────────
var string g_plan = "1. Exit Behavior"
var string g_visual = "2. Visual"
var string g_bus_state = "3. Expert Mapping - Entry States"
var string g_bus_plan = "4. Expert Mapping - Trade Plan"

move_be_after_tp1 = input.bool(true, "Move stop to break-even after TP1", group = g_plan, tooltip = "After TP1 hits, the displayed Stop bumps up to entry price. The hard-stop alert then fires at break-even instead of the original invalidation. Most-asked-for safety feature.")
use_defensive_exit = input.bool(true, "Defensive exit on setup invalidation", group = g_plan, tooltip = "Fire EXIT if the entry-stack collapses (Armed/Confirmed/Ready all drop to false) while still in trade — before stop is hit.")
defensive_grace_bars = input.int(2, "Defensive grace bars", minval = 0, maxval = 20, group = g_plan, tooltip = "Tolerate this many bars of state collapse before firing the defensive exit. Avoids one-bar flickers.")
confirm_bars_only = input.bool(true, "Evaluate on confirmed bars only", group = g_plan, tooltip = "Gate state-machine transitions and exit detection to barstate.isconfirmed. Recommended ON to avoid intrabar flicker (re-arm / multi-trigger alerts on the same bar). Turn OFF only if you explicitly want intrabar reactions.")

show_levels = input.bool(true, "Show Stop/TP1/TP2 lines while in trade", group = g_visual)
show_labels = input.bool(true, "Show ENTER / EXIT labels", group = g_visual)
show_table = input.bool(true, "Show status table", group = g_visual)

src_schema = input.source(close, "BUS SchemaVersion", group = g_bus_state, display = display.none, tooltip = "Bind all rows to the matching SMC Long-Dip Suite BUS outputs. SchemaVersion must read 7001; otherwise the companion fails closed.")
src_armed = input.source(close, "BUS Armed", group = g_bus_state, display = display.none)
src_confirmed = input.source(close, "BUS Confirmed", group = g_bus_state, display = display.none)
src_ready = input.source(close, "BUS Ready", group = g_bus_state, display = display.none)
src_trigger = input.source(close, "BUS Trigger", group = g_bus_plan, display = display.none)
src_invalidation = input.source(close, "BUS Invalidation", group = g_bus_plan, display = display.none)
src_stop = input.source(close, "BUS StopLevel", group = g_bus_plan, display = display.none)
src_target1 = input.source(close, "BUS Target1", group = g_bus_plan, display = display.none)
src_target2 = input.source(close, "BUS Target2", group = g_bus_plan, display = display.none)

// ───────────────────────── Helpers ─────────────────────────
state_on(float value) =>
    not na(value) and value > 0.5

float EXPECTED_SCHEMA = 7001
bool schema_ok = not na(src_schema) and math.round(src_schema) == EXPECTED_SCHEMA
bool armed = schema_ok and state_on(src_armed)
bool confirmed = schema_ok and state_on(src_confirmed)
bool ready = schema_ok and state_on(src_ready)
bool any_state = armed or confirmed or ready

bool risk_ok = schema_ok and not na(src_trigger) and not na(src_invalidation) and
     not na(src_stop) and not na(src_target1) and not na(src_target2) and
     src_stop <= src_invalidation and src_invalidation < src_trigger and
     src_target1 > src_trigger and src_target2 > src_target1

// ───────────────────────── Position-Lifecycle State Machine ─────────────────────────
// States:
//   0 = FLAT (no exposure, watching)
//   1 = ARMED (state on, levels published, waiting for trigger to be hit)
//   2 = IN_TRADE (price has touched trigger, position considered open)
// Transitions are evaluated on confirmed bars to avoid intrabar flicker.

var int   pos_state          = 0
var float entry_price        = na
var float entry_stop         = na
var float tp1_price          = na
var float tp2_price          = na
var int   entry_bar          = na
var bool  tp1_hit_already    = false
var int   collapse_count     = 0

// Optional gate: only mutate state on confirmed bars to avoid intrabar flicker.
bool eval_now = (not confirm_bars_only) or barstate.isconfirmed

// Latch ARMED when the stack provides valid levels and at least one state is on.
// Stays ARMED while levels exist and we're not yet in trade.
if eval_now and pos_state == 0 and any_state and risk_ok
    pos_state := 1
    entry_stop := src_stop
    entry_price := src_trigger
    tp1_price := src_target1
    tp2_price := src_target2

// While ARMED, refresh the producer-owned plan before the assumed fill.
if eval_now and pos_state == 1 and risk_ok
    entry_stop := src_stop
    entry_price := src_trigger
    tp1_price := src_target1
    tp2_price := src_target2

// Trigger fill: high crosses entry_price → enter IN_TRADE.
bool just_entered = false
if eval_now and pos_state == 1 and any_state and risk_ok and not na(entry_price) and high >= entry_price
    pos_state := 2
    entry_bar := bar_index
    tp1_hit_already := false
    collapse_count := 0
    just_entered := true

// Fail closed before fill if schema, lifecycle, or any critical plan level is
// missing/incoherent (no exit alert — the assumed trade never opened).
if eval_now and pos_state == 1 and (not any_state or not risk_ok)
    pos_state := 0
    entry_price := na
    entry_stop := na
    tp1_price := na
    tp2_price := na

// ───────────────────────── Exit Detection (only when IN_TRADE) ─────────────────────────
bool exit_stop_hit = false
bool exit_tp1_hit = false
bool exit_tp2_hit = false
bool exit_defensive = false

if eval_now and pos_state == 2
    // 1. Hard stop — close below invalidation, use close not low to avoid wick flicker.
    if not na(entry_stop) and close < entry_stop
        exit_stop_hit := true

    // 2. TP1 — first time high reaches TP1 price.
    if not exit_stop_hit and not tp1_hit_already and not na(tp1_price) and high >= tp1_price
        exit_tp1_hit := true
        tp1_hit_already := true
        // Breakeven-after-T1: bump the stop up to entry price (never down).
        if move_be_after_tp1 and not na(entry_price)
            entry_stop := math.max(entry_stop, entry_price)

    // 3. TP2 — high reaches TP2 price → full close.
    if not exit_stop_hit and not na(tp2_price) and high >= tp2_price
        exit_tp2_hit := true

    // 4. Defensive — entry stack collapses while in trade, with grace window.
    if use_defensive_exit
        if not any_state
            collapse_count := collapse_count + 1
        else
            collapse_count := 0
        if collapse_count > defensive_grace_bars and not exit_stop_hit and not exit_tp2_hit
            exit_defensive := true

// On any full exit (stop / tp2 / defensive), reset back to FLAT.
bool full_exit = exit_stop_hit or exit_tp2_hit or exit_defensive
if full_exit
    pos_state := 0
    entry_price := na
    entry_stop := na
    tp1_price := na
    tp2_price := na
    entry_bar := na
    tp1_hit_already := false
    collapse_count := 0

// ───────────────────────── Alerts ─────────────────────────
// H-1 (system review 2026-04-24): bind alertcondition() to bar-close gate.
// Reuses eval_now as the single source of truth for the bar-close gate
// (PR #1940 review). The literal _alertGate token is preserved because
// the audit pin tests/test_pine_alert_bar_close_gate.py recognises.
_alertGate = eval_now
alertcondition(_alertGate and just_entered, title = "ENTER LONG (trigger filled)", message = "SMC Exit Signal: trigger filled — position OPEN")
alertcondition(_alertGate and exit_stop_hit, title = "EXIT — Stop hit", message = "SMC Exit Signal: STOP HIT — close full position")
alertcondition(_alertGate and exit_tp1_hit, title = "EXIT — TP1 (take half)", message = "SMC Exit Signal: TP1 reached — take half, move stop to entry")
alertcondition(_alertGate and exit_tp2_hit, title = "EXIT — TP2 (close rest)", message = "SMC Exit Signal: TP2 reached — close remaining position")
alertcondition(_alertGate and exit_defensive, title = "EXIT — Defensive (setup invalidated)", message = "SMC Exit Signal: setup collapsed in-trade — defensive exit")
alertcondition(_alertGate and (exit_stop_hit or exit_tp2_hit or exit_defensive), title = "EXIT (any full close)", message = "SMC Exit Signal: full exit triggered")

// ───────────────────────── Visuals ─────────────────────────
plot(show_levels and pos_state == 2 ? entry_stop : na, "Stop", color = color.new(color.red, 0), linewidth = 2, style = plot.style_linebr)
plot(show_levels and pos_state == 2 ? tp1_price : na, "TP1", color = color.new(color.orange, 0), linewidth = 1, style = plot.style_linebr)
plot(show_levels and pos_state == 2 ? tp2_price : na, "TP2", color = color.new(color.green, 0), linewidth = 2, style = plot.style_linebr)
plot(show_levels and pos_state == 2 ? entry_price : na, "Entry", color = color.new(color.aqua, 0), linewidth = 1, style = plot.style_linebr)

if show_labels
    if just_entered
        label.new(bar_index, low, "🟢 ENTER", style = label.style_label_up, color = color.new(color.green, 20), textcolor = color.white, size = size.small)
    if exit_stop_hit
        label.new(bar_index, high, "🔴 EXIT — Stop", style = label.style_label_down, color = color.new(color.red, 10), textcolor = color.white, size = size.small)
    if exit_tp1_hit
        label.new(bar_index, high, "🟠 TP1 — take half", style = label.style_label_down, color = color.new(color.orange, 10), textcolor = color.white, size = size.small)
    if exit_tp2_hit
        label.new(bar_index, high, "🟢 EXIT — TP2", style = label.style_label_down, color = color.new(color.green, 10), textcolor = color.white, size = size.small)
    if exit_defensive
        label.new(bar_index, high, "🟡 EXIT — Defensive", style = label.style_label_down, color = color.new(color.yellow, 10), textcolor = color.black, size = size.small)

// ───────────────────────── Status table (top-right) ─────────────────────────
if show_table and barstate.islast
    var table tbl = table.new(position.top_right, 2, 7, frame_color = color.gray, frame_width = 1, border_color = color.gray, border_width = 1)
    string state_txt = pos_state == 0 ? "FLAT" : pos_state == 1 ? "ARMED" : "IN-TRADE"
    color  state_bg  = pos_state == 0 ? color.new(color.gray, 70) : pos_state == 1 ? color.new(color.yellow, 70) : color.new(color.green, 70)
    string bus_txt = schema_ok ? (risk_ok ? "PLAN VALID" : "WAITING PLAN") : "NOT CONNECTED"
    color bus_bg = schema_ok ? (risk_ok ? color.new(color.green, 70) : color.new(color.yellow, 70)) : color.new(color.red, 60)

    table.cell(tbl, 0, 0, "SMC Exit", text_color = color.white, bgcolor = color.new(color.black, 30), text_size = size.small)
    table.cell(tbl, 1, 0, "", text_color = color.white, bgcolor = color.new(color.black, 30), text_size = size.small)

    table.cell(tbl, 0, 1, "BUS", text_color = color.white, bgcolor = color.new(color.black, 50), text_size = size.small)
    table.cell(tbl, 1, 1, bus_txt, text_color = color.white, bgcolor = bus_bg, text_size = size.small)

    table.cell(tbl, 0, 2, "State", text_color = color.white, bgcolor = color.new(color.black, 50), text_size = size.small)
    table.cell(tbl, 1, 2, state_txt, text_color = color.white, bgcolor = state_bg, text_size = size.small)

    table.cell(tbl, 0, 3, "Entry", text_color = color.white, bgcolor = color.new(color.black, 50), text_size = size.small)
    table.cell(tbl, 1, 3, na(entry_price) ? "—" : str.tostring(entry_price, format.mintick), text_color = color.white, bgcolor = color.new(color.aqua, 70), text_size = size.small)

    table.cell(tbl, 0, 4, "Stop", text_color = color.white, bgcolor = color.new(color.black, 50), text_size = size.small)
    table.cell(tbl, 1, 4, na(entry_stop) ? "—" : str.tostring(entry_stop, format.mintick), text_color = color.white, bgcolor = color.new(color.red, 60), text_size = size.small)

    table.cell(tbl, 0, 5, "TP1", text_color = color.white, bgcolor = color.new(color.black, 50), text_size = size.small)
    table.cell(tbl, 1, 5, na(tp1_price) ? "—" : str.tostring(tp1_price, format.mintick), text_color = color.white, bgcolor = color.new(color.orange, 60), text_size = size.small)

    table.cell(tbl, 0, 6, "TP2", text_color = color.white, bgcolor = color.new(color.black, 50), text_size = size.small)
    table.cell(tbl, 1, 6, na(tp2_price) ? "—" : str.tostring(tp2_price, format.mintick), text_color = color.white, bgcolor = color.new(color.green, 60), text_size = size.small)

Overview

SMC Exit Signal monitors trigger levels, stops, and take-profit targets to track active trades directly on the chart. It can dynamically adjust the stop loss to break-even after reaching target 1 and trigger a defensive exit if setup conditions collapse. The indicator plots active trade levels, displays enter and exit labels, and shows an on-screen status table.

Details

Published by

skipp-dev on GitHub

Code credit

preuss_steffen, as written in the script's header

Draws

On the price chart

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Move stop to break-even after TP1booltruemove_be_after_tp1
Defensive exit on setup invalidationbooltrueuse_defensive_exit
Defensive grace barsint2defensive_grace_bars
Evaluate on confirmed bars onlybooltrueconfirm_bars_only
Show Stop/TP1/TP2 lines while in tradebooltrueshow_levels
Show ENTER / EXIT labelsbooltrueshow_labels
Show status tablebooltrueshow_table
BUS SchemaVersionsourceclosesrc_schema
BUS Armedsourceclosesrc_armed
BUS Confirmedsourceclosesrc_confirmed
BUS Readysourceclosesrc_ready
BUS Triggersourceclosesrc_trigger
Show all 16 settings
SettingTypeDefaultVariable
BUS Invalidationsourceclosesrc_invalidation
BUS StopLevelsourceclosesrc_stop
BUS Target1sourceclosesrc_target1
BUS Target2sourceclosesrc_target2
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

575 stars

This overlay indicator scans a pasted list of symbols for ICT liquidity sweep patterns using prior swing sweeps. The screening method looks back one, two, or three swings and can list long and short signals in a results table with adjustable rows, position, an

Indicator v5 SMC / ICT / price actionScreeners & dashboards
Updated 1 year ago · MPL-2.0 GitHub repository of ICT Liquidity Sweep Pattern Scanner

Golden Bullet Strategy

by TradersPost
228 stars

The Golden Bullet Strategy is an overlay signal indicator based on Smart Money Concepts and time-based liquidity models. It identifies liquidity sweeps of a designated reference session range during a specified hunt window. It then confirms Market Structure Sh

Indicator v6 SMC / ICT / price actionSessions & time
Updated 3 months ago · None stated GitHub repository of Golden Bullet Strategy
56 stars

This indicator identifies fractal-based pivot highs and lows to map out market structure directly on the price chart. It detects bullish and bearish structure breaks, automatically labeling Break of Structure (BOS) and Change of Character (ChoCH) events when p

Indicator v5 SMC / ICT / price actionSupport & resistance
Updated 2 months ago · None stated GitHub repository of Market Structure (Fractal)
53 stars

Apex Trend & Liquidity Master calculates a trend cloud using customizable moving averages expanded by a volatility multiplier directly on the main price chart. It identifies dynamic support and resistance liquidity zones from swing high and low pivots, extendi

Indicator v6 TrendSupport & resistance
Updated 2 months ago · MPL-2.0 GitHub repository of Apex Trend & Liquidity Master
23 stars

MTF State of Delivery tracks lower timeframe and higher timeframe orderflow delivery states by identifying bullish and bearish delivery levels across timeframes. It plots confirmed and pending orderflow lines directly on the price chart and provides an optiona

Indicator v5 SMC / ICT / price actionSupport & resistance
Updated 4 weeks ago · Custom licence GitHub repository of MTF State of Delivery by traderprimez

More SMC / ICT scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers