Strategy · Pine Script v6 · On the chart

SMC Long-Dip Strategy

by skipp-dev· code credited to preuss_steffen

This strategy executes long-only dip setups on the price chart by linking to external Smart Money Concepts core signals.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code194
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 strategy, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart. The trades and results appear in the Strategy Tester tab; adjust the settings with the gear icon.

Source Code

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

SMC_Long_Dip_Strategy.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

import preuss_steffen/smc_micro_profiles_generated/569 as mp
import preuss_steffen/smc_utils/4 as u

// Product role: pro execution surface on the frozen 8-channel executable contract.
// Product scope: this strategy executes long-only setups from the linked SMC Core long-dip specialist.
//   Short-parity execution requires a separate strategy track; it is not an implicit promise of this surface.
// Visible setup controls tune only wrapper behavior; linked core outputs stay in explicit operator-only expert-mapping groups.

// Strategy orders are staged on confirmed bars via process_orders_on_close, so the backtest path does not rely on intrabar lookahead.
strategy("SMC Long-Dip Strategy", overlay = true, pyramiding = 0, process_orders_on_close = true)

var string g_setup = "1. Execution Setup"
var string g_trade_plan = "2. Trade Plan"
var string g_bus_entry = "3. Chart Link - Entry States"
var string g_bus_plan = "4. Chart Link - Trade Plan"

entry_mode = input.string("Strict", "Execution Stage", options = ["Armed", "Confirmed", "Ready", "Best", "Strict"], group = g_setup, tooltip = "Choose which linked core stage is allowed to stage the execution trigger.")
min_quality_score = input.float(0.0, "Minimum Quality Score", step = 0.25, group = g_setup, tooltip = "Minimum quality score required before the linked core setup can stage an execution plan.")
use_regime_gate = input.bool(true, "Respect Regime Gate", group = g_setup, tooltip = "When enabled, the strategy respects TRADE_STATE, macro events, and earnings from the linked library. Disable to see raw signal performance without regime filtering.\n\n⚠️ BACKTEST NOTE: Library data is a snapshot of a single day. In backtests, today's regime/earnings/macro values are applied to ALL historical bars. For accurate historical backtests, set this to OFF and evaluate the pure signal performance. The regime gate is designed for LIVE TRADING, not historical backtesting.")
backtest_mode = input.bool(false, "Backtest Mode (Ignore Library)", group = g_setup, tooltip = "When ON, all library-based filters are bypassed. Use this for honest historical backtests showing pure price-structure signal performance.\n\nWhen OFF (default), the strategy uses live library data for entry gating (regime, earnings, macro events).")
strict_universe_entries = input.bool(false, "Strict Universe Mode", group = g_setup, tooltip = "When enabled, live entries are disabled unless the chart symbol is inside the latest scanned universe. Backtest Mode bypasses this gate with the other library filters. Status text: Strategy entries are disabled because this symbol is outside the scanned universe. Strategy entries are disabled because universe data is not available.")
use_take_profit = input.bool(true, "Use Take Profit", group = g_trade_plan, tooltip = "Stage a take-profit target on top of the linked core execution trigger and invalidation plan.")
take_profit_r = input.float(2.0, "Take Profit (R)", minval = 0.0, step = 0.25, group = g_trade_plan, tooltip = "Take-profit distance in R measured from execution trigger to invalidation.", active = use_take_profit)

// Rows are declared in the Suite's BUS plot() order. TradingView lists a source
// study's outputs as one flat list in that plot order (it knows nothing about
// these groups), so keeping the rows ascending across ALL groups means every
// dropdown pick moves strictly downwards — bind top to bottom without scrolling
// back up. QualityScore therefore sits with the plan rows (plot 9, after
// Trigger 7 / Invalidation 8) rather than with the entry states.
src_armed = input.source(close, "BUS Armed", group = g_bus_entry, tooltip = "Bind these chart-link inputs top-to-bottom to the matching linked core outputs from SMC Long-Dip Suite. The rows follow the Suite's output order in the dropdown.")
src_confirmed = input.source(close, "BUS Confirmed", group = g_bus_entry)
src_ready = input.source(close, "BUS Ready", group = g_bus_entry)
src_entry_best = input.source(close, "BUS EntryBest", group = g_bus_entry)
src_entry_strict = input.source(close, "BUS EntryStrict", group = g_bus_entry)
src_trigger = input.source(close, "BUS Trigger", group = g_bus_plan, tooltip = "Bind these plan inputs after the state group so the linked execution plan stays deterministic.")
src_invalidation = input.source(close, "BUS Invalidation", group = g_bus_plan)
src_quality_score = input.source(close, "BUS QualityScore", group = g_bus_plan)

