TradingView indicator calculations

Ehlers Decycler: removing cycles without future data

The Ehlers Decycler subtracts a high-pass component from price to reduce short-cycle fluctuations while retaining the price level. This page implements the 2015 Simple Decycler with a two-pole high-pass recurrence. It uses current and earlier bars only. That makes the calculation causal, but it does not make every price change immediate: the worked examples show residual oscillation and a delayed, overshooting response to a sudden jump.

See the decision guide

Use the public Simple Decycler formula

The September 2015 Stocks & Commodities Traders Tips page publishes the calculation alongside the Decyclers article. Let P be price, H the high-pass component and D the Decycler. The formulas below use radians; the published degree argument 0.707 × 360 / L becomes 0.707 × 2π / L. L is the high-pass period, and brackets refer to earlier bars.

  • At L = 125, α = 0.034920868, q = 0.965079132 and k = 0.965383999. Keep full precision internally; these displays are rounded.
  • The example preserves 0.707 from the published formula. Replacing it with 1/√2 changes the coefficients slightly. Record this choice when comparing ports.
  • D + H = P is an arithmetic identity. It does not mean the two outputs are statistically independent or that their squared amplitudes add to the input energy.
QuantityCalculation
Angle and coefficientθ = 0.707 × 2π / L; α = (cos θ + sin θ − 1) / cos θ
Feedback and input weightsq = 1 − α; k = (1 − α/2)²
High-pass componentH = k(P − 2P[1] + P[2]) + 2qH[1] − q²H[2]
Price overlayD = P − H

Choose a period without assuming a hard cutoff

A larger L gives the high-pass component access to slower fluctuations, so subtraction suppresses more of them from the Decycler. It also makes the recursive startup last longer. The reference setting 125 counts chart bars: 125 daily observations and 125 five-minute observations do not represent the same elapsed time.

  • These are independently calculated steady-state gains, not market returns. For a cycle of T bars, set z = exp(−i2π/T), H(z) = k(1 − z)²/(1 − qz)² and D(z) = 1 − H(z). The table reports |D(z)|.
  • Subtract complex responses before taking their magnitude. The remaining amplitude is |1 − H(z)|, not 1 − |H(z)|, because the high-pass component also changes phase.
  • The response has no rectangular cutoff. At L = 125, a 500-bar sine has gain 1.088669, so some slow components are amplified slightly. The price overlay is not guaranteed to stay inside the recent price range.
  • The code accepts integer periods from 4 to 2000. This explicit range keeps the coefficient denominator away from zero and |q| below 1. It is an implementation constraint, not a recommended trading range.
High-pass period LRemaining amplitude of a 20-bar sine
200.998084 × input amplitude
600.446439 × input amplitude
1250.221958 × input amplitude
2500.111883 × input amplitude

Compare a rising series with the same cycle in a range

Use L = 125 and set H to zero at n = 0 and n = 1. The trend fixture is P[n] = 100 + 0.05n + 2 sin(2πn/20). The range fixture removes the 0.05n term. Both are synthetic price-unit calculations, evaluated after 1000 samples; neither uses exchange data.

  • Over one full 20-bar cycle, the trend input and its Decycler both rise by 1. The range Decycler returns to its earlier value. A linear ramp has zero second difference, so it does not enter H under these zero seeds.
  • The input cycle amplitude is 2. Its remaining Decycler amplitude is approximately 2 × 0.221958444 = 0.443917. The range output therefore still rises and falls despite having no trend.
  • At n = 1010 the range price is 100 while D is 100.437710. The phase shift can put the overlay above price; a slope color or price crossing alone cannot distinguish a trend from a recurring oscillation.
  • Reproduce the rows with the Pine input modes Trend plus cycle and Cycle only. Match Sample index in the Data Window rather than a market timestamp: synthetic n starts at the first loaded bar.
Sample nTrend inputTrend DecyclerRange inputRange Decycler
1000150.000000149.562290100.00000099.562290
1005152.250000150.323976102.000000100.073976
1010150.500000150.937710100.000000100.437710
1015148.750000150.67602498.00000099.926024
1020151.000000150.562290100.00000099.562290

A sudden price jump exposes delay and overshoot

For a separate counterexample, keep price at 100 through n = 999, then hold it at 110 from n = 1000 onward. Use the same L = 125 and zero seeds. Before the jump H is zero; the first changed bar therefore has H = k × 10 = 9.653839990 and D = 100.346160010.

  • The maximum in this step response is 111.353664 at n = 1056. Price never exceeded 110. The overshoot comes from the filter state, not from an unseen market price or future data.
  • The earlier linear-ramp result and this jump result are compatible. Different inputs have different frequency content, so a universal zero-lag claim would be misleading.
  • Price gaps, reversals and regime changes can produce temporary disagreement between price and the filtered slope. Any trading rule needs its own entry, exit, cost and fill assumptions.
Sample nInputDecycler
1000110.000000100.346160
1020110.000000108.689743
1060110.000000111.339854
1120110.000000110.453185

Separate a valid recurrence from a warmed-up output

