Indicator · Pine Script v6 · On the chart

MA Cascade Engine [WavesUnchained]

by casoon

Calculates and plots a three-tiered moving average framework consisting of Fast, Base, and Anchor curves directly on the price chart.

View on GitHub

GitHub stars9on the repository
Pine versionv6current
Lines of code1,926
Settings40inputs
LicenceMIT
Last updateyesterday27 Oct 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

1,926 lines of Pine Script v6 from indicators/trend_direction/ma_cascade_engine/ma_cascade_engine.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

ma_cascade_engine.pine
//@version=6
// ============================================================================
// MA Cascade Engine [WavesUnchained]
// Version: 1.5.0
// Author: WavesUnchained
// Build: 2026-10-02
// ============================================================================
// Moving averages are not treated as isolated crossover signals.
//
// Architecture:
//   1. Visual Layer     - Fast, Base and Anchor curves
//   2. Feature Layer    - Direction, slope, curvature, separation,
//                         extension, cross frequency and MA respect
//   3. State Layer      - Expansion, pullback, compression,
//                         transition and overextension
//   4. Decision Layer   - Permission, setup, trigger, weakness and exit
//
// Important:
//   The included JMA is an open Jurik-style approximation. It is not the
//   proprietary original Jurik Moving Average implementation.
// ============================================================================

indicator(
     "MA Cascade Engine [WavesUnchained]",
     shorttitle = "MA Cascade",
     overlay = true,
     max_labels_count = 500
)

// ============================================================================
// CONSTANTS
// ============================================================================

int STATE_BULL_EXPANSION = 1
int STATE_BULL_PULLBACK  = 2
int STATE_NEUTRAL        = 3
int STATE_BEAR_PULLBACK  = 4
int STATE_BEAR_EXPANSION = 5
int STATE_OVEREXTENDED   = 6
int STATE_TRANSITION     = 7

// ============================================================================
// INPUT GROUPS
// ============================================================================

string GROUP_PRESET     = "01. Moving Average Preset"
string GROUP_CUSTOM     = "02. Custom Moving Averages"
string GROUP_SLOPE      = "03. Slope and Curvature"
string GROUP_STRUCTURE  = "04. Structure and Extension"
string GROUP_RESPECT    = "05. MA Respect"
string GROUP_SIGNALS    = "06. Signals"
string GROUP_SCORE      = "07. Score"
string GROUP_VISUAL     = "08. Visualisation"

// ============================================================================
// PRESET INPUTS
// ============================================================================

string presetInput = input.string(
     "Balanced",
     "Preset",
     options = [
         "Responsive",
         "Balanced",
         "Structural",
         "Custom"
     ],
     group = GROUP_PRESET
)

series float sourceInput = input.source(
     close,
     "Source",
     group = GROUP_PRESET
)

int jmaPhaseInput = input.int(
     0,
     "JMA Phase",
     minval = -100,
     maxval = 100,
     tooltip = "Controls the responsiveness and possible overshoot of the Jurik-style approximation.",
     group = GROUP_PRESET
)

float jmaPowerInput = input.float(
     2.0,
     "JMA Power",
     minval = 1.0,
     maxval = 8.0,
     step = 0.1,
     group = GROUP_PRESET
)

// ============================================================================
// CUSTOM MA INPUTS
// ============================================================================

string customFastTypeInput = input.string(
     "JMA",
     "Fast Type",
     options = [
         "JMA",
         "EMA",
         "SMA",
         "RMA",
         "WMA",
         "HMA",
         "DEMA",
         "KAMA"
     ],
     group = GROUP_CUSTOM
)

int customFastLengthInput = input.int(
     21,
     "Fast Length",
     minval = 1,
     group = GROUP_CUSTOM
)

string customBaseTypeInput = input.string(
     "EMA",
     "Base Type",
     options = [
         "JMA",
         "EMA",
         "SMA",
         "RMA",
         "WMA",
         "HMA",
         "DEMA",
         "KAMA"
     ],
     group = GROUP_CUSTOM
)

int customBaseLengthInput = input.int(
     50,
     "Base Length",
     minval = 1,
     group = GROUP_CUSTOM
)

string customAnchorTypeInput = input.string(
     "SMA",
     "Anchor Type",
     options = [
         "JMA",
         "EMA",
         "SMA",
         "RMA",
         "WMA",
         "HMA",
         "DEMA",
         "KAMA"
     ],
     group = GROUP_CUSTOM
)

int customAnchorLengthInput = input.int(
     200,
     "Anchor Length",
     minval = 2,
     group = GROUP_CUSTOM
)

// ============================================================================
// SLOPE AND CURVATURE INPUTS
// ============================================================================

int atrLengthInput = input.int(
     14,
     "ATR Length",
     minval = 2,
     group = GROUP_SLOPE
)

int slopeLookbackInput = input.int(
     5,
     "Slope Lookback",
     minval = 1,
     maxval = 100,
     group = GROUP_SLOPE
)

float minimumFastSlopeInput = input.float(
     0.015,
     "Minimum Fast Slope per Bar",
     minval = 0.0,
     step = 0.005,
     tooltip = "ATR-normalised minimum slope per bar required for a trigger.",
     group = GROUP_SLOPE
)

float minimumBaseSlopeInput = input.float(
     0.008,
     "Minimum Base Slope per Bar",
     minval = 0.0,
     step = 0.001,
     tooltip = "ATR-normalised minimum slope per bar required for a directional regime.",
     group = GROUP_SLOPE
)

int curvatureLookbackInput = input.int(
     3,
     "Curvature Lookback",
     minval = 1,
     maxval = 50,
     group = GROUP_SLOPE
)

float minimumCurvatureInput = input.float(
     0.005,
     "Minimum Trigger Curvature",
     minval = 0.0,
     step = 0.001,
     group = GROUP_SLOPE
)

// ============================================================================
// STRUCTURE INPUTS
// ============================================================================

float entanglementSpreadInput = input.float(
     0.15,
     "Entanglement Spread",
     minval = 0.01,
     step = 0.01,
     tooltip = "If both MA separations are smaller than this ATR value, the averages are considered entangled.",
     group = GROUP_STRUCTURE
)

int crossFrequencyLookbackInput = input.int(
     30,
     "Cross Frequency Lookback",
     minval = 5,
     maxval = 300,
     group = GROUP_STRUCTURE
)

int maximumCrossesInput = input.int(
     6,
     "Maximum Crosses",
     minval = 1,
     maxval = 50,
     tooltip = "Maximum permitted price/Base-MA crossings within the lookback.",
     group = GROUP_STRUCTURE
)

