//@version=6
// ============================================================================
// Market Pressure Scale [WavesUnchained]
// Version: 2.4.4
// Author: WavesUnchained
// Build: 2026-10-12
// ============================================================================
// Two-component oscillator separating setup pressure (compression + S/R proximity)
// from impulse pressure (range expansion + volume + body + trend), with phase
// classification, a Move Strength column gauge for the expected magnitude
// of the eventual move, and a DMI-free Reversal signal.
//
// Features:
// ✓ Setup Pressure — ATR/BB compression, S/R proximity, volume drying up
// ✓ Impulse Pressure — range expansion, volume, body size
// ✓ Range Chop Filter — ADX/DMI regime detection suppresses Failed Coil /
// Reversal signals inside dead mid-range chop
// ✓ Phase classification: Sideways/Chop / Impulse Running / Sideways / Neutral
// ✓ Move Strength — expected magnitude of the eventual move (compression depth +
// range-edge location + ADX), plotted as blue columns behind the two curves
// ✓ Reversal — Impulse exhaustion + rejection wick + candle confirmation at a
// range extreme, weighted by Setup compression; direction-native, does not rely on DMI
// ✓ Failed Coil requires price to actually fall back toward the middle of the range
// ✓ Naked Impulse requires ADX to still be weak (a real trend doesn't count as "naked")
// ✓ Directional bias via configurable fast/slow MA cross
// ✓ Range position (close relative to N-bar range)
// ✓ Dashboard table with phase, bias, range position, move strength, plain-language action (off by default)
// ✓ Configurable output smoothing — EMA / RMA / SMA / WMA / HMA / JMA
// ✓ Alerts for all phase transitions and signal markers
// ✓ Debug: Pine Logs output of full Reversal context per bar at a range extreme (off by default)
//
// Data Contract:
// Price: REQUIRED chart symbol
// Volume: OPTIONAL real trade volume only — Setup/Impulse Pressure volume sub-weights renormalize onto remaining components when not real
// OI: NO
// Reference: NO
// Verdict: CFD-degraded
//
// ============================================================================
indicator("Market Pressure Scale [WavesUnchained]", format=format.price, precision=2, shorttitle="MPS", overlay=false, max_labels_count=500)
// Inputs
normLen = input.int(100, "Normalisation", minval=20)
atrLen = input.int(14, "ATR Length")
bbLen = input.int(20, "BB Length")
bbMult = input.float(2.0, "BB Multiplier")
volLen = input.int(20, "Volume MA")
srLen = input.int(50, "Range / S/R Lookback")
biasGR = "Bias"
biasType = input.string("HMA", "Type",
options=["EMA", "RMA", "SMA", "WMA", "HMA", "JMA"], group=biasGR)
biasFastLen = input.int(9, "Fast Length", minval=1, group=biasGR)
biasSlowLen = input.int(21, "Slow Length", minval=1, group=biasGR)
smGR = "Smoothing"
smoothLen = input.int(3, "Length", minval=1, maxval=50, group=smGR)
smoothType = input.string("EMA", "Type",
options=["EMA", "RMA", "SMA", "WMA", "HMA", "JMA"], group=smGR)
jmaPhase = input.int(50, " JMA Phase", minval=-100, maxval=100, group=smGR)
jmaPower = input.float(2.0, " JMA Power", minval=1.0, maxval=4.0, step=0.25, group=smGR)
dashGR = "Dashboard"
showTable = input.bool(false, "Show Table", group=dashGR)
sigGR = "Signal Markers"
showMarkers = input.bool(true, "Show Markers", group=sigGR)
showFailed = input.bool(true, " Failed Coil", group=sigGR,
tooltip="Setup was high but Impulse never confirmed — stalled breakout, likely range continues.")
showNaked = input.bool(true, " Naked Impulse", group=sigGR,
tooltip="Impulse > 70 but Setup collapses below 40 — move running without structural backing.")
showReversal = input.bool(true, " Reversal", group=sigGR,
tooltip="At a range extreme: the recent Impulse is fading from its own high AND there's a rejection wick against the extreme, weighted by Setup compression. Direction-native — does not use DMI.")
strengthGR = "Move Strength"
showStrengthBg = input.bool(true, "Show Columns", group=strengthGR,
tooltip="Blue columns (5 opacity bands) tracking the expected magnitude of the eventual move: compression depth + range-edge location + ADX, suppressed while the Range Chop Filter is active. Plotted behind Setup/Impulse Pressure instead of a full-pane background.")
debugGR = "Debug"
showDebugLog = input.bool(false, "Log Reversal Context (Pine Logs)", group=debugGR,
tooltip="Writes two things to Pine Logs: 1) rangePos/chop/setup/impulse/exhaustion/wick/score on every confirmed bar at a range extreme, for diagnosing Reversal signals. 2) every raw ingredient (atr/volume/volRel/compression/srProximity/etc.) whenever Setup or Impulse Pressure comes back na, for diagnosing feeds whose volume series carries no usable turnover.")
// Helpers
clamp(x, lo, hi) =>
math.max(lo, math.min(hi, x))
norm100(src, len) =>
hi = ta.highest(src, len)
lo = ta.lowest(src, len)
hi == lo ? 50.0 : 100.0 * (src - lo) / (hi - lo)
f_jma(src, length, phase, power) =>
var float jma = na
var float e0 = na
var float e1 = na
var float e2 = na
_pr = phase < -100 ? 0.5 : phase > 100 ? 2.5 : phase / 100.0 + 1.5
_beta = 0.45 * (length - 1) / (0.45 * (length - 1) + 2)
_alpha = math.pow(_beta, power)
e0 := (1 - _alpha) * src + _alpha * nz(e0[1], src)
e1 := (src - e0) * (1 - _beta) + _beta * nz(e1[1], 0)
e2 := (e0 + _pr * e1 - nz(jma[1], src)) * math.pow(1 - _alpha, 2) + math.pow(_alpha, 2) * nz(e2[1], 0)
jma := nz(jma[1], src) + e2
jma
f_smooth(src, length, mode) =>
switch mode
'SMA' => ta.sma(src, length)
'RMA' => ta.rma(src, length)
'HMA' => ta.hma(src, length)
'WMA' => ta.wma(src, length)
'JMA' => f_jma(src, length, jmaPhase, jmaPower)
=> ta.ema(src, length)
// Move Strength color — quantized into 5 tiers so consecutive bars read as a
// clear step change instead of a near-uniform continuous gradient
f_strengthColor(v) =>
_t = v >= 85 ? 10 : v >= 65 ? 35 : v >= 45 ? 58 : v >= 25 ? 80 : 95
color.new(#2196F3, _t)
// Base values
atr = ta.atr(atrLen)
atrPct = atr / close
basis = ta.sma(close, bbLen)
dev = bbMult * ta.stdev(close, bbLen)
bbUpper = basis + dev
bbLower = basis - dev
bbWidth = (bbUpper - bbLower) / basis
// Echtes Handelsvolumen? Nur "tick" schließt aus; "n/a" zählt, wenn der Feed Volumen liefert (DATA_VALIDITY §2).
bool volumeIsReal = (ta.cum(nz(volume)) > 0 and syminfo.volumetype != "tick") and not na(volume)
_volSma = ta.sma(volume, volLen)
volRel = not volumeIsReal or na(_volSma) or _volSma <= 0 ? 1.0 : volume / _volSma
barRange = high - low
bodySize = math.abs(close - open)
bodyRatio = bodySize / math.max(barRange, syminfo.mintick)
lowerWick = math.min(close, open) - low
upperWick = high - math.max(close, open)
_biasFast = f_smooth(close, biasFastLen, biasType)
_biasSlow = f_smooth(close, biasSlowLen, biasType)
bullBias = _biasFast > _biasSlow
bearBias = _biasFast < _biasSlow
// Range / Support / Resistance
rangeHigh = ta.highest(high, srLen)
rangeLow = ta.lowest(low, srLen)
rangeSize = rangeHigh - rangeLow
nearHigh = math.abs(rangeHigh - close) / math.max(atr, syminfo.mintick)
nearLow = math.abs(close - rangeLow) / math.max(atr, syminfo.mintick)
srProximity = clamp(100 - math.min(nearHigh, nearLow) * 50, 0, 100)
rangePosition = rangeSize == 0 ? 50 : 100 * (close - rangeLow) / rangeSize
// Range Chop Filter — ADX/DMI regime detection to keep Failed Coil / Reversal
// from firing on dead mid-range chop, where compression + edge proximity are
// coincidental rather than a genuine squeeze
[diPlus, diMinus, adx] = ta.dmi(14, 14)
chopMarket = adx < 16 and math.abs(diPlus - diMinus) < 5 and rangePosition > 20 and rangePosition < 80
validSetupZone = rangePosition < 20 or rangePosition > 80
// Setup Pressure — high when volatility is low, BBs tight, price near range
// extreme AND volume is drying up (a genuine squeeze, not a high-volume push)
atrCompression = 100 - norm100(atrPct, normLen)
bbCompression = 100 - norm100(bbWidth, normLen)
compression = (atrCompression + bbCompression) / 2
volQuiet = 100 - norm100(volRel, normLen)
// Volume weight (0.15) drops out when volume isn't real; the remaining two
// weights are renormalized onto the full 1.0 (0.55/0.85, 0.30/0.85) instead
// of just zeroing the term, so Setup Pressure doesn't systematically shrink
// on feeds without real trade volume.
float setupPressure = na
if volumeIsReal
setupPressure := compression * 0.55 + srProximity * 0.30 + volQuiet * 0.15
else
setupPressure := compression * (0.55 / 0.85) + srProximity * (0.30 / 0.85)
setupPressure := clamp(setupPressure, 0, 100)
// Impulse Pressure — high when range, body and volume expand
rangeExpansion = norm100(barRange / math.max(atr, syminfo.mintick), normLen)
volumePressure = norm100(volRel, normLen)
bodyPressure = norm100(bodyRatio, normLen)
// Same renormalization as Setup Pressure: without real volume the 0.15 volume
// weight drops out and range/body are scaled onto the full 1.0 (0.45/0.85,
// 0.40/0.85) instead of adding a constant mid-value volume term.
float impulsePressure = na
if volumeIsReal
impulsePressure := rangeExpansion * 0.45 + bodyPressure * 0.40 + volumePressure * 0.15
else
impulsePressure := rangeExpansion * (0.45 / 0.85) + bodyPressure * (0.40 / 0.85)
impulsePressure := clamp(impulsePressure, 0, 100)
// Smoothing
setupPressure := f_smooth(setupPressure, smoothLen, smoothType)
impulsePressure := f_smooth(impulsePressure, smoothLen, smoothType)
// Debug: dump every ingredient when Setup/Impulse comes back na, so a broken
// input can be found from evidence instead of guessing at more zero-division fixes
if showDebugLog and (na(setupPressure) or na(impulsePressure)) and barstate.isconfirmed
log.info("MPS NAN CTX atr=" + str.tostring(atr) +
" volume=" + str.tostring(volume) +
" volSma=" + str.tostring(_volSma) +
" volRel=" + str.tostring(volRel) +
" atrPct=" + str.tostring(atrPct) +
" bbWidth=" + str.tostring(bbWidth) +
" compression=" + str.tostring(compression) +
" srProximity=" + str.tostring(srProximity) +
" volQuiet=" + str.tostring(volQuiet) +
" rangeExpansion=" + str.tostring(rangeExpansion) +
" bodyPressure=" + str.tostring(bodyPressure) +
" volumePressure=" + str.tostring(volumePressure) +
" setup=" + str.tostring(setupPressure) +
" impulse=" + str.tostring(impulsePressure))
// Move Strength — expected magnitude of the eventual move once Setup releases:
// compression depth (energy stored) + range-edge location + ADX (trend
// confirmation), suppressed toward zero while chopMarket is active.
adxNorm = clamp(adx / 50 * 100, 0, 100)
moveStrength = compression * 0.45 + srProximity * 0.35 + adxNorm * 0.20
moveStrength := chopMarket ? moveStrength * 0.35 : moveStrength
moveStrength := clamp(moveStrength, 0, 100)
// Signal detection
var bool inCoil = false
var bool coilIgnited = false
coilEntry = validSetupZone and not chopMarket and ta.crossover(setupPressure, 65) and impulsePressure < 40
if coilEntry
inCoil := true
coilIgnited := false
if inCoil and impulsePressure >= 45
coilIgnited := true
backToRange = rangePosition > 25 and rangePosition < 75
sigFailed = inCoil and not coilIgnited and ta.crossunder(setupPressure, 52) and backToRange
sigNaked = impulsePressure > 70 and ta.crossunder(setupPressure, 40) and adx < 25
if sigFailed or setupPressure < 40
inCoil := false
// Reversal — exhaustion of the move that got us here + rejection at a range
// extreme (indicator-design §6.1: regime veto -> exhaustion -> confirmation ->
// quality, combined as one score per direction instead of an AND-chain).
// Direction-native: never touches DMI, so it isn't subject to the lag a
// DMI-based directional read would have at turning points.
impulseHigh10 = ta.highest(impulsePressure, 10)
exhaustionScore = impulseHigh10 > 50 ? clamp(impulseHigh10 - impulsePressure, 0, 100) : 0
lowerWickRatio = lowerWick / math.max(barRange, syminfo.mintick) * 100
upperWickRatio = upperWick / math.max(barRange, syminfo.mintick) * 100
reversalActive = validSetupZone and not chopMarket
reversalLongScore = exhaustionScore * 0.45 + lowerWickRatio * 0.30 + setupPressure * 0.25
reversalShortScore = exhaustionScore * 0.45 + upperWickRatio * 0.30 + setupPressure * 0.25
// Candle confirmation — the trigger bar itself must close in the direction of
// the reversal, not just show a rejection wick, so a big wick that closes back
// toward the extreme doesn't count
bullReject = close > open and close > (low + barRange * 0.6)
bearReject = close < open and close < (high - barRange * 0.6)
sigReversalLong = reversalActive and rangePosition < 20 and bullReject and ta.crossover(reversalLongScore, 60)
sigReversalShort = reversalActive and rangePosition > 80 and bearReject and ta.crossover(reversalShortScore, 60)
// Kept as a short window rather than the single trigger bar, for the
// dashboard's Action row (a one-bar-only flag reads as "nothing" most of the time)
recentRevLong = ta.barssince(sigReversalLong) <= 2
recentRevShort = ta.barssince(sigReversalShort) <= 2
if showDebugLog and validSetupZone and barstate.isconfirmed
log.info("MPS REVERSAL CTX rangePos=" + str.tostring(rangePosition, "#.0") +
" chop=" + str.tostring(chopMarket) +
" setup=" + str.tostring(setupPressure, "#.0") +
" impulse=" + str.tostring(impulsePressure, "#.0") +
" impulseHigh10=" + str.tostring(impulseHigh10, "#.0") +
" exhaustion=" + str.tostring(exhaustionScore, "#.0") +
" lowerWickR=" + str.tostring(lowerWickRatio, "#.0") +
" upperWickR=" + str.tostring(upperWickRatio, "#.0") +
" longScore=" + str.tostring(reversalLongScore, "#.0") +
" shortScore=" + str.tostring(reversalShortScore, "#.0"))
// Phase — priority order: Chop > Impulse > Sideways > Neutral
phase = if chopMarket
"Sideways / Chop"
else if impulsePressure > 70
"Impulse Running"
else if setupPressure < 40 and impulsePressure < 40
"Sideways / Quiet"
else
"Neutral"
biasText = bullBias ? "Bullish" : bearBias ? "Bearish" : "Flat"
// Colors
setupColor = setupPressure > 65 ? color.orange : color.new(color.orange, 45)
impulseColor = impulsePressure > 70 ? color.lime : color.new(color.lime, 45)
// Move Strength — columns instead of a full-pane background, so it adds
// information without washing out Setup/Impulse Pressure. Plotted first so it
// sits behind both curves.
plot(showStrengthBg ? moveStrength : na, "Move Strength", color=f_strengthColor(moveStrength), style=plot.style_columns)
plot(setupPressure, "Setup Pressure", color=setupColor, linewidth=3)
plot(impulsePressure, "Impulse Pressure", color=impulseColor, linewidth=4)
hline(40, "Quiet", color=color.new(color.gray, 55), linestyle=hline.style_dashed)
hline(65, "Setup Zone", color=color.new(color.gray, 40), linestyle=hline.style_dashed)
hline(70, "Impulse Zone", color=color.new(color.gray, 25), linestyle=hline.style_dashed)
// Signal markers
if showMarkers
if showFailed and sigFailed
label.new(bar_index, setupPressure, "FC",
style=label.style_label_down, color=color.new(#d50000, 15),
textcolor=color.white, size=size.small,
tooltip="Failed Coil — Setup was high but Impulse never confirmed.\nBreakout attempt stalled. Expect range continuation or a full reset before the next setup forms.")
if showNaked and sigNaked
label.new(bar_index, impulsePressure, "NI",
style=label.style_label_down, color=color.new(#d50000, 15),
textcolor=color.white, size=size.small,
tooltip="Naked Impulse — Impulse > 70 but Setup collapsed below 40.\nMove is running without structural backing. Late-entry risk — momentum may stall or reverse sharply.")
if showReversal and sigReversalLong
label.new(bar_index, impulsePressure, "◆",
style=label.style_label_up, color=color.new(#00c853, 15),
textcolor=color.white, size=size.small,
tooltip="Reversal Long — Impulse fading from a recent high, rejection wick at range low, weighted by Setup compression.\nExhaustion + rejection, not DMI-based — an early counter-trend candidate.")
if showReversal and sigReversalShort
label.new(bar_index, impulsePressure, "◆",
style=label.style_label_down, color=color.new(#d50000, 15),
textcolor=color.white, size=size.small,
tooltip="Reversal Short — Impulse fading from a recent high, rejection wick at range high, weighted by Setup compression.\nExhaustion + rejection, not DMI-based — an early counter-trend candidate.")
// Table
color tc = color.new(color.gray, 20)
color hd = color.new(color.gray, 90)
setupDir = setupPressure > setupPressure[1] + 0.5 ? "↑" : setupPressure < setupPressure[1] - 0.5 ? "↓" : "→"
impulseDir = impulsePressure > impulsePressure[1] + 0.5 ? "↑" : impulsePressure < impulsePressure[1] - 0.5 ? "↓" : "→"
var table t = table.new(position.top_right, 3, 8,
bgcolor = color.new(color.white, 5),
border_color = color.new(color.gray, 60),
border_width = 1,
frame_color = color.new(color.gray, 40),
frame_width = 1)
if barstate.islast and showTable
phaseActive = not chopMarket and impulsePressure > 70
color phaseBg = color.new(color.gray, 80)
if phaseActive
phaseBg := color.new(#00c853, 20)
phaseTC = phaseActive ? color.white : tc
table.cell(t, 0, 0, "Phase", text_color=tc, bgcolor=hd, text_size=size.small)
table.cell(t, 1, 0, phase, text_color=phaseTC, bgcolor=phaseBg, text_size=size.small)
table.cell(t, 2, 0, "", bgcolor=hd, text_size=size.small)
table.cell(t, 0, 1, "Setup", text_color=tc, text_size=size.small, tooltip="How much the market is coiling: ATR/BB compression, S/R proximity, relative volume. >65 = strong setup.")
table.cell(t, 1, 1, str.tostring(setupPressure, "#.0") + " / 100", text_color=tc, text_size=size.small)
table.cell(t, 2, 1, setupDir, text_color=color.new(color.orange, 0), text_size=size.small)
table.cell(t, 0, 2, "Impulse", text_color=tc, text_size=size.small, tooltip="How much a directional move is underway: range expansion vs ATR, volume, candle body size. >70 = impulse running.")
table.cell(t, 1, 2, str.tostring(impulsePressure, "#.0") + " / 100", text_color=tc, text_size=size.small)
table.cell(t, 2, 2, impulseDir, text_color=color.new(#00c853, 0), text_size=size.small)
biasTC = bullBias ? color.new(#00c853, 0) : bearBias ? color.new(#d50000, 0) : tc
table.cell(t, 0, 3, "Bias", text_color=tc, text_size=size.small, tooltip="Directional bias from a fast/slow MA cross. Bullish = fast MA above slow MA.")
table.cell(t, 1, 3, biasText, text_color=biasTC, text_size=size.small)
table.cell(t, 2, 3, "", text_color=tc, text_size=size.small)
table.cell(t, 0, 4, "Range Pos.", text_color=tc, text_size=size.small, tooltip="Where the close sits within the N-bar high/low range. 0% = at range low, 100% = at range high.")
table.cell(t, 1, 4, str.tostring(rangePosition, "#.0") + " %", text_color=tc, text_size=size.small)
table.cell(t, 2, 4, "", text_color=tc, text_size=size.small)
// Separator
table.cell(t, 0, 5, "", bgcolor=color.new(color.gray, 80))
table.cell(t, 1, 5, "", bgcolor=color.new(color.gray, 80))
table.cell(t, 2, 5, "", bgcolor=color.new(color.gray, 80))
// Move Strength
strengthTc = moveStrength > 50 ? color.white : tc
color strengthBg = f_strengthColor(moveStrength)
table.cell(t, 0, 6, "Move Str.", text_color=tc, bgcolor=na, text_size=size.small, tooltip="Expected magnitude of the eventual move: compression depth + range-edge proximity + ADX trend confirmation, suppressed during chop.")
table.cell(t, 1, 6, str.tostring(moveStrength, "#.0") + " / 100", text_color=strengthTc, bgcolor=strengthBg, text_size=size.small)
table.cell(t, 2, 6, "", text_color=tc, bgcolor=na, text_size=size.small)
// Action — a plain-language read of the same priority order as the signals above
string actionText = "Wait"
color actionBg = color.new(color.gray, 80)
color actionTc = tc
if chopMarket
actionText := "Ignore / Chop"
else if setupPressure > 65 and impulsePressure < 45
actionText := "Watch Setup"
actionBg := color.new(#ffd600, 30)
else if impulsePressure > 70
actionText := "Trend Running"
actionBg := color.new(#00c853, 20)
actionTc := color.white
else if recentRevLong
actionText := "Long Reversal"
actionBg := color.new(#00c853, 20)
actionTc := color.white
else if recentRevShort
actionText := "Short Reversal"
actionBg := color.new(#d50000, 20)
actionTc := color.white
table.cell(t, 0, 7, "Action", text_color=tc, bgcolor=na, text_size=size.small, tooltip="Plain-language read of the current state, same priority order as the phase/signals above.")
table.cell(t, 1, 7, actionText, text_color=actionTc, bgcolor=actionBg, text_size=size.small)
table.cell(t, 2, 7, "", text_color=tc, bgcolor=na, text_size=size.small)
// Alerts
bool alertsOnBarClose = input.bool(true, "Alerts only on bar close (confirmed)", group="Alerts")
bool alertOk = not alertsOnBarClose or barstate.isconfirmed
alertcondition(alertOk and (impulsePressure > 70), "Impulse Running", "MPS · IMPULSE RUNNING · {{ticker}} {{interval}}")
alertcondition(alertOk and (setupPressure < 40 and impulsePressure < 40), "Sideways / Quiet", "MPS · SIDEWAYS QUIET · {{ticker}} {{interval}}")
alertcondition(alertOk and (sigFailed), "Signal: Failed Coil", "MPS · FAILED COIL · {{ticker}} {{interval}}")
alertcondition(alertOk and (sigNaked), "Signal: Naked Impulse", "MPS · NAKED IMPULSE · {{ticker}} {{interval}}")
alertcondition(alertOk and (sigReversalLong), "Signal: Reversal Long", "MPS · REVERSAL LONG · {{ticker}} {{interval}}")
alertcondition(alertOk and (sigReversalShort), "Signal: Reversal Short", "MPS · REVERSAL SHORT · {{ticker}} {{interval}}")
Overview
Setup pressure combines ATR and Bollinger compression, support and resistance proximity, and drying volume. Impulse pressure combines range expansion, volume, and candle body size. A range-chop filter uses ADX and DMI to suppress failed-coil and reversal markers in mid-range chop. Move strength appears as columns. Fast and slow moving-average bias, output smoothing, and an optional dashboard change how phases and markers are shown. Volume weights drop out when volume is not real trade volume.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Normalisation
int
100
normLen
ATR Length
int
14
atrLen
BB Length
int
20
bbLen
BB Multiplier
float
2.0
bbMult
Volume MA
int
20
volLen
Range / S/R Lookback
int
50
srLen
Type
string
HMA
biasType
Fast Length
int
9
biasFastLen
Slow Length
int
21
biasSlowLen
Length
int
3
smoothLen
Type
string
EMA
smoothType
JMA Phase
int
50
jmaPhase
Show all 21 settings
Setting
Type
Default
Variable
JMA Power
float
2.0
jmaPower
Show Table
bool
false
showTable
Show Markers
bool
true
showMarkers
Failed Coil
bool
true
showFailed
Naked Impulse
bool
true
showNaked
Reversal
bool
true
showReversal
Show Columns
bool
true
showStrengthBg
Log Reversal Context (Pine Logs)
bool
false
showDebugLog
Alerts only on bar close (confirmed)
bool
true
alertsOnBarClose
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 indicator standardizes price inputs using z-score normalization before calculating a relative strength index (RSI). It generates trade signals when standardized price components cross over or under the standardized RSI feature. Signals can be filtered by
PPO ATR Bands plots a percentage price oscillator in a separate pane. It compares a Hull average of typical price with a volume-weighted exponential average of Parabolic SAR, then scales three true-range bands around the slow average into matching oscillator l
This indicator plots the Commodity Channel Index in a separate pane and surrounds it with a Donchian channel whose lookback length changes with volatility. It measures volatility as a ratio of short and long ATR values, then ranks that ratio and shortens or le
The Expectation Maximization Gaussian Mixture Regime indicator clusters market states into two to five components using an online Expectation-Maximization Gaussian Mixture Model. It processes three input features: volatility-normalized momentum, relative volat
This indicator calculates the Relative Strength Index (RSI) alongside a simple moving average to generate directional momentum signals in a separate pane. It supports Break Flip and Break Continuous scanning modes for long and short setups. A wide array of opt
This Pine v4 study ports early NostalgiaForInfinity V6 conditions onto the price chart. It computes two Bollinger setups, several EMAs and SMAs, RSI, MFI, a percent SMA spread labeled EWO, a 14-period choppiness value, and short and longer volume medians. Fixe