Indicator · Pine Script v6 · Own pane

Adaptive Cycle Detector [WavesUnchained]

by casoon

The Adaptive Cycle Detector estimates the dominant market cycle from WaveTrend oscillator zero-crossing frequency and applies smoothing to recommend adaptive indicator lengths.

View on GitHub

GitHub stars9on the repository
Pine versionv6current
Lines of code157
Settings10inputs
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

157 lines of Pine Script v6 from indicators/trend_strength/adaptive_cycle_detector/adaptive_cycle_detector.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

adaptive_cycle_detector.pine
//@version=6
// ============================================================================
// Adaptive Cycle Detector [WavesUnchained]
// Version: 1.0.2
// Author: WavesUnchained
// Build: 2026-10-02 00:00:00
// ============================================================================
// Estimates the dominant market cycle from WT/StochRSI zero-crossing frequency
// and recommends adaptive indicator lengths. Fast markets (frequent oscillator
// crossings) get shorter lengths; slow swing markets get longer lengths.
//
// Also measures ATR regime (volatility trend) and trend clarity (ADX) to further
// adapt length recommendations. Pure Hilbert-Transform is approximated with a
// zero-crossing period estimator, which is accurate enough for length adaptation.
//
// Features:
//   ✓ Dominant cycle estimation via WT zero-crossing period (bars between crossings)
//   ✓ ATR regime: rising / falling / flat volatility (supports cycle length)
//   ✓ Trend clarity via ADX (trend vs chop mode)
//   ✓ Adaptive length recommendations for WT, StochRSI, MFI
//   ✓ Smoothed cycle period plot with min/max bounds
//   ✓ Dashboard with current period estimate and recommendations
//
// ============================================================================

indicator("Adaptive Cycle Detector [WavesUnchained]", "Adapt Cycle [WU]", format=format.price, precision=2, overlay=false)

// ─── Inputs ───────────────────────────────────────────────────────────────────

grCyc       = "Cycle Detection"
cycLookback = input.int(100,  "Lookback for Crossing Count", minval=20, maxval=500, group=grCyc,
     tooltip="How many bars to look back when counting WT zero crossings. Longer = smoother estimate, less responsive.")
cycSmooth   = input.int(5,    "Period Estimate Smoothing",  minval=1, maxval=20, group=grCyc)
minPeriod   = input.int(8,    "Minimum Cycle Period",       minval=4, maxval=30, group=grCyc)
maxPeriod   = input.int(60,   "Maximum Cycle Period",       minval=20, maxval=200, group=grCyc)

grWT    = "Base WaveTrend"
wtChLen = input.int(10, "Channel Length", minval=1, group=grWT)
wtAvLen = input.int(21, "Average Length", minval=1, group=grWT)

grAdx     = "ADX"
adxLen    = input.int(14, "ADX Length", minval=5, group=grAdx)
trendThr  = input.int(25, "Trend Threshold", minval=10, maxval=50, group=grAdx,
     tooltip="ADX above this value indicates a trending market — favor longer adaptive lengths to catch the full swing.")

grD      = "Display"
showDash = input.bool(true, "Show Dashboard", group=grD)
showBand = input.bool(true, "Show Min/Max Band", group=grD)

// ─── Base oscillators ─────────────────────────────────────────────────────────

_wtEsa = ta.ema(hlc3, wtChLen)
_wtD   = ta.ema(math.abs(hlc3 - _wtEsa), wtChLen)
_wtCi  = (hlc3 - _wtEsa) / (0.015 * math.max(_wtD, syminfo.mintick))
wtOsc  = ta.ema(_wtCi, wtAvLen)

atr14  = ta.atr(14)
atrMa  = ta.sma(atr14, 20)
atrUp  = atr14 > atrMa * 1.05
atrDn  = atr14 < atrMa * 0.95

// ADX (third element of ta.dmi is the ADX line)
[_, _, _adx] = ta.dmi(adxLen, adxLen)
adx    = _adx
trending = adx > trendThr

// ─── Cycle estimation via zero-crossing period ────────────────────────────────

// Count WT zero crossings in cycLookback bars
crossingUp   = ta.crossover(wtOsc,  0)
crossingDown = ta.crossunder(wtOsc, 0)
anyCrossing  = crossingUp or crossingDown