float pullbackDistanceInput = input.float(
     0.70,
     "Maximum Pullback Distance",
     minval = 0.05,
     step = 0.05,
     tooltip = "Maximum ATR distance from the Base MA for a Long/Short Setup. Applies to setups only — the Bull/Bear Pullback states are not gated by it.",
     group = GROUP_STRUCTURE
)

float pullbackSpreadInput = input.float(
     0.75,
     "Maximum Fast/Base Pullback Spread",
     minval = 0.05,
     step = 0.05,
     group = GROUP_STRUCTURE
)

float maximumExtensionInput = input.float(
     1.75,
     "Maximum Price Extension",
     minval = 0.25,
     step = 0.05,
     tooltip = "Price distance from the Fast MA in ATR units after which new entries are blocked.",
     group = GROUP_STRUCTURE
)

float extremeVolatilityRatioInput = input.float(
     1.80,
     "Extreme Volatility Ratio",
     minval = 1.0,
     step = 0.05,
     tooltip = "Current ATR divided by its long-term average ATR.",
     group = GROUP_STRUCTURE
)

int volatilityBaselineInput = input.int(
     100,
     "Volatility Baseline",
     minval = 20,
     maxval = 500,
     group = GROUP_STRUCTURE
)

// ============================================================================
// MA RESPECT INPUTS
// ============================================================================

bool useRespectInput = input.bool(
     true,
     "Use Base Respect in Score",
     group = GROUP_RESPECT
)

bool useAnchorRespectInput = input.bool(
     true,
     "Use Anchor Respect in Score",
     group = GROUP_RESPECT
)

float touchToleranceInput = input.float(
     0.15,
     "Touch Tolerance",
     minval = 0.01,
     step = 0.01,
     tooltip = "ATR tolerance around the Base and Anchor MA.",
     group = GROUP_RESPECT
)

int reactionBarsInput = input.int(
     5,
     "Reaction Horizon",
     minval = 1,
     maxval = 30,
     tooltip = "Number of bars after a touch at which the reaction is evaluated.",
     group = GROUP_RESPECT
)

float reactionMoveInput = input.float(
     0.50,
     "Required Reaction Move",
     minval = 0.05,
     step = 0.05,
     tooltip = "Required move away from the Base or Anchor MA in ATR units.",
     group = GROUP_RESPECT
)

float respectInvalidationInput = input.float(
     0.35,
     "Respect Invalidation",
     minval = 0.05,
     step = 0.05,
     tooltip = "Maximum adverse penetration through the Base or Anchor MA in ATR units.",
     group = GROUP_RESPECT
)

int respectLookbackInput = input.int(
     150,
     "Respect Statistics Lookback",
     minval = 20,
     maxval = 1000,
     group = GROUP_RESPECT
)

// ============================================================================
// SIGNAL INPUTS
// ============================================================================

bool requirePriceConfirmationInput = input.bool(
     true,
     "Require Previous-Bar Break",
     tooltip = "Long triggers must close above the previous high; short triggers below the previous low.",
     group = GROUP_SIGNALS
)

bool requireCurvatureInput = input.bool(
     true,
     "Require Positive Trigger Curvature",
     group = GROUP_SIGNALS
)

bool showPermissionSignalsInput = input.bool(
     false,
     "Show Permission Changes",
     group = GROUP_SIGNALS
)

bool showReactivationSignalsInput = input.bool(
     true,
     "Show Reactivation Signals",
     group = GROUP_SIGNALS
)

bool showAnchorRejectionSignalsInput = input.bool(
     true,
     "Show Anchor Rejection Signals",
     tooltip = "Confirmed bounce off the Anchor MA: price approached from the reaction side, touched it without also touching the Base MA, then moved away and held for the Reaction Horizon.",
     group = GROUP_SIGNALS
)

bool showExitSignalsInput = input.bool(
     false,
     "Show Exit Signals",
     group = GROUP_SIGNALS
)

// ============================================================================
// SCORE INPUTS
// ============================================================================

float strongBiasThresholdInput = input.float(
     60.0,
     "Strong Bias Threshold",
     minval = 25.0,
     maxval = 100.0,
     step = 1.0,
     group = GROUP_SCORE
)

float directionalBiasThresholdInput = input.float(
     25.0,
     "Directional Bias Threshold",
     minval = 5.0,
     maxval = 75.0,
     step = 1.0,
     group = GROUP_SCORE
)

// ============================================================================
// VISUAL INPUTS
// ============================================================================

bool showFastInput = input.bool(
     true,
     "Show Fast Curve",
     group = GROUP_VISUAL
)

bool showBaseInput = input.bool(
     true,
     "Show Base Curve",
     group = GROUP_VISUAL
)

bool showAnchorInput = input.bool(
     true,
     "Show Anchor Curve",
     group = GROUP_VISUAL
)

bool colourCurvesBySlopeInput = input.bool(
     true,
     "Colour Curves by Slope",
     group = GROUP_VISUAL
)

bool showStateBackgroundInput = input.bool(
     false,
     "Show State Background",
     group = GROUP_VISUAL
)

bool showBarColoursInput = input.bool(
     false,
     "Colour Price Bars",
     group = GROUP_VISUAL
)

bool showStatusLabelInput = input.bool(
     true,
     "Show Right-Side Status",
     tooltip = "Small state-coloured marker to the right of price. Hover it for the full readout (state, bias, score, permission, setup, MA respect, preset).",
     group = GROUP_VISUAL
)

int statusOffsetInput = input.int(
     10,
     "Status Horizontal Offset",
     minval = 0,
     maxval = 50,
     group = GROUP_VISUAL
)

float statusVerticalOffsetInput = input.float(
     0.30,
     "Status Vertical Offset in ATR",
     minval = -5.0,
     maxval = 5.0,
     step = 0.10,
     group = GROUP_VISUAL
)

// ============================================================================
// UTILITY FUNCTIONS
// ============================================================================

f_clamp(float value, float minimum, float maximum) =>
    math.max(minimum, math.min(maximum, value))

f_safeDivide(float numerator, float denominator) =>
    denominator != 0.0 ? numerator / denominator : 0.0

f_sign(float value) =>
    value > 0.0 ? 1.0 : value < 0.0 ? -1.0 : 0.0

