//@version=6
// ============================================================================
// Modern Trend Regime [WavesUnchained]
// Version: 1.8.0
// Author: WavesUnchained
// Build: 2026-10-02 00:00:00
// ============================================================================
// Vereinfachtes Trend- und Range-System ohne Ichimoku-Begriffe.
//
// Features:
// ✓ Marktmodus-Erkennung: Trend / Range / Übergang mit Score- statt AND-Logik
// ✓ Übergang wird bei Strukturverlust sofort aktiv, neue Modi werden bestätigt
// ✓ Trendbestätigung an der Regime-Änderung selbst, nicht am rohen Cross
// ✓ Echte Range-Struktur mit eingefrorenen Grenzen (nicht nur ATR-Band)
// ✓ Zeitlich begrenzte Range-Ausbrüche, entprellte Range-Reaktionen
// ✓ Optionale Reaktionsqualität, Range-Mitte/Quartile und Diagnose-Tabelle
// ✓ Strukturvorschau: Trennung als Deckkraft, zeitrichtiger Struktur-Ausbruch
// ✓ Sechs abgestimmte Presets + Benutzerdefiniert
// ✓ Mehrere moderne Visualisierungsmodi
// ============================================================================
indicator(
"Modern Trend Regime [WavesUnchained]",
shorttitle = "MTR",
overlay = true,
max_labels_count = 500
)
// ─────────────────────────────────────────────────────────────────────────────
// PRESET
// ─────────────────────────────────────────────────────────────────────────────
groupPreset = "Voreinstellung"
preset = input.string(
"Standard",
"Preset",
options = [
"Standard",
"Schnell",
"Ruhig",
"Trendfolge",
"Range Trading",
"Ausbruch",
"Benutzerdefiniert"
],
group = groupPreset,
tooltip = "Wählt eine abgestimmte Grundeinstellung. Benutzerdefiniert verwendet die Werte aus den '– Benutzerdefiniert'-Gruppen."
)
// ─────────────────────────────────────────────────────────────────────────────
// BERECHNUNG
// ─────────────────────────────────────────────────────────────────────────────
groupCalculation = "Berechnung"
calculationMode = input.string(
"Preisspanne",
"Berechnungsmethode",
options = ["Preisspanne", "EMA", "WMA", "SMA"],
group = groupCalculation
)
priceSource = input.source(
close,
"Preisquelle",
group = groupCalculation
)
groupCalculationCustom = "Berechnung – Benutzerdefiniert"
customFastLength = input.int(
9,
"Fast Trend Länge",
minval = 2,
group = groupCalculationCustom
)
customBaseLength = input.int(
26,
"Trend Basis Länge",
minval = 2,
group = groupCalculationCustom
)
customSlowLength = input.int(
52,
"Langfristige Struktur",
minval = 3,
group = groupCalculationCustom
)
customAtrLength = input.int(
14,
"ATR Zeitraum",
minval = 2,
group = groupCalculationCustom
)
// ─────────────────────────────────────────────────────────────────────────────
// MARKTMODUS
// ─────────────────────────────────────────────────────────────────────────────
groupRegimeCustom = "Marktmodus – Benutzerdefiniert"
customRegimeLength = input.int(
20,
"Analysezeitraum",
minval = 5,
group = groupRegimeCustom
)
customAdxLength = input.int(
14,
"Trendstärke Zeitraum",
minval = 3,
group = groupRegimeCustom
)
customRangeAdxThreshold = input.float(
18.0,
"Seitwärts unter Trendstärke",
minval = 5,
maxval = 40,
step = 0.5,
group = groupRegimeCustom,
tooltip = "Niedrige Werte erkennen nur sehr ruhige Seitwärtsphasen."
)
customTrendAdxThreshold = input.float(
23.0,
"Trend über Trendstärke",
minval = 5,
maxval = 50,
step = 0.5,
group = groupRegimeCustom
)
customRangeEfficiencyThreshold = input.float(
0.28,
"Seitwärts unter Richtungseffizienz",
minval = 0.05,
maxval = 0.8,
step = 0.01,
group = groupRegimeCustom
)
customTrendEfficiencyThreshold = input.float(
0.42,
"Trend über Richtungseffizienz",
minval = 0.05,
maxval = 1.0,
step = 0.01,
group = groupRegimeCustom
)
customRangeSlopeThreshold = input.float(
0.025,
"Maximale Basis-Steigung (ATR/Kerze)",
minval = 0.0,
step = 0.005,
group = groupRegimeCustom,
tooltip = "Durchschnittliche Steigung der Trend Basis pro Kerze, normalisiert auf ATR."
)
customCompressionThreshold = input.float(
0.45,
"Maximale Strukturbreite in ATR",
minval = 0.05,
step = 0.05,
group = groupRegimeCustom
)
customRegimeConfirmationBars = input.int(
3,
"Bestätigungskerzen",
minval = 1,
maxval = 10,
group = groupRegimeCustom,
tooltip = "Der neue Marktmodus muss mehrere Kerzen bestehen bleiben."
)
// ─────────────────────────────────────────────────────────────────────────────
// RANGE-MODUS
// ─────────────────────────────────────────────────────────────────────────────
groupRange = "Seitwärtsmodus"
groupRangeCustom = "Seitwärtsmodus – Benutzerdefiniert"
customBreakoutBufferAtr = input.float(
0.10,
"Ausbruchspuffer in ATR",
minval = 0,
step = 0.05,
group = groupRangeCustom
)
customBreakoutValidityBars = input.int(
10,
"Ausbruch maximal nach Range-Ende",
minval = 1,
maxval = 100,
group = groupRangeCustom
)
customRangeStructureLength = input.int(
20,
"Range-Struktur Zeitraum",
minval = 3,
maxval = 200,
group = groupRangeCustom,
tooltip = "Bestimmt den Rückblick für die beim Range-Eintritt fixierten Grenzen."
)
customRangeReactionZoneAtr = input.float(
0.10,
"Reaktionszone in ATR",
minval = 0.0,
maxval = 1.0,
step = 0.05,
group = groupRangeCustom,
tooltip = "Erweitert die Reaktionszone von der fixierten Grenze nach innen."
)
showRangeReactions = input.bool(
true,
"Range-Reaktionen anzeigen",
group = groupRange
)
showRangeBreakouts = input.bool(
true,
"Range-Ausbrüche anzeigen",
group = groupRange
)
rangeReactionNeedsCandle = input.bool(
true,
"Reaktionskerze verlangen",
group = groupRange,
tooltip = "Long benötigt eine positive, Short eine negative Kerze."
)
strongRangeReactionEnabled = input.bool(
false,
"Starke Schlusskursposition verlangen",
group = groupRange,
tooltip = "Filtert schwache Zurückweisungen. Long muss im oberen, Short im unteren Kerzenbereich schließen."
)
rangeReactionClosePosition = input.float(
0.65,
"Minimale Reaktionsqualität",
minval = 0.50,
maxval = 0.95,
step = 0.05,
group = groupRange,
tooltip = "0,65 bedeutet: Long schließt in den oberen 35 %, Short in den unteren 35 % der Kerze."
)
showRangeMidpoint = input.bool(
true,
"Range-Mitte anzeigen",
group = groupRange
)
showRangeQuartiles = input.bool(
false,
"Range-Quartile anzeigen",
group = groupRange
)
// ─────────────────────────────────────────────────────────────────────────────
// TRENDSIGNALE
// ─────────────────────────────────────────────────────────────────────────────
groupSignals = "Trendmodus"
showTrendFlips = input.bool(
true,
"Trend-Bestätigung anzeigen",
group = groupSignals,
tooltip = "Markiert, wenn die State Machine tatsächlich in einen neuen Trend wechselt (nicht jeder Fast/Base-Cross)."
)
confirmOnClose = input.bool(
true,
"Nur bestätigte Kerzen",
group = groupSignals
)
// ─────────────────────────────────────────────────────────────────────────────
// VISUALISIERUNG
// ─────────────────────────────────────────────────────────────────────────────
groupDisplay = "Visualisierung"
visualMode = input.string(
"Trendband",
"Darstellungsmodus",
options = [
"Trendband",
"Range-Korridor",
"Regime-Leiste",
"Minimal",
"Alles"
],
group = groupDisplay
)
showFastTrend = input.bool(
false,
"Fast Trend anzeigen",
group = groupDisplay
)
showTrendBase = input.bool(
true,
"Trend Basis anzeigen",
group = groupDisplay
)
colorBars = input.bool(
true,
"Kerzen nach Marktmodus färben",
group = groupDisplay
)
showTransitionBackground = input.bool(
false,
"Übergangsphasen hinterlegen",
group = groupDisplay
)
bandWidthAtr = input.float(
0.22,
"Trendband Breite in ATR",
minval = 0.05,
step = 0.01,
group = groupDisplay
)
structurePreviewEnabled = input.bool(
true,
"Strukturvorschau anzeigen",
group = groupDisplay,
tooltip = "Verschiebt die aktuell berechnete Struktur optisch nach rechts. Es handelt sich nicht um eine Kursprognose."
)
structurePreviewOffset = input.int(
26,
"Strukturvorschau-Verschiebung",
minval = 1,
maxval = 200,
group = groupDisplay
)
showStructureBreakout = input.bool(
true,
"Struktur-Ausbruch markieren",
group = groupDisplay,
tooltip = "Markiert, wenn der Kurs die zeitlich korrekt ausgerichtete Strukturvorschau durchbricht (der Wert, der heute tatsächlich als Wolke sichtbar ist — nicht die unverschobene Zukunftsvorschau). Reine Information, kein Teil der Regime-Bestätigung."
)
regimeRailUsesEvidence = input.bool(
true,
"Regime-Leiste nach Evidenz abstufen",
group = groupDisplay,
tooltip = "Höhere Deckkraft bedeutet mehr erfüllte Score-Faktoren, keine statistische Wahrscheinlichkeit."
)
groupDiagnostics = "Diagnose"
showDebugTable = input.bool(
false,
"Diagnose-Tabelle anzeigen",
group = groupDiagnostics
)
// ─────────────────────────────────────────────────────────────────────────────
// FARBEN
// ─────────────────────────────────────────────────────────────────────────────
bullColor = color.rgb(38, 166, 154)
bearColor = color.rgb(239, 83, 80)
rangeColor = color.rgb(126, 87, 194)
transitionColor = color.rgb(120, 123, 134)
fastColor = color.rgb(255, 167, 38)
baseColor = color.rgb(66, 165, 245)
// ─────────────────────────────────────────────────────────────────────────────
// GEMEINSAM
// ─────────────────────────────────────────────────────────────────────────────
barConfirmed = not confirmOnClose or barstate.isconfirmed
// ─────────────────────────────────────────────────────────────────────────────
// PRESET-WERTE
// ─────────────────────────────────────────────────────────────────────────────
fastLength = switch preset
"Standard" => 9
"Schnell" => 7
"Ruhig" => 12
"Trendfolge" => 10
"Range Trading" => 8
"Ausbruch" => 10
"Benutzerdefiniert" => customFastLength
=> 9
baseLength = switch preset
"Standard" => 26
"Schnell" => 18
"Ruhig" => 30
"Trendfolge" => 28
"Range Trading" => 22
"Ausbruch" => 26
"Benutzerdefiniert" => customBaseLength
=> 26
slowLength = switch preset
"Standard" => 52
"Schnell" => 36
"Ruhig" => 60
"Trendfolge" => 65
"Range Trading" => 44
"Ausbruch" => 52
"Benutzerdefiniert" => customSlowLength
=> 52
regimeLength = switch preset
"Standard" => 20
"Schnell" => 14
"Ruhig" => 30
"Trendfolge" => 25
"Range Trading" => 18
"Ausbruch" => 20
"Benutzerdefiniert" => customRegimeLength
=> 20
adxLength = switch preset
"Standard" => 14
"Schnell" => 10
"Ruhig" => 18
"Trendfolge" => 14
"Range Trading" => 12
"Ausbruch" => 14
"Benutzerdefiniert" => customAdxLength
=> 14
rangeAdxThreshold = switch preset
"Standard" => 18.0
"Schnell" => 17.0
"Ruhig" => 19.0
"Trendfolge" => 16.0
"Range Trading" => 21.0
"Ausbruch" => 20.0
"Benutzerdefiniert" => customRangeAdxThreshold
=> 18.0
trendAdxThreshold = switch preset
"Standard" => 23.0
"Schnell" => 21.0
"Ruhig" => 25.0
"Trendfolge" => 27.0
"Range Trading" => 24.0
"Ausbruch" => 25.0
"Benutzerdefiniert" => customTrendAdxThreshold
=> 23.0
rangeEfficiencyThreshold = switch preset
"Standard" => 0.28
"Schnell" => 0.25
"Ruhig" => 0.30
"Trendfolge" => 0.22
"Range Trading" => 0.34
"Ausbruch" => 0.30
"Benutzerdefiniert" => customRangeEfficiencyThreshold
=> 0.28
trendEfficiencyThreshold = switch preset
"Standard" => 0.42
"Schnell" => 0.38
"Ruhig" => 0.46
"Trendfolge" => 0.50
"Range Trading" => 0.44
"Ausbruch" => 0.48
"Benutzerdefiniert" => customTrendEfficiencyThreshold
=> 0.42
rangeSlopeThreshold = switch preset
"Standard" => 0.025
"Schnell" => 0.035
"Ruhig" => 0.020
"Trendfolge" => 0.018
"Range Trading" => 0.040
"Ausbruch" => 0.025
"Benutzerdefiniert" => customRangeSlopeThreshold
=> 0.025
compressionThreshold = switch preset
"Standard" => 0.45
"Schnell" => 0.50
"Ruhig" => 0.40
"Trendfolge" => 0.35
"Range Trading" => 0.60
"Ausbruch" => 0.38
"Benutzerdefiniert" => customCompressionThreshold
=> 0.45
regimeConfirmationBars = switch preset
"Standard" => 3
"Schnell" => 2
"Ruhig" => 5
"Trendfolge" => 4
"Range Trading" => 2
"Ausbruch" => 3
"Benutzerdefiniert" => customRegimeConfirmationBars
=> 3
breakoutBufferAtr = switch preset
"Standard" => 0.10
"Schnell" => 0.05
"Ruhig" => 0.15
"Trendfolge" => 0.15
"Range Trading" => 0.10
"Ausbruch" => 0.20
"Benutzerdefiniert" => customBreakoutBufferAtr
=> 0.10
atrLength = switch preset
"Standard" => 14
"Schnell" => 10
"Ruhig" => 20
"Trendfolge" => 14
"Range Trading" => 14
"Ausbruch" => 14
"Benutzerdefiniert" => customAtrLength
=> 14
rangeStructureLength = switch preset
"Standard" => math.min(regimeLength, baseLength)
"Schnell" => math.min(regimeLength, baseLength)
"Ruhig" => math.min(regimeLength, baseLength)
"Trendfolge" => math.min(regimeLength, baseLength)
"Range Trading" => math.min(regimeLength, baseLength)
"Ausbruch" => math.min(regimeLength, baseLength)
"Benutzerdefiniert" => customRangeStructureLength
=> math.min(regimeLength, baseLength)
breakoutValidityBars = switch preset
"Standard" => 10
"Schnell" => 10
"Ruhig" => 10
"Trendfolge" => 10
"Range Trading" => 10
"Ausbruch" => 10
"Benutzerdefiniert" => customBreakoutValidityBars
=> 10
rangeReactionZoneAtr = switch preset
"Standard" => 0.10
"Schnell" => 0.10
"Ruhig" => 0.10
"Trendfolge" => 0.10
"Range Trading" => 0.10
"Ausbruch" => 0.10
"Benutzerdefiniert" => customRangeReactionZoneAtr
=> 0.10
// ─────────────────────────────────────────────────────────────────────────────
// FUNKTIONEN
// ─────────────────────────────────────────────────────────────────────────────
f_midpoint(int length) =>
(ta.highest(high, length) + ta.lowest(low, length)) / 2.0
f_line(float source, int length, string mode) =>
switch mode
"EMA" => ta.ema(source, length)
"WMA" => ta.wma(source, length)
"SMA" => ta.sma(source, length)
=> f_midpoint(length)
f_regime_name(int regime) =>
switch regime
1 => "Bull"
-1 => "Bear"
2 => "Range"
=> "Übergang"
// ─────────────────────────────────────────────────────────────────────────────
// BASISSTRUKTUR
// ─────────────────────────────────────────────────────────────────────────────
fastTrend = f_line(priceSource, fastLength, calculationMode)
trendBase = f_line(priceSource, baseLength, calculationMode)
slowTrend = f_line(priceSource, slowLength, calculationMode)
atr = ta.atr(atrLength)
structureFast = (fastTrend + trendBase) / 2.0
structureUpper = math.max(structureFast, slowTrend)
structureLower = math.min(structureFast, slowTrend)
structureWidth = structureUpper - structureLower
// ─────────────────────────────────────────────────────────────────────────────
// TRENDSTÄRKE
// ─────────────────────────────────────────────────────────────────────────────
[plusDi, minusDi, adx] = ta.dmi(adxLength, adxLength)
directionalMove = math.abs(close - close[regimeLength])
totalMovement = math.sum(
math.abs(close - close[1]),
regimeLength
)
efficiencyRatio =
totalMovement > 0
? directionalMove / totalMovement
: 0.0
baseSlopeAtr =
atr > 0 and regimeLength > 0
? math.abs(trendBase - trendBase[regimeLength]) / (atr * regimeLength)
: 0.0
structureWidthAtr =
atr > 0
? structureWidth / atr
: 0.0
// ─────────────────────────────────────────────────────────────────────────────
// MARKTMODUS-KANDIDATEN
// ─────────────────────────────────────────────────────────────────────────────
// Marktmodus:
// 1 = Aufwärtstrend
// -1 = Abwärtstrend
// 2 = Seitwärtsphase
// 0 = Übergang
var int candidateState = 0
var int candidateCount = 0
var int marketRegime = 0
rangeScore =
(adx < rangeAdxThreshold ? 1 : 0) +
(efficiencyRatio < rangeEfficiencyThreshold ? 1 : 0) +
(baseSlopeAtr < rangeSlopeThreshold ? 1 : 0) +
(structureWidthAtr < compressionThreshold ? 1 : 0)
requiredRangeScore = preset == "Range Trading" ? 3 : 4
rangeEntryCandidate = rangeScore >= requiredRangeScore
// Geteilte Stärke (ADX, Efficiency Ratio) + drei Richtungsfaktoren (DI, Stack,
// Preis) als Score statt harter 5er-AND-Kette — sonst reißt ein einzelner
// schwacher Faktor (typischerweise Efficiency Ratio bei volatilen Instrumenten
// wie NatGas) die Trendbestätigung praktisch permanent ab.
sharedTrendScore =
(adx > trendAdxThreshold ? 1 : 0) +
(efficiencyRatio > trendEfficiencyThreshold ? 1 : 0)
bullDirectionScore =
(plusDi > minusDi ? 1 : 0) +
(fastTrend > trendBase and trendBase > slowTrend ? 1 : 0) +
(close > trendBase ? 1 : 0)
bearDirectionScore =
(minusDi > plusDi ? 1 : 0) +
(fastTrend < trendBase and trendBase < slowTrend ? 1 : 0) +
(close < trendBase ? 1 : 0)
bullScore = sharedTrendScore + bullDirectionScore
bearScore = sharedTrendScore + bearDirectionScore
// Mit Schwelle 4 von 5 kann Richtung allein (max. 3 Punkte) nie ausreichen —
// mindestens ADX oder Efficiency Ratio muss immer mitspielen.
requiredTrendScore = preset == "Range Trading" ? 5 : 4
// Ein neuer Modus benötigt den vollen Score. Der aktive Modus darf mit einem
// Punkt weniger weiterlaufen, solange kein anderer Modus den Eintrittsscore
// erreicht. Diese Hysterese reduziert Wechsel an den binären Schwellen.
bullEntryCandidate = bullScore >= requiredTrendScore
bearEntryCandidate = bearScore >= requiredTrendScore
bullHoldCandidate =
marketRegime == 1 and
bullScore >= math.max(requiredTrendScore - 1, 1) and
not bearEntryCandidate and
not rangeEntryCandidate
bearHoldCandidate =
marketRegime == -1 and
bearScore >= math.max(requiredTrendScore - 1, 1) and
not bullEntryCandidate and
not rangeEntryCandidate
rangeHoldCandidate =
marketRegime == 2 and
rangeScore >= math.max(requiredRangeScore - 1, 1) and
not bullEntryCandidate and
not bearEntryCandidate
candidateRegime =
marketRegime == 1 and bearEntryCandidate ? -1 :
marketRegime == -1 and bullEntryCandidate ? 1 :
bullEntryCandidate ? 1 :
bearEntryCandidate ? -1 :
rangeEntryCandidate ? 2 :
bullHoldCandidate ? 1 :
bearHoldCandidate ? -1 :
rangeHoldCandidate ? 2 :
0
if barConfirmed
if candidateRegime == 0
// Verlust einer eindeutigen Struktur sofort anzeigen, statt den alten Modus zu halten.
marketRegime := 0
candidateState := 0
candidateCount := 0
else
regimeReplaced =
marketRegime != 0 and
candidateRegime != marketRegime
// Jeder andere Kandidat (Gegentrend oder Trend <-> Range) beendet den
// alten Modus sofort, statt ihn bis zur Bestätigung des neuen zu halten.
// Die Bestätigungszählung für den neuen Modus läuft dabei weiter.
if regimeReplaced
marketRegime := 0
if candidateRegime == candidateState
candidateCount += 1
else
candidateState := candidateRegime
candidateCount := 1
if candidateCount >= regimeConfirmationBars
marketRegime := candidateState
isBullTrend = marketRegime == 1
isBearTrend = marketRegime == -1
isRange = marketRegime == 2
isTransition = marketRegime == 0
// ─────────────────────────────────────────────────────────────────────────────
// RANGE-STRUKTUR
// ─────────────────────────────────────────────────────────────────────────────
// Grenzen werden beim Range-Eintritt aus dem Swing-High/Low eingefroren, statt
// einem beweglichen ATR-Band um die Trend Basis zu folgen — sonst laufen die
// "Range"-Grenzen dem Kurs hinterher und Reaktionen/Ausbrüche bedeuten etwas
// anderes als ihr Name verspricht.
var float activeRangeHigh = na
var float activeRangeLow = na
var bool rangeInitialized = false
rangeStarted = isRange and not isRange[1]
rangeEnded = not isRange and isRange[1]
swingHigh = ta.highest(high, rangeStructureLength)
swingLow = ta.lowest(low, rangeStructureLength)
if barConfirmed
if rangeStarted
activeRangeHigh := swingHigh
activeRangeLow := swingLow
rangeInitialized := true
if rangeEnded
rangeInitialized := false
// ─────────────────────────────────────────────────────────────────────────────
// RANGE-REAKTIONEN
// ─────────────────────────────────────────────────────────────────────────────
bullishCandle = close > open
bearishCandle = close < open
activeRangeMid =
rangeInitialized
? (activeRangeHigh + activeRangeLow) / 2.0
: na
activeRangeUpperQuartile =
rangeInitialized
? activeRangeLow + (activeRangeHigh - activeRangeLow) * 0.75
: na
activeRangeLowerQuartile =
rangeInitialized
? activeRangeLow + (activeRangeHigh - activeRangeLow) * 0.25
: na
lowerReactionLevel =
rangeInitialized
? math.min(activeRangeLow + atr * rangeReactionZoneAtr, activeRangeMid)
: na
upperReactionLevel =
rangeInitialized
? math.max(activeRangeHigh - atr * rangeReactionZoneAtr, activeRangeMid)
: na
candleRange = math.max(high - low, syminfo.mintick)
closePosition = (close - low) / candleRange
strongBullReaction = closePosition >= rangeReactionClosePosition
strongBearReaction = closePosition <= 1.0 - rangeReactionClosePosition
lowerZoneTouched =
rangeInitialized and
low <= lowerReactionLevel and
close > activeRangeLow
upperZoneTouched =
rangeInitialized and
high >= upperReactionLevel and
close < activeRangeHigh
rawRangeLongReaction =
isRange and
lowerZoneTouched and
(
not rangeReactionNeedsCandle or
bullishCandle
) and
(not strongRangeReactionEnabled or strongBullReaction)
rawRangeShortReaction =
isRange and
upperZoneTouched and
(
not rangeReactionNeedsCandle or
bearishCandle
) and
(not strongRangeReactionEnabled or strongBearReaction)
// Nur die erste Kerze einer Berührung zählt — sonst feuert ein mehrtägiger
// Grenztest an jeder einzelnen Kerze erneut. Eine Berührung, die bereits auf
// der Range-Eintrittskerze beginnt, zählt nicht: diese Kerze hat die
// eingefrorene Grenze selbst gesetzt.
rangeLongReaction =
rawRangeLongReaction and
not rawRangeLongReaction[1] and
not rangeStarted and
barConfirmed
rangeShortReaction =
rawRangeShortReaction and
not rawRangeShortReaction[1] and
not rangeStarted and
barConfirmed
// ─────────────────────────────────────────────────────────────────────────────
// RANGE-AUSBRÜCHE
// ─────────────────────────────────────────────────────────────────────────────
// Beim Range-Eintritt scharfgeschaltet, nach dem Range-Ende nur für eine
// begrenzte Zahl von Kerzen gültig und nach dem ersten Ausbruch entschärft.
// Ein Ausbruch braucht einen frischen Durchbruch auf der Signalkerze (Vorkerze
// noch innerhalb Grenze + Puffer) — ist der Kurs schon während der Range über
// die Grenze gedriftet, gibt es keinen verspäteten Ausbruch.
var bool breakoutArmed = false
var int barsSinceRangeEnd = na
if barConfirmed
if rangeStarted
breakoutArmed := true
barsSinceRangeEnd := na
if rangeEnded
barsSinceRangeEnd := 0
else if breakoutArmed and not na(barsSinceRangeEnd)
barsSinceRangeEnd += 1
if breakoutArmed and not na(barsSinceRangeEnd) and barsSinceRangeEnd > breakoutValidityBars
breakoutArmed := false
bullRangeBreakout =
breakoutArmed and
not isRange and
not na(barsSinceRangeEnd) and
barsSinceRangeEnd <= breakoutValidityBars and
not na(activeRangeHigh) and
close > activeRangeHigh + atr * breakoutBufferAtr and
close[1] <= activeRangeHigh + atr[1] * breakoutBufferAtr and
barConfirmed
bearRangeBreakout =
breakoutArmed and
not isRange and
not na(barsSinceRangeEnd) and
barsSinceRangeEnd <= breakoutValidityBars and
not na(activeRangeLow) and
close < activeRangeLow - atr * breakoutBufferAtr and
close[1] >= activeRangeLow - atr[1] * breakoutBufferAtr and
barConfirmed
if barConfirmed and (bullRangeBreakout or bearRangeBreakout)
breakoutArmed := false
// ─────────────────────────────────────────────────────────────────────────────
// TREND-BESTÄTIGUNG
// ─────────────────────────────────────────────────────────────────────────────
// Der rohe Fast/Base-Cross feuert auf jeden Wackler, auch mitten in einer
// Seitwärtsphase, die (noch) nicht als Range bestätigt ist. Das Signal wird
// deshalb an die Regime-Änderung selbst gekoppelt: es feuert genau einmal,
// wenn die State Machine (Score-Range, DI-Richtung, Preisbestätigung,
// Bestätigungskerzen) tatsächlich in einen neuen Trend wechselt.
bullFlip =
isBullTrend and
not isBullTrend[1] and
barConfirmed
bearFlip =
isBearTrend and
not isBearTrend[1] and
barConfirmed
// ─────────────────────────────────────────────────────────────────────────────
// STRUKTUR-AUSBRUCH
// ─────────────────────────────────────────────────────────────────────────────
// Die Strukturvorschau wird um `structurePreviewOffset` Bars nach rechts
// verschoben gezeichnet — der Wert, der HEUTE als Wolke unter dem aktuellen Kurs
// sichtbar ist, wurde also vor `structurePreviewOffset` Bars berechnet. Für
// "Kurs vs. Wolke" muss deshalb gegen diesen zeitversetzten Wert geprüft werden,
// nicht gegen die gerade berechnete (unverschobene) Zukunftsvorschau — die ist
// noch gar nicht erreichbar.
visibleStructureUpper = structureUpper[structurePreviewOffset]
visibleStructureLower = structureLower[structurePreviewOffset]
structureBreakoutBull =
structurePreviewEnabled and
not na(visibleStructureUpper) and
ta.crossover(close, visibleStructureUpper) and
not isRange and
structureFast > slowTrend and
barConfirmed
structureBreakoutBear =
structurePreviewEnabled and
not na(visibleStructureLower) and
ta.crossunder(close, visibleStructureLower) and
not isRange and
structureFast < slowTrend and
barConfirmed
// Visuelle Priorität bei mehreren Ereignissen auf derselben Kerze. Alerts
// bleiben getrennt, damit kein fachliches Ereignis verloren geht.
bullFlipMarker = bullFlip and not bullRangeBreakout
bearFlipMarker = bearFlip and not bearRangeBreakout
structureBreakoutBullMarker =
structureBreakoutBull and
not bullRangeBreakout and
not bullFlip
structureBreakoutBearMarker =
structureBreakoutBear and
not bearRangeBreakout and
not bearFlip
// ─────────────────────────────────────────────────────────────────────────────
// DARSTELLUNGSMODI
// ─────────────────────────────────────────────────────────────────────────────
showBand =
visualMode == "Trendband" or
visualMode == "Alles"
showRangeCorridor =
visualMode == "Range-Korridor" or
visualMode == "Alles"
showRegimeRail =
visualMode == "Regime-Leiste" or
visualMode == "Alles"
showMinimal =
visualMode == "Minimal"
// ─────────────────────────────────────────────────────────────────────────────
// BASISLINIEN
// ─────────────────────────────────────────────────────────────────────────────
plot(
showFastTrend and not showMinimal
? fastTrend
: na,
"Fast Trend",
color = fastColor,
linewidth = 1
)
plot(
showTrendBase
? trendBase
: na,
"Trend Basis",
color = isBullTrend
? bullColor
: isBearTrend
? bearColor
: isRange
? rangeColor
: baseColor,
linewidth = 2
)
// ─────────────────────────────────────────────────────────────────────────────
// TRENDBAND
// ─────────────────────────────────────────────────────────────────────────────
trendBandUpper =
trendBase + atr * bandWidthAtr
trendBandLower =
trendBase - atr * bandWidthAtr
bandUpperPlot = plot(
showBand and not isRange
? trendBandUpper
: na,
"Trendband oben",
color = color.new(
isBullTrend ? bullColor :
isBearTrend ? bearColor :
transitionColor,
70
)
)
bandLowerPlot = plot(
showBand and not isRange
? trendBandLower
: na,
"Trendband unten",
color = color.new(
isBullTrend ? bullColor :
isBearTrend ? bearColor :
transitionColor,
70
)
)
fill(
bandUpperPlot,
bandLowerPlot,
color = color.new(
isBullTrend ? bullColor :
isBearTrend ? bearColor :
transitionColor,
88
),
title = "Trendband"
)
// ─────────────────────────────────────────────────────────────────────────────
// RANGE-KORRIDOR
// ─────────────────────────────────────────────────────────────────────────────
rangeUpperPlot = plot(
showRangeCorridor and isRange and rangeInitialized
? activeRangeHigh
: na,
"Range oben",
color = color.new(rangeColor, 25),
linewidth = 2,
style = plot.style_linebr
)
rangeLowerPlot = plot(
showRangeCorridor and isRange and rangeInitialized
? activeRangeLow
: na,
"Range unten",
color = color.new(rangeColor, 25),
linewidth = 2,
style = plot.style_linebr
)
fill(
rangeUpperPlot,
rangeLowerPlot,
color = color.new(rangeColor, 91),
title = "Range-Korridor"
)
plot(
showRangeCorridor and showRangeMidpoint and isRange and rangeInitialized
? activeRangeMid
: na,
"Range-Mitte",
color = color.new(rangeColor, 35),
linewidth = 1,
style = plot.style_linebr
)
plot(
showRangeCorridor and showRangeQuartiles and isRange and rangeInitialized
? activeRangeUpperQuartile
: na,
"Range oberes Quartil",
color = color.new(rangeColor, 65),
linewidth = 1,
style = plot.style_linebr
)
plot(
showRangeCorridor and showRangeQuartiles and isRange and rangeInitialized
? activeRangeLowerQuartile
: na,
"Range unteres Quartil",
color = color.new(rangeColor, 65),
linewidth = 1,
style = plot.style_linebr
)
// ─────────────────────────────────────────────────────────────────────────────
// STRUKTURVORSCHAU
// ─────────────────────────────────────────────────────────────────────────────
// Verschiebt die aktuell berechnete Struktur optisch nach rechts — keine
// Kursprognose, nur eine besser lesbare Darstellung des Ist-Zustands.
previewUpper = plot(
structurePreviewEnabled
? structureUpper
: na,
"Strukturvorschau oben",
color = color.new(
structureFast > slowTrend ? bullColor : bearColor,
65
),
offset = structurePreviewOffset
)
previewLower = plot(
structurePreviewEnabled
? structureLower
: na,
"Strukturvorschau unten",
color = color.new(
structureFast > slowTrend ? bullColor : bearColor,
65
),
offset = structurePreviewOffset
)
// Wolkendicke als Strukturtrennung: Eine breite Struktur zeigt eine starke
// Separation zwischen schneller und langsamer Marktstruktur. Sie ist keine
// statistische Konfidenzangabe. Die Deckkraft visualisiert nur diese Separation.
previewThicknessRatio = math.min(structureWidthAtr / (compressionThreshold * 3), 1.0)
previewFillTransparency = int(math.round(96 - previewThicknessRatio * 16))
fill(
previewUpper,
previewLower,
color = structurePreviewEnabled
? color.new(
structureFast > slowTrend ? bullColor : bearColor,
previewFillTransparency
)
: na,
title = "Strukturvorschau"
)
// ─────────────────────────────────────────────────────────────────────────────
// REGIME-LEISTE
// ─────────────────────────────────────────────────────────────────────────────
regimeColor =
isBullTrend ? bullColor :
isBearTrend ? bearColor :
isRange ? rangeColor :
transitionColor
regimeEvidence =
isBullTrend ? bullScore / 5.0 :
isBearTrend ? bearScore / 5.0 :
isRange ? rangeScore / 4.0 :
math.max(bullScore, bearScore) / 5.0
regimeRailTransparency =
regimeRailUsesEvidence
? int(math.round(55 - regimeEvidence * 45))
: 10
plotshape(
showRegimeRail,
title = "Marktmodus-Leiste",
style = shape.square,
location = location.bottom,
color = color.new(regimeColor, regimeRailTransparency),
size = size.tiny
)
// ─────────────────────────────────────────────────────────────────────────────
// SIGNALMARKER
// ─────────────────────────────────────────────────────────────────────────────
if showTrendFlips and bullFlipMarker
label.new(
bar_index,
low,
text = "",
yloc = yloc.belowbar,
style = label.style_triangleup,
color = bullColor,
size = size.tiny,
tooltip = "Aufwärtstrend bestätigt"
)
if showTrendFlips and bearFlipMarker
label.new(
bar_index,
high,
text = "",
yloc = yloc.abovebar,
style = label.style_triangledown,
color = bearColor,
size = size.tiny,
tooltip = "Abwärtstrend bestätigt"
)
if showStructureBreakout and structureBreakoutBullMarker
label.new(
bar_index,
low,
text = "",
yloc = yloc.belowbar,
style = label.style_arrowup,
color = bullColor,
size = size.tiny,
tooltip = "Struktur-Ausbruch bullisch: Kurs über der Strukturvorschau"
)
if showStructureBreakout and structureBreakoutBearMarker
label.new(
bar_index,
high,
text = "",
yloc = yloc.abovebar,
style = label.style_arrowdown,
color = bearColor,
size = size.tiny,
tooltip = "Struktur-Ausbruch bärisch: Kurs unter der Strukturvorschau"
)
plotshape(
showRangeReactions and rangeLongReaction,
title = "Range-Reaktion Long",
style = shape.circle,
location = location.belowbar,
color = rangeColor,
size = size.tiny,
text = "R"
)
plotshape(
showRangeReactions and rangeShortReaction,
title = "Range-Reaktion Short",
style = shape.circle,
location = location.abovebar,
color = rangeColor,
size = size.tiny,
text = "R"
)
plotshape(
showRangeBreakouts and bullRangeBreakout,
title = "Range-Ausbruch Long",
style = shape.labelup,
location = location.belowbar,
color = bullColor,
textcolor = color.white,
text = "BREAK",
size = size.tiny
)
plotshape(
showRangeBreakouts and bearRangeBreakout,
title = "Range-Ausbruch Short",
style = shape.labeldown,
location = location.abovebar,
color = bearColor,
textcolor = color.white,
text = "BREAK",
size = size.tiny
)
// ─────────────────────────────────────────────────────────────────────────────
// KERZEN UND HINTERGRUND
// ─────────────────────────────────────────────────────────────────────────────
barcolor(
colorBars
? color.new(regimeColor, isTransition ? 65 : 20)
: na
)
bgcolor(
showTransitionBackground and isTransition
? color.new(transitionColor, 94)
: na,
title = "Übergangsphase"
)
// ─────────────────────────────────────────────────────────────────────────────
// DIAGNOSE
// ─────────────────────────────────────────────────────────────────────────────
var table debugTable = table.new(
position.top_right,
2,
12,
frame_color = color.new(transitionColor, 55),
frame_width = 1,
border_color = color.new(transitionColor, 75),
border_width = 1
)
if barstate.islast
if showDebugTable
table.set_bgcolor(debugTable, color.new(color.rgb(30, 32, 38), 8))
table.cell(debugTable, 0, 0, "Diagnose", text_color = color.white, bgcolor = color.new(regimeColor, 20))
table.cell(debugTable, 1, 0, "Wert", text_color = color.white, bgcolor = color.new(regimeColor, 20))
table.cell(debugTable, 0, 1, "ADX", text_color = color.white)
table.cell(debugTable, 1, 1, str.tostring(adx, "#.0"), text_color = color.white)
table.cell(debugTable, 0, 2, "Efficiency", text_color = color.white)
table.cell(debugTable, 1, 2, str.tostring(efficiencyRatio, "#.00"), text_color = color.white)
table.cell(debugTable, 0, 3, "Basis-Steigung", text_color = color.white)
table.cell(debugTable, 1, 3, str.tostring(baseSlopeAtr, "#.000"), text_color = color.white)
table.cell(debugTable, 0, 4, "Strukturbreite", text_color = color.white)
table.cell(debugTable, 1, 4, str.tostring(structureWidthAtr, "#.00"), text_color = color.white)
table.cell(debugTable, 0, 5, "Range Score", text_color = color.white)
table.cell(debugTable, 1, 5, str.tostring(rangeScore) + "/4", text_color = color.white)
table.cell(debugTable, 0, 6, "Bull Score", text_color = color.white)
table.cell(debugTable, 1, 6, str.tostring(bullScore) + "/5", text_color = color.white)
table.cell(debugTable, 0, 7, "Bear Score", text_color = color.white)
table.cell(debugTable, 1, 7, str.tostring(bearScore) + "/5", text_color = color.white)
table.cell(debugTable, 0, 8, "Kandidat", text_color = color.white)
table.cell(debugTable, 1, 8, f_regime_name(candidateRegime), text_color = color.white)
table.cell(debugTable, 0, 9, "Marktmodus", text_color = color.white)
table.cell(debugTable, 1, 9, f_regime_name(marketRegime), text_color = color.white)
table.cell(debugTable, 0, 10, "Bestätigung", text_color = color.white)
table.cell(debugTable, 1, 10, str.tostring(candidateCount) + "/" + str.tostring(regimeConfirmationBars), text_color = color.white)
table.cell(debugTable, 0, 11, "Regime-Evidenz", text_color = color.white)
table.cell(debugTable, 1, 11, str.tostring(regimeEvidence * 100, "#") + " %", text_color = color.white)
else
table.clear(debugTable, 0, 0, 1, 11)
// ─────────────────────────────────────────────────────────────────────────────
// ALERTS
// ─────────────────────────────────────────────────────────────────────────────
alertcondition(
bullFlip,
"Aufwärtstrend bestätigt",
"Modern Trend Regime: Aufwärtstrend bestätigt bei {{ticker}} auf {{interval}}."
)
alertcondition(
bearFlip,
"Abwärtstrend bestätigt",
"Modern Trend Regime: Abwärtstrend bestätigt bei {{ticker}} auf {{interval}}."
)
alertcondition(
structureBreakoutBull,
"Struktur-Ausbruch bullisch",
"Modern Trend Regime: Kurs bricht über die Strukturvorschau bei {{ticker}} auf {{interval}}."
)
alertcondition(
structureBreakoutBear,
"Struktur-Ausbruch bärisch",
"Modern Trend Regime: Kurs bricht unter die Strukturvorschau bei {{ticker}} auf {{interval}}."
)
alertcondition(
rangeLongReaction,
"Range-Reaktion Long",
"Modern Trend Regime: Bullische Reaktion an der unteren Range-Grenze bei {{ticker}}."
)
alertcondition(
rangeShortReaction,
"Range-Reaktion Short",
"Modern Trend Regime: Bärische Reaktion an der oberen Range-Grenze bei {{ticker}}."
)
alertcondition(
bullRangeBreakout,
"Bullischer Range-Ausbruch",
"Modern Trend Regime: Bullischer Ausbruch aus einer Seitwärtsphase bei {{ticker}}."
)
alertcondition(
bearRangeBreakout,
"Bärischer Range-Ausbruch",
"Modern Trend Regime: Bärischer Ausbruch aus einer Seitwärtsphase bei {{ticker}}."
)
Overview
Modern Trend Regime [WavesUnchained] builds fast, base, and slow structure from a price-range, EMA, WMA, or SMA calculation, then compares ATR-normalized slope, directional efficiency, ADX strength, and compression. On the price chart it draws a trend band, frozen range boundaries, optional midpoint and quartiles, confirmed trend flips, and time-limited breakout and reaction marks. Presets and custom lengths change sensitivity; confirmed-bar mode waits for closed candles.
Trend, range, and transition regime scoring
Frozen range boundaries with midpoint and quartiles
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Preset
string
Standard
preset
Berechnungsmethode
string
Preisspanne
calculationMode
Preisquelle
source
close
priceSource
Fast Trend Länge
int
9
customFastLength
Trend Basis Länge
int
26
customBaseLength
Langfristige Struktur
int
52
customSlowLength
ATR Zeitraum
int
14
customAtrLength
Analysezeitraum
int
20
customRegimeLength
Trendstärke Zeitraum
int
14
customAdxLength
Seitwärts unter Trendstärke
float
18.0
customRangeAdxThreshold
Trend über Trendstärke
float
23.0
customTrendAdxThreshold
Seitwärts unter Richtungseffizienz
float
0.28
customRangeEfficiencyThreshold
Show all 40 settings
Setting
Type
Default
Variable
Trend über Richtungseffizienz
float
0.42
customTrendEfficiencyThreshold
Maximale Basis-Steigung (ATR/Kerze)
float
0.025
customRangeSlopeThreshold
Maximale Strukturbreite in ATR
float
0.45
customCompressionThreshold
Bestätigungskerzen
int
3
customRegimeConfirmationBars
Ausbruchspuffer in ATR
float
0.10
customBreakoutBufferAtr
Ausbruch maximal nach Range-Ende
int
10
customBreakoutValidityBars
Range-Struktur Zeitraum
int
20
customRangeStructureLength
Reaktionszone in ATR
float
0.10
customRangeReactionZoneAtr
Range-Reaktionen anzeigen
bool
true
showRangeReactions
Range-Ausbrüche anzeigen
bool
true
showRangeBreakouts
Reaktionskerze verlangen
bool
true
rangeReactionNeedsCandle
Starke Schlusskursposition verlangen
bool
false
strongRangeReactionEnabled
Minimale Reaktionsqualität
float
0.65
rangeReactionClosePosition
Range-Mitte anzeigen
bool
true
showRangeMidpoint
Range-Quartile anzeigen
bool
false
showRangeQuartiles
Trend-Bestätigung anzeigen
bool
true
showTrendFlips
Nur bestätigte Kerzen
bool
true
confirmOnClose
Darstellungsmodus
string
Trendband
visualMode
Fast Trend anzeigen
bool
false
showFastTrend
Trend Basis anzeigen
bool
true
showTrendBase
Kerzen nach Marktmodus färben
bool
true
colorBars
Übergangsphasen hinterlegen
bool
false
showTransitionBackground
Trendband Breite in ATR
float
0.22
bandWidthAtr
Strukturvorschau anzeigen
bool
true
structurePreviewEnabled
Strukturvorschau-Verschiebung
int
26
structurePreviewOffset
Struktur-Ausbruch markieren
bool
true
showStructureBreakout
Regime-Leiste nach Evidenz abstufen
bool
true
regimeRailUsesEvidence
Diagnose-Tabelle anzeigen
bool
false
showDebugTable
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 indicator detects bullish and bearish Cup and Handle patterns directly on the price chart using pivot points. It integrates a Volatility Matrix based on Bollinger Bands squeezes alongside a 200-period simple moving average trend filter to identify breakdow
This Pine Script indicator plots a range filter line along with high and low target bands on the price chart. It calculates a smoothed average range using a sampling period and multiplier, then applies a filter to detect upward and downward trends. Signals tri
This overlay indicator draws trendlines on the price chart and marks breakouts with optional targets. It builds a slope from successive changes in a wick or body source over a user-set period, then extends the line by a selected multiple of the bar interval. P
This indicator plots Donchian Channel boundary lines along with dynamic fan projections directly on the price chart. It calculates the highest high, lowest low, and median price over a customizable lookback period. Whenever price establishes a new channel high
Sideway Zones Live is an overlay indicator that estimates inner and outer sideways bands from recent highs and lows with a rational quadratic kernel. It tracks swing pivots over a loopback period and counts bars that remain between the outer high and low. Afte
Dynamic Linear Regression calculates and plots linear regression trendlines and standard deviation channels directly on the price chart over a user-selected time period. Traders can configure static channels locked at the end time, dynamic channels that contin