// Count crossings in lookback to estimate frequency (rolling sum — O(1) per bar)
crossCount = int(nz(math.sum(anyCrossing ? 1.0 : 0.0, cycLookback)))

// Half-period from crossing count: period = 2 * lookback / crossings (each half-cycle = one crossing)
rawPeriod = crossCount > 0 ? int(2.0 * cycLookback / crossCount) : maxPeriod
clampedPeriod = math.max(minPeriod, math.min(maxPeriod, rawPeriod))

// Smooth the period estimate
cycPeriod = ta.ema(float(clampedPeriod), cycSmooth)

// ─── Adaptive length recommendations ─────────────────────────────────────────
// Base length = period / 4 (quarter-cycle is the standard WT channel length)
// Trend mode: longer (period / 3), Chop mode: shorter (period / 5)

baseLen = int(cycPeriod / 4.0)
trendFactor = trending ? 1.25 : atrDn ? 0.80 : 1.0
adaptLen = math.max(5, math.min(50, int(baseLen * trendFactor)))

recWT  = adaptLen
recSt  = math.max(8, math.min(30, int(cycPeriod / 3.0)))
recMfi = math.max(7, math.min(30, int(cycPeriod / 4.0)))

// ─── Plots ────────────────────────────────────────────────────────────────────

// Reference hlines for typical cycle lengths
hline(8,  "Fast Market",  color=color.new(color.green,  60), linestyle=hline.style_dotted)
hline(21, "Normal",       color=color.new(color.gray,   50), linestyle=hline.style_dashed)
hline(40, "Slow Swing",   color=color.new(color.orange, 60), linestyle=hline.style_dotted)