state_on(float value) =>
    not na(value) and value > 0.5

bool armed = state_on(src_armed)
bool confirmed = state_on(src_confirmed)
bool ready = state_on(src_ready)
bool entry_best = state_on(src_entry_best)
bool entry_strict = state_on(src_entry_strict)

bool selected_state = false
if entry_mode == "Armed"
    selected_state := armed
else if entry_mode == "Confirmed"
    selected_state := confirmed
else if entry_mode == "Ready"
    selected_state := ready
else if entry_mode == "Best"
    selected_state := entry_best
else
    selected_state := entry_strict

bool risk_levels_ok = not na(src_trigger) and not na(src_invalidation) and src_trigger > src_invalidation
bool quality_ok = na(src_quality_score) ? false : src_quality_score >= min_quality_score

// Regime gate — mirrors the live product behavior
bool regime_allows_entry = mp.TRADE_STATE != "BLOCKED"
bool no_macro_event_block = not mp.HIGH_IMPACT_MACRO_TODAY or mp.MARKET_REGIME != "RISK_OFF"
bool not_earnings_ticker = not u.csv_has_symbol_token(mp.EARNINGS_TODAY_TICKERS, syminfo.ticker, syminfo.tickerid)
// Snapshot-gates apply LIVE only: mp.* is a single-day snapshot that Pine
// broadcasts as a constant onto ALL historical bars (look-ahead in backtest).
bool snapshot_gates_live = barstate.isrealtime and not backtest_mode
bool regime_gate_ok = use_regime_gate and snapshot_gates_live ? (regime_allows_entry and no_macro_event_block and not_earnings_ticker) : true
string strategy_symbol_key = syminfo.ticker
string strategy_symbol_key_qualified = syminfo.tickerid
bool strategy_universe_initialized = mp.UNIVERSE_TICKERS != ""
bool strategy_ticker_in_universe = strategy_universe_initialized and u.csv_has_symbol_token(mp.UNIVERSE_TICKERS, strategy_symbol_key, strategy_symbol_key_qualified)
bool strategy_universe_partial_context = strategy_ticker_in_universe and (mp.PROVIDER_COUNT == 0 or mp.STALE_PROVIDERS != "" or mp.EVENT_PROVIDER_STATUS != "ok")
int strategy_universe_status_code = u.universe_status_code(strategy_universe_initialized, strategy_ticker_in_universe, strategy_universe_partial_context)
bool universe_gate_ok = not strict_universe_entries or not snapshot_gates_live or strategy_universe_status_code == 3 or strategy_universe_status_code == 2
string universe_strict_block_text = strict_universe_entries and not backtest_mode ? u.universe_status_strategy_text(strategy_universe_status_code) : ""

// Entry/exit logic is evaluated from confirmed BUS inputs; no intrabar lookahead is used in this strategy wrapper.
bool can_stage_entry = selected_state and quality_ok and risk_levels_ok and regime_gate_ok and universe_gate_ok

float risk_per_unit = risk_levels_ok ? src_trigger - src_invalidation : na
float take_profit_price = na
if use_take_profit and risk_levels_ok
    take_profit_price := src_trigger + risk_per_unit * take_profit_r

var float active_invalidation = na
var float active_take_profit = na

if strategy.position_size <= 0
    if can_stage_entry
        strategy.entry("L", strategy.long, stop = src_trigger)
        // Arm the protective exit immediately (Pine holds from_entry exits
        // pending until the entry fills), so invalidation applies on the
        // entry bar itself — the post-fill block below then overrides it with
        // the frozen active_* levels via the same order id.
        strategy.exit("L Exit", "L", stop = src_invalidation,
                      limit = use_take_profit ? take_profit_price : na)
    else
        strategy.cancel("L")
        strategy.cancel("L Exit")

if strategy.position_size > 0 and strategy.position_size[1] <= 0
    active_invalidation := src_invalidation
    active_take_profit := use_take_profit ? take_profit_price : na

