Andean Oscillator — Indie Version

Table of Contents

Andean Oscillator — Indie Version

This is a refined version of the Andean Oscillator by © alexgrover, designed specifically for the Indie platform.

The Andean Oscillator uses an online algorithm to analyze price trends through exponential envelope smoothing. This version adds structural and visual improvements for better clarity and usability.

Features:

Good for momentum and trend following strategies, this version of the Andean Oscillator has a cleaner, more usable visual structure while keeping the math of the original.

Indie script V5 source code:

# This work is licensed under the Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
# https://creativecommons.org/licenses/by-nc-sa/4.0/
# Inspired by the original concept by © alexgrover
# Indie version rewritten and enhanced by Pavel Medd
# Education purposes

# indie:lang_version = 5
from indie import indicator, param, plot, color, MutSeriesF
from indie.algorithms import Ema
from math import sqrt

# Indicator declaration and parameters
@indicator('Dynamic Andean Oscillator')
@param.int('length', default=50)  # Base length for smoothing
@param.int('sig_length', default=9, title='Signal Length')  # EMA period for signal line

# Plotting configuration
@plot.line('bull_line', title='Bullish Component', color=color.GREEN, line_width=2)
@plot.line('bear_line', title='Bearish Component', color=color.RED, line_width=2)
@plot.line(title='Signal', color=color.YELLOW, line_width=2)
@plot.columns('bull_hist', title='Bull Histogram', color=color.rgba(204, 255, 0, 0.3), base_value=0.0)
@plot.columns('bear_hist', title='Bear Histogram', color=color.rgba(246, 45, 174, 0.3), base_value=0.0)
def Main(self, length, sig_length):
    # Core smoothing coefficient for exponential update
    alpha = 2 / (length + 1)

    # Mutable time series to retain recursive envelope values
    up1 = MutSeriesF.new(self.close[0])  # Exponential smoothing of max(close, open)
    up2 = MutSeriesF.new(self.close[0] * self.close[0])  # Squared smoothing (for variance-like calc)
    dn1 = MutSeriesF.new(self.close[0])
    dn2 = MutSeriesF.new(self.close[0] * self.close[0])

    # Previous values (time index -1)
    prev_up1 = up1[1]
    prev_up2 = up2[1]
    prev_dn1 = dn1[1]
    prev_dn2 = dn2[1]

    # Recursive exponential envelope update (upper band)
    up1[0] = max(self.close[0], self.open[0], prev_up1 - (prev_up1 - self.close[0]) * alpha)
    up2[0] = max(self.close[0]**2, self.open[0]**2, prev_up2 - (prev_up2 - self.close[0]**2) * alpha)

    # Recursive exponential envelope update (lower band)
    dn1[0] = min(self.close[0], self.open[0], prev_dn1 + (self.close[0] - prev_dn1) * alpha)
    dn2[0] = min(self.close[0]**2, self.open[0]**2, prev_dn2 + (self.close[0]**2 - prev_dn2) * alpha)

    # Deviation from the envelope mean (bull/bear volatility proxy)
    bull_var = dn2[0] - dn1[0] * dn1[0]
    bear_var = up2[0] - up1[0] * up1[0]

    # Square root of variance, safely clamped to avoid math domain errors
    bull = sqrt(bull_var) if bull_var > 0 else 0.0
    bear = sqrt(bear_var) if bear_var > 0 else 0.0

    # Signal line: EMA of the max component (trend highlight)
    signal_input = MutSeriesF.new(max(bull, bear))
    signal = Ema.new(signal_input, sig_length)[0]

    # Amplitude: difference in bull/bear strengths
    amp = abs(bull - bear)

    # Colored histogram: green if bull > bear, red otherwise
    hist_green = amp if bull > bear else 0.0
    hist_red = amp if bear > bull else 0.0

    return bull, bear, signal, hist_green, hist_red