//@version=6
// ============================================================================
// Relative Leg Efficiency (RLE) — Panel + Chart [WavesUnchained]
// Version: 1.0.0
// Author: WavesUnchained
// Build: 2025-12-24 01:16:05
// ============================================================================
// Pivot-to-pivot RLE scoring with panel + chart visualization
//
// Features:
// ✓ Panel plots for live and confirmed RLE
// ✓ Chart leg lines and labels at pivots
// ✓ Counter-pressure via body-weighted or count mode
// ✓ ATR-based label offsets
//
// ============================================================================
indicator("Relative Leg Efficiency (RLE) — Panel + Chart [WavesUnchained]", overlay=false, max_labels_count=500, max_lines_count=500, max_bars_back=5000)
// ═══════════════════════════════════════════════════════════════════════════
// Relative Leg Efficiency (RLE) — Panel + Chart
// ═══════════════════════════════════════════════════════════════════════════
// Version: 1.0.0
// Author: WavesUnchained
//
// MODULES:
// - inputs.pine
// - helpers.pine
// - pivots.pine
// - state.pine
// - panel.pine
// ═══════════════════════════════════════════════════════════════════════════
// NOTE: Modules are combined by the build system.
// ============================================================================
// INLINE MODULES (Combined at build time)
// ============================================================================
// ============================================================================
// MODULE: inputs
// ============================================================================
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Inputs
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
groupPivots = "Pivots / Legs"
leftBars = input.int(4, "Pivot Left Bars", minval=1, group=groupPivots)
rightBars = input.int(4, "Pivot Right Bars", minval=1, group=groupPivots)
minLegBars = input.int(6, "Min Leg Bars", minval=1, group=groupPivots)
groupMath = "RLE Components"
pathSrc = input.source(hlc3, "Path Source (for path length)", group=groupMath)
directMode = input.string("PivotPrice", "Direct Distance Mode", options=["PathSource","PivotPrice"], group=groupMath)
liveEndMode = input.string("close", "Live End Price", options=["close","high/low"], group=groupMath)
tfMode = input.string("Bars (current TF)", "Time Factor Mode", options=["Bars (current TF)","Time (TF-neutral)"], group=groupMath)
timeRefMinutes = input.int(120, "Time Reference Minutes (TF-neutral)", minval=1, group=groupMath)
useTF = input.bool(false, "Use Time Factor (TF) in score", group=groupMath)
useBodyWeighted = input.bool(true, "Counter Pressure: Body-weighted (else count)", group=groupMath)
minOppBodyAtr = input.float(0.0, "Ignore tiny opposite bodies (ATR multiple, 0=off)", step=0.1, group=groupMath)
atrLen = input.int(14, "ATR Length", minval=1, group=groupMath)
timeRefBars = input.int(24, "Time Reference Bars (penalty after this)", minval=1, group=groupMath)
wPath = input.float(0.50, "Weight: Path", minval=0, maxval=1, step=0.05, group=groupMath)
wTime = input.float(0.20, "Weight: Time", minval=0, maxval=1, step=0.05, group=groupMath)
wCounter = input.float(0.30, "Weight: Counter", minval=0, maxval=1, step=0.05, group=groupMath)
cpEndFrac = input.float(0.30, "CP: End segment fraction", minval=0.05, maxval=0.60, step=0.05, group=groupMath)
cpEndWeight = input.float(0.70, "CP: Weight end segment", minval=0.0, maxval=1.0, step=0.05, group=groupMath)
relLookbackLegs = input.int(60, "Relative lookback legs", minval=20, maxval=300, group=groupMath)
relMode = input.string("Percentile", "Relative mode", options=["Percentile","Z-Score"], group=groupMath)
divEnable = input.bool(true, "Divergence labels", group=groupMath)
divDropPct = input.float(12.0, "Div: min drop vs prev (%)", minval=1, maxval=80, step=1, group=groupMath)
groupReg = "Regime / Filters"
regLookback = input.int(8, "Regime legs lookback", minval=3, maxval=30, group=groupReg)
regChopPeMax = input.float(0.45, "Chop if PE <=", minval=0.10, maxval=0.90, step=0.05, group=groupReg)
regTrendMin = input.float(0.60, "Trend score min (0..1)", minval=0, maxval=1, step=0.05, group=groupReg)
regChopMax = input.float(0.40, "Chop score max (0..1)", minval=0, maxval=1, step=0.05, group=groupReg)
trendMinLegRLE = input.float(60, "Trend filter: last leg RLE >=", minval=0, maxval=100, group=groupReg)
trendMinRelPct = input.float(60, "Trend filter: RLE percentile >=", minval=0, maxval=100, group=groupReg)
mrMaxLegRLE = input.float(45, "MR filter: last leg RLE <=", minval=0, maxval=100, group=groupReg)
mrMinChopShare = input.float(0.50, "MR filter: chop share >=", minval=0, maxval=1, step=0.05, group=groupReg)
groupViz = "Visuals"
showChartDrawings = input.bool(true, "Show Chart Drawings (Lines/Labels)", group=groupViz)
showPanel = input.bool(true, "Show Panel", group=groupViz)
showLegLines = input.bool(true, "Draw Leg Lines on Chart", group=groupViz)
showEndLabels = input.bool(true, "Show RLE Labels at Leg End", group=groupViz)
showLiveLabel = input.bool(false, "Show Live RLE Label (updates)", group=groupViz)
labelSize = input.string("small", "Label Size", options=["small","normal","large"], group=groupViz)
maxDrawnLegs = input.int(120, "Max Drawn Legs", minval=10, maxval=500, group=groupViz)
showStateTag = input.bool(true, "Append State Tag to Labels", group=groupViz)
thrHigh = input.float(80, "Threshold High", minval=0, maxval=100, group=groupViz)
thrMid = input.float(70, "Threshold Mid", minval=0, maxval=100, group=groupViz)
thrLow = input.float(55, "Threshold Low", minval=0, maxval=100, group=groupViz)
colBull = input.color(color.new(color.lime, 0), "Bull (Up-Leg)", group=groupViz)
colBear = input.color(color.new(color.red, 0), "Bear (Down-Leg)", group=groupViz)
colMid = input.color(color.new(color.yellow, 0), "Medium Quality", group=groupViz)
colBad = input.color(color.new(color.gray, 0), "Low Quality", group=groupViz)
lineWidth = input.int(2, "Leg Line Width", minval=1, maxval=4, group=groupViz)
labelYOffsetAtr = input.float(0.20, "Label Y Offset (ATR)", minval=0, maxval=2, step=0.05, group=groupViz)
groupLog = "Logging"
logEnable = input.bool(false, "Enable Pine log", group=groupLog)
logMode = input.string("Batch (last bar)", "Log mode", options=["Batch (last bar)","Streaming"], group=groupLog)
logEveryN = input.int(10, "Log every N bars", minval=1, group=groupLog)
logLookback = input.int(2000, "Log lookback bars", minval=100, group=groupLog)
logMaxLines = input.int(800, "Log max lines (batch)", minval=100, maxval=5000, group=groupLog)
logIncludeFinal = input.bool(true, "Include final values", group=groupLog)
logIncludeLive = input.bool(true, "Include live values", group=groupLog)
logIncludeConfig = input.bool(true, "Log config once", group=groupLog)
atr = ta.atr(atrLen)
// ============================================================================
// MODULE: helpers
// ============================================================================
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Helpers
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
clamp01(x) => math.max(0.0, math.min(1.0, x))
clamp100(x) => math.max(0.0, math.min(100.0, x))
// Optional TF weight
wTimeEffective = useTF ? wTime : 0.0
// --- FAST AGGREGATES (Cum-Sums) ---
stepPath = math.abs(pathSrc - pathSrc[1])
cumPath = ta.cum(stepPath)
bodyAbs = math.abs(close - open)
cumBody = ta.cum(bodyAbs)
minOppNow = minOppBodyAtr > 0 ? (atr * minOppBodyAtr) : 0.0
bodyOK = (minOppBodyAtr == 0.0) or (bodyAbs >= minOppNow)
bullBodyOK = (close > open and bodyOK) ? bodyAbs : 0.0
bearBodyOK = (close < open and bodyOK) ? bodyAbs : 0.0
bullCountOK = (close > open and bodyOK) ? 1.0 : 0.0
bearCountOK = (close < open and bodyOK) ? 1.0 : 0.0
cumBullBodyOK = ta.cum(bullBodyOK)
cumBearBodyOK = ta.cum(bearBodyOK)
cumBullCountOK = ta.cum(bullCountOK)
cumBearCountOK = ta.cum(bearCountOK)
// Sum over bar-offset range iFrom..iTo inclusive
seg_sum(series float cum, int iFrom, int iTo) =>
cum[iFrom] - cum[iTo + 1]
// Relative stats helpers
f_percentile(float[] arr, float v) =>
int n = array.size(arr)
if n == 0
na
else
int c = 0
for k = 0 to n - 1
if array.get(arr, k) <= v
c += 1
c / n
f_mean(float[] arr) =>
int n = array.size(arr)
if n == 0
na
else
float s = 0.0
for k = 0 to n - 1
s += array.get(arr, k)
s / n
f_std(float[] arr, float mu) =>
int n = array.size(arr)
if n < 2 or na(mu)
na
else
float s2 = 0.0
for k = 0 to n - 1
float d = array.get(arr, k) - mu
s2 += d * d
math.sqrt(s2 / (n - 1))
f_z(float[] arr, float v) =>
float mu = f_mean(arr)
float sd = f_std(arr, mu)
(not na(sd) and sd > 0) ? ((v - mu) / sd) : na
f_avg_last(float[] arr, int n) =>
int sz = array.size(arr)
if sz == 0
na
else
int take = math.min(n, sz)
float s = 0.0
for k = 0 to take - 1
s += array.get(arr, sz - 1 - k)
s / take
f_chop_share_last(float[] peArr, int n, float peMax) =>
int sz = array.size(peArr)
if sz == 0
na
else
int take = math.min(n, sz)
int c = 0
for k = 0 to take - 1
float pe = array.get(peArr, sz - 1 - k)
if pe <= peMax
c += 1
c / take
f_label_size() =>
switch labelSize
"large" => size.large
"normal" => size.normal
=> size.small
// Quality color based on score (for both legs)
scoreColor(score, dir) =>
base = dir == 1 ? colBull : colBear
score >= thrHigh ? base : score >= thrMid ? colMid : score >= thrLow ? color.new(base, 35) : colBad
// Compute RLE for a finished leg between startIdx and endIdx (both are bar_index values in the past)
f_rle_for_leg(int startIdx, float startPrice, int endIdx, float endPrice, int dir) =>
// Offsets from current bar (0 = now, bigger = past)
int oStart = bar_index - startIdx
int oEnd = bar_index - endIdx
// Safety: ensure ordering
bool ok = oStart > oEnd and oStart < 5000 and oEnd >= 0 and (oStart + 1) < 5000
float direct = na
if directMode == "PathSource"
direct := math.abs(pathSrc[oEnd] - pathSrc[oStart])
else
direct := math.abs(endPrice - startPrice)
int bars = endIdx - startIdx
float pathSum = na
float totalBody = na
float oppBody = na
int oppCount = na
if ok
int iFrom = oEnd + 1
int iTo = oStart
// Path length: sum stepPath[k] for k=oEnd..oStart-1
pathSum := (cumPath[oEnd] - cumPath[oStart])
// Body sum: sum bodyAbs[i] for i=oEnd+1..oStart
totalBody := seg_sum(cumBody, iFrom, iTo)
float oppFullBody = na
float oppFullCnt = na
if useBodyWeighted
oppFullBody := dir == 1 ? seg_sum(cumBearBodyOK, iFrom, iTo) : seg_sum(cumBullBodyOK, iFrom, iTo)
else
oppFullCnt := dir == 1 ? seg_sum(cumBearCountOK, iFrom, iTo) : seg_sum(cumBullCountOK, iFrom, iTo)
float pe = pathSum > 0 ? clamp01(direct / pathSum) : 0.0
// Time factor: penalty for slow legs (0..1)
float tf = 1.0
if useTF
tf := 1.0 / (1.0 + (bars / math.max(1.0, timeRefBars)))
if tfMode == "Time (TF-neutral)"
int startTime = time[oStart]
int endTime = time[oEnd]
float legMinutes = (endTime - startTime) / 60000.0
tf := 1.0 / (1.0 + (legMinutes / math.max(1.0, timeRefMinutes)))
int segLen = iTo - iFrom + 1
int nEnd = math.max(1, int(math.round(segLen * cpEndFrac)))
int endFrom = iFrom
int endTo = math.min(iTo, iFrom + nEnd - 1)
float endBody = seg_sum(cumBody, endFrom, endTo)
float oppEndBody = na
float oppEndCnt = na
if useBodyWeighted
oppEndBody := dir == 1 ? seg_sum(cumBearBodyOK, endFrom, endTo) : seg_sum(cumBullBodyOK, endFrom, endTo)
else
oppEndCnt := dir == 1 ? seg_sum(cumBearCountOK, endFrom, endTo) : seg_sum(cumBullCountOK, endFrom, endTo)
float cpFull = useBodyWeighted ? (totalBody > 0 ? clamp01(1.0 - (oppFullBody / totalBody)) : 1.0) : (bars > 0 ? clamp01(1.0 - (int(oppFullCnt) / bars)) : 1.0)
float cpEnd = useBodyWeighted ? (endBody > 0 ? clamp01(1.0 - (oppEndBody / endBody)) : cpFull) : (nEnd > 0 ? clamp01(1.0 - (int(oppEndCnt) / nEnd)) : cpFull)
float cp = clamp01((1.0 - cpEndWeight) * cpFull + cpEndWeight * cpEnd)
float wSum = math.max(0.0001, (wPath + wTimeEffective + wCounter))
float score = 100.0 * (wPath * pe + wTimeEffective * tf + wCounter * cp) / wSum
oppBody := oppFullBody
oppCount := int(oppFullCnt)
[clamp100(score), pe, tf, cp, bars, direct, pathSum, totalBody, oppBody, oppCount]
else
[na, na, na, na, na, na, na, na, na, na]
// Live estimate from last pivot to current bar
f_rle_live(int startIdx, float startPrice, int dir) =>
int endIdx = bar_index
float endPrice = liveEndMode == "close" ? close : (dir == 1 ? high : low)
f_rle_for_leg(startIdx, startPrice, endIdx, endPrice, dir)
// ============================================================================
// MODULE: pivots
// ============================================================================
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Pivot detection (confirmed pivots)
// pivots are confirmed only after rightBars, pivot bar is (bar_index - rightBars)
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ph = ta.pivothigh(high, leftBars, rightBars)
pl = ta.pivotlow(low, leftBars, rightBars)
bool newPH = not na(ph)
bool newPL = not na(pl)
int pivotIdx = bar_index - rightBars
float pivotPrice = na
int pivotType = 0 // +1 = high, -1 = low
if newPH
pivotPrice := ph
pivotType := +1
else if newPL
pivotPrice := pl
pivotType := -1
// ============================================================================
// MODULE: state
// ============================================================================
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// State: last confirmed pivot (start of active leg)
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
var int lastPivotIdx = na
var float lastPivotPrice = na
var int lastPivotType = 0
var float lastFinalRLE = na
var float lastFinalPE = na
var float lastFinalTF = na
var float lastFinalCP = na
var int lastFinalBars = na
var int lastFinalDir = 0
var float lastFinalDirect = na
var float lastFinalPathSum = na
var float lastFinalTotalBody = na
var float lastFinalOppBody = na
var int lastFinalOppCount = na
var float lastRelRLE = na
var float lastRelPE = na
var float lastRelCP = na
var float prevUpPE = na
var float prevUpPrice = na
var float prevDnPE = na
var float prevDnPrice = na
var float[] histRLE = array.new_float()
var float[] histPE = array.new_float()
var float[] histCP = array.new_float()
var float regAvgPE = na
var float regAvgCP = na
var float regAvgRLE = na
var float regChopShr = na
var float regScore = na
var bool regimeTrend = false
var bool regimeChop = false
var bool trendOk = false
var bool mrOk = false
var float relRLEpct = na
var label liveLbl = na
var line[] legLines = array.new_line()
var label[] endLabels = array.new_label()
f_push_line(line ln) =>
array.push(legLines, ln)
if array.size(legLines) > maxDrawnLegs
line.delete(array.shift(legLines))
f_push_label(label lb) =>
array.push(endLabels, lb)
if array.size(endLabels) > maxDrawnLegs
label.delete(array.shift(endLabels))
f_state_tag(float pe, float tf, float cp) =>
if pe > 0.75 and tf > 0.55 and cp > 0.55
"Drive"
else if pe > 0.65 and tf < 0.45 and cp > 0.55
"Grind"
else if pe < 0.45 and cp < 0.45
"Chop"
else if pe > 0.60 and cp < 0.45
"Exhaust"
else
"Neutral"
f_push_hist(float[] arr, float v) =>
array.push(arr, v)
if array.size(arr) > relLookbackLegs
array.shift(arr)
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// When we get a new pivot: close the leg from lastPivot -> this pivot
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
if pivotType != 0
if na(lastPivotIdx)
lastPivotIdx := pivotIdx
lastPivotPrice := pivotPrice
lastPivotType := pivotType
else
if pivotType != lastPivotType
int startIdx = lastPivotIdx
float startPrice = lastPivotPrice
int endIdx = pivotIdx
float endPrice = pivotPrice
int bars = endIdx - startIdx
if bars >= minLegBars
int dir = (endPrice >= startPrice) ? 1 : -1
[score, pe, tf, cp, lbars, direct, pathSum, totalBody, oppBody, oppCount] = f_rle_for_leg(startIdx, startPrice, endIdx, endPrice, dir)
if not na(score)
lastFinalRLE := score
lastFinalPE := pe
lastFinalTF := tf
lastFinalCP := cp
lastFinalBars := lbars
lastFinalDir := dir
lastFinalDirect := direct
lastFinalPathSum := pathSum
lastFinalTotalBody := totalBody
lastFinalOppBody := oppBody
lastFinalOppCount := oppCount
f_push_hist(histRLE, score)
f_push_hist(histPE, pe)
f_push_hist(histCP, cp)
if array.size(histRLE) >= 20
if relMode == "Percentile"
lastRelRLE := 100.0 * f_percentile(histRLE, score)
lastRelPE := 100.0 * f_percentile(histPE, pe)
lastRelCP := 100.0 * f_percentile(histCP, cp)
else
lastRelRLE := f_z(histRLE, score)
lastRelPE := f_z(histPE, pe)
lastRelCP := f_z(histCP, cp)
regAvgPE := array.size(histPE) > 0 ? f_avg_last(histPE, regLookback) : na
regAvgCP := array.size(histCP) > 0 ? f_avg_last(histCP, regLookback) : na
regAvgRLE := array.size(histRLE) > 0 ? f_avg_last(histRLE, regLookback) : na
regChopShr := array.size(histPE) > 0 ? f_chop_share_last(histPE, regLookback, regChopPeMax) : na
regScore := na
if not na(regAvgPE) and not na(regAvgCP) and not na(regChopShr)
float peN = clamp01(regAvgPE)
float cpN = clamp01(regAvgCP)
float chopPenalty = clamp01(regChopShr)
regScore := clamp01(0.45 * peN + 0.45 * cpN + 0.10 * (1.0 - chopPenalty))
regimeTrend := not na(regScore) and regScore >= regTrendMin
regimeChop := not na(regScore) and regScore <= regChopMax
relRLEpct := na
if relMode == "Percentile"
relRLEpct := lastRelRLE
trendOk := regimeTrend and not na(lastFinalRLE) and lastFinalRLE >= trendMinLegRLE and (na(relRLEpct) or relRLEpct >= trendMinRelPct)
mrOk := regimeChop and not na(lastFinalRLE) and lastFinalRLE <= mrMaxLegRLE and (not na(regChopShr) and regChopShr >= mrMinChopShare)
if divEnable
float drop = divDropPct / 100.0
if dir == 1 and pivotType == +1
if not na(prevUpPE) and endPrice > prevUpPrice and pe < prevUpPE * (1.0 - drop)
if showChartDrawings
label.new(endIdx, endPrice + atr * labelYOffsetAtr, "RLE DIV ↓",
xloc=xloc.bar_index,
style=label.style_label_down,
textcolor=color.white,
color=color.new(color.orange, 0),
force_overlay=true)
prevUpPE := pe
prevUpPrice := endPrice
if dir == -1 and pivotType == -1
if not na(prevDnPE) and endPrice < prevDnPrice and pe < prevDnPE * (1.0 - drop)
if showChartDrawings
label.new(endIdx, endPrice - atr * labelYOffsetAtr, "RLE DIV ↑",
xloc=xloc.bar_index,
style=label.style_label_up,
textcolor=color.white,
color=color.new(color.aqua, 0),
force_overlay=true)
prevDnPE := pe
prevDnPrice := endPrice
if showChartDrawings and showLegLines
line ln = line.new(startIdx, startPrice, endIdx, endPrice,
xloc=xloc.bar_index,
color=scoreColor(score, dir),
width=lineWidth,
force_overlay=true)
f_push_line(ln)
if showChartDrawings and showEndLabels
string styleEnd = dir == 1 ? label.style_label_down : label.style_label_up
float yOff = atr * labelYOffsetAtr
float y = dir == 1 ? (endPrice + yOff) : (endPrice - yOff)
labelSz = f_label_size()
string labelTxt = "RLE " + str.tostring(score, "#.0")
if showStateTag
string tag = f_state_tag(pe, tf, cp)
labelTxt := labelTxt + " | " + tag
string tip = str.format( "Relative Leg Efficiency (RLE)\nScore: {0} / 100\n\nPath Efficiency (PE): {1}%\nTime Factor (TF): {2}%\nCounter Pressure (CP): {3}%\n\nBars in leg: {4}", str.tostring(score, "#.0"), str.tostring(pe * 100, "#.0"), str.tostring(tf * 100, "#.0"), str.tostring(cp * 100, "#.0"), str.tostring(lbars) )
label lb = label.new(endIdx, y, labelTxt,
xloc=xloc.bar_index,
style=styleEnd,
color=scoreColor(score, dir),
textcolor=color.white,
size=labelSz,
force_overlay=true,
tooltip=tip)
f_push_label(lb)
lastPivotIdx := pivotIdx
lastPivotPrice := pivotPrice
lastPivotType := pivotType
else
if pivotType == +1 and pivotPrice > lastPivotPrice
lastPivotIdx := pivotIdx
lastPivotPrice := pivotPrice
if pivotType == -1 and pivotPrice < lastPivotPrice
lastPivotIdx := pivotIdx
lastPivotPrice := pivotPrice
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Live RLE (optional) from last pivot to current bar
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
int activeDir =
lastPivotType == -1 ? 1 : lastPivotType == +1 ? -1 : 0
float rleLive = na
float peLive = na
float tfLive = na
float cpLive = na
int barsLive = na
float directLive = na
float pathSumLive = na
float totalBodyLive = na
float oppBodyLive = na
int oppCountLive = na
if not na(lastPivotIdx) and activeDir != 0
[rleLive, peLive, tfLive, cpLive, barsLive, directLive, pathSumLive, totalBodyLive, oppBodyLive, oppCountLive] = f_rle_live(lastPivotIdx, lastPivotPrice, activeDir)
if showChartDrawings and showLiveLabel
if not na(liveLbl)
label.delete(liveLbl)
if not na(rleLive)
string styleLive = activeDir == 1 ? label.style_label_down : label.style_label_up
float yOff = atr * labelYOffsetAtr
float y = activeDir == 1 ? (high + yOff) : (low - yOff)
labelSz = f_label_size()
string labelTxt = "Live " + str.tostring(rleLive, "#.0")
string tip = str.format( "Live estimate (can change until the leg is confirmed)\n\nRLE: {0}\nPE: {1}%\nTF: {2}%\nCP: {3}%\nBars: {4}", str.tostring(rleLive, "#.0"), str.tostring(peLive * 100, "#.0"), str.tostring(tfLive * 100, "#.0"), str.tostring(cpLive * 100, "#.0"), str.tostring(barsLive) )
liveLbl := label.new(bar_index, y, labelTxt,
xloc=xloc.bar_index,
style=styleLive,
color=scoreColor(rleLive, activeDir),
textcolor=color.white,
size=labelSz,
force_overlay=true,
tooltip=tip)
else
if not na(liveLbl)
label.delete(liveLbl)
liveLbl := na
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Logging (last bar): sample past bars for optimization
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
var int logLastBar = na
if logEnable and logMode == "Batch (last bar)" and barstate.islast
if na(logLastBar) or logLastBar != bar_index
logLastBar := bar_index
if logIncludeConfig
log.info(str.format( "RLE_CFG,directMode={0},tfMode={1},liveEndMode={2},wPath={3},wTime={4},wCounter={5},timeRefBars={6},timeRefMinutes={7},minOppBodyAtr={8},useBodyWeighted={9},minLegBars={10}", directMode, tfMode, liveEndMode, str.tostring(wPath, "#.00"), str.tostring(wTime, "#.00"), str.tostring(wCounter, "#.00"), str.tostring(timeRefBars), str.tostring(timeRefMinutes), str.tostring(minOppBodyAtr, "#.00"), str.tostring(useBodyWeighted), str.tostring(minLegBars) ))
int logCount = 0
for i = 0 to logLookback
if i <= bar_index and (i % logEveryN == 0)
if logCount >= logMaxLines
break
logCount += 1
string fScore = logIncludeFinal ? str.tostring(lastFinalRLE[i], "#.0") : ""
string fPE = logIncludeFinal ? str.tostring(lastFinalPE[i], "#.000") : ""
string fTF = logIncludeFinal ? str.tostring(lastFinalTF[i], "#.000") : ""
string fCP = logIncludeFinal ? str.tostring(lastFinalCP[i], "#.000") : ""
string fBars = logIncludeFinal ? str.tostring(lastFinalBars[i]) : ""
string fDir = logIncludeFinal ? str.tostring(lastFinalDir[i]) : ""
string fDirect = logIncludeFinal ? str.tostring(lastFinalDirect[i], "#.000") : ""
string fPath = logIncludeFinal ? str.tostring(lastFinalPathSum[i], "#.000") : ""
string fBody = logIncludeFinal ? str.tostring(lastFinalTotalBody[i], "#.000") : ""
string fOppB = logIncludeFinal ? str.tostring(lastFinalOppBody[i], "#.000") : ""
string fOppC = logIncludeFinal ? str.tostring(lastFinalOppCount[i]) : ""
string fTag = logIncludeFinal and not na(lastFinalPE[i]) ? f_state_tag(lastFinalPE[i], lastFinalTF[i], lastFinalCP[i]) : ""
string fRelRLE = logIncludeFinal ? str.tostring(lastRelRLE[i], "#.000") : ""
string fRelPE = logIncludeFinal ? str.tostring(lastRelPE[i], "#.000") : ""
string fRelCP = logIncludeFinal ? str.tostring(lastRelCP[i], "#.000") : ""
string fRegSc = logIncludeFinal ? str.tostring(regScore[i], "#.000") : ""
string fChop = logIncludeFinal ? str.tostring(regChopShr[i], "#.000") : ""
string fTrend = logIncludeFinal ? str.tostring(trendOk[i]) : ""
string fMR = logIncludeFinal ? str.tostring(mrOk[i]) : ""
bool liveOk = logIncludeLive and (i == 0)
string lScore = liveOk ? str.tostring(rleLive, "#.0") : ""
string lPE = liveOk ? str.tostring(peLive, "#.000") : ""
string lTF = liveOk ? str.tostring(tfLive, "#.000") : ""
string lCP = liveOk ? str.tostring(cpLive, "#.000") : ""
string lBars = liveOk ? str.tostring(barsLive) : ""
string lDir = liveOk ? str.tostring(activeDir) : ""
string lDirect = liveOk ? str.tostring(directLive, "#.000") : ""
string lPath = liveOk ? str.tostring(pathSumLive, "#.000") : ""
string lBody = liveOk ? str.tostring(totalBodyLive, "#.000") : ""
string lOppB = liveOk ? str.tostring(oppBodyLive, "#.000") : ""
string lOppC = liveOk ? str.tostring(oppCountLive) : ""
string lTag = liveOk and not na(peLive) ? f_state_tag(peLive, tfLive, cpLive) : ""
log.info(str.format( "RLE,bar={0},time={1},final_score={2},final_pe={3},final_tf={4},final_cp={5},final_bars={6},final_dir={7},final_direct={8},final_path={9},final_body={10},final_opp_body={11},final_opp_count={12},final_tag={13},final_rel_rle={14},final_rel_pe={15},final_rel_cp={16},reg_score={17},chop_share={18},trend_ok={19},mr_ok={20},live_score={21},live_pe={22},live_tf={23},live_cp={24},live_bars={25},live_dir={26},live_direct={27},live_path={28},live_body={29},live_opp_body={30},live_opp_count={31},live_tag={32}", str.tostring(bar_index - i), str.tostring(time[i]), fScore, fPE, fTF, fCP, fBars, fDir, fDirect, fPath, fBody, fOppB, fOppC, fTag, fRelRLE, fRelPE, fRelCP, fRegSc, fChop, fTrend, fMR, lScore, lPE, lTF, lCP, lBars, lDir, lDirect, lPath, lBody, lOppB, lOppC, lTag ))
if logEnable and logMode == "Streaming"
if barstate.isconfirmed and (bar_index % logEveryN == 0)
string fScore = logIncludeFinal ? str.tostring(lastFinalRLE, "#.0") : ""
string fPE = logIncludeFinal ? str.tostring(lastFinalPE, "#.000") : ""
string fTF = logIncludeFinal ? str.tostring(lastFinalTF, "#.000") : ""
string fCP = logIncludeFinal ? str.tostring(lastFinalCP, "#.000") : ""
string fBars = logIncludeFinal ? str.tostring(lastFinalBars) : ""
string fDir = logIncludeFinal ? str.tostring(lastFinalDir) : ""
string fDirect = logIncludeFinal ? str.tostring(lastFinalDirect, "#.000") : ""
string fPath = logIncludeFinal ? str.tostring(lastFinalPathSum, "#.000") : ""
string fBody = logIncludeFinal ? str.tostring(lastFinalTotalBody, "#.000") : ""
string fOppB = logIncludeFinal ? str.tostring(lastFinalOppBody, "#.000") : ""
string fOppC = logIncludeFinal ? str.tostring(lastFinalOppCount) : ""
string fTag = logIncludeFinal and not na(lastFinalPE) ? f_state_tag(lastFinalPE, lastFinalTF, lastFinalCP) : ""
string fRelRLE = logIncludeFinal ? str.tostring(lastRelRLE, "#.000") : ""
string fRelPE = logIncludeFinal ? str.tostring(lastRelPE, "#.000") : ""
string fRelCP = logIncludeFinal ? str.tostring(lastRelCP, "#.000") : ""
string fRegSc = logIncludeFinal ? str.tostring(regScore, "#.000") : ""
string fChop = logIncludeFinal ? str.tostring(regChopShr, "#.000") : ""
string fTrend = logIncludeFinal ? str.tostring(trendOk) : ""
string fMR = logIncludeFinal ? str.tostring(mrOk) : ""
string lScore = logIncludeLive ? str.tostring(rleLive, "#.0") : ""
string lPE = logIncludeLive ? str.tostring(peLive, "#.000") : ""
string lTF = logIncludeLive ? str.tostring(tfLive, "#.000") : ""
string lCP = logIncludeLive ? str.tostring(cpLive, "#.000") : ""
string lBars = logIncludeLive ? str.tostring(barsLive) : ""
string lDir = logIncludeLive ? str.tostring(activeDir) : ""
string lDirect = logIncludeLive ? str.tostring(directLive, "#.000") : ""
string lPath = logIncludeLive ? str.tostring(pathSumLive, "#.000") : ""
string lBody = logIncludeLive ? str.tostring(totalBodyLive, "#.000") : ""
string lOppB = logIncludeLive ? str.tostring(oppBodyLive, "#.000") : ""
string lOppC = logIncludeLive ? str.tostring(oppCountLive) : ""
string lTag = logIncludeLive and not na(peLive) ? f_state_tag(peLive, tfLive, cpLive) : ""
log.info(str.format( "RLE,bar={0},time={1},final_score={2},final_pe={3},final_tf={4},final_cp={5},final_bars={6},final_dir={7},final_direct={8},final_path={9},final_body={10},final_opp_body={11},final_opp_count={12},final_tag={13},final_rel_rle={14},final_rel_pe={15},final_rel_cp={16},reg_score={17},chop_share={18},trend_ok={19},mr_ok={20},live_score={21},live_pe={22},live_tf={23},live_cp={24},live_bars={25},live_dir={26},live_direct={27},live_path={28},live_body={29},live_opp_body={30},live_opp_count={31},live_tag={32}", str.tostring(bar_index), str.tostring(time), fScore, fPE, fTF, fCP, fBars, fDir, fDirect, fPath, fBody, fOppB, fOppC, fTag, fRelRLE, fRelPE, fRelCP, fRegSc, fChop, fTrend, fMR, lScore, lPE, lTF, lCP, lBars, lDir, lDirect, lPath, lBody, lOppB, lOppC, lTag ))
// ============================================================================
// MODULE: panel
// ============================================================================
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Panel plots
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
panelDisplay = showPanel ? display.pane : display.none
// Invisible anchor to force pane creation when overlay=true
plot(showPanel ? 0 : na, "Pane Anchor", color=color.new(color.gray, 100), display=panelDisplay)
plot(showPanel ? thrHigh : na, "High", color=color.new(color.white, 70), display=panelDisplay)
plot(showPanel ? thrMid : na, "Mid", color=color.new(color.white, 75), display=panelDisplay)
plot(showPanel ? thrLow : na, "Low", color=color.new(color.white, 80), display=panelDisplay)
plot(lastFinalRLE, "RLE Final (confirmed)", style=plot.style_stepline, linewidth=2, display=panelDisplay)
plot(rleLive, "RLE Live (estimate)", linewidth=1, display=panelDisplay)
plot(showPanel ? (lastFinalPE * 100.0) : na, "PE % (final)", display=panelDisplay)
plot(showPanel ? (lastFinalCP * 100.0) : na, "CP % (final)", display=panelDisplay)
plot(showPanel ? lastRelRLE : na, "REL RLE", display=panelDisplay)
plot(showPanel ? lastRelPE : na, "REL PE", display=panelDisplay)
plot(showPanel ? lastRelCP : na, "REL CP", display=panelDisplay)
plotchar(showPanel ? trendOk : na, "trendOk", "▲", location=location.top, size=size.tiny, color=color.new(color.lime, 0), display=panelDisplay)
plotchar(showPanel ? mrOk : na, "mrOk", "▼", location=location.top, size=size.tiny, color=color.new(color.aqua, 0), display=panelDisplay)
plot(showPanel ? (regScore * 100.0) : na, "RegimeScore %", display=panelDisplay)
plot(showPanel ? (regChopShr * 100.0) : na, "ChopShare %", display=panelDisplay)
alertcondition(trendOk, "RLE Trend OK", "RLE regime says TREND ok (trendOk=true)")
alertcondition(mrOk, "RLE MR OK", "RLE regime says MEAN-REVERSION ok (mrOk=true)")
Overview
Plotted in a separate pane with chart pivot overlays, it calculates path distance, execution duration, and counter-pressure to produce efficiency scores. Traders can adjust pivot detection sensitivity, weight components for path, time, and counter-pressure, and set percentile lookbacks. It also features market regime detection to classify trends or chop, alongside divergence labels on efficiency drops.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Pivot Left Bars
int
4
leftBars
Pivot Right Bars
int
4
rightBars
Min Leg Bars
int
6
minLegBars
Path Source (for path length)
source
hlc3
pathSrc
Direct Distance Mode
string
PivotPrice
directMode
Live End Price
string
close
liveEndMode
Time Factor Mode
string
Bars (current TF)
tfMode
Time Reference Minutes (TF-neutral)
int
120
timeRefMinutes
Use Time Factor (TF) in score
bool
false
useTF
Counter Pressure: Body-weighted (else count)
bool
true
useBodyWeighted
Ignore tiny opposite bodies (ATR multiple, 0=off)
float
0.0
minOppBodyAtr
ATR Length
int
14
atrLen
Show all 40 settings
Setting
Type
Default
Variable
Time Reference Bars (penalty after this)
int
24
timeRefBars
Weight: Path
float
0.50
wPath
Weight: Time
float
0.20
wTime
Weight: Counter
float
0.30
wCounter
CP: End segment fraction
float
0.30
cpEndFrac
CP: Weight end segment
float
0.70
cpEndWeight
Relative lookback legs
int
60
relLookbackLegs
Relative mode
string
Percentile
relMode
Divergence labels
bool
true
divEnable
Div: min drop vs prev (%)
float
12.0
divDropPct
Regime legs lookback
int
8
regLookback
Chop if PE <=
float
0.45
regChopPeMax
Trend score min (0..1)
float
0.60
regTrendMin
Chop score max (0..1)
float
0.40
regChopMax
Trend filter: last leg RLE >=
float
60
trendMinLegRLE
Trend filter: RLE percentile >=
float
60
trendMinRelPct
MR filter: last leg RLE <=
float
45
mrMaxLegRLE
MR filter: chop share >=
float
0.50
mrMinChopShare
Show Chart Drawings (Lines/Labels)
bool
true
showChartDrawings
Show Panel
bool
true
showPanel
Draw Leg Lines on Chart
bool
true
showLegLines
Show RLE Labels at Leg End
bool
true
showEndLabels
Show Live RLE Label (updates)
bool
false
showLiveLabel
Label Size
string
small
labelSize
Max Drawn Legs
int
120
maxDrawnLegs
Append State Tag to Labels
bool
true
showStateTag
Threshold High
float
80
thrHigh
Threshold Mid
float
70
thrMid
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.
The GBPJPY System is a MACD divergence strategy for the GBPJPY pair. It calculates MACD on the 1-hour timeframe, RCI on the current bar, and EMA on the 4-hour timeframe to detect trend reversals and divergences. The script plots entry signals, stop loss, take
This indicator plots a momentum-based ZigZag on the price chart from a QQE calculation driven by a multi-timeframe RSI. It marks bullish and bearish ZigZag segments, optional divergence and convergence between price and that RSI, and an optional Supertrend lin
This indicator combines a scaled Forecast Oscillator with a Point of Force state detector. The Forecast Oscillator calculates the percentage deviation of price from its linear regression curve and normalizes the output between 0 and 1, plotting a line in a sep
WaveTrend 3D is a redesigned oscillator that implements the classic WaveTrend algorithm with kernel-based regression for trend reversal confirmation and multi-timeframe support. It calculates a smoothed oscillator line and displays a symmetrical three-dimensio
This indicator calculates a Relative Strength Index using Wilder or Cutler calculation methods, accompanied by an optional smoothing moving average and a signal line. Plotted in a separate pane, it features defined bull and bear control and critical threshold
This indicator plots a smoothed fear index in a separate pane. It measures how far the current low sits below the highest close over a lookback, scales that reading by an ATR percentile, and smooths it with a zero-lag EMA. A volatility regime raises or lowers