// Open Jurik-style approximation.
// This is not the proprietary original JMA.
f_jma(series float source, int length, int phase, float power) =>
    float safeLength = math.max(length, 1)

    float phaseRatio =
         phase < -100 ? 0.5 :
         phase > 100  ? 2.5 :
         phase / 100.0 + 1.5

    float beta =
         0.45 * (safeLength - 1.0) /
         (0.45 * (safeLength - 1.0) + 2.0)

    float alpha = math.pow(beta, power)

    var float e0 = na
    var float e1 = na
    var float e2 = na
    var float result = na

    e0 := (1.0 - alpha) * source + alpha * nz(e0[1], source)
    e1 := (source - e0) * (1.0 - beta) + beta * nz(e1[1], 0.0)

    e2 :=
         (
             e0 +
             phaseRatio * e1 -
             nz(result[1], source)
         ) *
         math.pow(1.0 - alpha, 2.0) +
         math.pow(alpha, 2.0) *
         nz(e2[1], 0.0)

    result := e2 + nz(result[1], source)
    result

f_dema(series float source, int length) =>
    float emaOne = ta.ema(source, length)
    float emaTwo = ta.ema(emaOne, length)
    2.0 * emaOne - emaTwo

f_kama(series float source, int length) =>
    float fastSc = 2.0 / (2.0 + 1.0)
    float slowSc = 2.0 / (30.0 + 1.0)

    float change = math.abs(source - source[length])
    float volatility = ta.sma(math.abs(source - source[1]), length) * length

    float efficiencyRatio = f_safeDivide(change, volatility)
    float smoothingConstant = math.pow(efficiencyRatio * (fastSc - slowSc) + slowSc, 2.0)

    var float result = na
    result := nz(result[1], source) + smoothingConstant * (source - nz(result[1], source))
    result

f_ma(
     series float source,
     int length,
     string maType,
     int jmaPhase,
     float jmaPower
 ) =>
    switch maType
        "JMA"  => f_jma(source, length, jmaPhase, jmaPower)
        "EMA"  => ta.ema(source, length)
        "SMA"  => ta.sma(source, length)
        "RMA"  => ta.rma(source, length)
        "WMA"  => ta.wma(source, length)
        "HMA"  => ta.hma(source, length)
        "DEMA" => f_dema(source, length)
        "KAMA" => f_kama(source, length)
        => ta.ema(source, length)

f_slopeColour(float slope) =>
    slope > 0.0 ? color.lime :
     slope < 0.0 ? color.red :
     color.gray

// ============================================================================
// PRESET RESOLUTION
// ============================================================================

string fastType =
     presetInput == "Responsive" ? "JMA" :
     presetInput == "Balanced"   ? "JMA" :
     presetInput == "Structural" ? "EMA" :
     customFastTypeInput

int fastLength =
     presetInput == "Responsive" ? 9 :
     presetInput == "Balanced"   ? 21 :
     presetInput == "Structural" ? 20 :
     customFastLengthInput

string baseType =
     presetInput == "Responsive" ? "JMA" :
     presetInput == "Balanced"   ? "EMA" :
     presetInput == "Structural" ? "SMA" :
     customBaseTypeInput

int baseLength =
     presetInput == "Responsive" ? 21 :
     presetInput == "Balanced"   ? 50 :
     presetInput == "Structural" ? 50 :
     customBaseLengthInput

string anchorType =
     presetInput == "Responsive" ? "JMA" :
     presetInput == "Balanced"   ? "SMA" :
     presetInput == "Structural" ? "SMA" :
     customAnchorTypeInput

int anchorLength =
     presetInput == "Responsive" ? 50 :
     presetInput == "Balanced"   ? 200 :
     presetInput == "Structural" ? 200 :
     customAnchorLengthInput

// ============================================================================
// MOVING AVERAGES
// ============================================================================

float fastMa = f_ma(
     sourceInput,
     fastLength,
     fastType,
     jmaPhaseInput,
     jmaPowerInput
)

float baseMa = f_ma(
     sourceInput,
     baseLength,
     baseType,
     jmaPhaseInput,
     jmaPowerInput
)

float anchorMa = f_ma(
     sourceInput,
     anchorLength,
     anchorType,
     jmaPhaseInput,
     jmaPowerInput
)

// ============================================================================
// VOLATILITY NORMALISATION
// ============================================================================

float atr = ta.atr(atrLengthInput)
float safeAtr = math.max(atr, syminfo.mintick)

float atrBaseline = ta.sma(atr, volatilityBaselineInput)
float volatilityRatio = f_safeDivide(atr, atrBaseline)

bool extremeVolatility =
     not na(volatilityRatio) and
     volatilityRatio >= extremeVolatilityRatioInput

// ============================================================================
// DIRECTION
// ============================================================================

bool bullishOrder =
     fastMa > baseMa and
     baseMa > anchorMa

bool bearishOrder =
     fastMa < baseMa and
     baseMa < anchorMa

bool priceAboveFast = close > fastMa
bool priceBelowFast = close < fastMa
bool priceAboveBase = close > baseMa
bool priceBelowBase = close < baseMa

// ============================================================================
// ATR-NORMALISED SLOPE
// ============================================================================

float fastSlope =
     f_safeDivide(
         fastMa - fastMa[slopeLookbackInput],
         safeAtr * slopeLookbackInput
     )

float baseSlope =
     f_safeDivide(
         baseMa - baseMa[slopeLookbackInput],
         safeAtr * slopeLookbackInput
     )

float anchorSlope =
     f_safeDivide(
         anchorMa - anchorMa[slopeLookbackInput],
         safeAtr * slopeLookbackInput
     )

bool fastRising = fastSlope > minimumFastSlopeInput
bool fastFalling = fastSlope < -minimumFastSlopeInput

bool baseRising = baseSlope > minimumBaseSlopeInput
bool baseFalling = baseSlope < -minimumBaseSlopeInput

// ============================================================================
// CURVATURE
// ============================================================================

float fastCurvature =
     fastSlope -
     fastSlope[curvatureLookbackInput]

float baseCurvature =
     baseSlope -
     baseSlope[curvatureLookbackInput]

bool bullishCurvature =
     fastCurvature > minimumCurvatureInput

bool bearishCurvature =
     fastCurvature < -minimumCurvatureInput

// ============================================================================
// SEPARATION
// ============================================================================

float fastBaseSpread =
     f_safeDivide(fastMa - baseMa, safeAtr)

float baseAnchorSpread =
     f_safeDivide(baseMa - anchorMa, safeAtr)

float absoluteFastBaseSpread = math.abs(fastBaseSpread)
float absoluteBaseAnchorSpread = math.abs(baseAnchorSpread)

float fastBaseSpreadChange =
     fastBaseSpread -
     fastBaseSpread[1]

float baseAnchorSpreadChange =
     baseAnchorSpread -
     baseAnchorSpread[1]

bool bullishSpreadExpansion =
     fastBaseSpread > 0.0 and
     baseAnchorSpread > 0.0 and
     fastBaseSpreadChange > 0.0 and
     baseAnchorSpreadChange > 0.0

