//@version=6
// ============================================================================
// Candle Pressure Index [WavesUnchained]
// Version: 1.1.5
// Author: WavesUnchained
// Build: 2026-10-12
// ============================================================================
// Measures buying vs. selling pressure from raw candle microstructure —
// no derived oscillators, only price geometry and relative volume.
// Per-bar pressure = (2 × close_location − 1) × body_ratio × volume_rank.
//
// Features:
// ✓ Per-bar pressure: close location × body ratio × relative volume
// ✓ CPI oscillator (EMA of pressure, −1 to +1 range)
// ✓ Momentum line (CPI 1st derivative)
// ✓ Initiation / Absorption spike markers (extreme single-bar pressure)
// ✓ Optional zero-cross pressure-turn markers with momentum gate
// ✓ Dashboard: state, CPI value, momentum direction, bar pressure
// ✓ Alerts: pressure turns, initiation/absorption spike
//
// Data Contract:
// Price: REQUIRED chart symbol
// Volume: REQUIRED real trade volume — feed must deliver volume and
// syminfo.volumetype must not be "tick"; otherwise not available
// OI: NO
// Reference: NO
// Verdict: Exchange-only
// ============================================================================
indicator("Candle Pressure Index [WavesUnchained]", "CPI [WU]", format=format.price, precision=2, overlay=false)
// ─── Inputs ───────────────────────────────────────────────────────────────────
grCPI = "Candle Pressure Index"
cpiLen = input.int(20, "Smoothing Length", minval=2, maxval=100, group=grCPI)
volLookback = input.int(20, "Volume Rank Lookback", minval=5, maxval=100, group=grCPI)
spikeThresh = input.float(0.6, "Spike Threshold", minval=0.2, maxval=1.0, step=0.05, group=grCPI,
tooltip="Minimum |raw pressure| to mark a bar as an initiation or absorption spike.")
grD = "Display"
showDash = input.bool(true, "Show Dashboard", group=grD)
// Echtes Handelsvolumen? Nur "tick" schließt es ausdrücklich aus (Anzahl
// Transaktionen, keine Menge). "n/a" heißt laut Referenz "kein Volumen ODER Art
// nicht angegeben" — die meisten Feeds außer Krypto melden das, auch Futures mit
// echten Kontrakten. Dort entscheidet, ob der Feed überhaupt Volumen liefert.
var bool feedHasVolume = false
if nz(volume) > 0
feedHasVolume := true
bool volumeIsReal = syminfo.volumetype != "tick" and feedHasVolume
float vol = volumeIsReal ? volume : na
// ─── Per-bar raw pressure ─────────────────────────────────────────────────────
// close_location: 0 = closed at low, 1 = closed at high
// body_ratio: 0 = doji, 1 = marubozu
// volume_rank: bar volume relative to recent max (0–1)
// net_pressure: (2 × close_location − 1) × body_ratio × volume_rank
// → +1 strongest bull, −1 strongest bear
hl = high - low
closeLoc = hl > 0 ? (close - low) / hl : 0.5
bodyRat = hl > 0 ? math.abs(close - open) / hl : 0.0
volMax = ta.highest(vol, volLookback)
volRank = not volumeIsReal ? na : volMax > 0 ? vol / volMax : 0.5
rawP = (2.0 * closeLoc - 1.0) * bodyRat * volRank
// ─── CPI oscillator ───────────────────────────────────────────────────────────
cpi = ta.ema(rawP, cpiLen)
cpiAcc = cpi - nz(cpi[1])
// ─── Spikes ───────────────────────────────────────────────────────────────────
spikeBull = rawP >= spikeThresh
spikeBear = rawP <= -spikeThresh
// ─── Colors ───────────────────────────────────────────────────────────────────
bullC = color.new(#00c853, 0)
bearC = color.new(#d50000, 0)
neutC = color.new(color.gray, 30)
cpiColor = cpi > 0.15 ? bullC : cpi < -0.15 ? bearC : neutC
accColor = cpiAcc >= 0 ? color.new(#00c853, 50) : color.new(#d50000, 50)
// ─── Plots ────────────────────────────────────────────────────────────────────
hline(0, "Zero", color=color.new(color.gray, 50))
hline(0.3, "Bull Zone", color=color.new(#00c853, 70), linestyle=hline.style_dotted)
hline(-0.3, "Bear Zone", color=color.new(#d50000, 70), linestyle=hline.style_dotted)
plot(cpi, "CPI", color=cpiColor, linewidth=2)
plot(cpiAcc, "Momentum", color=accColor, linewidth=1)
plotshape(spikeBull, "Initiation", shape.circle, location.bottom,
color=color.new(#00c853, 30), size=size.tiny)
plotshape(spikeBear, "Absorption", shape.circle, location.top,
color=color.new(#d50000, 30), size=size.tiny)
// ─── Dashboard ────────────────────────────────────────────────────────────────
color tc = color.new(color.gray, 20)
color hd = color.new(color.gray, 90)
var table t = table.new(position.top_right, 2, 5,
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 showDash and barstate.islast and volumeIsReal
table.cell(t, 0, 0, "CPI", text_color=tc, bgcolor=hd, text_size=size.small)
table.cell(t, 1, 0, "Value", text_color=tc, bgcolor=hd, text_size=size.small)
cpiState = cpi > 0.3 ? "Strong Bull" : cpi > 0.15 ? "Bull" : cpi < -0.3 ? "Strong Bear" : cpi < -0.15 ? "Bear" : "Neutral"
cpiStateC = cpi > 0.15 ? bullC : cpi < -0.15 ? bearC : tc
table.cell(t, 0, 1, "State", text_color=tc, text_size=size.small)
table.cell(t, 1, 1, cpiState, text_color=cpiStateC, text_size=size.small)
table.cell(t, 0, 2, "CPI", text_color=tc, text_size=size.small)
table.cell(t, 1, 2, str.tostring(cpi, "#.##"), text_color=cpiStateC, text_size=size.small)
accStr = cpiAcc >= 0 ? "Rising ↑" : "Falling ↓"
accC2 = cpiAcc >= 0 ? bullC : bearC
table.cell(t, 0, 3, "Momentum", text_color=tc, text_size=size.small)
table.cell(t, 1, 3, accStr, text_color=accC2, text_size=size.small)
table.cell(t, 0, 4, "Bar Pressure", text_color=tc, text_size=size.small)
table.cell(t, 1, 4, str.tostring(rawP, "#.##"), text_color=tc, text_size=size.small)
// Kurzer Hinweis unten rechts; was fehlt, steht im Data Contract oben.
var table volWarn = table.new(position.bottom_right, 1, 1)
if barstate.islast and not volumeIsReal
table.cell(volWarn, 0, 0, "CPI · not available",
bgcolor = color.new(color.orange, 20), text_color = color.white, 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 (spikeBull), "CPI Initiation Spike", "CPI · INITIATION SPIKE · {{ticker}} {{interval}}")
alertcondition(alertOk and (spikeBear), "CPI Absorption Spike", "CPI · ABSORPTION SPIKE · {{ticker}} {{interval}}")
Overview
Each bar combines close location, body ratio, and volume rank into a raw pressure value. An exponential moving average of that pressure forms the CPI oscillator between minus one and plus one, while a momentum line tracks its first derivative. Spike markers flag extreme initiation or absorption bars, and optional markers show zero-cross turns gated by momentum. Settings change smoothing, volume lookback, and spike threshold. It plots in a separate pane and requires real trade volume rather than tick volume.
Per-bar pressure from close location, body ratio and volume rank
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Smoothing Length
int
20
cpiLen
Volume Rank Lookback
int
20
volLookback
Spike Threshold
float
0.6
spikeThresh
Show Dashboard
bool
true
showDash
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 measures directional momentum by evaluating candlestick body proportions and volume over a user-defined lookback window. It computes the ratio of candle body to total range, weights the cumulative value by volume and absolute body size, and dete
Oscillator Suite plots a normalised price oscillator in a separate pane and overlays a signal line that can use SMA, EMA, WMA, HMA, RMA, VWMA, T3, ZEMA, KAMA, or GKEMA. It marks bullish and bearish divergences, a smoothed money-flow series, confluence areas an
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 indicator plots a smoothed Z-score of cumulative volume delta in a separate pane, showing whether buying or selling pressure is dominant and when the reading enters extreme zones. It marks spot accumulation, climax or exhaustion, and pivot-based price-vol
Nexural Pressure Pro is a composite pressure indicator that measures directional market momentum using volume-weighted directional movement, order flow delta, aggression, and efficiency ratio metrics. It filters out low-activity bars using configurable volume
This overlay indicator screens a pasted list of up to forty symbols and draws a table on the price chart. It classifies bullish or bearish setups from the percent change between the current candle and the candle 250 bars back, then shows RSI with a simple movi