// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © AlgoAlpha //@version=6 // Inputs indicator("Stochastic Z-Score kèm xu hướng ", "Stoch Z-Score kèm xu hướng") src = input.source(hlc3, title = "Nguồn dữ liệu", group = "Calculation", tooltip = "Price series used for all calculations. Changing it alters the base values from which the Z-score and momentum are derived.") len = input.int(21, title = "Độ dài", group = "Calculation", tooltip = "Look-back period for moving averages and deviations. Higher values give smoother, slower signals; lower values make the oscillator faster and more sensitive.") hist = input.bool(false, title = "Hiển thị xu hướng", group = "Appearance", tooltip = "Toggle display of the raw, unsmoothed Z-score as columns. Useful for visualising noise layer beneath the smoothed oscillator.") green = input.color(#00ffbb, title = "Bullish Colour", group = "Appearance", tooltip = "Primary colour for bullish visual elements. Adjust for preferred palette – affects bars, fills, and labels when momentum is positive.") red = input.color(#ff1100, title = "Bearish Colour", group = "Appearance", tooltip = "Primary colour for bearish visual elements. Adjust for preferred palette – affects bars, fills, and labels when momentum is negative.") basis = ta.sma(src, len) zscore = (src - basis) / ta.stdev(src, len) stochZ = ta.stoch(zscore, zscore, zscore, len) scaledSZ= stochZ/25-2 smoothed_scaled = ta.hma(scaledSZ, len) ltm = ta.alma(zscore, len, 0, 0.1) // Plots & Visuals zscore_color = color.new(color.from_gradient(zscore, -2, 2, red, green), math.max(math.min(int((1-math.abs(zscore)/4)*100), 70), 70)) plot(zscore, color = zscore_color, linewidth = 2, display = hist ? display.all : display.none, style = plot.style_columns, title = "Z-Score") smoothed_scaled_prev = smoothed_scaled[1] smoothed_scaled_color = color.new(color.gray, smoothed_scaled > smoothed_scaled_prev ? 0 : 50) main = plot(smoothed_scaled, title = "Smoothed Oscillator", color = smoothed_scaled_color, linewidth = 3) main1 = plot(smoothed_scaled_prev, title = "Oscillator (Lag 1)", color = color.new(color.gray, smoothed_scaled > smoothed_scaled_prev ? 20 : 70), display = display.none) ltm_color = color.new(ltm > 0 ? green : red, 70) longtm = plot(ltm, title = "Long-Term Momentum (ALMA)", color = ltm_color, display = display.none) mid = plot(0, title = "Zero Line", display = display.none) upper_color = color.new(color.from_gradient(math.max(0, smoothed_scaled), 0, 2, color.gray, red), 70) lower_color = color.new(color.from_gradient(math.min(0, smoothed_scaled), -2, 0, green, color.gray), 70) u = plot(2, "Upper", upper_color, linewidth = 3) d = plot(-2, "Down", lower_color, linewidth = 3) u1 = plot(2.5, "Upper Outer", color.from_gradient(math.max(0, smoothed_scaled), 0, 2.5, color.gray, red), linewidth = 3) d1 = plot(-2.5, "Down Outer", color.from_gradient(math.min(0, smoothed_scaled), -2.5, 0, green, color.gray), linewidth = 3) plotchar(ta.cross(smoothed_scaled, smoothed_scaled_prev) ? smoothed_scaled_prev : na, "Momentum Shift", "●", location.absolute, chart.fg_color, size = size.tiny) plotchar(ta.crossover(smoothed_scaled, smoothed_scaled_prev) and ltm > 0 and smoothed_scaled_prev < -2 ? -3 : na, "Bullish Reversal", "▲", location.absolute, green, size = size.tiny) plotchar(ta.crossunder(smoothed_scaled, smoothed_scaled_prev) and ltm < 0 and smoothed_scaled_prev > 2 ? 3 : na, "Bearish Reversal", "▼", location.absolute, red, size = size.tiny) plotshape(ta.crossover(smoothed_scaled, smoothed_scaled_prev) and ltm > 0 and smoothed_scaled_prev < -2, "Bullish Trend", shape.labelup, location.belowbar, color.new(green, 50), text = "▲", textcolor = chart.fg_color, size = size.small, force_overlay = true) plotshape(ta.crossunder(smoothed_scaled, smoothed_scaled_prev) and ltm < 0 and smoothed_scaled_prev > 2, "Bearish Trend", shape.labeldown, location.abovebar, color.new(red, 50), text = "▼", textcolor = chart.fg_color, size = size.small, force_overlay = true) upper_fill_color = color.new(color.from_gradient(math.max(0, smoothed_scaled), 0, 2, chart.bg_color, red), 50) upper_fill_color_100 = color.new(color.from_gradient(math.max(0, smoothed_scaled), 0, 2, chart.bg_color, red), 100) lower_fill_color = color.new(color.from_gradient(math.min(0, smoothed_scaled), -2, 0, green, chart.bg_color), 100) lower_fill_color_50 = color.new(color.from_gradient(math.min(0, smoothed_scaled), -2, 0, green, chart.bg_color), 50) fill(u1, u, 2.5, 2, upper_fill_color, upper_fill_color_100, "Upper Fill") fill(d, d1, -2, -2.5, lower_fill_color, lower_fill_color_50, "Lower Fill") fill(main, main1, color.new(color.gray, smoothed_scaled > smoothed_scaled_prev ? 20 : 70), "Oscillator Fill") fill(longtm, mid, ltm, 0, ltm_color, color.new(ltm > 0 ? green : red, 90)) // Alerts alertcondition(ta.cross(smoothed_scaled, smoothed_scaled_prev), title = "Momentum Shift", message = "Stochastic Z-Score momentum direction changed.") alertcondition(ta.crossover(smoothed_scaled, smoothed_scaled_prev) and ltm > 0 and smoothed_scaled_prev < -2, title = "Bullish Reversal", message = "Bullish reversal detected (oscillator crosses up while long-term momentum is positive).") alertcondition(ta.crossunder(smoothed_scaled, smoothed_scaled_prev) and ltm < 0 and smoothed_scaled_prev > 2, title = "Bearish Reversal", message = "Bearish reversal detected (oscillator crosses down while long-term momentum is negative).") alertcondition(ta.crossover(smoothed_scaled, 0), title = "Oscillator Crosses Above Zero", message = "Oscillator crossed above the zero line (bullish momentum).") alertcondition(ta.crossunder(smoothed_scaled, 0), title = "Oscillator Crosses Below Zero", message = "Oscillator crossed below the zero line (bearish momentum).") alertcondition(ta.crossover(ltm, 0), title = "Long-Term Momentum Bullish", message = "Long-term momentum (ALMA) crossed above zero.") alertcondition(ta.crossunder(ltm, 0), title = "Long-Term Momentum Bearish", message = "Long-term momentum (ALMA) crossed below zero.") alertcondition(smoothed_scaled > 2.5, title = "Overbought", message = "Oscillator entered overbought zone (> 2.5).") alertcondition(smoothed_scaled < -2.5, title = "Oversold", message = "Oscillator entered oversold zone (< -2.5).")