bool bearishSpreadExpansion =
     fastBaseSpread < 0.0 and
     baseAnchorSpread < 0.0 and
     fastBaseSpreadChange < 0.0 and
     baseAnchorSpreadChange < 0.0

bool fastBaseCompression =
     absoluteFastBaseSpread <
     absoluteFastBaseSpread[1]

bool baseAnchorCompression =
     absoluteBaseAnchorSpread <
     absoluteBaseAnchorSpread[1]

bool spreadCompression =
     fastBaseCompression or
     baseAnchorCompression

// ============================================================================
// PRICE EXTENSION
// ============================================================================

float priceExtension =
     f_safeDivide(close - fastMa, safeAtr)

float priceBaseDistance =
     f_safeDivide(close - baseMa, safeAtr)

bool bullishOverextension =
     priceExtension > maximumExtensionInput

bool bearishOverextension =
     priceExtension < -maximumExtensionInput

// ============================================================================
// CROSS FREQUENCY AND ENTANGLEMENT
// ============================================================================

bool priceBaseCross =
     ta.cross(close, baseMa)

bool fastBaseCross =
     ta.cross(fastMa, baseMa)

float priceBaseCrossCount =
     ta.sma(
         priceBaseCross ? 1.0 : 0.0,
         crossFrequencyLookbackInput
     ) * crossFrequencyLookbackInput

float fastBaseCrossCount =
     ta.sma(
         fastBaseCross ? 1.0 : 0.0,
         crossFrequencyLookbackInput
     ) * crossFrequencyLookbackInput

float combinedCrossCount =
     priceBaseCrossCount +
     fastBaseCrossCount

bool spreadEntanglement =
     absoluteFastBaseSpread < entanglementSpreadInput and
     absoluteBaseAnchorSpread < entanglementSpreadInput

bool crossEntanglement =
     combinedCrossCount >= maximumCrossesInput

bool flatEntanglement =
     math.abs(fastSlope) < minimumFastSlopeInput and
     math.abs(baseSlope) < minimumBaseSlopeInput

bool entangled =
     spreadEntanglement or
     crossEntanglement or
     (
         flatEntanglement and
         absoluteFastBaseSpread <
         entanglementSpreadInput * 1.5
     )

// ============================================================================
// MA RESPECT
// ============================================================================

bool touchedBase =
     low <= baseMa + touchToleranceInput * safeAtr and
     high >= baseMa - touchToleranceInput * safeAtr

// One sample per touch episode: only the first bar of a run of touching bars
// is logged, so a multi-bar hug of the line counts once, not once per bar.
bool baseTouchStart =
     touchedBase and
     not touchedBase[1]

bool eligibleHistoricTouch =
     baseTouchStart[reactionBarsInput]

// Approach side: the bar before the touch episode closed above (bullish) or
// below (bearish) the MA. A move through the line from the other side is a
// breakout, not a bounce, and is never logged as respect.
bool baseApproachFromAbove =
     close[1] > baseMa[1]

bool baseApproachFromBelow =
     close[1] < baseMa[1]

bool historicBaseApproachFromAbove =
     baseApproachFromAbove[reactionBarsInput]

bool historicBaseApproachFromBelow =
     baseApproachFromBelow[reactionBarsInput]

float historicTouchBase =
     baseMa[reactionBarsInput]

float historicTouchAtr =
     safeAtr[reactionBarsInput]

float reactionPeriodLow =
     ta.lowest(low, reactionBarsInput + 1)

float reactionPeriodHigh =
     ta.highest(high, reactionBarsInput + 1)

bool bullishRespectSuccess =
     eligibleHistoricTouch and
     historicBaseApproachFromAbove and
     close >=
         historicTouchBase +
         reactionMoveInput *
         historicTouchAtr and
     reactionPeriodLow >=
         historicTouchBase -
         respectInvalidationInput *
         historicTouchAtr

bool bearishRespectSuccess =
     eligibleHistoricTouch and
     historicBaseApproachFromBelow and
     close <=
         historicTouchBase -
         reactionMoveInput *
         historicTouchAtr and
     reactionPeriodHigh <=
         historicTouchBase +
         respectInvalidationInput *
         historicTouchAtr

float validTouchCount =
     ta.sma(
         eligibleHistoricTouch ? 1.0 : 0.0,
         respectLookbackInput
     ) * respectLookbackInput

float bullishRespectCount =
     ta.sma(
         bullishRespectSuccess ? 1.0 : 0.0,
         respectLookbackInput
     ) * respectLookbackInput

float bearishRespectCount =
     ta.sma(
         bearishRespectSuccess ? 1.0 : 0.0,
         respectLookbackInput
     ) * respectLookbackInput

float bullishRespectRate =
     validTouchCount > 0.0 ?
         bullishRespectCount /
         validTouchCount :
         0.0

float bearishRespectRate =
     validTouchCount > 0.0 ?
         bearishRespectCount /
         validTouchCount :
         0.0

float directionalRespect =
     bullishRespectRate -
     bearishRespectRate

// ============================================================================
// ANCHOR RESPECT
// ============================================================================

bool touchedAnchor =
     low <= anchorMa + touchToleranceInput * safeAtr and
     high >= anchorMa - touchToleranceInput * safeAtr

bool anchorTouchStart =
     touchedAnchor and
     not touchedAnchor[1]

// An Anchor touch that also touches the Base MA is the same touch already
// logged by Base Respect — only Anchor-only touches are counted here.
bool anchorOnlyTouchStart =
     anchorTouchStart and
     not touchedBase

bool eligibleHistoricAnchorTouch =
     anchorOnlyTouchStart[reactionBarsInput]

bool anchorApproachFromAbove =
     close[1] > anchorMa[1]

bool anchorApproachFromBelow =
     close[1] < anchorMa[1]

bool historicAnchorApproachFromAbove =
     anchorApproachFromAbove[reactionBarsInput]

bool historicAnchorApproachFromBelow =
     anchorApproachFromBelow[reactionBarsInput]

float historicTouchAnchor =
     anchorMa[reactionBarsInput]

float historicTouchAnchorAtr =
     safeAtr[reactionBarsInput]

bool bullishAnchorRespectSuccess =
     eligibleHistoricAnchorTouch and
     historicAnchorApproachFromAbove and
     close >=
         historicTouchAnchor +
         reactionMoveInput *
         historicTouchAnchorAtr and
     reactionPeriodLow >=
         historicTouchAnchor -
         respectInvalidationInput *
         historicTouchAnchorAtr