if strategy.position_size > 0
    float exit_stop = na(active_invalidation) ? src_invalidation : active_invalidation
    float exit_limit = use_take_profit ? active_take_profit : na
    if not na(exit_stop)
        strategy.exit("L Exit", "L", stop = exit_stop, limit = exit_limit)
else
    active_invalidation := na
    active_take_profit := na

plot(src_trigger, "Execution Trigger", color = color.new(color.aqua, 0), linewidth = 2, style = plot.style_linebr)
plot(src_invalidation, "Execution Invalidation", color = color.new(color.orange, 0), linewidth = 2, style = plot.style_linebr)

// ── Performance Summary Table (v7.1) ──
// Shows key backtest metrics directly in the chart so users can see at a glance
// whether the system works for the current symbol/timeframe combination.

var string g_perf = "3. Performance Display"
show_performance = input.bool(true, "Show Performance Table", group = g_perf, tooltip = "Display a compact performance summary table in the chart.")

var int total_trades = 0
var int winning_trades = 0
var int losing_trades = 0
var float total_r = 0.0
var float max_drawdown_pct = 0.0
var float peak_equity = 0.0
var float gross_profit = 0.0
var float gross_loss = 0.0
var float best_trade_r = 0.0
var float worst_trade_r = 0.0

// Sample equity every bar — including during the first still-open trade — so
// max drawdown is not blind until the first trade closes.
float current_equity = strategy.equity
peak_equity := math.max(peak_equity, current_equity)
float dd_pct = peak_equity > 0 ? (peak_equity - current_equity) / peak_equity * 100.0 : 0.0
max_drawdown_pct := math.max(max_drawdown_pct, dd_pct)

if strategy.closedtrades > 0
    total_trades := strategy.closedtrades
    winning_trades := strategy.wintrades
    losing_trades := strategy.losstrades
    gross_profit := strategy.grossprofit
    gross_loss := math.abs(strategy.grossloss)

float win_rate = total_trades > 0 ? 100.0 * winning_trades / total_trades : 0.0
float profit_factor = gross_loss > 0 ? gross_profit / gross_loss : 0.0
// Honest per-trade return: fixed-1-contract sizing has no fixed 1%-risk unit,
// so express the average as % of initial capital rather than a fake R multiple.
float avg_trade_pct = total_trades > 0 ? (strategy.netprofit / strategy.initial_capital) * 100.0 / total_trades : 0.0

var table perf_tbl = table.new(position.bottom_left, 2, 9, border_width = 0)

perf_row(table tbl, int row, string label_text, string value_text, color bg, color txt) =>
    table.cell(tbl, 0, row, label_text, bgcolor = bg, text_color = txt, text_halign = text.align_left, text_size = size.small)
    table.cell(tbl, 1, row, value_text, bgcolor = bg, text_color = txt, text_halign = text.align_right, text_size = size.small)

if show_performance and barstate.islast
    color txt = chart.fg_color
    color header_bg = color.new(color.black, 100)
    color ok_bg = color.new(color.teal, 85)
    color warn_bg = color.new(color.orange, 80)
    color bad_bg = color.new(color.red, 80)

    color wr_bg = win_rate >= 50 ? ok_bg : win_rate >= 40 ? warn_bg : bad_bg
    color pf_bg = profit_factor >= 1.5 ? ok_bg : profit_factor >= 1.0 ? warn_bg : bad_bg
    color dd_bg = max_drawdown_pct <= 10 ? ok_bg : max_drawdown_pct <= 20 ? warn_bg : bad_bg
    color universe_bg = strategy_universe_status_code == 3 ? ok_bg : strategy_universe_status_code == 2 ? warn_bg : bad_bg
    string universe_status_line = u.universe_status_badge(strategy_universe_status_code) + (universe_strict_block_text != "" ? " | " + universe_strict_block_text : "")

    perf_row(perf_tbl, 0, "SMC Strategy v7", total_trades > 0 ? "Performance" : "No Trades Yet", header_bg, txt)
    perf_row(perf_tbl, 1, "Universe", universe_status_line, universe_bg, txt)
    perf_row(perf_tbl, 2, "Trades", str.tostring(total_trades) + "  (W:" + str.tostring(winning_trades) + " / L:" + str.tostring(losing_trades) + ")", ok_bg, txt)
    perf_row(perf_tbl, 3, "Win Rate", str.tostring(win_rate, '#.#') + "%", wr_bg, txt)
    perf_row(perf_tbl, 4, "Profit Factor", str.tostring(profit_factor, '#.##'), pf_bg, txt)
    perf_row(perf_tbl, 5, "Net Profit", str.tostring(strategy.netprofit, '#.##'), strategy.netprofit >= 0 ? ok_bg : bad_bg, txt)
    perf_row(perf_tbl, 6, "Max Drawdown", str.tostring(max_drawdown_pct, '#.#') + "%", dd_bg, txt)
    perf_row(perf_tbl, 7, "Avg Trade %", str.tostring(avg_trade_pct, '#.##') + "%", total_trades > 0 and avg_trade_pct > 0 ? ok_bg : warn_bg, txt)
    perf_row(perf_tbl, 8, "Mode", backtest_mode ? "Backtest (pure signal)" : use_regime_gate ? "Live (regime gated)" : "Live (ungated)", header_bg, txt)
