//@version=6
// ============================================================================
// Reversal Engine Score [WavesUnchained] — Strategy (standalone)
// Version: 1.6.3
// Author: WavesUnchained
// Build: 2026-10-12 00:00:00
// ============================================================================
// Score-based liquidity sweep reversal detector with HTF trend confluence.
//
// Features:
// ✓ Mandatory gate model — sweep + close position + body + ATR corridor + HTF
// ✓ Quality score (0–2 optional conditions) replaces additive sum
// ✓ Per-direction quality thresholds (Long/Short configurable separately)
// ✓ Short optionals: RSI > 50 (elevated), no HH
// ✓ Structural SL — sweep low/high as base + configurable ATR noise buffer
// ✓ R-multiple TP — adapts to actual risk distance (TP = entry ± risk × factor)
// ✓ ATR corridor filter — rejects both low-volatility noise and spike regimes
// ✓ Liquidity sweep detection (swing violation + recovery close)
// ✓ HTF trend filter via dual EMA on configurable timeframe
// ✓ Spike filter — blocks sweeps deeper than N×ATR (real breakdowns, not reversals)
// ✓ Break-even stop triggered at configurable R-multiple of initial risk
// ✓ Structural exit — close on new LL (long) or new HH (short)
// ✓ Price structure labels (HH / HL / LH / LL) at confirmed pivots
// ✓ Outcome-based label coloring (blue = no follow-through within N bars)
// ✓ Alert conditions for BUY / SELL / either
//
// ============================================================================
strategy("Reversal Engine Score [WavesUnchained] — Strategy", overlay=true,
max_lines_count=500,
max_labels_count=500,
default_qty_type=strategy.percent_of_equity, default_qty_value=10,
commission_type=strategy.commission.percent, commission_value=0.02,
slippage=1, max_bars_back=500)
// Synthetische Bar-Preise (Heikin Ashi, Renko …): Orders füllen zu Marktpreisen,
// der Backtest gilt dort nicht. Kurzer Hinweis unten rechts statt auf der Kerze.
var table chartTypeWarn = table.new(position.bottom_right, 1, 1)
if barstate.islast and not chart.is_standard
table.cell(chartTypeWarn, 0, 0, "RES Strategy · backtest invalid on this chart type",
bgcolor = color.new(color.red, 10), text_color = color.white, text_size = size.small)
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Groups
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
g_display = "Anzeige"
g_quality = "Signal-Qualität"
g_gates = "Pflicht-Gates"
g_ma = "Reclaim MA"
g_sltp = "SL / TP"
gStruct = "Marktstruktur"
gOutcome = "Outcome"
g_strat = "Strategy"
g_filters = "Filters"
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Inputs
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// — Anzeige ———————————————————————————
only15m = input.bool(true, "Nur auf 15M aktiv", group = g_display)
showLevels = input.bool(true, "SL/TP-Level anzeigen", group = g_display)
showTrendBackground = input.bool(false, "Trend-Hintergrund", group = g_display)
showScoreLabel = input.bool(true, "Score am Signal anzeigen", group = g_display)
// — Signal-Qualität ———————————————————
minQualityLong = input.int(2, "Min. Qualität Long (0–2)", minval = 0, maxval = 2, group = g_quality,
tooltip = "Mindestanzahl optionaler Bedingungen für Longs. 2 = alle Optionals erforderlich (empfohlen).")
minQualityShort = input.int(1, "Min. Qualität Short (0–2)", minval = 0, maxval = 2, group = g_quality,
tooltip = "Mindestanzahl optionaler Bedingungen für Shorts. Short-Optionals sind reversal-spezifisch (RSI > 50, kein HH).")
rsiLen = input.int(14, "RSI Länge", minval = 1, group = g_quality)
// — Pflicht-Gates —————————————————————
// Gate A — Liquidity Sweep
useGateA = input.bool(true, "Gate A — Liquidity Sweep", group = g_gates,
tooltip = "Long: Low verletzt Swing-Low und schließt darüber zurück. Short: High verletzt Swing-High und schließt darunter zurück.")
swingLen = input.int(10, " [A] Sweep Lookback", minval = 2, group = g_gates)
// Gate B — Close-Position (⅓-Regel)
useGateB = input.bool(false, "Gate B — Close-Position (⅓-Regel)", group = g_gates,
tooltip = "Long: Close im oberen Drittel der Candle. Short: Close im unteren Drittel. Bestätigt Rejection-Charakter.")
// Gate C — Body-Größe
useGateC = input.bool(false, "Gate C — Body-Größe", group = g_gates,
tooltip = "Candle-Body muss Mindestgröße relativ zur ATR erreichen. Filtert Doji/Spinning-Top Entries.")
minBodyAtr = input.float(0.25, " [C] Min. Body / ATR", step = 0.05, group = g_gates)
// Gate D — ATR Minimum
useGateD = input.bool(true, "Gate D — ATR Minimum", group = g_gates,
tooltip = "ATR muss über dem Minimalwert × ATR-Basis liegen. Filtert Low-Vola-Noise-Phasen. Kein oberes Cap — hohe ATR ist bei Liquidity-Sweeps erwünscht.")
atrLen = input.int(14, " [D] ATR Länge", minval = 1, group = g_gates)
atrBaseLen = input.int(50, " [D] ATR Basislänge", minval = 5, group = g_gates)
atrLowFactor = input.float(0.60, " [D] Min (× Basis)", step = 0.05, group = g_gates,
tooltip = "ATR muss über diesem Faktor × 50-Bar-ATR-Basis liegen. Werte 0.5–0.8 sinnvoll.")
// Gate E — Spike-Filter
useGateE = input.bool(false, "Gate E — Spike-Filter", group = g_gates,
tooltip = "Sweeps tiefer als N×ATR werden blockiert — echte Breakdowns, keine Reversals.")
spikeAtrMult = input.float(0.80, " [E] Max Sweep-Tiefe (ATR×)", step = 0.05, group = g_gates,
tooltip = "Maximale erlaubte Sweep-Tiefe in ATR-Vielfachen.")
// Gate F — HTF Trendfilter
useGateF = input.bool(true, "Gate F — HTF Trendfilter", group = g_gates,
tooltip = "Blockiert Longs wenn HTF bearish (FastEMA < SlowEMA), Shorts wenn HTF bullish. Verhindert Counter-Trend-Entries.")
htf = input.timeframe("60", " [F] Timeframe", group = g_gates)
htfFastLen = input.int(50, " [F] EMA schnell", minval = 1, group = g_gates)
htfSlowLen = input.int(200, " [F] EMA langsam", minval = 1, group = g_gates)
// Gate G — 1H WT Confluence
useGateG = input.bool(false, "Gate G — 1H WT Confluence", group = g_gates,
tooltip = "Long nur wenn 1H WT1 ≤ OS-Schwelle. Short nur wenn 1H WT1 ≥ OB-Schwelle. Stellt sicher, dass der 1H WaveTrend im Extrembereich ist.")
wtChLen = input.int(10, " [G/H] WT Channel Length", minval = 1, group = g_gates)
wtAvgLen = input.int(21, " [G/H] WT Average Length", minval = 1, group = g_gates)
gateG_os = input.float(-30.0, " [G] 1H OS Threshold (long)", step = 1.0, group = g_gates,
tooltip = "1H WT1 muss ≤ diesem Wert liegen für Long-Entries. Typisch: −20 bis −40.")
gateG_ob = input.float( 30.0, " [G] 1H OB Threshold (short)", step = 1.0, group = g_gates,
tooltip = "1H WT1 muss ≥ diesem Wert liegen für Short-Entries. Typisch: +20 bis +40.")
// Gate H — 4H WT Confluence
useGateH = input.bool(false, "Gate H — 4H WT Confluence", group = g_gates,
tooltip = "Long nur wenn 4H WT1 ≤ OS-Schwelle. Short nur wenn 4H WT1 ≥ OB-Schwelle. Stellt sicher, dass der 4H WaveTrend im Extrembereich ist.")
gateH_os = input.float(-30.0, " [H] 4H OS Threshold (long)", step = 1.0, group = g_gates,
tooltip = "4H WT1 muss ≤ diesem Wert liegen für Long-Entries. Typisch: −20 bis −40.")
gateH_ob = input.float( 30.0, " [H] 4H OB Threshold (short)", step = 1.0, group = g_gates,
tooltip = "4H WT1 muss ≥ diesem Wert liegen für Short-Entries. Typisch: +20 bis +40.")
// — Reclaim MA ————————————————————————
emaLen = input.int(21, "Länge", minval = 1, group = g_ma)
smoothType = input.string("EMA", "Typ", group = g_ma,
options = ["EMA", "RMA", "SMA", "WMA", "HMA", "JMA"],
tooltip = "Glättungstyp für die Reclaim-MA. EMA = Standard. JMA = reaktionsschnell mit weniger Lag.")
jmaPhase = input.int(50, " JMA Phase", minval = -100, maxval = 100, group = g_ma,
tooltip = "Nur relevant wenn Typ = JMA. Steuert Phasenverschiebung (−100 bis +100).")
jmaPower = input.float(2.0, " JMA Power", minval = 1.0, maxval = 4.0, step = 0.25, group = g_ma,
tooltip = "Nur relevant wenn Typ = JMA. Stärke der Glättung (1 = leicht, 4 = stark).")
// — SL / TP ———————————————————————————
slAtrBuffer = input.float(0.30, "SL Puffer (ATR×)", step = 0.05, group = g_sltp,
tooltip = "ATR-Puffer unterhalb des Sweep-Tiefs (Long) / oberhalb des Sweep-Hochs (Short). Struktur ist der primäre SL.")
tpRMult = input.float(1.50, "TP Risk-Multiple", step = 0.1, group = g_sltp,
tooltip = "TP = Entry ± Risk × Multiple. Risk = Abstand Entry zu strukturellem SL.")
sigCooldown = input.int(5, "Cooldown nach Signal", minval = 0, group = g_sltp)
pivLen = input.int(5, "Pivot Length", minval = 2, maxval = 20, group = gStruct)
showPivots = input.bool(false, "Struktur-Labels (HH/HL/LH/LL) anzeigen", group = gStruct)
outcomeWindow = input.int(20, "Outcome-Fenster (Bars)", minval = 5, maxval = 500, group = gOutcome,
tooltip = "Nach dieser Anzahl Bars ohne neues Hoch (Long) / neues Tief (Short) wird das Signal-Label blau.")
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 15M Check
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
is15m = timeframe.period == "15"
isActive = only15m ? is15m : true
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Smoothing helpers
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
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)
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Core
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
emaReclaim = f_smooth(close, emaLen, smoothType)
rsiValue = ta.rsi(close, rsiLen)
atrValue = ta.atr(atrLen)
atrBase = ta.sma(atrValue, atrBaseLen)
htfEmaFast = request.security(syminfo.tickerid, htf, ta.ema(close, htfFastLen), barmerge.gaps_off, barmerge.lookahead_off)
htfEmaSlow = request.security(syminfo.tickerid, htf, ta.ema(close, htfSlowLen), barmerge.gaps_off, barmerge.lookahead_off)
bullTrend = htfEmaFast > htfEmaSlow
bearTrend = htfEmaFast < htfEmaSlow
f_wt1(src, chLen, avgLen) =>
_esa = ta.ema(src, chLen)
_d = ta.ema(math.abs(src - _esa), chLen)
_ci = (src - _esa) / (0.015 * _d)
ta.ema(_ci, avgLen)
wt1_1H = request.security(syminfo.tickerid, "60", f_wt1(hlc3, wtChLen, wtAvgLen), barmerge.gaps_off, barmerge.lookahead_off)
wt1_4H = request.security(syminfo.tickerid, "240", f_wt1(hlc3, wtChLen, wtAvgLen), barmerge.gaps_off, barmerge.lookahead_off)
prevSwingLow = ta.lowest(low[1], swingLen)
prevSwingHigh = ta.highest(high[1], swingLen)
rangeValue = high - low
bodyValue = math.abs(close - open)
closeInUpperThird = rangeValue > 0 and close > low + rangeValue * 0.65
closeInLowerThird = rangeValue > 0 and close < high - rangeValue * 0.65
liquiditySweepLong = low < prevSwingLow and close > prevSwingLow
liquiditySweepShort = high > prevSwingHigh and close < prevSwingHigh
atrOk = atrValue > atrBase * atrLowFactor
bodyOk = bodyValue > atrValue * minBodyAtr
sweepDepthLong = prevSwingLow - low
sweepDepthShort = high - prevSwingHigh
sweepNotTooDeepLong = not useGateE or sweepDepthLong <= atrValue * spikeAtrMult
sweepNotTooDeepShort = not useGateE or sweepDepthShort <= atrValue * spikeAtrMult
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Price structure (HH / HL / LH / LL)
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
_phFound = not na(ta.pivothigh(high, pivLen, pivLen))
_plFound = not na(ta.pivotlow(low, pivLen, pivLen))
var float _lastSwingHigh1 = na
var float _lastSwingHigh2 = na
var float _lastSwingLow1 = na
var float _lastSwingLow2 = na
if _phFound
_lastSwingHigh2 := _lastSwingHigh1
_lastSwingHigh1 := high[pivLen]
if _plFound
_lastSwingLow2 := _lastSwingLow1
_lastSwingLow1 := low[pivLen]
hasHighStructure = not na(_lastSwingHigh1) and not na(_lastSwingHigh2)
hasLowStructure = not na(_lastSwingLow1) and not na(_lastSwingLow2)
hhDetected = hasHighStructure and _lastSwingHigh1 > _lastSwingHigh2
lhDetected = hasHighStructure and _lastSwingHigh1 < _lastSwingHigh2
hlDetected = hasLowStructure and _lastSwingLow1 > _lastSwingLow2
llDetected = hasLowStructure and _lastSwingLow1 < _lastSwingLow2
longPivotFail = hasLowStructure and llDetected
shortPivotFail = hasHighStructure and hhDetected
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Signal logic — Pflicht-Gates + optionale Qualität
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Mandatory gates — each can be toggled off individually
longGateOk = (not useGateA or liquiditySweepLong) and
(not useGateB or closeInUpperThird) and
(not useGateC or bodyOk) and
(not useGateD or atrOk) and
sweepNotTooDeepLong and
(not useGateF or not bearTrend) and
(not useGateG or wt1_1H <= gateG_os) and
(not useGateH or wt1_4H <= gateH_os)
shortGateOk = (not useGateA or liquiditySweepShort) and
(not useGateB or closeInLowerThird) and
(not useGateC or bodyOk) and
(not useGateD or atrOk) and
sweepNotTooDeepShort and
(not useGateF or not bullTrend) and
(not useGateG or wt1_1H >= gateG_ob) and
(not useGateH or wt1_4H >= gateH_ob)
// Optional quality points (0–2)
longQuality = 0
longQuality += rsiValue > 50 ? 1 : 0
longQuality += not llDetected ? 1 : 0
// Short optionals use reversal-appropriate conditions (inverted vs. longs):
// RSI > 50 = RSI still elevated → shorting from overbought territory
shortQuality = 0
shortQuality += rsiValue > 50 ? 1 : 0 // RSI above midline = reversal from overbought
shortQuality += not hhDetected ? 1 : 0 // no higher-high structure
f_tier(q) =>
q >= 2 ? "A" : q >= 1 ? "B" : "C"
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Cooldown + final signals
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
var int lastSignalBar = na
cooldownOk = na(lastSignalBar) or bar_index - lastSignalBar > sigCooldown
rawLongSignal = isActive and longGateOk and longQuality >= minQualityLong
rawShortSignal = isActive and shortGateOk and shortQuality >= minQualityShort
longSignal = rawLongSignal and cooldownOk and barstate.isconfirmed
shortSignal = rawShortSignal and cooldownOk and barstate.isconfirmed
if longSignal or shortSignal
lastSignalBar := bar_index
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Strategy-ready values
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
entryLong = longSignal ? close : na
entryShort = shortSignal ? close : na
_lStructSL = math.min(low, prevSwingLow) - atrValue * slAtrBuffer
_sStructSL = math.max(high, prevSwingHigh) + atrValue * slAtrBuffer
longStop = longSignal ? _lStructSL : na
longTake = longSignal ? close + (close - _lStructSL) * tpRMult : na
shortStop = shortSignal ? _sStructSL : na
shortTake = shortSignal ? close - (_sStructSL - close) * tpRMult : na
signalDirection = longSignal ? 1 : shortSignal ? -1 : 0
signalScore = longSignal ? longQuality : shortSignal ? shortQuality : na
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Plots
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
plot(emaReclaim, "Reclaim MA", color = color.new(color.blue, 0), linewidth = 1)
plotshape(longSignal, title = "BUY Signal", style = shape.triangleup, location = location.belowbar, size = size.small, color = color.lime, text = "BUY")
plotshape(shortSignal, title = "SELL Signal", style = shape.triangledown, location = location.abovebar, size = size.small, color = color.red, text = "SELL")
plot(showLevels ? longStop : na, "Long SL", color = color.new(color.red, 0), style = plot.style_linebr)
plot(showLevels ? longTake : na, "Long TP", color = color.new(color.green, 0), style = plot.style_linebr)
plot(showLevels ? shortStop : na, "Short SL", color = color.new(color.red, 0), style = plot.style_linebr)
plot(showLevels ? shortTake : na, "Short TP", color = color.new(color.green, 0), style = plot.style_linebr)
plot(signalDirection, "Signal Direction", display = display.none)
plot(signalScore, "Signal Score", display = display.none)
plot(entryLong, "Entry Long", display = display.none)
plot(entryShort, "Entry Short", display = display.none)
plot(longStop, "Long Stop", display = display.none)
plot(longTake, "Long Take", display = display.none)
plot(shortStop, "Short Stop", display = display.none)
plot(shortTake, "Short Take", display = display.none)
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Structure labels (HH / HL / LH / LL)
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
colorBull = #16a34a
colorBear = #dc2626
colorWarn = #1565c0
if showPivots and _phFound and lhDetected
label.new(bar_index - pivLen, high[pivLen], "LH",
style = label.style_label_down, color = color.new(colorBear, 30),
textcolor = color.white, size = size.tiny, force_overlay = true)
if showPivots and _phFound and hhDetected
label.new(bar_index - pivLen, high[pivLen], "HH",
style = label.style_label_down, color = color.new(colorBull, 30),
textcolor = color.white, size = size.tiny, force_overlay = true)
if showPivots and _plFound and hlDetected
label.new(bar_index - pivLen, low[pivLen], "HL",
style = label.style_label_up, color = color.new(colorBull, 30),
textcolor = color.white, size = size.tiny, force_overlay = true)
if showPivots and _plFound and llDetected
label.new(bar_index - pivLen, low[pivLen], "LL",
style = label.style_label_up, color = color.new(colorBear, 30),
textcolor = color.white, size = size.tiny, force_overlay = true)
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Signal labels + Outcome tracking
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
var label[] _pendingLbl = array.new_label()
var int[] _pendingBar = array.new_int()
var float[] _pendingRef = array.new_float()
var bool[] _pendingLong = array.new_bool()
if showScoreLabel and longSignal
string structCtx = longPivotFail ? "⚠ Struktur: LL (gegenläufig)" : "✓ Struktur ok"
string tip = "Qualität: " + f_tier(longQuality) + " (" + str.tostring(longQuality) + "/2)\n"
tip += "── Pflicht-Gates ──\n"
tip += liquiditySweepLong ? "✓ Liquidity Sweep\n" : "✗ Liquidity Sweep\n"
tip += closeInUpperThird ? "✓ Close oberes Drittel\n" : "✗ Close oberes Drittel\n"
tip += bodyOk ? "✓ Body size\n" : "✗ Body size\n"
tip += atrOk ? "✓ ATR Korridor\n" : "✗ ATR Korridor\n"
tip += not bearTrend ? "✓ HTF nicht bearish\n" : "✗ HTF nicht bearish\n"
tip += "── Optional ──\n"
tip += rsiValue > 50 ? "✓ RSI > 50 (+1)\n" : "✗ RSI > 50\n"
tip += not llDetected ? "✓ Kein LL (+1)\n" : "✗ Kein LL\n"
tip += structCtx
lbl = label.new(bar_index, low,
"BUY — " + f_tier(longQuality),
style = label.style_label_up,
textcolor = color.white,
color = colorBull,
tooltip = tip)
array.push(_pendingLbl, lbl)
array.push(_pendingBar, bar_index)
array.push(_pendingRef, high)
array.push(_pendingLong, true)
if showScoreLabel and shortSignal
string structCtx = shortPivotFail ? "⚠ Struktur: HH (gegenläufig)" : "✓ Struktur ok"
string tip = "Qualität: " + f_tier(shortQuality) + " (" + str.tostring(shortQuality) + "/2)\n"
tip += "── Pflicht-Gates ──\n"
tip += liquiditySweepShort ? "✓ Liquidity Sweep\n" : "✗ Liquidity Sweep\n"
tip += closeInLowerThird ? "✓ Close unteres Drittel\n" : "✗ Close unteres Drittel\n"
tip += bodyOk ? "✓ Body size\n" : "✗ Body size\n"
tip += atrOk ? "✓ ATR Korridor\n" : "✗ ATR Korridor\n"
tip += not bullTrend ? "✓ HTF nicht bullish\n" : "✗ HTF nicht bullish\n"
tip += "── Optional ──\n"
tip += rsiValue > 50 ? "✓ RSI > 50 (+1)\n" : "✗ RSI > 50\n"
tip += not hhDetected ? "✓ Kein HH (+1)\n" : "✗ Kein HH\n"
tip += structCtx
lbl = label.new(bar_index, high,
"SELL — " + f_tier(shortQuality),
style = label.style_label_down,
textcolor = color.white,
color = colorBear,
tooltip = tip)
array.push(_pendingLbl, lbl)
array.push(_pendingBar, bar_index)
array.push(_pendingRef, low)
array.push(_pendingLong, false)
// Outcome: kein neues Hoch/Tief im Fenster → Label blau
if array.size(_pendingLbl) > 0
for i = array.size(_pendingLbl) - 1 to 0
_lbl = array.get(_pendingLbl, i)
_sigBar = array.get(_pendingBar, i)
_ref = array.get(_pendingRef, i)
_isLong = array.get(_pendingLong, i)
if bar_index > _sigBar
_win = _isLong ? high > _ref : low < _ref
_expired = bar_index - _sigBar >= outcomeWindow
if _win or _expired
if not _win
label.set_color(_lbl, colorWarn)
array.remove(_pendingLbl, i)
array.remove(_pendingBar, i)
array.remove(_pendingRef, i)
array.remove(_pendingLong, i)
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Backgrounds
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
bgcolor(showTrendBackground and bullTrend ? color.new(color.green, 92) : na)
bgcolor(showTrendBackground and bearTrend ? color.new(color.red, 92) : na)
bgcolor(only15m and not is15m ? color.new(color.orange, 85) : na)
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Alerts
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ─── Strategy inputs ─────────────────────────────────────────────────────────
tradeDirInput = input.string("Both", "Trade Direction",
options=["Both", "Long Only", "Short Only"], group=g_strat,
tooltip="Filter entries by direction. Useful for asymmetric instruments.")
confirmClose = input.bool(true, "Entries on Confirmed Bar Only", group=g_strat,
tooltip="Only trigger entries on closed bars. Prevents repainting in live trading.")
cooldownBars = input.int(0, "Cooldown Bars After Exit", minval=0, group=g_strat,
tooltip="Block new entries for N bars after a position closes. Set 0 to disable.")
enableBE = input.bool(false, "Break-Even Stop", group=g_strat,
tooltip="Move SL to entry price once the trade is N×R in profit.")
beTriggerR = input.float(1.0, "Break-Even Trigger (R×)", minval=0.1, step=0.1, group=g_strat,
tooltip="R-multiple of initial risk that triggers break-even. 1.0 = move SL to entry when trade is 1R in profit.")
enableStructExit = input.bool(false, "Struktureller Exit (LL/HH)", group=g_strat,
tooltip="Close Long bei neuem LL; Close Short bei neuem HH. Schützt offene Gewinne wenn Gegenstruktur bricht.")
useSession = input.bool(false, "Session Filter", group=g_filters)
sessionInput = input.session("0000-2345", "Session", group=g_filters)
useDateRange = input.bool(false, "Date Range", group=g_filters)
dateFrom = input.time(timestamp("01 Jan 2020 00:00 +0000"), "From", group=g_filters)
dateTo = input.time(timestamp("31 Dec 2030 23:59 +0000"), "To", group=g_filters)
useMaxDD = input.bool(false, "Max Drawdown", group=g_filters)
maxDD = input.float(20.0, "Max Drawdown (%)", minval=1, step=1, group=g_filters)
useMaxIntraDD = input.bool(false, "Max Intraday Loss", group=g_filters)
maxIntraDD = input.float(5.0, "Max Intraday Loss (%)", minval=1, step=1, group=g_filters)
useLossStreak = input.bool(false, "Losing Streak Limit", group=g_filters)
maxLossStreak = input.int(5, "Max Consecutive Losses", minval=1, group=g_filters)
strategy.risk.max_drawdown(useMaxDD ? maxDD : 100, strategy.percent_of_equity)
strategy.risk.max_intraday_loss(useMaxIntraDD ? maxIntraDD : 100, strategy.percent_of_equity)
var int _genLossStreak = 0
if strategy.losstrades > strategy.losstrades[1]
_genLossStreak := _genLossStreak + 1
if strategy.wintrades > strategy.wintrades[1]
_genLossStreak := 0
_genFilterOk = (not useSession or not na(time(timeframe.period, sessionInput))) and
(not useDateRange or (time >= dateFrom and time <= dateTo)) and
(not useLossStreak or _genLossStreak < maxLossStreak)
var int _lastExitBar = na
_justClosed = strategy.closedtrades > 0 and strategy.closedtrades.exit_bar_index(strategy.closedtrades - 1) == bar_index
if _justClosed
_lastExitBar := bar_index
_inCooldown = cooldownBars > 0 and not na(_lastExitBar) and (bar_index - _lastExitBar) < cooldownBars
_canEntry = not _inCooldown and (not confirmClose or barstate.isconfirmed) and _genFilterOk
// ─── Strategy execution (standalone, directional fixed SL/TP) ─────────────────
_canLong = tradeDirInput != "Short Only"
_canShort = tradeDirInput != "Long Only"
var float _longSL = na
var float _longTP = na
var float _shortSL = na
var float _shortTP = na
var float _longRisk0 = na
var float _shortRisk0 = na
if (longSignal) and _canLong and _canEntry
_longSL := longStop
_longTP := longTake
_longRisk0 := close - longStop
strategy.entry("Long", strategy.long)
_longRisk = close - _longSL
log.info("RES ENTRY | dir=long | quality={0}/2 | tier={1} | gates=sweep:{2},closeUpper:{3},body:{4},atr:{5},htf:{6},spike:{7} | opt=rsi:{8},noLL:{9} | wt1h={10} | wt4h={11} | sl={12} | tp={13} | risk={14}",
str.tostring(longQuality),
f_tier(longQuality),
str.tostring(liquiditySweepLong),
str.tostring(closeInUpperThird),
str.tostring(bodyOk),
str.tostring(atrOk),
str.tostring(not bearTrend),
str.tostring(sweepNotTooDeepLong),
str.tostring(rsiValue > 50),
str.tostring(not llDetected),
str.tostring(wt1_1H, "#.#"),
str.tostring(wt1_4H, "#.#"),
str.tostring(_longSL, format.mintick),
str.tostring(_longTP, format.mintick),
str.tostring(_longRisk, format.mintick))
if (shortSignal) and _canShort and _canEntry
_shortSL := shortStop
_shortTP := shortTake
_shortRisk0 := shortStop - close
strategy.entry("Short", strategy.short)
_shortRisk = _shortSL - close
log.info("RES ENTRY | dir=short | quality={0}/2 | tier={1} | gates=sweep:{2},closeLower:{3},body:{4},atr:{5},htf:{6},spike:{7} | opt=rsiAbove50:{8},noHH:{9} | wt1h={10} | wt4h={11} | sl={12} | tp={13} | risk={14}",
str.tostring(shortQuality),
f_tier(shortQuality),
str.tostring(liquiditySweepShort),
str.tostring(closeInLowerThird),
str.tostring(bodyOk),
str.tostring(atrOk),
str.tostring(not bullTrend),
str.tostring(sweepNotTooDeepShort),
str.tostring(rsiValue > 50),
str.tostring(not hhDetected),
str.tostring(wt1_1H, "#.#"),
str.tostring(wt1_4H, "#.#"),
str.tostring(_shortSL, format.mintick),
str.tostring(_shortTP, format.mintick),
str.tostring(_shortRisk, format.mintick))
// ─── Exit logging ─────────────────────────────────────────────────────────────
if _justClosed
_idx = strategy.closedtrades - 1
_dir = strategy.closedtrades.size(_idx) > 0 ? "long" : "short"
_entPx = strategy.closedtrades.entry_price(_idx)
_extPx = strategy.closedtrades.exit_price(_idx)
_pnl = strategy.closedtrades.profit(_idx)
log.info("RES EXIT | dir={0} | entryPx={1} | exitPx={2} | pnl={3} | reason={4}",
_dir,
str.tostring(_entPx, format.mintick),
str.tostring(_extPx, format.mintick),
str.tostring(_pnl, "#.##"),
strategy.closedtrades.exit_id(_idx))
// ─── Break-even management (R-based) ─────────────────────────────────────────
if enableBE and not na(_longRisk0) and strategy.position_size > 0
if close - strategy.position_avg_price >= beTriggerR * _longRisk0
_longSL := math.max(_longSL, strategy.position_avg_price)
if enableBE and not na(_shortRisk0) and strategy.position_size < 0
if strategy.position_avg_price - close >= beTriggerR * _shortRisk0
_shortSL := math.min(_shortSL, strategy.position_avg_price)
// ─── Bracket exits (uses updated SL after BE) ────────────────────────────────
if strategy.position_size > 0
strategy.exit("Long Exit", "Long", stop=_longSL, limit=_longTP)
if strategy.position_size < 0
strategy.exit("Short Exit", "Short", stop=_shortSL, limit=_shortTP)
// ─── Structural exit (pivot-based) ───────────────────────────────────────────
// Fires on the bar a NEW LL/HH pivot confirms — llDetected/hhDetected are persistent states
// and would close a short that was entered while an older HH was still on record.
if enableStructExit
if strategy.position_size > 0 and _plFound and llDetected
strategy.close("Long", comment="ll-struct")
if strategy.position_size < 0 and _phFound and hhDetected
strategy.close("Short", comment="hh-struct")
Overview
Reversal Engine Score [WavesUnchained] Strategy evaluates setups using mandatory conditions such as swing sweeps, body and ATR filters, and dual EMA higher-timeframe trend alignment, alongside optional WaveTrend momentum filters. Positions enter when calculated quality scores meet user-defined thresholds. Risk management uses structural stop losses anchored to sweep extremes with ATR buffers, R-multiple take profits, and optional break-even adjustments. All trade signals, score labels, and stop or target levels plot directly on the price chart.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Nur auf 15M aktiv
bool
true
only15m
SL/TP-Level anzeigen
bool
true
showLevels
Trend-Hintergrund
bool
false
showTrendBackground
Score am Signal anzeigen
bool
true
showScoreLabel
Min. Qualität Long (0–2)
int
2
minQualityLong
Min. Qualität Short (0–2)
int
1
minQualityShort
RSI Länge
int
14
rsiLen
Gate A — Liquidity Sweep
bool
true
useGateA
[A] Sweep Lookback
int
10
swingLen
Gate B — Close-Position (⅓-Regel)
bool
false
useGateB
Gate C — Body-Größe
bool
false
useGateC
[C] Min. Body / ATR
float
0.25
minBodyAtr
Show all 40 settings
Setting
Type
Default
Variable
Gate D — ATR Minimum
bool
true
useGateD
[D] ATR Länge
int
14
atrLen
[D] ATR Basislänge
int
50
atrBaseLen
[D] Min (× Basis)
float
0.60
atrLowFactor
Gate E — Spike-Filter
bool
false
useGateE
[E] Max Sweep-Tiefe (ATR×)
float
0.80
spikeAtrMult
Gate F — HTF Trendfilter
bool
true
useGateF
[F] Timeframe
timeframe
60
htf
[F] EMA schnell
int
50
htfFastLen
[F] EMA langsam
int
200
htfSlowLen
Gate G — 1H WT Confluence
bool
false
useGateG
[G/H] WT Channel Length
int
10
wtChLen
[G/H] WT Average Length
int
21
wtAvgLen
[G] 1H OS Threshold (long)
float
-30.0
gateG_os
[G] 1H OB Threshold (short)
float
30.0
gateG_ob
Gate H — 4H WT Confluence
bool
false
useGateH
[H] 4H OS Threshold (long)
float
-30.0
gateH_os
[H] 4H OB Threshold (short)
float
30.0
gateH_ob
Länge
int
21
emaLen
Typ
string
EMA
smoothType
JMA Phase
int
50
jmaPhase
JMA Power
float
2.0
jmaPower
SL Puffer (ATR×)
float
0.30
slAtrBuffer
TP Risk-Multiple
float
1.50
tpRMult
Cooldown nach Signal
int
5
sigCooldown
Pivot Length
int
5
pivLen
Struktur-Labels (HH/HL/LH/LL) anzeigen
bool
false
showPivots
Outcome-Fenster (Bars)
int
20
outcomeWindow
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.
ScarAlgo v1 is a trend-following and market-structure strategy plotted directly on the main price chart. It triggers entries using an ATR-based trailing envelope filtered by a configurable multi-timeframe moving average, while employing a WaveTrend momentum os
Donald - AI Futures 5M 15M Timeframe is an overlay trading strategy designed for intraday futures trading. It utilizes rational quadratic kernel regression to construct dynamic momentum zones and smoothed price boundaries on the main price chart. The strategy
This strategy overlays the price chart and looks for VWAP pullbacks. It goes long when a short SMA crosses above VWAP after RSI has been oversold within ten bars, and short on the opposite cross after RSI has been overbought. Optional Minervini-style moving-av
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
This strategy trades 1-minute futures contracts on Binance. It plots pivot high and low resistance and support levels on the price chart, along with an EMA and a custom Cto indicator. Long and short entries trigger on EMA and Cto crossovers combined with price
This strategy enters trades in the opposite direction of filled value gaps, operating under the assumption that price action will resume the primary trend after filling a recent gap. It plots directly on the main price chart and supports MA-based trend filters