bool bearishAnchorRespectSuccess =
     eligibleHistoricAnchorTouch and
     historicAnchorApproachFromBelow and
     close <=
         historicTouchAnchor -
         reactionMoveInput *
         historicTouchAnchorAtr and
     reactionPeriodHigh <=
         historicTouchAnchor +
         respectInvalidationInput *
         historicTouchAnchorAtr

float validAnchorTouchCount =
     ta.sma(
         eligibleHistoricAnchorTouch ? 1.0 : 0.0,
         respectLookbackInput
     ) * respectLookbackInput

float bullishAnchorRespectCount =
     ta.sma(
         bullishAnchorRespectSuccess ? 1.0 : 0.0,
         respectLookbackInput
     ) * respectLookbackInput

float bearishAnchorRespectCount =
     ta.sma(
         bearishAnchorRespectSuccess ? 1.0 : 0.0,
         respectLookbackInput
     ) * respectLookbackInput

float bullishAnchorRespectRate =
     validAnchorTouchCount > 0.0 ?
         bullishAnchorRespectCount /
         validAnchorTouchCount :
         0.0

float bearishAnchorRespectRate =
     validAnchorTouchCount > 0.0 ?
         bearishAnchorRespectCount /
         validAnchorTouchCount :
         0.0

float directionalAnchorRespect =
     bullishAnchorRespectRate -
     bearishAnchorRespectRate

// ============================================================================
// REGIME
// ============================================================================

bool longRegime =
     baseMa > anchorMa and
     baseSlope > minimumBaseSlopeInput

bool shortRegime =
     baseMa < anchorMa and
     baseSlope < -minimumBaseSlopeInput

// Permission describes direction, not entry timing.
bool longPermission =
     longRegime and
     not entangled and
     not bullishOverextension

bool shortPermission =
     shortRegime and
     not entangled and
     not bearishOverextension

// ============================================================================
// SETUPS
// ============================================================================

bool priceNearBase =
     math.abs(priceBaseDistance) <=
     pullbackDistanceInput

bool fastNearBase =
     absoluteFastBaseSpread <=
     pullbackSpreadInput

bool longSetup =
     longRegime and
     not entangled and
     not bullishOverextension and
     priceNearBase

bool shortSetup =
     shortRegime and
     not entangled and
     not bearishOverextension and
     priceNearBase

// ============================================================================
// TRIGGERS
// ============================================================================

bool longPriceReclaim =
     close > fastMa and
     close[1] <= fastMa[1]

bool shortPriceReclaim =
     close < fastMa and
     close[1] >= fastMa[1]

bool longPriceConfirmation =
     not requirePriceConfirmationInput or
     close > high[1]

bool shortPriceConfirmation =
     not requirePriceConfirmationInput or
     close < low[1]

bool longCurvatureConfirmation =
     not requireCurvatureInput or
     bullishCurvature

bool shortCurvatureConfirmation =
     not requireCurvatureInput or
     bearishCurvature

bool longTrigger =
     longPriceReclaim and
     fastSlope > minimumFastSlopeInput and
     fastSlope > fastSlope[1] and
     longCurvatureConfirmation and
     longPriceConfirmation

bool shortTrigger =
     shortPriceReclaim and
     fastSlope < -minimumFastSlopeInput and
     fastSlope < fastSlope[1] and
     shortCurvatureConfirmation and
     shortPriceConfirmation

bool enterLong =
     longSetup and
     longTrigger and
     not bullishOverextension and
     not entangled

bool enterShort =
     shortSetup and
     shortTrigger and
     not bearishOverextension and
     not entangled

// ============================================================================
// EXIT
// ============================================================================

bool exitLong =
     close < baseMa and
     (
         baseSlope <= 0.0 or
         ta.crossunder(fastMa, baseMa)
     )

bool exitShort =
     close > baseMa and
     (
         baseSlope >= 0.0 or
         ta.crossover(fastMa, baseMa)
     )

// ============================================================================
// STATE ENGINE
// ============================================================================

bool bullExpansionState =
     bullishOrder and
     fastRising and
     baseRising and
     bullishSpreadExpansion and
     priceAboveFast and
     not bullishOverextension and
     not entangled

bool bearExpansionState =
     bearishOrder and
     fastFalling and
     baseFalling and
     bearishSpreadExpansion and
     priceBelowFast and
     not bearishOverextension and
     not entangled

bool bullPullbackState =
     longRegime and
     not bullExpansionState and
     not entangled and
     not bullishOverextension and
     (
         priceNearBase or
         fastNearBase or
         spreadCompression
     )

bool bearPullbackState =
     shortRegime and
     not bearExpansionState and
     not entangled and
     not bearishOverextension and
     (
         priceNearBase or
         fastNearBase or
         spreadCompression
     )

bool overextendedState =
     (
         longRegime and
         bullishOverextension
     ) or
     (
         shortRegime and
         bearishOverextension
     )

bool transitionState =
     not entangled and
     not longRegime and
     not shortRegime and
     (
         math.abs(fastSlope) >=
             minimumFastSlopeInput or
         math.abs(baseSlope) >=
             minimumBaseSlopeInput
     )

int marketState =
     overextendedState  ? STATE_OVEREXTENDED :
     bullExpansionState ? STATE_BULL_EXPANSION :
     bearExpansionState ? STATE_BEAR_EXPANSION :
     bullPullbackState  ? STATE_BULL_PULLBACK :
     bearPullbackState  ? STATE_BEAR_PULLBACK :
     transitionState    ? STATE_TRANSITION :
     STATE_NEUTRAL

// ============================================================================
// FADING
// ============================================================================

bool longFading =
     close < fastMa and
     fastCurvature < 0.0 and
     fastBaseCompression

bool shortFading =
     close > fastMa and
     fastCurvature > 0.0 and
     fastBaseCompression

bool bullRegimeFading =
     longRegime and
     longFading

bool bearRegimeFading =
     shortRegime and
     shortFading

bool stateFading =
     bullRegimeFading or
     bearRegimeFading

// ============================================================================
// SCORE
// ============================================================================

// Direction: maximum +/-30.
float directionScore =
     10.0 * f_sign(fastMa - baseMa) +
     15.0 * f_sign(baseMa - anchorMa) +
      5.0 * f_sign(close - baseMa)

// Slope: maximum +/-25.
float fastSlopeScore =
     10.0 *
     f_clamp(
         f_safeDivide(
             fastSlope,
             math.max(
                 minimumFastSlopeInput,
                 0.001
             )
         ),
         -1.0,
         1.0
     )

float baseSlopeScore =
     10.0 *
     f_clamp(
         f_safeDivide(
             baseSlope,
             math.max(
                 minimumBaseSlopeInput,
                 0.001
             )
         ),
         -1.0,
         1.0
     )

