
QuaScript Documentation
Language guide, engine API, 601 builtins and the preset library · v3.0.0-phase1
Trend
Adaptive Trend Cloud
analysis · presets/analysis/trend/adaptive_trend_cloud.qs · uses viz/palette
Three adaptive averages (Kalman, Jurik and Kaufman) fused into a fast and a slow trend line. The cloud between them is a gradient whose colors follow the regime, the fast line is shaded by trend strength (slope in ATR units), candles take the regime color and every regime change is tagged. A dashboard summarises regime, strength and efficiency on the last bar.
analysis "Adaptive Trend Cloud" {
overlay = true
max_objects = 200
}
/// Three adaptive averages (Kalman, Jurik and Kaufman) fused into a fast and a slow trend line.
/// The cloud between them is a gradient whose colors follow the regime, the fast line is shaded
/// by trend strength (slope in ATR units), candles take the regime color and every regime change
/// is tagged. A dashboard summarises regime, strength and efficiency on the last bar.
use "viz/palette" as pal
src = param.source(close, title = "Source")
fast_len = param.int(12, title = "Fast length", min = 2, max = 200, group = "Averages")
slow_len = param.int(48, title = "Slow length", min = 5, max = 500, group = "Averages")
noise = param.float(0.05, title = "Kalman process noise", min = 0.0001, max = 1, step = 0.005, group = "Averages")
color_bars = param.bool(true, title = "Color candles", group = "Style")
kal = ta.kalman(src, noise, 0.5)
jur = ta.jurik(src, fast_len, 0, 2)
kam = ta.kaufman(src, fast_len, 2, 30)
fast = (kal + jur + kam) / 3
slow = ta.ema(ta.kaufman(src, slow_len, 2, 30), 3)
a = ta.atr(14)
strength = math.clamp((fast - fast[3]) / math.max(a, 1e-12), -1.5, 1.5)
regime = fast > slow ? 1 : -1
in_regime = ta.bars_since(regime != regime[1])
er = math.abs(src - src[slow_len]) / math.max(stat.sum(math.abs(src - src[1]), slow_len), 1e-12)
heat = strength >= 0 ? color.gradient(strength, 0, 1.5, color.slate.400, color.emerald.300) : color.gradient(strength, -1.5, 0, color.rose.400, color.slate.400)
p_fast = render.line(fast, "Fast trend", color = heat, width = 3)
p_slow = render.line(slow, "Slow trend", color = regime > 0 ? color.teal.600 : color.rose.700, width = 2)
render.band(p_fast, p_slow, texture = "gradient", upper_color = color.emerald.400, lower_color = color.rose.500, opacity = 0.35, title = "Trend cloud")
// outer glow: two faint ATR envelopes around the slow line
p_hi = render.line(slow + 2 * a, "Upper envelope", color = color.translucent(color.sky.300, 75), width = 1, stroke = style.dotted)
p_lo = render.line(slow - 2 * a, "Lower envelope", color = color.translucent(color.sky.300, 75), width = 1, stroke = style.dotted)
render.band(p_hi, p_lo, color = color.sky.500, opacity = 0.04, title = "Envelope")
flip_up = regime > 0 and regime[1] < 0
flip_dn = regime < 0 and regime[1] > 0
if flip_up { draw.tag.create(bar.index, low - 0.5 * a, "Bull regime", color = color.emerald.600, shape = shape.tag_up) }
if flip_dn { draw.tag.create(bar.index, high + 0.5 * a, "Bear regime", color = color.rose.600, shape = shape.tag_down) }
render.mark(ta.cross_up(src, fast) and regime > 0, shape = shape.circle, at = anchor.below_bar, color = color.emerald.300, size = 0.5, title = "Pullback buy")
render.mark(ta.cross_down(src, fast) and regime < 0, shape = shape.circle, at = anchor.above_bar, color = color.rose.300, size = 0.5, title = "Pullback sell")
render.candle_color(color_bars ? (regime > 0 ? color.gradient(strength, -0.5, 1.5, color.teal.800, color.emerald.400) : color.gradient(strength, -1.5, 0.5, color.rose.400, color.rose.800)) : na)
persist t = draw.table.create(anchor.top_right, 4, 2)
if bar.is_last {
draw.table.cell(t, 0, 0, "Regime", text_color = color.slate.400)
draw.table.cell(t, 0, 1, regime > 0 ? "Bull" : "Bear", bg_color = pal.trend_color(regime))
draw.table.cell(t, 1, 0, "Strength", text_color = color.slate.400)
draw.table.cell(t, 1, 1, str.format("{:.2f}", strength), bg_color = pal.signed_heat(strength, 1.5))
draw.table.cell(t, 2, 0, "Efficiency", text_color = color.slate.400)
draw.table.cell(t, 2, 1, str.format("{:.0f}%", er * 100), bg_color = color.gradient(er, 0, 0.6, color.slate.700, color.amber.500))
draw.table.cell(t, 3, 0, "Bars in regime", text_color = color.slate.400)
draw.table.cell(t, 3, 1, str.of(in_regime))
}
alert.rule(flip_up, "Bull regime", "Fast adaptive trend crossed above the slow trend")
alert.rule(flip_dn, "Bear regime", "Fast adaptive trend crossed below the slow trend")Volatility-Adaptive SuperTrend
analysis · presets/analysis/trend/adaptive_vol_supertrend.qs
A supertrend whose ATR multiple adapts to the volatility regime: the percentile rank of ATR over a long window moves the factor between a tight and a wide setting, so stops hug price in calm markets and give room in turbulent ones. The stop band is gradient filled to price, the factor in use is shown as a dashboard, and every flip draws the new leg's risk zone.
analysis "Volatility-Adaptive SuperTrend" {
overlay = true
max_objects = 300
}
/// A supertrend whose ATR multiple adapts to the volatility regime: the percentile rank of ATR
/// over a long window moves the factor between a tight and a wide setting, so stops hug price in
/// calm markets and give room in turbulent ones. The stop band is gradient filled to price, the
/// factor in use is shown as a dashboard, and every flip draws the new leg's risk zone.
tight = param.float(1.5, title = "Calm factor", min = 0.5, max = 5, step = 0.1)
wide = param.float(4.0, title = "Turbulent factor", min = 1, max = 10, step = 0.1)
len = param.int(10, title = "ATR length", min = 2, max = 100)
rank = param.int(300, title = "Regime window", min = 50, max = 3000)
a = ta.atr(len)
pr = math.coalesce(stat.percent_rank(a, rank), 50) / 100
factor = tight + (wide - tight) * pr
mid = bar.mid
persist up = na
persist dn = na
persist dir = 1
basic_up = mid - factor * a
basic_dn = mid + factor * a
up := math.is_na(up) ? basic_up : close[1] > up ? math.max(basic_up, up) : basic_up
dn := math.is_na(dn) ? basic_dn : close[1] < dn ? math.min(basic_dn, dn) : basic_dn
prev_dir = dir
if dir < 0 and close > dn[1] { dir := 1 }
else if dir > 0 and close < up[1] { dir := -1 }
stop = dir > 0 ? up : dn
flip = dir != prev_dir
pc = render.line(close, "Close", color = color.transparent, width = 0)
ps = render.line(stop, "Adaptive stop", color = dir > 0 ? color.gradient(pr, 0, 1, color.emerald.300, color.teal.600) : color.gradient(pr, 0, 1, color.rose.300, color.red.600), width = 2.5)
render.band(pc, ps, texture = "gradient", upper_color = color.emerald.500, lower_color = color.rose.500, opacity = 0.16, title = "Risk band")
if flip {
draw.zone.create(bar.index, dir > 0 ? close : stop, bar.index + 10, dir > 0 ? stop : close,
color = color.translucent(dir > 0 ? color.emerald.500 : color.rose.500, 85), text = str.format("Risk {:.2f}", math.abs(close - stop)))
}
render.mark(flip and dir > 0, shape = shape.tag_up, at = anchor.below_bar, color = color.emerald.500, text = "Long")
render.mark(flip and dir < 0, shape = shape.tag_down, at = anchor.above_bar, color = color.rose.500, text = "Short")
render.candle_color(dir > 0 ? color.emerald.500 : color.rose.500)
persist t = draw.table.create(anchor.top_right, 3, 2)
if bar.is_last {
draw.table.cell(t, 0, 0, "Trend", text_color = color.slate.400)
draw.table.cell(t, 0, 1, dir > 0 ? "Long" : "Short", bg_color = dir > 0 ? color.emerald.700 : color.rose.700)
draw.table.cell(t, 1, 0, "Volatility rank", text_color = color.slate.400)
draw.table.cell(t, 1, 1, str.format("{:.0f}%", pr * 100), bg_color = color.gradient(pr, 0, 1, color.sky.800, color.orange.700))
draw.table.cell(t, 2, 0, "Factor", text_color = color.slate.400)
draw.table.cell(t, 2, 1, str.format("{:.2f} x ATR", factor))
}
alert.rule(flip and dir > 0, "Adaptive trend long", "Close above the adaptive stop")
alert.rule(flip and dir < 0, "Adaptive trend short", "Close below the adaptive stop")ADX / DMI
analysis · presets/analysis/trend/adx.qs
Average directional index with the +DI / -DI lines.
analysis "ADX / DMI" {
overlay = false
}
// Average directional index with the +DI / -DI lines.
len = param.int(14, title = "DI length", min = 1, max = 100)
smooth = param.int(14, title = "ADX smoothing", min = 1, max = 100)
(adx, plus_di, minus_di) = ta.adx(len, smooth)
render.line(adx, "ADX", color = color.purple.500, width = 2)
render.line(plus_di, "+DI", color = color.emerald.500, width = 1)
render.line(minus_di, "-DI", color = color.rose.500, width = 1)
render.level(25, "Trend", color = color.slate.500, stroke = style.dashed)
render.level(50, "Strong trend", color = color.yellow.500, stroke = style.dotted)
render.mark(ta.cross_up(adx, 25), shape = shape.star, at = anchor.below_bar, color = color.yellow.500, text = "Trend")
render.mark(ta.cross_up(adx, 50), shape = shape.diamond, at = anchor.above_bar, color = color.purple.500, text = "Strong")
alert.rule(ta.cross_up(adx, 25), "Trend expanding", "ADX crossed above 25")
alert.rule(ta.cross_up(adx, 50), "Strong trend", "ADX crossed above 50")Aroon x Vortex
analysis · presets/analysis/trend/aroon_vortex_combo.qs
Trend age (Aroon) and trend thrust (Vortex) in one pane: the Aroon oscillator as a colored histogram, both Vortex lines rescaled around zero and a mark when both agree on a new trend.
analysis "Aroon x Vortex" {
overlay = false
}
/// Trend age (Aroon) and trend thrust (Vortex) in one pane: the Aroon oscillator as a colored
/// histogram, both Vortex lines rescaled around zero and a mark when both agree on a new trend.
len = param.int(25, title = "Aroon length", min = 2, max = 200)
vlen = param.int(14, title = "Vortex length", min = 2, max = 200)
(aup, adn, aosc) = ta.aroon(len)
(vp, vm) = ta.vortex(vlen)
vdiff = (vp - vm) * 100
agree_up = aosc > 50 and vp > vm
agree_dn = aosc < -50 and vp < vm
render.histogram(aosc, "Aroon oscillator", color = aosc >= 0 ? color.translucent(color.teal.500, 40) : color.translucent(color.rose.500, 40))
render.line(vdiff, "Vortex spread x100", color = color.amber.400, width = 2)
render.level(50, "Up trend", color = color.teal.700, stroke = style.dotted)
render.level(-50, "Down trend", color = color.rose.700, stroke = style.dotted)
render.level(0, "Zero", color = color.slate.600)
render.mark(agree_up and not agree_up[1], shape = shape.triangle_up, at = anchor.bottom, color = color.teal.400, text = "Up")
render.mark(agree_dn and not agree_dn[1], shape = shape.triangle_down, at = anchor.top, color = color.rose.400, text = "Down")
alert.rule(agree_up, "Aroon and Vortex agree: up", "Both trend measures point up")
alert.rule(agree_dn, "Aroon and Vortex agree: down", "Both trend measures point down")Choppiness Regime Cloud
analysis · presets/analysis/trend/choppiness_regime.qs
The choppiness index and the efficiency ratio decide whether the market trends or ranges. Trending stretches get a directional Kaufman cloud; ranging stretches get a Donchian box fill with its mid-line, so the chart shows which playbook applies. A table summarises the regime.
analysis "Choppiness Regime Cloud" {
overlay = true
}
/// The choppiness index and the efficiency ratio decide whether the market trends or ranges.
/// Trending stretches get a directional Kaufman cloud; ranging stretches get a Donchian box fill
/// with its mid-line, so the chart shows which playbook applies. A table summarises the regime.
len = param.int(14, title = "Choppiness length", min = 5, max = 200)
chop_hi = param.float(61.8, title = "Range threshold", min = 50, max = 80, step = 0.1)
chop_lo = param.float(45, title = "Trend threshold", min = 20, max = 50, step = 0.1)
chop = ta.choppiness(len)
er = hft.efficiency(close, len * 2)
ranging = chop > chop_hi
trending = chop < chop_lo or er > 0.35
(dmid, dup, dlo) = ta.donchian(len * 2)
k = ta.kaufman(close, len, 2, 30)
k_slow = ta.kaufman(close, len * 3, 2, 30)
pk = render.line(trending ? k : na, "Trend line", color = k > k_slow ? color.teal.300 : color.pink.300, width = 2.5)
pks = render.line(trending ? k_slow : na, "Trend base", color = color.translucent(color.slate.300, 50), width = 1)
render.band(pk, pks, texture = "gradient", upper_color = color.teal.500, lower_color = color.pink.500, opacity = 0.25, title = "Trend cloud")
pu = render.line(ranging ? dup : na, "Range top", color = color.amber.400, width = 1.5)
pl = render.line(ranging ? dlo : na, "Range bottom", color = color.amber.400, width = 1.5)
render.line(ranging ? dmid : na, "Range mid", color = color.translucent(color.amber.300, 40), width = 1, stroke = style.dashed)
render.band(pu, pl, color = color.amber.500, opacity = 0.07, title = "Range box")
render.background(ranging ? color.translucent(color.amber.500, 94) : na)
render.mark(trending and not trending[1], shape = shape.circle, at = anchor.below_bar, color = color.teal.300, size = 0.5, title = "Trend starts")
render.mark(ranging and not ranging[1], shape = shape.square, at = anchor.above_bar, color = color.amber.300, size = 0.5, title = "Range starts")
persist t = draw.table.create(anchor.top_right, 3, 2)
if bar.is_last {
draw.table.cell(t, 0, 0, "Regime", text_color = color.slate.400)
draw.table.cell(t, 0, 1, trending ? "Trending" : ranging ? "Ranging" : "Transition", bg_color = trending ? color.teal.700 : ranging ? color.amber.700 : color.slate.700)
draw.table.cell(t, 1, 0, "Choppiness", text_color = color.slate.400)
draw.table.cell(t, 1, 1, str.format("{:.1f}", chop))
draw.table.cell(t, 2, 0, "Efficiency", text_color = color.slate.400)
draw.table.cell(t, 2, 1, str.format("{:.0f}%", er * 100))
}
alert.rule(trending and not trending[1], "Trend regime", "Choppiness fell below the trend threshold")
alert.rule(ranging and not ranging[1], "Range regime", "Choppiness rose above the range threshold")Untitled
analysis · presets/analysis/trend/donchian_channels.qs
Donchian Channels with Volatility Cloud & Breakout Shapes
analysis "Untitled" {
render = canvas
overlay = true
}
// Donchian Channels with Volatility Cloud & Breakout Shapes
len = param.float(20, "length", min=1, max=200)
upper = ta.highest(high, len)
lower = ta.lowest(low, len)
basis = (upper + lower) * 0.5
p_upper = render.line(upper, "Upper Band", color=color.cyan.500)
p_basis = render.line(basis, "Midline", color=color.amber.500)
p_lower = render.line(lower, "Lower Band", color=color.cyan.500)
render.band(p_upper, p_lower, color=color.cyan.500, opacity=0.12, title="Donchian Cloud")
render.mark(close > upper[1], shape=shape.arrow_up, text="NEW HIGH", color=color.emerald.500, at=anchor.above_bar)
render.mark(close < lower[1], shape=shape.arrow_down, text="NEW LOW", color=color.rose.500, at=anchor.below_bar)
alert.rule(close > upper[1], "Donchian Breakout", "Price reached new highest high")
alert.rule(close < lower[1], "Donchian Breakdown", "Price reached new lowest low")Ehlers Cycle Trend
analysis · presets/analysis/trend/ehlers_cycle_trend.qs
John Ehlers' filters combined: a super smoother as the fast line, a decycler as the trend, and a Hull basis as confirmation. The decycler cloud changes color with the cycle, the fast line is shaded by its distance from the trend in ATR units and arrows mark cycle turns that agree with the trend.
analysis "Ehlers Cycle Trend" {
overlay = true
}
/// John Ehlers' filters combined: a super smoother as the fast line, a decycler as the trend, and
/// a Hull basis as confirmation. The decycler cloud changes color with the cycle, the fast line
/// is shaded by its distance from the trend in ATR units and arrows mark cycle turns that agree
/// with the trend.
fast_len = param.int(10, title = "Smoother length", min = 2, max = 100)
cycle_len = param.int(60, title = "Decycler length", min = 10, max = 400)
hull_len = param.int(55, title = "Hull length", min = 5, max = 400)
ss = ta.super_smoother(close, fast_len)
dc = ta.decycler(close, cycle_len)
hb = ta.hull(close, hull_len)
a = ta.atr(20)
dist = (ss - dc) / math.max(a, 1e-12)
up = ss > dc
p_ss = render.spline(ss, "Super smoother", color = color.gradient(dist, -2, 2, color.rose.300, color.cyan.300), width = 2.5)
p_dc = render.line(dc, "Decycler", color = up ? color.cyan.600 : color.rose.600, width = 2)
render.band(p_ss, p_dc, texture = "cloud", upper_color = color.cyan.500, lower_color = color.rose.500, opacity = 0.2, title = "Cycle cloud")
render.line(hb, "Hull basis", color = color.translucent(color.amber.300, 35), width = 1, stroke = style.dashed)
turn_up = ss > ss[1] and ss[1] <= ss[2] and close > hb
turn_dn = ss < ss[1] and ss[1] >= ss[2] and close < hb
render.mark(turn_up and up, shape = shape.arrow_up, at = anchor.below_bar, color = color.cyan.300, title = "Cycle low")
render.mark(turn_dn and not up, shape = shape.arrow_down, at = anchor.above_bar, color = color.rose.300, title = "Cycle high")
render.candle_color(up ? color.gradient(dist, 0, 2, color.slate.500, color.cyan.400) : color.gradient(dist, -2, 0, color.rose.400, color.slate.500))
alert.rule(ta.cross_up(ss, dc), "Cycle trend up", "Super smoother crossed above the decycler")
alert.rule(ta.cross_down(ss, dc), "Cycle trend down", "Super smoother crossed below the decycler")Hull Wave Ribbon
analysis · presets/analysis/trend/hull_wave_ribbon.qs
Eight Hull moving averages (lengths 9 .. 72) stacked as a ribbon whose every line is colored by its own slope. Consecutive lines are filled pairwise, so the ribbon reads as a single wave that twists at turns. Candles take the share of rising lines.
analysis "Hull Wave Ribbon" {
overlay = true
}
/// Eight Hull moving averages (lengths 9 .. 72) stacked as a ribbon whose every line is colored
/// by its own slope. Consecutive lines are filled pairwise, so the ribbon reads as a single wave
/// that twists at turns. Candles take the share of rising lines.
src = param.source(close, title = "Source")
base = param.int(9, title = "Shortest length", min = 2, max = 100)
gap = param.int(9, title = "Length step", min = 1, max = 50)
h1 = ta.hull(src, base)
h2 = ta.hull(src, base + gap)
h3 = ta.hull(src, base + 2 * gap)
h4 = ta.hull(src, base + 3 * gap)
h5 = ta.hull(src, base + 4 * gap)
h6 = ta.hull(src, base + 5 * gap)
h7 = ta.hull(src, base + 6 * gap)
h8 = ta.hull(src, base + 7 * gap)
fn tone(h: float) -> color {
return h > h[1] ? color.cyan.400 : color.fuchsia.400
}
up = (h1 > h1[1] ? 1 : 0) + (h2 > h2[1] ? 1 : 0) + (h3 > h3[1] ? 1 : 0) + (h4 > h4[1] ? 1 : 0) + (h5 > h5[1] ? 1 : 0) + (h6 > h6[1] ? 1 : 0) + (h7 > h7[1] ? 1 : 0) + (h8 > h8[1] ? 1 : 0)
q1 = render.line(h1, "Hull 1", color = tone(h1), width = 2)
q2 = render.line(h2, "Hull 2", color = color.translucent(tone(h2), 20), width = 1)
q3 = render.line(h3, "Hull 3", color = color.translucent(tone(h3), 30), width = 1)
q4 = render.line(h4, "Hull 4", color = color.translucent(tone(h4), 35), width = 1)
q5 = render.line(h5, "Hull 5", color = color.translucent(tone(h5), 40), width = 1)
q6 = render.line(h6, "Hull 6", color = color.translucent(tone(h6), 45), width = 1)
q7 = render.line(h7, "Hull 7", color = color.translucent(tone(h7), 50), width = 1)
q8 = render.line(h8, "Hull 8", color = tone(h8), width = 2.5)
render.band(q1, q2, color = color.indigo.400, opacity = 0.05, title = "Wave 1")
render.band(q2, q3, color = color.indigo.400, opacity = 0.06, title = "Wave 2")
render.band(q3, q4, color = color.indigo.500, opacity = 0.07, title = "Wave 3")
render.band(q4, q5, color = color.indigo.500, opacity = 0.08, title = "Wave 4")
render.band(q5, q6, color = color.violet.500, opacity = 0.08, title = "Wave 5")
render.band(q6, q7, color = color.violet.500, opacity = 0.09, title = "Wave 6")
render.band(q7, q8, color = color.violet.600, opacity = 0.1, title = "Wave 7")
render.candle_color(color.gradient(up, 0, 8, color.fuchsia.500, color.cyan.400))
render.mark(up == 8 and up[1] < 8, shape = shape.triangle_up, at = anchor.below_bar, color = color.cyan.300, title = "All rising")
render.mark(up == 0 and up[1] > 0, shape = shape.triangle_down, at = anchor.above_bar, color = color.fuchsia.300, title = "All falling")
alert.rule(up == 8 and up[1] < 8, "Hull ribbon up", "All eight Hull averages are rising")
alert.rule(up == 0 and up[1] > 0, "Hull ribbon down", "All eight Hull averages are falling")Ichimoku Cloud
analysis · presets/analysis/trend/ichimoku_cloud.qs
Conversion / base lines and the leading spans shifted forward by the displacement, with a cloud-textured band whose color follows the span order.
analysis "Ichimoku Cloud" {
overlay = true
}
// Conversion / base lines and the leading spans shifted forward by the displacement, with a
// cloud-textured band whose color follows the span order.
conv_len = param.int(9, title = "Conversion", min = 1, max = 100)
base_len = param.int(26, title = "Base", min = 1, max = 100)
span_len = param.int(52, title = "Span B", min = 1, max = 200)
(conv, base, span_a, span_b, lagging) = ta.ichimoku(conv_len, base_len, span_len, 26)
render.line(conv, "Conversion", color = color.blue.500, width = 1.5)
render.line(base, "Base", color = color.amber.500, width = 1.5)
render.line(close, "Lagging", color = color.slate.400, width = 1, offset = -26)
pa = render.line(span_a, "Span A", color = color.emerald.500, width = 1, offset = 26)
pb = render.line(span_b, "Span B", color = color.rose.500, width = 1, offset = 26)
render.band(pa, pb, texture = "cloud", upper_color = color.emerald.500, lower_color = color.rose.500, opacity = 0.25, puff_scale = 1.2, title = "Cloud")
render.mark(ta.cross_up(conv, base), shape = shape.triangle_up, at = anchor.below_bar, color = color.emerald.500, text = "TK bull")
render.mark(ta.cross_down(conv, base), shape = shape.triangle_down, at = anchor.above_bar, color = color.rose.500, text = "TK bear")
alert.rule(ta.cross_up(conv, base), "Ichimoku bullish cross", "Conversion line crossed above the base line")
alert.rule(ta.cross_down(conv, base), "Ichimoku bearish cross", "Conversion line crossed below the base line")Ichimoku Kinetic Cloud
analysis · presets/analysis/trend/ichimoku_kinetic.qs
The full Ichimoku system with a cloud-textured kumo whose colors follow the leading spans, a conversion line shaded by its distance from the base line, tagged TK crosses graded by their position against the cloud, kumo twists, candle colors for the cloud bias and a dashboard. The cloud is projected 26 bars ahead.
analysis "Ichimoku Kinetic Cloud" {
overlay = true
max_objects = 200
}
/// The full Ichimoku system with a cloud-textured kumo whose colors follow the leading spans, a
/// conversion line shaded by its distance from the base line, tagged TK crosses graded by their
/// position against the cloud, kumo twists, candle colors for the cloud bias and a dashboard.
/// The cloud is projected 26 bars ahead.
conv = param.int(9, title = "Conversion", min = 2, max = 100)
base = param.int(26, title = "Base", min = 2, max = 200)
span = param.int(52, title = "Span B", min = 2, max = 400)
(tenkan, kijun, sa, sb, lag) = ta.ichimoku(conv, base, span, 26)
a = ta.atr(14)
spread = (tenkan - kijun) / math.max(a, 1e-12)
p_sa = render.line(sa, "Leading span A", color = sa >= sb ? color.emerald.400 : color.rose.400, width = 1, offset = 26)
p_sb = render.line(sb, "Leading span B", color = color.translucent(color.slate.300, 40), width = 1, offset = 26)
render.band(p_sa, p_sb, texture = "cloud", upper_color = color.emerald.500, lower_color = color.rose.500, opacity = 0.22, title = "Kumo")
render.line(tenkan, "Conversion", color = color.gradient(spread, -1.5, 1.5, color.rose.300, color.sky.300), width = 2)
render.line(kijun, "Base", color = color.amber.400, width = 2)
render.line(close, "Lagging span", color = color.translucent(color.violet.300, 45), width = 1, offset = -26)
// the cloud under the current bar was projected 26 bars ago
top_now = math.max(sa[26], sb[26])
bot_now = math.min(sa[26], sb[26])
above = close > top_now
below = close < bot_now
tk_up = ta.cross_up(tenkan, kijun)
tk_dn = ta.cross_down(tenkan, kijun)
if tk_up { draw.tag.create(bar.index, low - 0.4 * a, above ? "TK+ strong" : below ? "TK+ weak" : "TK+", color = above ? color.emerald.500 : below ? color.emerald.800 : color.emerald.700, shape = shape.tag_up, size = 0.8) }
if tk_dn { draw.tag.create(bar.index, high + 0.4 * a, below ? "TK- strong" : above ? "TK- weak" : "TK-", color = below ? color.rose.500 : above ? color.rose.800 : color.rose.700, shape = shape.tag_down, size = 0.8) }
twist = (sa > sb) != (sa[1] > sb[1]) and not math.is_na(sb[1])
render.mark(twist, shape = shape.diamond, at = anchor.top, color = color.amber.300, size = 0.6, title = "Kumo twist")
render.candle_color(above ? color.emerald.500 : below ? color.rose.500 : color.slate.400)
persist t = draw.table.create(anchor.top_left, 3, 2)
if bar.is_last {
draw.table.cell(t, 0, 0, "Cloud", text_color = color.slate.400)
draw.table.cell(t, 0, 1, above ? "Above" : below ? "Below" : "Inside", bg_color = above ? color.emerald.700 : below ? color.rose.700 : color.slate.700)
draw.table.cell(t, 1, 0, "TK spread", text_color = color.slate.400)
draw.table.cell(t, 1, 1, str.format("{:.2f} ATR", spread), bg_color = color.gradient(spread, -1.5, 1.5, color.rose.800, color.emerald.700))
draw.table.cell(t, 2, 0, "Future cloud", text_color = color.slate.400)
draw.table.cell(t, 2, 1, sa >= sb ? "Bullish" : "Bearish", bg_color = sa >= sb ? color.emerald.800 : color.rose.800)
}
alert.rule(tk_up and above, "Strong TK cross up", "Conversion crossed above base above the cloud")
alert.rule(tk_dn and below, "Strong TK cross down", "Conversion crossed below base below the cloud")Kalman Trend
analysis · presets/analysis/trend/kalman_trend.qs
A Kalman-filtered price with a slope-colored line, a +-k sigma residual channel and a background shade whenever the slope's z-score is extreme.
analysis "Kalman Trend" {
overlay = true
}
/// A Kalman-filtered price with a slope-colored line, a +-k sigma residual channel and a
/// background shade whenever the slope's z-score is extreme.
q = param.float(0.01, title = "Process noise", min = 0.0001, max = 1, step = 0.001)
r = param.float(0.1, title = "Measurement noise", min = 0.0001, max = 10, step = 0.01)
k = param.float(2.0, title = "Channel (sigma)", min = 0.5, max = 5, step = 0.1)
z_len = param.int(100, title = "Slope z-score length", min = 10, max = 1000)
kf = ta.kalman(close, q, r)
resid = close - kf
sd = stat.stdev(resid, 50)
slope = kf - kf[1]
z = stat.zscore(slope, z_len)
render.line(kf, "Kalman", color = slope >= 0 ? color.teal.400 : color.pink.400, width = 2)
p_up = render.line(kf + k * sd, "Upper", color = color.slate.500, width = 1, stroke = style.dashed)
p_dn = render.line(kf - k * sd, "Lower", color = color.slate.500, width = 1, stroke = style.dashed)
render.band(p_up, p_dn, color = color.slate.400, opacity = 0.05)
render.background(z > 2 ? color.translucent(color.teal.500, 90) : z < -2 ? color.translucent(color.pink.500, 90) : na)
render.mark(ta.cross_up(slope, 0), shape = shape.circle, at = anchor.below_bar, color = color.teal.400, size = 0.6)
render.mark(ta.cross_down(slope, 0), shape = shape.circle, at = anchor.above_bar, color = color.pink.400, size = 0.6)KAMA Efficiency Cloud
analysis · presets/analysis/trend/kama_cloud.qs
A fast and a slow Kaufman adaptive average with the cloud between them coloured by the efficiency of the move: bright when price travels straight (the averages speed up), faded when it chops (they flatten). Crosses are marked only when efficiency confirms them.
analysis "KAMA Efficiency Cloud" {
overlay = true
render = webgpu
short_title = "KAMA"
}
/// A fast and a slow Kaufman adaptive average with the cloud between them coloured by the
/// efficiency of the move: bright when price travels straight (the averages speed up), faded when
/// it chops (they flatten). Crosses are marked only when efficiency confirms them.
fast_n = param.int(10, title = "Fast length", min = 2, max = 200)
slow_n = param.int(40, title = "Slow length", min = 5, max = 500)
eff_n = param.int(20, title = "Efficiency window", min = 2, max = 500)
eff_min = param.float(0.3, title = "Confirming efficiency", min = 0, max = 1, step = 0.05)
f = ta.kaufman(close, fast_n, 2, 30)
s = ta.kaufman(close, slow_n, 2, 30)
er = hft.efficiency(close, eff_n)
up = f > s
pf = render.line(f, "Fast KAMA", color = up ? color.emerald.300 : color.rose.300, width = 2)
ps = render.line(s, "Slow KAMA", color = color.translucent(color.slate.300, 30), width = 1.5)
render.band(pf, ps, color = color.translucent(up ? color.emerald.500 : color.rose.500, 95 - 60 * math.coalesce(er, 0)), opacity = 1, title = "Efficiency cloud")
render.mark(ta.cross_up(f, s) and er > eff_min, shape = shape.tag_up, at = anchor.below_bar, color = color.emerald.400, text = "Up", title = "Efficient cross up")
render.mark(ta.cross_down(f, s) and er > eff_min, shape = shape.tag_down, at = anchor.above_bar, color = color.rose.400, text = "Down", title = "Efficient cross down")Untitled
analysis · presets/analysis/trend/keltner_channels.qs
Keltner Channels with Volatility Cloud Fill & Channel Breakouts
analysis "Untitled" {
render = canvas
overlay = true
}
// Keltner Channels with Volatility Cloud Fill & Channel Breakouts
len = param.float(20, "length", min=1, max=200)
mult = param.float(2.0, "multiplier", min=0.5, max=5.0, step=0.5)
basis = ta.ema(close, len)
range_val = mult * ta.atr(len)
upper = basis + range_val
lower = basis - range_val
p_upper = render.line(upper, "Upper Channel", color=color.blue.500)
p_basis = render.line(basis, "EMA Basis", color=color.amber.500)
p_lower = render.line(lower, "Lower Channel", color=color.blue.500)
render.band(p_upper, p_lower, color=color.blue.500, opacity=0.10, title="Keltner Cloud")
render.mark(ta.cross_up(close, upper), shape=shape.triangle_up, text="UPPER BREAK", color=color.emerald.500, at=anchor.above_bar)
render.mark(ta.cross_down(close, lower), shape=shape.triangle_down, text="LOWER BREAK", color=color.rose.500, at=anchor.below_bar)
alert.rule(close > upper, "Keltner Breakout", "Price broke above upper channel")
alert.rule(close < lower, "Keltner Breakdown", "Price broke below lower channel")McGinley Dynamic Ribbon
analysis · presets/analysis/trend/mcginley_ribbon.qs
Six McGinley Dynamics, an average that speeds up when price runs away from it and slows when price returns, so it hugs trends without the whipsaw of an EMA. The ribbon between consecutive lines is filled in the trend colour; a fully ordered ribbon (fast above slow throughout) tints the candles.
analysis "McGinley Dynamic Ribbon" {
overlay = true
render = webgpu
short_title = "MDR"
}
/// Six McGinley Dynamics, an average that speeds up when price runs away from it and slows when
/// price returns, so it hugs trends without the whipsaw of an EMA. The ribbon between consecutive
/// lines is filled in the trend colour; a fully ordered ribbon (fast above slow throughout) tints
/// the candles.
m8 = ta.mcginley(close, 8)
m13 = ta.mcginley(close, 13)
m21 = ta.mcginley(close, 21)
m34 = ta.mcginley(close, 34)
m55 = ta.mcginley(close, 55)
m89 = ta.mcginley(close, 89)
up_order = m8 > m13 and m13 > m21 and m21 > m34 and m34 > m55 and m55 > m89
dn_order = m8 < m13 and m13 < m21 and m21 < m34 and m34 < m55 and m55 < m89
prev = render.line(m8, "McGinley 8", color = color.sky.300, width = 1.6)
tone = up_order ? color.emerald.500 : dn_order ? color.rose.500 : color.slate.500
p13 = render.line(m13, "McGinley 13", color = color.translucent(color.sky.300, 20), width = 1)
p21 = render.line(m21, "McGinley 21", color = color.translucent(color.indigo.300, 20), width = 1)
p34 = render.line(m34, "McGinley 34", color = color.translucent(color.violet.300, 20), width = 1)
p55 = render.line(m55, "McGinley 55", color = color.translucent(color.fuchsia.300, 20), width = 1)
p89 = render.line(m89, "McGinley 89", color = color.fuchsia.400, width = 1.6)
render.band(prev, p21, color = tone, opacity = 0.14, title = "Fast ribbon")
render.band(p21, p55, color = tone, opacity = 0.1, title = "Middle ribbon")
render.band(p55, p89, color = tone, opacity = 0.07, title = "Slow ribbon")
render.candle_color(up_order ? color.emerald.400 : dn_order ? color.rose.400 : na)Parabolic SAR
analysis · presets/analysis/trend/parabolic_sar.qs
Stop-and-reverse dots with candle tint and reversal marks.
analysis "Parabolic SAR" {
overlay = true
}
// Stop-and-reverse dots with candle tint and reversal marks.
start = param.float(0.02, title = "Start", min = 0.001, max = 0.2, step = 0.001)
inc = param.float(0.02, title = "Increment", min = 0.001, max = 0.2, step = 0.001)
maxv = param.float(0.20, title = "Maximum", min = 0.01, max = 1, step = 0.01)
sar = ta.psar(start, inc, maxv)
up = close > sar
render.dots(sar, "SAR", color = up ? color.emerald.500 : color.rose.500, shape = shape.circle, size = 2)
render.candle_color(up ? color.emerald.500 : color.rose.500)
render.mark(ta.cross_up(close, sar), shape = shape.triangle_up, at = anchor.below_bar, color = color.emerald.500, text = "Buy")
render.mark(ta.cross_down(close, sar), shape = shape.triangle_down, at = anchor.above_bar, color = color.rose.500, text = "Sell")
alert.rule(ta.cross_up(close, sar), "SAR bullish reversal", "Price crossed above the SAR")
alert.rule(ta.cross_down(close, sar), "SAR bearish reversal", "Price crossed below the SAR")Regime Filter
analysis · presets/analysis/trend/regime_filter.qs · uses stats/filters, viz/palette
Classifies every bar as trending, ranging or noisy (Hurst exponent + efficiency ratio from the stats/filters library), shades the background and only shows trend signals in a trend regime.
analysis "Regime Filter" {
overlay = true
}
/// Classifies every bar as trending, ranging or noisy (Hurst exponent + efficiency ratio from the
/// stats/filters library), shades the background and only shows trend signals in a trend regime.
use "stats/filters" as flt
use "viz/palette" as pal
len = param.int(100, title = "Hurst window", min = 20, max = 1000)
fast = param.int(20, title = "Fast EMA", min = 2)
slow = param.int(50, title = "Slow EMA", min = 3)
r = flt.regime(len)
f = ta.ema(close, fast)
s = ta.ema(close, slow)
render.line(f, "Fast", color = color.sky.400)
render.line(s, "Slow", color = color.orange.400)
render.background(r == flt.Regime.trend ? color.translucent(pal.BULL, 92) : r == flt.Regime.noise ? color.translucent(color.slate.500, 92) : na)
render.mark(r.tradeable() and ta.cross_up(f, s), shape = shape.arrow_up, at = anchor.below_bar, color = pal.BULL, text = "Long")
render.mark(r.tradeable() and ta.cross_down(f, s), shape = shape.arrow_down, at = anchor.above_bar, color = pal.BEAR, text = "Short")Regression Supertrend
analysis · presets/analysis/trend/regression_supertrend.qs
A supertrend built on the regression line instead of raw price. The least-squares end point of the last bars filters noise without the lag of a moving average; the ATR trailing stop then ratchets around it, and flips only when the regression value (not a single wick) crosses it. A GPU gradient fills between the stop and the regression line, coloured by trend.
analysis "Regression Supertrend" {
overlay = true
render = webgpu
short_title = "RST"
}
/// A supertrend built on the regression line instead of raw price. The least-squares end point of
/// the last bars filters noise without the lag of a moving average; the ATR trailing stop then
/// ratchets around it, and flips only when the regression value (not a single wick) crosses it.
/// A GPU gradient fills between the stop and the regression line, coloured by trend.
len = param.int(30, title = "Regression window", min = 5, max = 500)
factor = param.float(2.5, title = "ATR factor", min = 0.5, max = 10, step = 0.1)
atr_n = param.int(14, title = "ATR length", min = 1, max = 200)
(reg, slope, _) = stat.linreg(close, len, 0)
a = ta.atr(atr_n)
up0 = reg - factor * a
dn0 = reg + factor * a
persist up = na
persist dn = na
persist dir = 1
up := math.is_na(up) ? up0 : reg[1] > up ? math.max(up0, up) : up0
dn := math.is_na(dn) ? dn0 : reg[1] < dn ? math.min(dn0, dn) : dn0
if dir == 1 and reg < up { dir := -1 }
else if dir == -1 and reg > dn { dir := 1 }
stop = dir == 1 ? up : dn
p_reg = render.line(reg, "Regression", color = color.translucent(color.white, 40), width = 1)
p_up = render.line(dir == 1 ? stop : na, "Bull stop", color = color.emerald.400, width = 2)
p_dn = render.line(dir == -1 ? stop : na, "Bear stop", color = color.rose.400, width = 2)
render.band(p_reg, p_up, texture = "gradient", direction = "edges", upper_color = color.emerald.500, lower_color = color.slate.950, opacity = 0.25, title = "Bull fill")
render.band(p_dn, p_reg, texture = "gradient", direction = "edges", upper_color = color.slate.950, lower_color = color.rose.500, opacity = 0.25, title = "Bear fill")
render.candle_color(dir == 1 ? color.emerald.500 : color.rose.500)
render.mark(dir == 1 and dir[1] == -1, shape = shape.tag_up, at = anchor.below_bar, color = color.emerald.400, text = "BUY", title = "Bull flip")
render.mark(dir == -1 and dir[1] == 1, shape = shape.tag_down, at = anchor.above_bar, color = color.rose.400, text = "SELL", title = "Bear flip")
alert.rule(dir != dir[1], "Regression supertrend flip", "The regression supertrend changed direction")SuperTrend Ensemble
analysis · presets/analysis/trend/supertrend_ensemble.qs
Five supertrends with factors from tight to wide vote on the trend. The consensus (-5 .. +5) colors the candles, the tightest and widest stops are joined by a cloud, consensus flips are tagged and each trend leg is drawn as a zone.
analysis "SuperTrend Ensemble" {
overlay = true
max_objects = 200
}
/// Five supertrends with factors from tight to wide vote on the trend. The consensus (-5 .. +5)
/// colors the candles, the tightest and widest stops are joined by a cloud, consensus flips are
/// tagged and each trend leg is drawn as a zone.
base = param.float(1.0, title = "Tightest factor", min = 0.5, max = 5, step = 0.1)
gap = param.float(0.75, title = "Factor step", min = 0.1, max = 3, step = 0.05)
len = param.int(10, title = "ATR length", min = 2, max = 100)
(s1, d1) = ta.supertrend(base, len)
(s2, d2) = ta.supertrend(base + gap, len)
(s3, d3) = ta.supertrend(base + 2 * gap, len)
(s4, d4) = ta.supertrend(base + 3 * gap, len)
(s5, d5) = ta.supertrend(base + 4 * gap, len)
score = d1 + d2 + d3 + d4 + d5
bull = score > 0
render.line(s2, "Stop 2", color = color.translucent(d2 > 0 ? color.emerald.400 : color.rose.400, 55), width = 1)
render.line(s3, "Stop 3", color = color.translucent(d3 > 0 ? color.emerald.400 : color.rose.400, 45), width = 1)
render.line(s4, "Stop 4", color = color.translucent(d4 > 0 ? color.emerald.400 : color.rose.400, 35), width = 1)
p1 = render.line(s1, "Tight stop", color = d1 > 0 ? color.emerald.300 : color.rose.300, width = 2)
p5 = render.line(s5, "Wide stop", color = d5 > 0 ? color.emerald.600 : color.rose.600, width = 2.5)
render.band(p1, p5, texture = "gradient", upper_color = color.emerald.500, lower_color = color.rose.500, opacity = 0.18, title = "Ensemble cloud")
render.candle_color(color.gradient(score, -5, 5, color.rose.500, color.emerald.400))
flip_up = score == 5 and score[1] < 5
flip_dn = score == -5 and score[1] > -5
persist zid = 0.0
persist leg_hi = na
persist leg_lo = na
if flip_up or flip_dn {
leg_hi := high
leg_lo := low
zid := draw.zone.create(bar.index, high, bar.index, low, color = color.translucent(flip_up ? color.emerald.500 : color.rose.500, 88))
draw.tag.create(bar.index, flip_up ? low : high, flip_up ? "5/5 Bull" : "5/5 Bear", color = flip_up ? color.emerald.600 : color.rose.600, shape = flip_up ? shape.tag_up : shape.tag_down)
} else if zid > 0 and math.abs(score) >= 3 {
leg_hi := math.max(leg_hi, high)
leg_lo := math.min(leg_lo, low)
draw.zone.update(zid, right = bar.index, top = leg_hi, bottom = leg_lo)
}
alert.rule(flip_up, "Ensemble bullish", "All five supertrends turned up")
alert.rule(flip_dn, "Ensemble bearish", "All five supertrends turned down")Supertrend Zones
analysis · presets/analysis/trend/supertrend_zones.qs · uses viz/palette
Supertrend with a zone drawn for every trend leg: the zone spans the leg from its first bar and grows while the trend lasts, between the stop line and the leg's extreme.
analysis "Supertrend Zones" {
overlay = true
max_objects = 300
}
/// Supertrend with a zone drawn for every trend leg: the zone spans the leg from its first bar
/// and grows while the trend lasts, between the stop line and the leg's extreme.
use "viz/palette" as pal
factor = param.float(3.0, title = "Factor", min = 0.5, max = 10, step = 0.1)
len = param.int(10, title = "ATR length", min = 1, max = 100)
(st, dir) = ta.supertrend(factor, len)
bull = dir > 0
flip = dir != dir[1] and not math.is_na(dir[1])
persist zone_id = 0.0
persist leg_start = 0
persist leg_extreme = na
if flip {
leg_start := bar.index
leg_extreme := bull ? high : low
zone_id := draw.zone.create(bar.index, bull ? high : st, bar.index, bull ? st : low,
color = color.translucent(bull ? pal.BULL : pal.BEAR, 85), text = bull ? "Up leg" : "Down leg")
} else if zone_id > 0 {
leg_extreme := bull ? math.max(leg_extreme, high) : math.min(leg_extreme, low)
draw.zone.update(zone_id, right = bar.index, top = bull ? leg_extreme : na, bottom = bull ? na : leg_extreme)
}
render.line(bull ? st : na, "Bull stop", color = pal.BULL, width = 2)
render.line(bull ? na : st, "Bear stop", color = pal.BEAR, width = 2)
render.candle_color(bull ? color.emerald.600 : color.rose.600)
render.mark(flip and bull, shape = shape.tag_up, at = anchor.below_bar, color = pal.BULL, text = "Buy")
render.mark(flip and not bull, shape = shape.tag_down, at = anchor.above_bar, color = pal.BEAR, text = "Sell")
alert.rule(flip and bull, "Trend up", "Supertrend turned bullish")
alert.rule(flip and not bull, "Trend down", "Supertrend turned bearish")Supertrend
analysis · presets/analysis/trend/supertrend.qs
ATR trailing stop split into bull / bear segments, shaded towards the bar midpoint.
analysis "Supertrend" {
overlay = true
}
// ATR trailing stop split into bull / bear segments, shaded towards the bar midpoint.
factor = param.float(3.0, title = "Factor", min = 0.5, max = 10, step = 0.1)
len = param.int(10, title = "ATR length", min = 1, max = 100)
(st, dir) = ta.supertrend(factor, len)
bull = dir > 0
p_up = render.line(bull ? st : na, "Bull", color = color.emerald.500, width = 2)
p_down = render.line(bull ? na : st, "Bear", color = color.rose.500, width = 2)
p_mid = render.line(bar.mid, "Mid", color = color.transparent, width = 0)
render.band(p_up, p_mid, color = color.emerald.500, opacity = 0.14)
render.band(p_down, p_mid, color = color.rose.500, opacity = 0.14)
render.candle_color(bull ? color.emerald.500 : color.rose.500)
flip_up = bull and dir[1] < 0
flip_dn = not bull and dir[1] > 0
render.mark(flip_up, shape = shape.tag_up, at = anchor.below_bar, color = color.emerald.500, text = "Buy")
render.mark(flip_dn, shape = shape.tag_down, at = anchor.above_bar, color = color.rose.500, text = "Sell")
alert.rule(flip_up, "Supertrend bullish", "The trend turned bullish")
alert.rule(flip_dn, "Supertrend bearish", "The trend turned bearish")Trend Spectrum Heatmap
analysis · presets/analysis/trend/trend_spectrum.qs
The slope of twenty moving averages (lengths 5 .. 100) in ATR units, one heatmap row each. Green rows rise, red rows fall, brightness is the speed. A trend is healthy when the whole column agrees; the consensus row on top sums the rows and arrows mark full alignment.
analysis "Trend Spectrum Heatmap" {
pane = hpane
height = 0.25
}
/// The slope of twenty moving averages (lengths 5 .. 100) in ATR units, one heatmap row each.
/// Green rows rise, red rows fall, brightness is the speed. A trend is healthy when the whole
/// column agrees; the consensus row on top sums the rows and arrows mark full alignment.
src = param.source(close, title = "Source")
gap = param.int(5, title = "Length step", min = 1, max = 50)
look = param.int(3, title = "Slope bars", min = 1, max = 20)
a = ta.atr(50)
votes = 0
for k in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] {
e = ta.ema(src, (k + 1) * gap)
s = (e - e[look]) / math.max(a * look, 1e-12)
if s > 0 { votes := votes + 1 }
c = s >= 0 ? color.gradient(s, 0, 0.6, color.slate.800, color.emerald.300) : color.gradient(s, -0.6, 0, color.rose.400, color.slate.800)
render.line(k, str.format("Row {}", k + 1), color = c, width = 7)
}
consensus = (votes - 10) / 10
render.line(21.5, "Consensus", color = color.gradient(consensus, -1, 1, color.rose.500, color.emerald.400), width = 11)
all_up = votes == 20
all_dn = votes == 0
render.mark(all_up and not all_up[1], shape = shape.arrow_up, at = anchor.bottom, color = color.emerald.400, title = "Full uptrend")
render.mark(all_dn and not all_dn[1], shape = shape.arrow_down, at = anchor.top, color = color.rose.400, title = "Full downtrend")
alert.rule(all_up and not all_up[1], "Spectrum aligned up", "All twenty averages are rising")
alert.rule(all_dn and not all_dn[1], "Spectrum aligned down", "All twenty averages are falling")VIDYA Bands
analysis · presets/analysis/trend/vidya_bands.qs
Chande's variable index dynamic average with ATR bands. VIDYA speeds up when momentum (CMO) is strong and stalls in ranges, so its slope doubles as a trend filter: flat VIDYA = range, the bands then act as fade levels; sloped VIDYA = trend, the bands act as breakout levels.
analysis "VIDYA Bands" {
overlay = true
render = webgpu
short_title = "VIDYA"
}
/// Chande's variable index dynamic average with ATR bands. VIDYA speeds up when momentum (CMO) is
/// strong and stalls in ranges, so its slope doubles as a trend filter: flat VIDYA = range, the
/// bands then act as fade levels; sloped VIDYA = trend, the bands act as breakout levels.
len = param.int(20, title = "Length", min = 2, max = 500)
cmo = param.int(9, title = "CMO length", min = 2, max = 200)
mult = param.float(1.5, title = "Band (ATR)", min = 0.2, max = 10, step = 0.1)
v = ta.vidya(close, len, cmo)
a = ta.atr(14)
slope = (v - v[5]) / math.max(a, 1e-12)
trending = math.abs(slope) > 0.5
pu = render.line(v + mult * a, "Upper", color = color.translucent(color.violet.300, 40), width = 1)
pv = render.line(v, "VIDYA", color = trending ? (slope > 0 ? color.emerald.300 : color.rose.300) : color.amber.300, width = 2)
pd = render.line(v - mult * a, "Lower", color = color.translucent(color.violet.300, 40), width = 1)
render.band(pu, pd, color = trending ? color.indigo.500 : color.amber.500, opacity = 0.07, title = "Band")
render.mark(not trending and high > v + mult * a and close < v + mult * a, shape = shape.circle, at = anchor.above_bar, color = color.amber.300, size = 0.5, title = "Range fade high")
render.mark(not trending and low < v - mult * a and close > v - mult * a, shape = shape.circle, at = anchor.below_bar, color = color.amber.300, size = 0.5, title = "Range fade low")Zero-Lag Trend Cloud
analysis · presets/analysis/trend/zero_lag_cloud.qs
A zero-lag EMA against a regular EMA of the same length: the gap between them is the momentum the lag hides. The cloud is filled in the trend colour with an edge gradient and the crossings are marked as early trend changes.
analysis "Zero-Lag Trend Cloud" {
overlay = true
render = webgpu
short_title = "ZLC"
}
/// A zero-lag EMA against a regular EMA of the same length: the gap between them is the momentum
/// the lag hides. The cloud is filled in the trend colour with an edge gradient and the crossings
/// are marked as early trend changes.
len = param.int(34, title = "Length", min = 2, max = 500)
z = ta.zero_lag(close, len)
e = ta.ema(close, len)
up = z > e
pz = render.line(z, "Zero-lag EMA", color = up ? color.emerald.300 : color.rose.300, width = 2)
pe = render.line(e, "EMA", color = color.translucent(color.slate.300, 30), width = 1.5)
render.band(pz, pe, texture = "gradient", direction = "edges", upper_color = up ? color.emerald.500 : color.slate.900, lower_color = up ? color.slate.900 : color.rose.500, opacity = 0.3, title = "Lag cloud")
render.mark(ta.cross_up(z, e), shape = shape.triangle_up, at = anchor.below_bar, color = color.emerald.300, size = 0.6, title = "Turn up")
render.mark(ta.cross_down(z, e), shape = shape.triangle_down, at = anchor.above_bar, color = color.rose.300, size = 0.6, title = "Turn down")ZigZag Fibonacci
analysis · presets/analysis/trend/zigzag_fib.qs
ZigZag swings joined by segments; after each new swing the retracement levels of the last leg are redrawn (0.236 .. 0.786 plus 1.0 / 1.618 extensions) with price labels.
analysis "ZigZag Fibonacci" {
overlay = true
max_objects = 500
}
/// ZigZag swings joined by segments; after each new swing the retracement levels of the last leg
/// are redrawn (0.236 .. 0.786 plus 1.0 / 1.618 extensions) with price labels.
deviation = param.float(5, title = "Deviation (%)", min = 0.5, max = 50, step = 0.5)
depth = param.int(10, title = "Depth", min = 2, max = 100)
(zz, zz_offset, zz_dir) = ta.zigzag(deviation, depth)
persist prev_price = na
persist prev_bar = 0
persist last_price = na
persist last_bar = 0
persist level_lines = list.create(float)
persist level_tags = list.create(float)
new_swing = not math.is_na(zz) and (math.is_na(last_price) or zz != last_price)
if new_swing {
prev_price := last_price
prev_bar := last_bar
last_price := zz
last_bar := bar.index - zz_offset
if not math.is_na(prev_price) {
draw.segment.create(prev_bar, prev_price, last_bar, last_price, color = zz_dir > 0 ? color.emerald.400 : color.rose.400, width = 2)
// replace the previous leg's levels
for i in 0..list.size(level_lines) { draw.segment.delete(list.get(level_lines, i)) }
for i in 0..list.size(level_tags) { draw.tag.delete(list.get(level_tags, i)) }
list.clear(level_lines)
list.clear(level_tags)
span = last_price - prev_price
for f in [0.236, 0.382, 0.5, 0.618, 0.786, 1.0, 1.618] {
y = last_price - span * f
list.push(level_lines, draw.segment.create(last_bar, y, bar.index + 30, y, color = f == 0.618 ? color.amber.400 : color.slate.500, stroke = f == 0.5 ? style.dashed : style.dotted, ray = ray.right))
list.push(level_tags, draw.tag.create(bar.index + 30, y, str.format("{} {:.2f}", f, y), color = color.slate.800, shape = shape.tag, size = 0.7))
}
}
}
render.dots(zz, "Swing", color = zz_dir > 0 ? color.emerald.400 : color.rose.400, shape = shape.diamond, size = 4)