color cycColor = color.new(#ef5350, 0)
if cycPeriod < 12
    cycColor := color.new(#00c853, 0)
else if cycPeriod < 28
    cycColor := color.new(#ffd600, 0)

plot(cycPeriod, "Cycle Period", color=cycColor, linewidth=2)

plot(showBand ? float(minPeriod) : na, "Min Period", color=color.new(color.gray, 70), linewidth=1)
plot(showBand ? float(maxPeriod) : na, "Max Period", color=color.new(color.gray, 70), linewidth=1)

// Adaptive length recommendation line
plot(float(adaptLen), "Recommended WT Length", color=color.new(#2196F3, 30), linewidth=1, style=plot.style_line)

// Mark zero crossings
plotshape(crossingUp,   "Cross Up",   shape.triangleup,   location.bottom, color.new(color.green, 20), size=size.tiny)
plotshape(crossingDown, "Cross Down", shape.triangledown, location.top,    color.new(color.red,   20), size=size.tiny)

// ─── Dashboard ────────────────────────────────────────────────────────────────

color tc = color.new(color.gray, 20)
color hd = color.new(color.gray, 90)

var table t = table.new(position.top_right, 2, 7,
     bgcolor=color.new(color.white, 5),
     border_color=color.new(color.gray, 60), border_width=1,
     frame_color=color.new(color.gray, 40), frame_width=1)

if showDash and barstate.islast
    modeText  = trending ? "Trend" : atrUp ? "Expansion" : atrDn ? "Compression" : "Normal"
    modeColor = trending ? color.new(#00c853, 0) : atrDn ? color.new(#2196F3, 0) : tc

    table.cell(t, 0, 0, "Adaptive Cycle", text_color=tc, bgcolor=hd, text_size=size.small)
    table.cell(t, 1, 0, modeText,         text_color=modeColor, bgcolor=hd, text_size=size.small)

    table.cell(t, 0, 1, "Cycle Period",   text_color=tc, text_size=size.small)
    table.cell(t, 1, 1, str.tostring(math.round(cycPeriod)) + " bars",
         text_color=cycColor, text_size=size.small)

    table.cell(t, 0, 2, "ADX",            text_color=tc, text_size=size.small)
    table.cell(t, 1, 2, str.tostring(adx, "#.#"),
         text_color=trending ? color.new(#00c853, 0) : tc, text_size=size.small)

    // Separator
    table.cell(t, 0, 3, "", bgcolor=color.new(color.gray, 80))
    table.cell(t, 1, 3, "", bgcolor=color.new(color.gray, 80))

    table.cell(t, 0, 4, "WT Length",      text_color=tc, text_size=size.small)
    table.cell(t, 1, 4, str.tostring(recWT), text_color=color.new(#2196F3, 0), text_size=size.small)

    table.cell(t, 0, 5, "StochRSI Length", text_color=tc, text_size=size.small)
    table.cell(t, 1, 5, str.tostring(recSt), text_color=color.new(#2196F3, 0), text_size=size.small)

    table.cell(t, 0, 6, "MFI Length",     text_color=tc, text_size=size.small)
    table.cell(t, 1, 6, str.tostring(recMfi), text_color=color.new(#2196F3, 0), text_size=size.small)

Overview

Fast markets with frequent crossings receive shorter lengths while slow swing markets get longer ones. The script also measures ATR regime for volatility trend and ADX for trend clarity to refine length suggestions for WaveTrend, Stochastic RSI and MFI. It plots the smoothed cycle period estimate together with minimum and maximum bounds in a separate pane plus a dashboard with current estimate and recommendations. Inputs control lookback for crossing count, smoothing factor, minimum and maximum cycle periods, WaveTrend channel and average lengths and ADX settings. The script draws exclusively in a separate pane with no trading signals or position rules.

Details

Published by

casoon on GitHub

Type

Indicator, Pine Script v6

Draws

Separate pane below the chart

Category

Oscillators & momentum, Volatility & bands, Trend, Screeners & dashboards

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
Lookback for Crossing Countint100cycLookback
Period Estimate Smoothingint5cycSmooth
Minimum Cycle Periodint8minPeriod
Maximum Cycle Periodint60maxPeriod
Channel Lengthint10wtChLen
Average Lengthint21wtAvLen
ADX Lengthint14adxLen
Trend Thresholdint25trendThr
Show DashboardbooltrueshowDash
Show Min/Max BandbooltrueshowBand
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

Manias, Panics and Crashes

by MeridianAlgo
9 stars

Manias, Panics and Crashes is a separate-pane market regime indicator that quantifies market sentiment and systemic risk. It processes technical metrics including RSI, moving averages, and volume alongside optional intermarket data such as VIX volatility and c

Indicator v6 Oscillators & momentumVolatility & bands
Updated 4 months ago · MIT GitHub repository of Manias, Panics and Crashes

Elton's Screener

by eltonaguiar
4 stars

Elton's Screener is an indicator that runs in a separate pane and scores one of twenty selectable strategies, or auto-selects a route from the symbol type. It filters signals by a minimum confidence level and a higher-timeframe EMA trend alignment. ATR multipl

Indicator v6 Screeners & dashboardsOscillators & momentum Repaints
Updated today · None stated GitHub repository of Elton's Screener

DEPV2 C6 Gölge Kasa

by YuceSezar89
1 stars

This indicator evaluates signal performance and multi-timeframe market dynamics through a shadow bankroll tracking framework. It measures market conditions across trend, momentum ROC Z-scores, ATR volatility expansion, and volume flow, alongside multi-timefram

Indicator v6 TrendOscillators & momentum
Updated 11 days ago · None stated GitHub repository of DEPV2 C6 Gölge Kasa
1 stars

Papan Gerak is a multi-dimension technical analysis dashboard aimed at Indonesian stocks. This base module declares the indicator in a separate pane and stores the display and calculation settings used by the dashboard. It covers table position, font size, com

Indicator v6 Screeners & dashboardsTrend
Updated 3 months ago · MIT GitHub repository of Saham: Papan Gerak By. Akhmfz

Market Regime Dashboard

by vantradelabs
2 stars

The Market Regime Dashboard is a multi-timeframe dashboard indicator that evaluates market conditions across three user-defined timeframes. It measures four core dimensions: trend strength using ADX and DI direction, momentum using RSI z-scores, volatility via

Indicator v6 Screeners & dashboardsTrend
Updated 2 months ago · Custom licence GitHub repository of Market Regime Dashboard

This indicator evaluates market conditions across four user-defined timeframes by combining RSI, MACD crossovers, triple EMA trend filters, Bollinger Band boundaries, and volume spikes. It computes aggregate bullish and bearish scores, plotting buy and sell si

Indicator v5 Screeners & dashboardsOscillators & momentum
Updated 8 months ago · None stated GitHub repository of Multi-Timeframe Trade Signal Indicator

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