float anchorSlopeScore =
     5.0 *
     f_clamp(
         f_safeDivide(
             anchorSlope,
             math.max(
                 minimumBaseSlopeInput * 0.5,
                 0.001
             )
         ),
         -1.0,
         1.0
     )

float slopeScore =
     fastSlopeScore +
     baseSlopeScore +
     anchorSlopeScore

// Expansion: maximum +/-20.
float fastBaseExpansionScore =
     10.0 *
     f_clamp(
         f_safeDivide(
             fastBaseSpreadChange,
             0.05
         ),
         -1.0,
         1.0
     )

float baseAnchorExpansionScore =
     10.0 *
     f_clamp(
         f_safeDivide(
             baseAnchorSpreadChange,
             0.03
         ),
         -1.0,
         1.0
     )

float expansionScore =
     fastBaseExpansionScore +
     baseAnchorExpansionScore

// Curvature: maximum +/-10.
float curvatureScore =
     6.0 *
     f_clamp(
         f_safeDivide(
             fastCurvature,
             math.max(
                 minimumCurvatureInput,
                 0.001
             )
         ),
         -1.0,
         1.0
     ) +
     4.0 *
     f_clamp(
         f_safeDivide(
             baseCurvature,
             math.max(
                 minimumCurvatureInput,
                 0.001
             )
         ),
         -1.0,
         1.0
     )

float preQualityScore =
     directionScore +
     slopeScore +
     expansionScore +
     curvatureScore

// Base Respect: maximum +/-8.
float respectScore =
     useRespectInput ?
         8.0 *
         f_clamp(
             directionalRespect,
             -1.0,
             1.0
         ) :
         0.0

// Anchor Respect: maximum +/-5.
float anchorRespectScore =
     useAnchorRespectInput ?
         5.0 *
         f_clamp(
             directionalAnchorRespect,
             -1.0,
             1.0
         ) :
         0.0

// Low-cross quality reinforces the current directional score.
// It does not independently create bullish or bearish bias.
float crossQuality =
     1.0 -
     f_clamp(
         f_safeDivide(
             combinedCrossCount,
             maximumCrossesInput
         ),
         0.0,
         1.0
     )

float crossQualityScore =
     7.0 *
     crossQuality *
     f_sign(preQualityScore)

float rawScore =
     preQualityScore +
     respectScore +
     anchorRespectScore +
     crossQualityScore

// Penalties reduce conviction toward zero instead of introducing
// an artificial bearish bias.
float penaltyFraction =
     (overextendedState ? 0.20 : 0.0) +
     (entangled ? 0.25 : 0.0) +
     (extremeVolatility ? 0.10 : 0.0)

float score =
     f_clamp(
         rawScore *
         math.max(
             0.0,
             1.0 - penaltyFraction
         ),
         -100.0,
         100.0
     )

// ============================================================================
// STATE TEXT AND COLOURS
// ============================================================================

string stateText =
     marketState == STATE_BULL_EXPANSION ? "Bull Expansion" :
     marketState == STATE_BULL_PULLBACK  ? "Bull Pullback" :
     marketState == STATE_BEAR_EXPANSION ? "Bear Expansion" :
     marketState == STATE_BEAR_PULLBACK  ? "Bear Pullback" :
     marketState == STATE_OVEREXTENDED   ? "Overextended" :
     marketState == STATE_TRANSITION     ? "Transition" :
     "Neutral Compression"

color stateColour =
     marketState == STATE_BULL_EXPANSION ? color.lime :
     marketState == STATE_BULL_PULLBACK  ? color.teal :
     marketState == STATE_BEAR_EXPANSION ? color.red :
     marketState == STATE_BEAR_PULLBACK  ? color.orange :
     marketState == STATE_OVEREXTENDED   ? color.yellow :
     marketState == STATE_TRANSITION     ? color.aqua :
     color.gray

string stateFadingSuffix =
     stateFading ?
         " (Fading)" :
         ""

color statusMarkerColour =
     stateFading ?
         color.new(stateColour, 45) :
         stateColour

string biasText =
     score >= strongBiasThresholdInput ?
         "Strong Long" :
     score >= directionalBiasThresholdInput ?
         "Long Bias" :
     score <= -strongBiasThresholdInput ?
         "Strong Short" :
     score <= -directionalBiasThresholdInput ?
         "Short Bias" :
         "Neutral"

string permissionText =
     longPermission ?
         "Long permitted" :
     shortPermission ?
         "Short permitted" :
         "No trend permission"

string setupText =
     longSetup ?
         "Long setup active" :
     shortSetup ?
         "Short setup active" :
         "No setup"

string respectText =
     bullishRespectRate >
         bearishRespectRate + 0.10 ?
         "Base respected bullish" :
     bearishRespectRate >
         bullishRespectRate + 0.10 ?
         "Base respected bearish" :
         "No clear base respect"

string anchorRespectText =
     bullishAnchorRespectRate >
         bearishAnchorRespectRate + 0.10 ?
         "Anchor respected bullish" :
     bearishAnchorRespectRate >
         bullishAnchorRespectRate + 0.10 ?
         "Anchor respected bearish" :
         "No clear anchor respect"

// ============================================================================
// MA PLOTS
// ============================================================================

color fastColour =
     colourCurvesBySlopeInput ?
         f_slopeColour(fastSlope) :
         color.aqua

color baseColour =
     colourCurvesBySlopeInput ?
         f_slopeColour(baseSlope) :
         color.orange

color anchorColour =
     colourCurvesBySlopeInput ?
         f_slopeColour(anchorSlope) :
         color.gray

plot(
     showFastInput ? fastMa : na,
     "Fast Curve",
     color = fastColour,
     linewidth = 2
)

plot(
     showBaseInput ? baseMa : na,
     "Base Curve",
     color = baseColour,
     linewidth = 2
)

plot(
     showAnchorInput ? anchorMa : na,
     "Anchor Curve",
     color = anchorColour,
     linewidth = 3
)

// ============================================================================
// BACKGROUND AND BAR COLOURS
// ============================================================================

color backgroundColour =
     marketState == STATE_BULL_EXPANSION ?
         color.new(color.lime, 90) :
     marketState == STATE_BULL_PULLBACK ?
         color.new(color.teal, 91) :
     marketState == STATE_BEAR_EXPANSION ?
         color.new(color.red, 90) :
     marketState == STATE_BEAR_PULLBACK ?
         color.new(color.orange, 91) :
     marketState == STATE_OVEREXTENDED ?
         color.new(color.yellow, 90) :
     marketState == STATE_TRANSITION ?
         color.new(color.aqua, 93) :
         color.new(color.gray, 95)

