Smooth Price Oscillator

Smooth Price Oscillator

Der Smooth Price Oscillator von BigBeluga nutzt den SuperSmoother-Filter von John Ehlers, um einen klaren und glatten Oszillator zur Identifizierung von Markttrends und mittleren Umkehrpunkten zu erzeugen. Durch das Filtern von Preisdaten über zwei unterschiedliche Zeiträume entfernt dieser Indikator effektiv Rauschen und ermöglicht es Händlern, sich auf wichtige Signale zu konzentrieren, ohne durch Marktschwankungen gestört zu werden.

Dieser Oszillator verwendet den SuperSmoother-Filter von Ehlers, der auf zwei verschiedene Perioden angewendet wird, um eine glatte Ausgabe zu erzeugen, die die Preisdynamik hervorhebt und Marktgeräusche reduziert. Die Dual-Perioden-Anwendung ermöglicht einen Vergleich langfristiger und kurzfristiger Preisbewegungen und eignet sich daher sowohl für Trendfolge- als auch für Umkehrstrategien.

Einfache Mean-Reversion-Signale: Werden ausgelöst, wenn sich der Oszillator zwischen den Schwellenwerten 1 und Überkauft oder zwischen den Schwellenwerten -1 und Überverkauft bewegt, was zusätzliche Umkehrmöglichkeiten bietet. Diese Signale sind nützlich, um kurzfristige Korrekturen in Trendmärkten zu erfassen.

Starke Mean-Reversion-Signale: Wird ausgelöst, wenn der Oszillator über dem überkauften (oberes Band) oder unter dem überverkauften (unteres Band) Schwellenwert liegt, was auf einen starken Umkehrpunkt hinweist. Zur besseren Erkennbarkeit sind diese Signale auf dem Diagramm mit einem „+“-Symbol gekennzeichnet.

Beide Arten von Signalen werden auf dem Oszillator und dem Hauptdiagramm dargestellt und helfen Händlern, potenzielle Handelseinstiege oder -ausstiege schnell zu erkennen.

Dynamische Bänder und Schwellenwerte:
Der Oszillator umfasst überkaufte und überverkaufte Bänder basierend auf einer dynamisch berechneten Standardabweichung und einem EMA. Diese Bänder bieten visuelle Grenzen zur Identifizierung extremer Preisbedingungen und helfen Händlern, potenzielle Umkehrungen auf diesen Niveaus vorherzusagen.
Schnappschüsse

Echtzeit-Beschriftungen:
An wichtigen Schwellenwerten und Bändern werden Beschriftungen angezeigt, um den Status des Oszillators anzuzeigen: „Überkauft“, „Überverkauft“ und „Neutral“. Mean-Reversion-Signale werden auch auf dem Hauptdiagramm angezeigt und bieten einen Überblick über die aktuellen Indikatorbedingungen auf einen Blick.
Schnappschüsse

Anpassbare Schwellenwerte:
Händler können den primären Schwellenwert und die Glättungslänge entsprechend ihrem Handelsstil anpassen. Ein höherer Schwellenwert kann die Signalfrequenz verringern, während eine niedrigere Einstellung eine größere Empfindlichkeit gegenüber Marktumkehrungen bietet.

Der Smooth Price Oscillator von BigBeluga ist ein verfeinerter, rauschgefilterter Indikator, der die mittleren Umkehrpunkte klarer hervorhebt. Durch die Bereitstellung sowohl starker als auch einfacher Umkehrsignale sowie dynamischer Überkauft-/Überverkauft-Bänder ermöglicht dieses Tool es Händlern, potenzielle Umkehrungen und Trendfortsetzungen problemlos zu erkennen. Seine doppelte Darstellung auf dem Oszillator und dem Hauptpreisdiagramm bietet Flexibilität und Präzision für jede Handelsstrategie, die sich auf die Erfassung zyklischer Marktbewegungen konzentriert.

// This work is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
// https://creativecommons.org/licenses/by-nc-sa/4.0/
// © BigBeluga

//@version=5
indicator("Smooth Price Oscillator [BigBeluga]")

// INPUTS ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{
// Input variables for length and threshold
int    len_smooth   = input.int(20, "Smoothing Length")
float  threshold    = input.float(1, "Threshold", step = 0.1)

// Length for calculating standard deviation
int    len_std      = 50

// Create an array to store standard deviation values
float[] std_array   = array.new<float>(len_std)
// }


// FUNCTIONS ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{
// @function SuperSmoother filter based on Ehlers Filter
// @param price (float) The price series to be smoothed
// @param period (int) The smoothing period
// @returns [float] Smoothed price
method smoother_F(float price, int period) =>
    float step     = 2.0 * math.pi / period
    float a1       = math.exp(-math.sqrt(2) * math.pi / period)
    float b1       = 2 * a1 * math.cos(math.sqrt(2) * step / period)
    float c2       = b1
    float c3       = -a1 * a1
    float c1       = 1 - c2 - c3
    float smoothed = 0.0
    smoothed := bar_index >= 4
                 ? c1 * (price + price[1]) / 2 + c2 * smoothed[1] + c3 * smoothed[2]
                 : price
    smoothed
// }


// CALCULATIONS――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{
// Smoothing lines using the SuperSmoother function
float line_long     = close.smoother_F(len_smooth * 2)
float line_short    = close.smoother_F(len_smooth)