This port sets H to zero on the first two bars and starts the recurrence on the third. It computes every subsequent bar, but hides output until n ≥ 5L and the chart bar is confirmed. The five-period display gate is a reproducible demonstration choice; it is not a universal accuracy guarantee.

  • The repeated feedback root is q. A difference in starting states can decay as (A + Bn)qⁿ. Larger L puts q closer to 1 and prolongs the effect; having two historical bars only makes the recurrence evaluable.
  • Compare the same later timestamps after loading more earlier history, using a stated price-unit tolerance. Different seeds, source series, sessions or available history can explain a mismatch even when both scripts compile.
  • A constant input remains constant with these seeds, and an exact linear ramp is preserved. Those special inputs do not establish warm-up accuracy for curved or discontinuous data.
  • The sample stops with an explicit error if the selected source contains na. It does not substitute zero for a missing price. A production port that resets or bridges gaps needs a separately documented policy.

Run the complete Pine Script v6 audit

Paste the code into Pine Editor and add it to a chart. Keep period 125 and select a synthetic input mode to reproduce the tables. Load at least 1121 chart bars for every displayed sample. The Data Window exposes the high-pass component and sample index; switch to Market to filter the selected price source.

  • The recursion uses only P, P[1], P[2], H[1] and H[2]. It contains no future reference, negative plot offset or higher-timeframe data request.
  • On an open market bar, the chosen source can change. This code calculates continuously and displays output only when barstate.isconfirmed is true. Confirmation controls the current chart bar; it does not prevent recalculation after data corrections or changes to loaded history.
  • If you add alerts, define whether the event is a price crossing, a slope change or a band crossing. Evaluate it on confirmed bars and select Once Per Bar Close. Compilation does not establish agreement with a different Decycler variant.
Original Pine implementation of the public 2015 formula, with explicit seeds and synthetic fixtures. It plots an indicator and does not place orders.pine
//@version=6
indicator("Ehlers Simple Decycler calculation audit", overlay = true, precision = 6)
period = input.int(125, "High-pass period in bars", minval = 4, maxval = 2000)
source = input.source(close, "Market source")
mode = input.string("Market", "Input mode", options = ["Market", "Trend plus cycle", "Cycle only", "Step"])
n = bar_index
wave = 2.0 * math.sin(2.0 * math.pi * n / 20.0)
p = switch mode
    "Trend plus cycle" => 100.0 + 0.05 * n + wave
    "Cycle only" => 100.0 + wave
    "Step" => n < 1000 ? 100.0 : 110.0
    => source
if na(p)
    runtime.error("The selected input has a missing value. Use a continuous source.")
theta = 0.707 * 2.0 * math.pi / period
alpha = (math.cos(theta) + math.sin(theta) - 1.0) / math.cos(theta)
q = 1.0 - alpha
k = math.pow(1.0 - alpha / 2.0, 2)
float hp = 0.0
if n >= 2
    hp := k * (p - 2.0 * p[1] + p[2]) + 2.0 * q * hp[1] - q * q * hp[2]
decycler = p - hp
ready = n >= 5 * period and barstate.isconfirmed
plot(ready ? decycler : na, "Decycler", color = color.blue, linewidth = 2)
plot(ready ? p : na, "Input", color = color.gray)
plot(ready ? hp : na, "High-pass component", display = display.data_window)
plot(n, "Sample index", display = display.data_window)

Keep the overlay distinct from the Roofing Filter

The Simple Decycler retains the price level through P − H. A Roofing Filter instead feeds a high-pass output into a low-pass smoother to emphasize an intermediate frequency band. It is normally plotted around zero. Substituting Roofing output for D in a price-crossing rule changes the meaning of that rule.

  • The 2015 Decycler Oscillator applies another high-pass stage to the Decycler and scales the result. It is a separate oscillator, not the overlay shown here.
  • Public TradingView publications also reference the earlier one-pole Decycler from Cycle Analytics for Traders. Record the formula and revision rather than assuming the name, period or color identifies this two-pole 2015 implementation.

Give Pineify the formula and the expected values

Ask the Pine Script AI Coding Agent to draft or review the public recurrence with the 0.707 constant, source input, zero seeds and closed-bar display rule. Include the synthetic fixtures and the numerical tables as acceptance checks. Inspect the resulting code, request a syntax check and compare its Data Window values before adding trading conditions.

  • Provide the public formula or code you are entitled to use. This workflow does not require copying a protected TradingView script.
  • The agent can help write and revise Pine code. A successful syntax check does not prove that the values match, that a trend exists or that a trading rule will make money.
Where Pineify fits

Pine Script AI Coding Agent

Draft or review a Decycler from the public formula, with explicit initialization and diagnostic values to compare against the synthetic examples.

Draft a Decycler script

Frequently asked questions

Educational information, not investment advice. The examples are synthetic filter calculations, not backtests or live results. Low delay, bar confirmation and syntax validation do not guarantee profitable signals.

Sources and verification

Published by Pineify. Pineify is an independent product and is not affiliated with TradingView. Sources support the technical explanations; examples do not establish trading performance.