bgcolor(
     showStateBackgroundInput ?
         backgroundColour :
         na,
     title = "State Background"
)

color calculatedBarColour =
     score >= strongBiasThresholdInput ?
         color.lime :
     score >= directionalBiasThresholdInput ?
         color.teal :
     score <= -strongBiasThresholdInput ?
         color.red :
     score <= -directionalBiasThresholdInput ?
         color.orange :
         color.gray

barcolor(
     showBarColoursInput ?
         calculatedBarColour :
         na
)

// ============================================================================
// SIGNAL PLOTS
// ============================================================================

bool longPermissionStarted =
     longPermission and
     not longPermission[1]

bool shortPermissionStarted =
     shortPermission and
     not shortPermission[1]

plotshape(
     showPermissionSignalsInput and
     longPermissionStarted,
     title = "Long Permission",
     style = shape.circle,
     location = location.belowbar,
     size = size.tiny,
     color = color.teal,
     text = "LP",
     textcolor = color.white
)

plotshape(
     showPermissionSignalsInput and
     shortPermissionStarted,
     title = "Short Permission",
     style = shape.circle,
     location = location.abovebar,
     size = size.tiny,
     color = color.orange,
     text = "SP",
     textcolor = color.white
)

plotshape(
     showReactivationSignalsInput and
     enterLong,
     title = "Long Reactivation",
     style = shape.triangleup,
     location = location.belowbar,
     size = size.small,
     color = color.lime,
     text = "LONG",
     textcolor = color.black
)

plotshape(
     showReactivationSignalsInput and
     enterShort,
     title = "Short Reactivation",
     style = shape.triangledown,
     location = location.abovebar,
     size = size.small,
     color = color.red,
     text = "SHORT",
     textcolor = color.white
)

plotshape(
     showAnchorRejectionSignalsInput and
     bullishAnchorRespectSuccess,
     title = "Bullish Anchor Rejection",
     style = shape.triangleup,
     location = location.belowbar,
     size = size.tiny,
     color = color.blue,
     text = "AR",
     textcolor = color.white,
     offset = -reactionBarsInput
)

plotshape(
     showAnchorRejectionSignalsInput and
     bearishAnchorRespectSuccess,
     title = "Bearish Anchor Rejection",
     style = shape.triangledown,
     location = location.abovebar,
     size = size.tiny,
     color = color.purple,
     text = "AR",
     textcolor = color.white,
     offset = -reactionBarsInput
)

plotshape(
     showExitSignalsInput and
     exitLong,
     title = "Exit Long",
     style = shape.xcross,
     location = location.abovebar,
     size = size.tiny,
     color = color.red,
     text = "XL",
     textcolor = color.white
)

plotshape(
     showExitSignalsInput and
     exitShort,
     title = "Exit Short",
     style = shape.xcross,
     location = location.belowbar,
     size = size.tiny,
     color = color.lime,
     text = "XS",
     textcolor = color.black
)

// ============================================================================
// RIGHT-SIDE STATUS LABEL
// ============================================================================

var label statusLabel = na

if barstate.islast
    if not na(statusLabel)
        label.delete(statusLabel)

    if showStatusLabelInput
        string presetText =
             presetInput +
             " · " +
             fastType +
             " " +
             str.tostring(fastLength) +
             " / " +
             baseType +
             " " +
             str.tostring(baseLength) +
             " / " +
             anchorType +
             " " +
             str.tostring(anchorLength)

        string statusTooltip =
             stateText +
             stateFadingSuffix +
             "\n" +
             biasText +
             " · Score " +
             str.tostring(
                 score,
                 "#.0"
             ) +
             "\n" +
             permissionText +
             "\n" +
             setupText +
             "\n" +
             respectText +
             "\n" +
             anchorRespectText +
             "\n" +
             presetText

        statusLabel := label.new(
             bar_index + statusOffsetInput,
             close +
                 statusVerticalOffsetInput *
                 safeAtr,
             "",
             xloc = xloc.bar_index,
             yloc = yloc.price,
             style = label.style_circle,
             color = statusMarkerColour,
             size = size.tiny,
             tooltip = statusTooltip
         )

// ============================================================================
// DATA WINDOW OUTPUTS
// ============================================================================

plot(
     score,
     "MA State Score",
     display = display.data_window
)

plot(
     fastSlope,
     "Fast Slope",
     display = display.data_window
)

plot(
     baseSlope,
     "Base Slope",
     display = display.data_window
)

plot(
     anchorSlope,
     "Anchor Slope",
     display = display.data_window
)

plot(
     fastCurvature,
     "Fast Curvature",
     display = display.data_window
)

plot(
     fastBaseSpread,
     "Fast/Base Spread",
     display = display.data_window
)

plot(
     baseAnchorSpread,
     "Base/Anchor Spread",
     display = display.data_window
)

plot(
     priceExtension,
     "Price Extension",
     display = display.data_window
)

plot(
     bullishRespectRate * 100.0,
     "Bullish Respect Rate",
     display = display.data_window
)

plot(
     bearishRespectRate * 100.0,
     "Bearish Respect Rate",
     display = display.data_window
)

plot(
     bullishAnchorRespectRate * 100.0,
     "Bullish Anchor Respect Rate",
     display = display.data_window
)

plot(
     bearishAnchorRespectRate * 100.0,
     "Bearish Anchor Respect Rate",
     display = display.data_window
)

plot(
     combinedCrossCount,
     "Cross Count",
     display = display.data_window
)

plot(
     stateFading ? 1.0 : 0.0,
     "State Fading",
     display = display.data_window
)

// ============================================================================
// ALERTS
// ============================================================================

alertcondition(
     longPermissionStarted,
     "Long Permission Started",
     "MA Cascade Engine: Long permission has started."
)

alertcondition(
     shortPermissionStarted,
     "Short Permission Started",
     "MA Cascade Engine: Short permission has started."
)

alertcondition(
     enterLong,
     "Long Reactivation",
     "MA Cascade Engine: Bullish pullback reactivation detected."
)

alertcondition(
     enterShort,
     "Short Reactivation",
     "MA Cascade Engine: Bearish pullback reactivation detected."
)

alertcondition(
     bullishAnchorRespectSuccess,
     "Bullish Anchor Rejection",
     "MA Cascade Engine: Price bounced off the Anchor MA to the upside."
)

alertcondition(
     bearishAnchorRespectSuccess,
     "Bearish Anchor Rejection",
     "MA Cascade Engine: Price bounced off the Anchor MA to the downside."
)