// Oscillator calculation
float oscillator    = line_short - line_long

// Standard deviation for the oscillator
float stdev_osc     = ta.stdev(oscillator, len_std)

// Populate standard deviation values into the array
for int i = 0 to len_std - 1
    array.set(std_array, i, stdev_osc[i])

// Shift array if size exceeds len_std
if array.size(std_array) >= len_std
    array.shift(std_array)

// Normalize the oscillator using the maximum value from the standard deviation array
float normalized_osc = ta.hma(oscillator / array.max(std_array), 30)

// Bands for the oscillator
float basis          =    ta.ema(normalized_osc, 250)
float deviation      =    2 * ta.stdev(normalized_osc, 250)
float upper_band     =    basis + deviation
float lower_band     =    basis - deviation
// }


// PLOT―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{
// Plot the upper and lower bands
plot(upper_band, color = color.gray, editable = false)
plot(lower_band, color = color.gray, editable = false)

// Plot horizontal lines and fill regions
p1   =   plot(threshold,  color = #787b867e,  editable = false)
p_1  =   plot(-threshold, color = #787b867e,  editable = false)
p0   =   plot(0,          color = color.gray, editable = false)
p4   =   plot(4,  display = display.none,       editable = false)
p_4  =   plot(-4, display = display.none,       editable = false)

plot_osc = plot(normalized_osc, color = chart.fg_color, editable = false)

// Fill bands
fill(p0, p1, threshold, 0, na, color.new(#278ed3, 70), editable = false)
fill(p0, p_1, 0, -threshold, color.new(#278ed3, 70), na, editable = false)
fill(p_1, p_4, -threshold, -4, na, color.new(color.aqua, 70), editable = false)
fill(p1, p4, 4, threshold, color.new(color.orange, 70), na, editable = false)
fill(p0, plot_osc, normalized_osc, 0, normalized_osc > 0 ? color.aqua : na, na, editable = false)
fill(p0, plot_osc, normalized_osc, 0, normalized_osc < 0 ? color.orange : na, na, editable = false)
// }


// SIGNALS―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{
// Buy/Sell signal conditions
bool signal_up = normalized_osc <-threshold and ta.crossover(normalized_osc, normalized_osc[1])
bool signal_dn = normalized_osc > threshold and ta.crossover(normalized_osc[1], normalized_osc)

// Remove old labels and create new labels for threshold values
if barstate.islast
    label.delete(
                 label.new(
                         bar_index, threshold, "+" + str.tostring(threshold),
                         color      = color(na),
                         textcolor  = chart.fg_color,
                         style      = label.style_label_left
                         )[1]
                 )

    label.delete(
                 label.new(
                         bar_index, -threshold, str.tostring(-threshold),
                         color      = color(na),
                         textcolor  = chart.fg_color,
                         style      = label.style_label_left
                         )[1]
                 )

    label.delete(
                 label.new(
                         bar_index, 0, "Neutral",
                         color      = color(na),
                         textcolor  = color.gray,
                         style      = label.style_label_left
                         )[1]
                 )

    label.delete(
                 label.new(
                         bar_index, upper_band, "Overbought",
                         color      = color(na),
                         textcolor  = color.orange,
                         style      = label.style_label_left
                         )[1]
                 )

    label.delete(
                 label.new(
                         bar_index, lower_band, "Oversold",
                         color      = color(na),
                         textcolor  = color.aqua,
                         style      = label.style_label_left
                         )[1]
                 )

// Plot chart signals for mean reversion
plotshape(signal_dn and normalized_osc < upper_band,
         location      = location.abovebar,
         style         = shape.xcross,
         size          = size.tiny,
         text          = "↷",
         textcolor     = chart.fg_color,
         color         = color.orange,
         title         = "Mean Reversion Down",
         force_overlay = true
     )

plotshape(signal_dn and normalized_osc > upper_band,
         location      = location.abovebar,
         style         = shape.xcross,
         size          = size.tiny,
         text          = "+\n↷",
         textcolor     = chart.fg_color,
         color         = color.orange,
         title         = "Strong Mean Reversion Down",
         force_overlay = true
     )

plotshape(signal_up and normalized_osc < lower_band,
         location      = location.belowbar,
         style         = shape.circle,
         size          = size.tiny,
         text          = "⤻\n+",
         textcolor     = chart.fg_color,
         color         = color.aqua,
         title         = "Strong Mean Reversion Up",
         force_overlay = true
     )

plotshape(signal_up and normalized_osc > lower_band,
         location      = location.belowbar,
         style         = shape.circle,
         size          = size.tiny,
         text          = "⤻",
         textcolor     = chart.fg_color,
         color         = color.aqua,
         title         = "Mean Reversion Up",
         force_overlay = true
     )

// Plot oscillator signals at exact levels
plotshape(
         series        = signal_up ? normalized_osc[1] : na,
         title         = "",
         style         = shape.circle,
         location      = location.absolute,
         size          = size.tiny,
         color         = color.aqua,
         force_overlay = false,
         offset        = -1
     )


plotshape(
         series        = signal_dn ? normalized_osc[1] : na,
         title         = "",
         style         = shape.xcross,
         location      = location.absolute,
         size          = size.tiny,
         color         = color.orange,
         force_overlay = false,
         offset        = -1
     )
// }