1Copy the scriptPress Copy script above, or the copy button on the code below.
2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
3Paste over the templateCreate a new library, select all of the template text and paste. Press Save and give it a name.
4Publish or import itA library draws nothing. Publish it from the editor, then import its functions in your own scripts.
Source Code
282 lines of Pine Script v6 from SMC++/smc_utils.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.
smc_utils.pine
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
//@version=6
library("smc_utils", overlay = true)
import preuss_steffen/smc_core_types/5 as ct
// --------------------------------------------------
// Generic helpers
// --------------------------------------------------
export in_range(float value, float max, float min = 0.0) =>
min <= value and value <= max
export in_range(float max1, float min1, float max2, float min2) =>
min2 <= min1 and min1 <= max2 and min2 <= max1 and max1 <= max2
export range_overlap(float max1, float min1, float max2, float min2) =>
min1 < max2 and max1 > min2
export auto_ltf_timeframe(int chart_seconds) =>
chart_seconds <= 60 ? '' :
chart_seconds <= 180 ? '1' :
chart_seconds <= 300 ? '1' :
chart_seconds <= 900 ? '3' :
chart_seconds <= 1800 ? '5' :
chart_seconds <= 3600 ? '15' :
chart_seconds <= 14400 ? '30' :
chart_seconds <= 86400 ? '60' :
chart_seconds <= 604800 ? '240' :
'1D'
export trend_text(int trend_value) =>
trend_value > 0 ? 'Bullish' : trend_value < 0 ? 'Bearish' : 'Neutral'
export trend_text_or_na(float trend_value) =>
na(trend_value) or trend_value == 0 ? 'n/a' : trend_value > 0 ? 'Bullish' : 'Bearish'
export format_level(float value) =>
na(value) ? 'n/a' : str.tostring(value, format.mintick)
export prefer_level(float primary_level, float fallback_level) =>
not na(primary_level) ? primary_level : fallback_level
export edge(bool condition) =>
condition and not condition[1]
export scaled_marker_gap(int base_gap, bool auto_scale, int chart_tf_seconds, int reference_tf_seconds, float max_scale) =>
scale_base = reference_tf_seconds > 0 ? reference_tf_seconds : 180
ratio = scale_base > 0 and chart_tf_seconds > 0 ? chart_tf_seconds / scale_base : 1.0
bounded_scale = auto_scale ? math.min(math.max(math.sqrt(ratio), 1.0), max_scale) : 1.0
int(math.round(base_gap * bounded_scale))
export ltf_stats(float[] opens, float[] closes, float[] volumes) =>
sample_count = opens.size()
bull_count = 0
bear_count = 0
bull_volume = 0.0
bear_volume = 0.0
if sample_count > 0
for i = 0 to sample_count - 1
open_value = opens.get(i)
close_value = closes.get(i)
volume_value = i < volumes.size() ? volumes.get(i) : 0.0
if close_value > open_value
bull_count += 1
bull_volume += volume_value
else if close_value < open_value
bear_count += 1
bear_volume += volume_value
total_volume = bull_volume + bear_volume
bull_share = sample_count > 0 ? bull_count / sample_count : na
volume_delta = total_volume > 0 ? (bull_volume - bear_volume) / total_volume : na
[sample_count, bull_share, volume_delta]
export weighted_avg4(float a, float b, float c, float d, float wa = 1.0, float wb = 1.0, float wc = 1.0, float wd = 1.0) =>
float wsum = wa + wb + wc + wd
wsum > 0 ? (a * wa + b * wb + c * wc + d * wd) / wsum : na
export lr_slope_pct(series float src, simple int len) =>
float lr_now = ta.linreg(src, len, 0)
float lr_prev = ta.linreg(src, len, 1)
float base = math.max(math.abs(src), syminfo.mintick)
100.0 * (lr_now - lr_prev) / base
export sd_lr2_pct(series float src, simple int len) =>
float lr0 = ta.linreg(src, len, 0)
float lr1 = ta.linreg(src, len, 1)
float lr_slope = lr0 - lr1
float denom = math.max(math.abs(src), syminfo.mintick)
not na(lr_slope[1]) ? 100.0 * (lr_slope - lr_slope[1]) / denom : na
export qema_like(series float src, simple int len) =>
float ema1 = ta.ema(src, len)
float ema2 = ta.ema(ema1, len)
float ema3 = ta.ema(ema2, len)
float ema4 = ta.ema(ema3, len)
float ema5 = ta.ema(ema4, len)
5.0 * ema1 - 10.0 * ema2 + 10.0 * ema3 - 5.0 * ema4 + ema5
export external_trend_gate(simple string symbol, simple int fast_len, simple int slow_len) =>
float ext_close = request.security(symbol, timeframe.period, close,
gaps = barmerge.gaps_off,
lookahead = barmerge.lookahead_off,
ignore_invalid_symbol = true,
calc_bars_count = 300)
float ext_close_sparse = request.security(symbol, timeframe.period, close,
gaps = barmerge.gaps_on,
lookahead = barmerge.lookahead_off,
ignore_invalid_symbol = true,
calc_bars_count = 300)
float ext_fast = ta.ema(ext_close_sparse, fast_len)
float ext_slow = ta.ema(ext_close_sparse, slow_len)
bool ext_missing = na(ext_close) or na(ext_fast) or na(ext_slow)
[ext_missing, not ext_missing and ext_close > ext_fast and ext_fast > ext_slow]
export external_breadth_gate(simple string symbol, simple string mode, simple int len) =>
float ext_breadth = request.security(symbol, timeframe.period, close,
gaps = barmerge.gaps_off,
lookahead = barmerge.lookahead_off,
ignore_invalid_symbol = true,
calc_bars_count = 100)
float ext_breadth_sparse = request.security(symbol, timeframe.period, close,
gaps = barmerge.gaps_on,
lookahead = barmerge.lookahead_off,
ignore_invalid_symbol = true,
calc_bars_count = 100)
float ext_ema = ta.ema(ext_breadth_sparse, len)
bool breadth_missing = na(ext_breadth) or (mode == 'Above EMA' and na(ext_ema))
bool breadth_pass = mode == 'Above EMA' ? ext_breadth > ext_ema : mode == 'Rising' ? ext_breadth > ext_breadth[1] : ext_breadth > 0
[breadth_missing, not breadth_missing and breadth_pass]
export normalize_csv_token(string s) =>
str.upper(str.replace_all(s, ' ', ''))
export csv_has_token(string csv, string token) =>
string haystack = ',' + normalize_csv_token(csv) + ','
string needle = ',' + normalize_csv_token(token) + ','
str.contains(haystack, needle)
export csv_has_symbol_token(string csv, string ticker, string tickerid) =>
csv_has_token(csv, ticker) or csv_has_token(csv, tickerid)
export universe_status_code(bool universe_initialized, bool ticker_in_universe, bool producer_context_partial) =>
universe_initialized ? ticker_in_universe ? producer_context_partial ? 2 : 3 : 1 : 0
export universe_status_badge(int status_code) =>
status_code == 3 ? 'UNIVERSE: VERIFIED' : status_code == 2 ? 'UNIVERSE: PARTIAL' : status_code == 1 ? 'UNIVERSE: NOT SCANNED' : 'UNIVERSE: UNINITIALIZED'
export universe_status_banner(int status_code) =>
status_code == 3 ? 'This symbol is part of the latest scanned universe. Full producer context is available.' : status_code == 2 ? 'This symbol has partial universe coverage. Core SMC logic runs, but some producer-based context may be missing.' : status_code == 1 ? 'This symbol is outside the latest scanned universe. Core SMC logic still runs, but producer-based context is unavailable.' : 'Universe data is not loaded. Core chart logic may run, but producer-based context cannot be validated.'
export universe_status_dashboard_text(int status_code) =>
status_code == 3 ? 'Status: Verified\nThis symbol is included in the latest scanned universe.\nAll available producer-based context can be used.' : status_code == 2 ? 'Status: Partial\nThis symbol is only partially covered by the latest universe snapshot.\nSome enriched context fields may be unavailable or incomplete.' : status_code == 1 ? 'Status: Not Scanned\nThis symbol was not included in the latest scanned universe.\nCore SMC chart logic remains active.\nProducer-based context is not available for this symbol.' : 'Status: Uninitialized\nUniverse membership could not be verified.\nProducer-based context is not loaded or not ready.\nUse caution until universe data is available.'
export universe_status_feature_matrix(int status_code) =>
status_code == 3 ? 'SMC Structure: Available\nMarket Structure Logic: Available\nProducer Context: Available\nNews Context: Available\nEarnings Context: Available\nMicrostructure Profile: Available\nMacro Regime Context: Available' : status_code == 2 ? 'SMC Structure: Available\nMarket Structure Logic: Available\nProducer Context: Limited\nNews Context: Limited\nEarnings Context: Limited\nMicrostructure Profile: Limited\nMacro Regime Context: Available' : status_code == 1 ? 'SMC Structure: Available\nMarket Structure Logic: Available\nProducer Context: Unavailable\nUniverse Membership: Not Verified\nNews Context: Unavailable\nEarnings Context: Unavailable\nMicrostructure Profile: Unavailable\nMacro Regime Context: Available' : 'SMC Structure: Available\nMarket Structure Logic: Available\nProducer Context: Not loaded\nUniverse Membership: Not Verified\nNews Context: Not verified\nEarnings Context: Not verified\nMicrostructure Profile: Not verified\nMacro Regime Context: Available'
export universe_status_strategy_text(int status_code) =>
status_code == 1 ? 'Strategy entries are disabled because this symbol is outside the scanned universe.' : status_code == 0 ? 'Strategy entries are disabled because universe data is not available.' : ''
export htf_fvg_key(int left_time, int right_time, float top, float bottom) =>
str.format('{0}|{1}|{2}|{3}', left_time, right_time, format_level(top), format_level(bottom))
export push_capped_label(label[] buffer, label new_label, int max_keep) =>
if not na(new_label)
if max_keep <= 0
label.delete(new_label)
else
buffer.push(new_label)
while buffer.size() > max_keep
label.delete(buffer.shift())
export trim_label_history(label[] history, int max_keep) =>
if max_keep <= 0
for i = history.size() - 1 to 0
label.delete(history.get(i))
history.clear()
else
while history.size() > max_keep
label.delete(history.shift())
// --------------------------------------------------
// Embedded helpers (extracted from Core Engine)
// --------------------------------------------------
export smc_lib_atr(simple int length) =>
float atr_value = ta.atr(length)
float tr_cum = ta.cum(ta.tr(true))
if bar_index < length
atr_value := tr_cum / (bar_index + 1)
atr_value
export smc_lib_ehma(float source, simple int length) =>
int half_length = math.max(1, int(math.round(length / 2.0)))
int sqrt_length = math.max(1, int(math.round(math.sqrt(length))))
ta.ema(2 * ta.ema(source, half_length) - ta.ema(source, length), sqrt_length)
export smc_lib_thma(float source, simple int length) =>
int len_sixth = math.max(1, int(math.round(length / 6.0)))
int len_quarter = math.max(1, int(math.round(length / 4.0)))
int len_half = math.max(1, int(math.round(length / 2.0)))
ta.wma(ta.wma(source, len_sixth) * 3 - ta.wma(source, len_quarter) - ta.wma(source, len_half), len_half)
export smc_lib_zlema(float source, simple int length) =>
// Zero Lag EMA (Ehlers/Way): EMA of de-lagged source — 2*src - src[lag]
int lag = math.max(0, int(math.round((length - 1) / 2.0)))
ta.ema(2 * source - source[lag], length)
export smc_lib_get_ma(simple ct.SmcLibMovingAverage select_ma = ct.SmcLibMovingAverage.SMA, float source, simple int length) =>
switch select_ma
ct.SmcLibMovingAverage.EMA => ta.ema(source, length)
ct.SmcLibMovingAverage.RMA => ta.rma(source, length)
ct.SmcLibMovingAverage.WMA => ta.wma(source, length)
ct.SmcLibMovingAverage.VWMA => ta.vwma(source, length)
ct.SmcLibMovingAverage.HMA => ta.hma(source, length)
ct.SmcLibMovingAverage.EHMA => smc_lib_ehma(source, length)
ct.SmcLibMovingAverage.THMA => smc_lib_thma(source, length)
ct.SmcLibMovingAverage.ZLEMA => smc_lib_zlema(source, length)
=> ta.sma(source, length)
export smc_lib_bb(float source, simple int length, float mult, simple ct.SmcLibMovingAverage select_ma) =>
float base = smc_lib_get_ma(select_ma, source, length)
float dev = mult * ta.stdev(source, length)
[base, base + dev, base - dev]
export smc_lib_dmi(simple int di_length = 17, simple int adx_smoothing = 14) =>
ta.dmi(di_length, adx_smoothing)
export smc_lib_detect_divergence(float osc, simple int pivot_confirmation_bars_left = 5, simple int pivot_confirmation_bars_right = 3, simple int pivot_min_x_distance = 5, simple int pivot_max_x_distance = 50, series float ref_low = low, series float ref_high = high, simple int pivot_min_y_distance_len = 14, simple float pivot_min_y_distance_dev_mult = 0.1, simple float pivot_min_y_distance_atr_mult = 0.1) =>
bool osc_pivot_l = not na(ta.pivotlow(osc, pivot_confirmation_bars_left, pivot_confirmation_bars_right))
bool osc_pivot_h = not na(ta.pivothigh(osc, pivot_confirmation_bars_left, pivot_confirmation_bars_right))
float pivot_osc_value = osc[pivot_confirmation_bars_right]
float osc_dev_value = nz(ta.dev(pivot_osc_value, pivot_min_y_distance_len), 0.0) * pivot_min_y_distance_dev_mult
float price_atr_value = smc_lib_atr(pivot_min_y_distance_len) * pivot_min_y_distance_atr_mult
var int osc_prev_l_idx = na
var float osc_prev_l_value = na
var float price_prev_l = na
var int osc_prev_h_idx = na
var float osc_prev_h_value = na
var float price_prev_h = na
if barstate.isconfirmed and (osc_pivot_h or osc_pivot_l)
float prev_pivot_value = osc_pivot_h ? osc_prev_h_value : osc_prev_l_value
float prev_pivot_price = osc_pivot_h ? price_prev_h : price_prev_l
float new_pivot_value = osc[pivot_confirmation_bars_right]
float new_pivot_price = osc_pivot_h ? ref_high[pivot_confirmation_bars_right] : ref_low[pivot_confirmation_bars_right]
int new_pivot_distance = osc_pivot_h ? bar_index - osc_prev_h_idx : bar_index - osc_prev_l_idx
bool has_prev_pivot = osc_pivot_h ? not na(osc_prev_h_idx) and not na(prev_pivot_value) and not na(prev_pivot_price) : not na(osc_prev_l_idx) and not na(prev_pivot_value) and not na(prev_pivot_price)
if osc_pivot_h
osc_prev_h_idx := bar_index
osc_prev_h_value := new_pivot_value
price_prev_h := new_pivot_price
if osc_pivot_l
osc_prev_l_idx := bar_index
osc_prev_l_value := new_pivot_value
price_prev_l := new_pivot_price
int mode = has_prev_pivot ? new_pivot_value < prev_pivot_value - osc_dev_value ? -1 : new_pivot_value > prev_pivot_value + osc_dev_value ? 1 : 0 : 0
int mode_p = has_prev_pivot ? new_pivot_price < prev_pivot_price - price_atr_value ? -1 : new_pivot_price > prev_pivot_price + price_atr_value ? 1 : 0 : 0
bool x_distance_in_range = has_prev_pivot and new_pivot_distance >= pivot_min_x_distance and new_pivot_distance <= pivot_max_x_distance
bool strong_bull = osc_pivot_l and x_distance_in_range and mode == 1 and mode_p == -1
bool medium_bull = osc_pivot_l and x_distance_in_range and mode == 1 and mode_p == 0
bool weak_bull = osc_pivot_l and x_distance_in_range and mode == 0 and mode_p == -1
bool hidden_bull = osc_pivot_l and x_distance_in_range and mode == -1 and mode_p == 1
bool strong_bear = osc_pivot_h and x_distance_in_range and mode == -1 and mode_p == 1
bool medium_bear = osc_pivot_h and x_distance_in_range and mode == -1 and mode_p == 0
bool weak_bear = osc_pivot_h and x_distance_in_range and mode == 0 and mode_p == 1
bool hidden_bear = osc_pivot_h and x_distance_in_range and mode == 1 and mode_p == -1
[strong_bull, strong_bear, medium_bull, medium_bear, weak_bull, weak_bear, hidden_bull, hidden_bear, osc_pivot_h, osc_pivot_l]
else
[false, false, false, false, false, false, false, false, osc_pivot_h, osc_pivot_l]
Overview
SMC Utils features functions for value range checks, range overlap determination, lower-timeframe selection, formatting price levels and trend states, dynamic marker gap scaling, and calculating lower-timeframe candle statistics and volume delta. Additionally, it offers linear regression slope percentage utilities. As a library, it produces no standalone visual output or trade signals on its own.
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.
This Pine Script v5 library provides functions to calculate and plot linear regression channels using sample point arrays. It evaluates paired X and Y arrays to calculate the regression slope, intercept, fitted values, maximum deviation, minimum deviation, and
This Pine Script v6 library calculates trade position sizes and provides risk management functions for external scripts. It computes position sizes from account equity, percentage risk, and stop-loss distance, and offers dynamic sizing adjustments based on vol
Chart Patterns is a Pine Script v6 library designed to scan for and render technical chart patterns directly on the price chart. It defines custom user-defined types to configure scanning parameters, such as Zigzag pivot offsets, error ratios, flat ratios, and
AuthLib is a Pine Script utility library providing access control and state management structures for technical indicators. It checks callers against a hardcoded array of authorized TradingView usernames before executing operations. The library exports user-de
WebhookMessageLibrary is a helper library designed to construct structured JSON payload messages for automated trading integrations like TradersPost. It defines custom exported types and constants for trade actions, market sentiments, quantities, limit prices,
PineDraw is a Pine Script v6 library that provides object primitives for drawing and updating price levels on the chart. It enables indicators and strategies to maintain lines, boxes, and labels in place by updating existing objects instead of deleting and rec