alertcondition(
     bullRegimeFading and not bullRegimeFading[1],
     "Bull Regime Fading",
     "MA Cascade Engine: The active bull regime is losing momentum (Fast MA decelerating, Fast/Base compressing)."
)

alertcondition(
     bearRegimeFading and not bearRegimeFading[1],
     "Bear Regime Fading",
     "MA Cascade Engine: The active bear regime is losing momentum (Fast MA decelerating, Fast/Base compressing)."
)

alertcondition(
     exitLong,
     "Exit Long",
     "MA Cascade Engine: Long exit condition detected."
)

alertcondition(
     exitShort,
     "Exit Short",
     "MA Cascade Engine: Short exit condition detected."
)

alertcondition(
     marketState == STATE_BULL_EXPANSION and
     marketState[1] != STATE_BULL_EXPANSION,
     "Bull Expansion Started",
     "MA Cascade Engine: Bull Expansion state has started."
)

alertcondition(
     marketState == STATE_BEAR_EXPANSION and
     marketState[1] != STATE_BEAR_EXPANSION,
     "Bear Expansion Started",
     "MA Cascade Engine: Bear Expansion state has started."
)

alertcondition(
     marketState == STATE_OVEREXTENDED and
     marketState[1] != STATE_OVEREXTENDED,
     "Market Overextended",
     "MA Cascade Engine: Direction remains present, but price is overextended."
)

Overview

MA Cascade Engine [WavesUnchained] evaluates moving average slopes, curvature, separation, and price extension to categorize market conditions into states such as expansion, pullback, compression, transition, or overextension. Configurable parameters include preset sensitivity profiles, custom moving average types (including Jurik-style JMA, EMA, and SMA), ATR volatility normalization, and MA respect tracking metrics.

Details

Published by

casoon on GitHub

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Moving averages, Trend

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Topics

pine-scriptpinescripttechnical-analysistrading-indicatorstrading-strategiestradingview

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
PresetstringBalancedpresetInput
SourcesourceclosesourceInput
JMA Phaseint0jmaPhaseInput
JMA Powerfloat2.0jmaPowerInput
Fast TypestringJMAcustomFastTypeInput
Fast Lengthint21customFastLengthInput
Base TypestringEMAcustomBaseTypeInput
Base Lengthint50customBaseLengthInput
Anchor TypestringSMAcustomAnchorTypeInput
Anchor Lengthint200customAnchorLengthInput
ATR Lengthint14atrLengthInput
Slope Lookbackint5slopeLookbackInput
Show all 40 settings
SettingTypeDefaultVariable
Minimum Fast Slope per Barfloat0.015minimumFastSlopeInput
Minimum Base Slope per Barfloat0.008minimumBaseSlopeInput
Curvature Lookbackint3curvatureLookbackInput
Minimum Trigger Curvaturefloat0.005minimumCurvatureInput
Entanglement Spreadfloat0.15entanglementSpreadInput
Cross Frequency Lookbackint30crossFrequencyLookbackInput
Maximum Crossesint6maximumCrossesInput
Maximum Pullback Distancefloat0.70pullbackDistanceInput
Maximum Fast/Base Pullback Spreadfloat0.75pullbackSpreadInput
Maximum Price Extensionfloat1.75maximumExtensionInput
Extreme Volatility Ratiofloat1.80extremeVolatilityRatioInput
Volatility Baselineint100volatilityBaselineInput
Use Base Respect in ScorebooltrueuseRespectInput
Use Anchor Respect in ScorebooltrueuseAnchorRespectInput
Touch Tolerancefloat0.15touchToleranceInput
Reaction Horizonint5reactionBarsInput
Required Reaction Movefloat0.50reactionMoveInput
Respect Invalidationfloat0.35respectInvalidationInput
Respect Statistics Lookbackint150respectLookbackInput
Require Previous-Bar BreakbooltruerequirePriceConfirmationInput
Require Positive Trigger CurvaturebooltruerequireCurvatureInput
Show Permission ChangesboolfalseshowPermissionSignalsInput
Show Reactivation SignalsbooltrueshowReactivationSignalsInput
Show Anchor Rejection SignalsbooltrueshowAnchorRejectionSignalsInput
Show Exit SignalsboolfalseshowExitSignalsInput
Strong Bias Thresholdfloat60.0strongBiasThresholdInput
Directional Bias Thresholdfloat25.0directionalBiasThresholdInput
Show Fast CurvebooltrueshowFastInput
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.

Similar Pine Scripts

948 stars

The Adaptive Laguerre Filter calculates a smoothed, dynamically adjusted trendline plotted directly on the main price chart. It dynamically adjusts its damping factor (alpha) based on recent price range variations and median percentile calculations over a spec

Indicator v4 TrendMoving averages
Updated 10 days ago · GPL-3.0 GitHub repository of Adaptive Laguerre Filter
330 stars

This script plots three moving averages on the price chart: a fast EMA or SMA with 10 periods, a slow EMA or SMA with 20 periods, and a trend EMA or SMA with 100 periods. It signals trend changes by drawing a white cross when the fast moving average crosses ab

Indicator v4 TrendMoving averages
Updated 2 months ago · None stated GitHub repository of 3 EMA/SMA + Cross [Alorse]
318 stars

This indicator plots four customizable moving averages directly on the main price chart using default lengths of 3, 8, 21, and 50 periods. It fills the space between adjacent averages in green or maroon depending on trend alignment. Additionally, it computes B

Indicator v5 Moving averagesTrend
Updated 2 months ago · MIT GitHub repository of Multiple Moving Averages

NVDA Trend Ribbon

by longsurf-ai
277 stars

This indicator plots three exponential moving averages and ATR volatility envelopes on the price chart. It compares the fast and slow EMAs to shade a trend ribbon and marks confirmed upward and downward crossovers with triangle labels. Settings change the thre

Indicator v6 TrendMoving averages
Updated yesterday · MIT GitHub repository of NVDA Trend Ribbon
257 stars

Donald SPX - Options Trading is an overlay indicator designed for intraday SPX analysis. It plots a 200-period Weighted Moving Average (WMA) on the price chart while evaluating multi-timeframe market structure across Daily, 15-minute, 5-minute, and 2-minute ba

Indicator v5 Moving averagesTrend Repaints
Updated 6 weeks ago · None stated GitHub repository of Donald SPX - Options Trading

60K均線

by TaichiS
219 stars

This multi-timeframe indicator calculates and plots 20-period and 60-period simple moving averages from the 60-minute timeframe directly onto the price chart. The 20-period average displays as a green line, while the 60-period average appears in blue. It serve

Indicator v4 Moving averagesTrend Repaints
Updated 5 years ago · None stated GitHub repository of 60K均線

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers