Jurik Moving Average on TradingView: Public Implementations Explained
A TradingView script named Jurik Moving Average may be a public approximation rather than the proprietary JMA. This guide tests one identified, licensed implementation. Its length, phase, power and starting values determine its output; the JMA label does not make different scripts interchangeable.
The worked example below uses hypothetical prices, not a market backtest. It measures filter response, not returns or signal accuracy.
Compare the same price sequenceWhich implementation are you using?
Jurik Research distributed licensed software. The historical AmiBroker integration manual requires licensed Jurik DLLs and documents a JMA interface with speed and phase. It does not publish the internal calculation. That manual is historical documentation, not evidence of current purchasing availability.
The example here adapts everget's public source at a fixed revision, whose header permits distribution under GPL-3.0. We preserve its notices and license, expose its settings, and add a first-price seed and a reproducible test mode. These are disclosed changes to the public implementation, not access to Jurik's original source.
For fixed inputs, beta and alpha below stay constant. There is no volatility estimate that updates alpha, so calling this particular recurrence volatility-adaptive would be inaccurate. Other public scripts can use different calculations.
Parameter mechanics in this example
- Length sets beta = 0.45 × (length − 1) / [0.45 × (length − 1) + 2]. Larger lengths increase beta toward 1.
- Power sets alpha = beta^power. For length above 1, increasing positive power lowers alpha and increases the immediate input weight.
- Phase sets the correction multiplier to phase / 100 + 1.5. The bounded range from -100 to 100 produces multipliers from 0.5 to 2.5.
- Initialization sets the previous E0 and output. This example seeds both with the first valid price and seeds E1 and E2 with zero.
Length 1 is a special case of this public formula: beta and alpha are zero and the output equals the input. Power must be positive; phase is bounded by the inputs. These are example constraints, not the proprietary product's complete parameter contract.
Same prices, different lag and overshoot
Start with 100 at bar 0, then use 110 for bars 1 through 20. Seed E0 and the output at 100, with E1 = E2 = 0. All rows use exactly this sequence. Values are rounded only for display.
| Length / phase / power | Bar 1 | Bar 3 | Bar 5 | First bar ≥ 105 | Max overshoot, bars 1 to 20 |
|---|---|---|---|---|---|
| 7 / -100 / 2 | 103.3226 | 108.4394 | 109.8488 | 2 | 0.0418 |
| 7 / 0 / 2 | 103.9530 | 109.4179 | 110.4140 | 2 | 0.4140 |
| 7 / 100 / 2 | 104.5834 | 110.3963 | 110.9792 | 2 | 1.0028 |
| 7 / 0 / 1 | 101.4345 | 105.8155 | 108.8748 | 3 | 0.4151 |
| 14 / 0 / 2 | 101.2987 | 105.5010 | 108.7149 | 3 | 0.6668 |
The first three rows isolate phase: raising it increases the peak beyond the input level. The power-1 row reaches 105 one bar later than power 2. Length 14 also takes an extra bar to reach that threshold. This threshold delay is one test measure; it is not a universal lag figure for live prices.
For length 7, phase 0 and power 2, beta = 27/47 and alpha = (27/47)² ≈ 0.330014. At bar 1, E0 ≈ 106.699864, E1 ≈ 1.404313 and E2 ≈ 3.953003, giving 103.953003. The positive correction can push the line above 110 even though the input never exceeds 110.
Why the starting state matters
With the same 7 / 0 / 2 settings, replacing missing previous states with zero produces 39.5300 on the first price of 100. The first-price seed produces 100.0000. That difference is a startup artifact, not a price move. Changing available chart history can change recursive values near the start; there is no universal warm-up bar count proved by this example.
Pine Script v6: inspect and reproduce the calculation
Copy into TradingView's Pine Editor and add it to a chart. Enable the synthetic step and use the first loaded bars to reproduce the table in the Data Window. Keep first-price seeding enabled. Disable the synthetic input before examining market data or creating an alert.
//@version=6
// Public approximation, not the proprietary Jurik algorithm.
// Copyright (c) 2007-present Jurik Research and Consulting. All rights reserved.
// Copyright (c) 2018-present, Alex Orekhov (everget).
// Adapted by Pineify, 2026-10-17: v6, first-price seed, reset on na,
// bounded inputs, synthetic test series and confirmed-close alerts.
// This adaptation is distributed under GPL-3.0:
// https://www.gnu.org/licenses/gpl-3.0.html
// Source: github.com/everget/tradingview-pinescript-indicators
// movings/jurik_moving_average.pine, commit 187e031f04069b1bed0db2d0ebe85f0fa4e0251b
indicator("Public JMA approximation: parameter test", overlay=true)
length = input.int(7, "Length", minval=1)
phase = input.int(0, "Phase", minval=-100, maxval=100)
power = input.float(2.0, "Power", minval=0.1)
src = input.source(close, "Source")
seedFirst = input.bool(true, "Seed with first price")
demo = input.bool(false, "Synthetic step: 100, then 110")
publicJma(float x, int n, int ph, float pw, bool seed) =>
beta = 0.45 * (n - 1) / (0.45 * (n - 1) + 2)
alpha = math.pow(beta, pw)
ratio = ph / 100.0 + 1.5
var float e0 = na
var float e1 = na
var float e2 = na
var float value = na
if na(x)
e0 := na
e1 := na
e2 := na
value := na
else
priorE0 = nz(e0[1], seed ? x : 0.0)
priorValue = nz(value[1], seed ? x : 0.0)
e0 := (1 - alpha) * x + alpha * priorE0
e1 := (x - e0) * (1 - beta) + beta * nz(e1[1])
e2 := (e0 + ratio * e1 - priorValue) * math.pow(1 - alpha, 2) + math.pow(alpha, 2) * nz(e2[1])
value := priorValue + e2
value
price = demo ? (bar_index == 0 ? 100.0 : 110.0) : src
value = publicJma(price, length, phase, power, seedFirst)
plot(value, "Public approximation", color=color.blue, linewidth=2)
plot(demo ? price : na, "Synthetic input", color=color.gray)
crossUp = ta.crossover(price, value)
crossDown = ta.crossunder(price, value)
alertcondition(not demo and barstate.isconfirmed and crossUp, "Close crossed above", "Source closed above the public approximation")
alertcondition(not demo and barstate.isconfirmed and crossDown, "Close crossed below", "Source closed below the public approximation")Source: everget public implementation. The displayed adaptation is licensed under GPL-3.0. A missing source value resets the state; the next valid value starts a new sequence. That differs from blindly replacing a missing price with zero.
Validate values before adding trading rules
- Record the script revision, symbol, exchange, chart timeframe, session, source, all three parameters and seed setting.
- Run the synthetic test first. Then compare market-data values against this exact implementation with matching history, rather than a different script carrying the JMA name.
- Inspect both a steady region and a sudden jump. Compare absolute output errors and overshoot before interpreting a crossover.
- Create alerts only after the comparison. The example evaluates crossings every bar and requires the chart bar to close before alerting.
TradingView documents barstate.isconfirmed and repainting behavior. Close confirmation addresses the open chart bar; it does not make a supplied external indicator source or higher-timeframe data safe automatically. Oscillating prices can repeatedly cross the filter, and overshoot can cause a cross without a new price trend. A syntax pass does not prove signal quality.
Continue with the Pine Script AI Coding Agent
Pineify's agent can create and edit Pine Script code documents and provides a syntax-check tool when requested. Supply the public source, license, parameter bounds, initialization policy and closed-bar conditions. Ask it to preserve the synthetic test so you can compare outputs in TradingView before adding alerts. It cannot establish equivalence to an undisclosed algorithm.
Educational information, not investment advice. Filter response is not evidence of profitability. No trading result is promised.
JMA questions
Sources and public implementation checked October 17, 2026.