else if barstate.islast and not show_performance
    table.clear(perf_tbl, 0, 0, 1, 8)
plot(use_take_profit ? (strategy.position_size > 0 ? active_take_profit : take_profit_price) : na, "Execution Take Profit", color = color.new(color.green, 0), linewidth = 1, style = plot.style_linebr)

Overview

SMC Long-Dip Strategy enters positions based on selectable execution stages when quality score and regime criteria are met. Risk management uses an invalidation price for stop loss and an optional take profit defined in R multiples. Main settings configure execution stages, quality thresholds, universe restrictions, and an isolated backtest mode. A notable limitation is that historical backtests apply static single-day library data unless backtest mode is enabled.

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
Execution StagestringStrictentry_mode
Minimum Quality Scorefloat0.0min_quality_score
Respect Regime Gatebooltrueuse_regime_gate
Backtest Mode (Ignore Library)boolfalsebacktest_mode
Strict Universe Modeboolfalsestrict_universe_entries
Use Take Profitbooltrueuse_take_profit
Take Profit (R)float2.0take_profit_r
BUS Armedsourceclosesrc_armed
BUS Confirmedsourceclosesrc_confirmed
BUS Readysourceclosesrc_ready
BUS EntryBestsourceclosesrc_entry_best
BUS EntryStrictsourceclosesrc_entry_strict
Show all 16 settings
SettingTypeDefaultVariable
BUS Triggersourceclosesrc_trigger
BUS Invalidationsourceclosesrc_invalidation
BUS QualityScoresourceclosesrc_quality_score
Show Performance Tablebooltrueshow_performance
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

Daily Bias + FVG Strategy

by TradersPost
228 stars

This overlay strategy plots previous-day high and low, the daily open, and fair value gap zones on the price chart. It takes entries on a selectable timeframe when the FVG requirement and an optional session window allow them, then uses an ATR or fixed pip sto

Strategy v6 SMC / ICT / price actionSupport & resistance Repaints
Updated 3 months ago · None stated GitHub repository of Daily Bias + FVG Strategy
105 stars

Gold Scalping BOS & CHoCH is an overlay strategy designed for detecting market structure shifts. It calculates rolling swing highs and lows to identify Break of Structure (BOS) and Change of Character (CHoCH) events. Long signals trigger when bullish BOS and C

Strategy v6 SMC / ICT / price actionSupport & resistance
Updated 1 year ago · None stated GitHub repository of Gold Scalping BOS & CHoCH
57 stars

This strategy identifies trend reversals through market structure changes (CHoCH) filtered by MACD momentum. It initiates long positions on bullish structure breaks when MACD is positive and above its signal line, and short positions on bearish breaks when MAC

Strategy v6 SMC / ICT / price actionOscillators & momentum Repaints
Updated 1 year ago · Apache-2.0 GitHub repository of Market Structure MACD 4H + Trailing
43 stars

Donald - AI Futures is a price-chart strategy that estimates inner and outer high-low zones and a smoothed close with rational quadratic kernel regression. It builds bullish and bearish momentum signals, optionally compares volume with a volume-weighted moving

Strategy v5 Oscillators & momentumSMC / ICT / price action Repaints
Updated 2 years ago · None stated GitHub repository of Donald - AI Futures

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