TradingView indicators

FRAMA and FRAMA Channels on TradingView

The Fractal Adaptive Moving Average changes its smoothing weight using a range-based estimate of price roughness. A FRAMA channel adds a separate width rule around that center. This guide explains the original calculation and defines one reproducible ATR channel extension, including its inputs, warm-up and closing-bar alerts.

Worked example and code, not a performance study. No settings or trading returns are established by this guide.

FRAMA formula: from ranges to adaptive smoothing

John Ehlers defines FRAMA using two adjacent half-windows and the full window. For an even length N, let h = N / 2. Each high-low range is divided by its own number of bars. The halves do not overlap. Read Ehlers' original paper (PDF mirror).

Nrecent = (highest high − lowest low over bars 0…h−1) / h

Nolder = (highest high − lowest low over bars h…N−1) / h

Nfull = (highest high − lowest low over bars 0…N−1) / N

D = [ln(Nrecent + Nolder) − ln(Nfull)] / ln(2)

α = clamp(exp(−4.6 × (D − 1)), 0.01, 1)

FRAMA = α × source + (1 − α) × previous FRAMA

Lower D produces a larger current-source weight; higher D produces more smoothing. At D = 1, α = 1. At D = 2, exp(−4.6) is approximately 0.010052. The 0.01 floor and 1 ceiling bound the weight. These are smoothing coefficients, not probabilities of a trend.

In this implementation, changing the source changes the filtered input only: the dimension still uses chart highs and lows. A close-based FRAMA and an hl2-based FRAMA can differ even when their dimension and alpha agree. The paper uses hl2 and length 16; this page's code keeps close and length 14 as explicit defaults.

A calculation you can reproduce

This hypothetical 16-bar window has older-half low/high 100/106 and recent-half low/high 102/108. Both halves contain 8 bars; the full range is 100 to 108. Assume the filter is warmed up, previous FRAMA is 100 and the current source is 104. These are demonstration inputs, not market observations.

StepCalculationResult
Recent half(108 − 102) / 80.75
Older half(106 − 100) / 80.75
Full window(108 − 100) / 160.50
Dimensionln((0.75 + 0.75) / 0.50) / ln(2)1.584963
Alphaexp(−4.6 × (1.584963 − 1))0.067825
Current FRAMA100 + 0.06782479 × (104 − 100)100.271299
ATR half-widthAssumed ATR = 3; multiplier = 1.54.50
Channel rails100.271299 ± 4.5095.771299 / 104.771299

Using raw ranges would give ln((6 + 6) / 8) / ln(2) = 0.584963, exactly 1 below the normalized estimate. Its alpha would hit the ceiling of 1, incorrectly replacing the filter value with 104. Normalization changes the behavior, not just the units.

The assumed ATR value is a separate input to this arithmetic example. Half-window extrema alone cannot reconstruct ATR, because true range also uses each previous close. The closing price 104 is below the upper rail 104.771299; the example does not establish an upper-rail crossover.

FRAMA + ATR channel v1: the extension used here

This page defines upper = FRAMA + k × ATR and lower = FRAMA − k × ATR. The ATR rails are an added construction; they are not part of Ehlers' original center-line formula. A script named "FRAMA Channel" may instead use a smoothed high-low range, standard deviation, different sources or different initialization. Compare its code before expecting matching plots.

Our v1 uses Pine's ta.atr with a separate ATR length, default 14, and multiplier k, default 1.5. ATR measures volatility using true range, including gaps from the previous close; it does not supply direction. TradingView documents the true-range calculation and RMA smoothing.

  • Center response: FRAMA length controls the ranges used for D. It is independent of the ATR lookback.
  • Rail distance: multiplier zero collapses both rails onto the center. A larger multiplier increases their distance for the same ATR.
  • Noise zone: "inside the channel" means price lies between this version's rails. It is not proof of random behavior. High D and high ATR can coexist.
  • Alert definition: close crosses the current upper or lower rail, confirmed at bar close. This compares two moving series; it is not a cross of yesterday's fixed rail. Both current and previous bars must have ready channel values.

At α = 1 with close as the source, the center equals the close. With a positive width, close cannot lie outside the current rails on that bar. Thus a fast center can suppress a channel event even during a large move. Switching to previous-bar rails would define a different event and needs separate testing.

FRAMA Pine Script v6 with optional ATR rails

Paste this indicator into TradingView's Pine Editor, save it and add it to the chart. Disable "Show ATR channel" to inspect the FRAMA center alone. This display switch does not disable alert conditions. The Data Window exposes D, alpha and ATR for comparison.

Pine Script v6 · FRAMA + ATR channel v1
//@version=6
indicator("FRAMA + ATR channel v1 (Pineify example)", overlay=true)

source = input.source(close, "FRAMA source")
length = input.int(14, "FRAMA length (even)", minval=4, maxval=500, step=2)
atrLength = input.int(14, "ATR length", minval=1)
multiplier = input.float(1.5, "ATR multiplier", minval=0.0, step=0.1)
showChannel = input.bool(true, "Show ATR channel")
if length % 2 != 0
    runtime.error("FRAMA length must be even; odd lengths are not rounded.")

half = int(length / 2)
recentHigh = ta.highest(high, half)
recentLow = ta.lowest(low, half)
nRecent = (recentHigh - recentLow) / half
nOlder = (recentHigh[half] - recentLow[half]) / half
nFull = (ta.highest(high, length) - ta.lowest(low, length)) / length
ready = bar_index >= length
validRanges = not na(nOlder) and nRecent > 0 and nOlder > 0 and nFull > 0
// Explicit fallback: retain dimension; use 1 until the first valid estimate.
var float dimension = 1.0
if ready and validRanges
    dimension := (math.log(nRecent + nOlder) - math.log(nFull)) / math.log(2.0)
alpha = math.max(0.01, math.min(1.0, math.exp(-4.6 * (dimension - 1.0))))
var float frama = na
frama := not ready or na(frama[1]) ? source : alpha * source + (1.0 - alpha) * frama[1]

// ATR rails are this example's extension, not part of the original FRAMA.
atrValue = ta.atr(atrLength)
upper = frama + multiplier * atrValue
lower = frama - multiplier * atrValue
channelReady = ready and not na(atrValue)
plot(frama, "FRAMA", color=color.blue, linewidth=2)
pUpper = plot(showChannel and channelReady ? upper : na, "Upper ATR rail", color=color.gray)
pLower = plot(showChannel and channelReady ? lower : na, "Lower ATR rail", color=color.gray)
fill(pUpper, pLower, color=color.new(color.blue, 92))
plot(ready ? dimension : na, "Dimension", display=display.data_window)
plot(ready ? alpha : na, "Alpha", display=display.data_window)
plot(atrValue, "ATR", display=display.data_window)

crossUp = ta.crossover(close, upper)
crossDown = ta.crossunder(close, lower)
upEvent = channelReady and channelReady[1] and barstate.isconfirmed and crossUp
downEvent = channelReady and channelReady[1] and barstate.isconfirmed and crossDown
alertcondition(upEvent, "Close crosses above upper rail", "Close crossed above the current FRAMA ATR upper rail at bar close.")
alertcondition(downEvent, "Close crosses below lower rail", "Close crossed below the current FRAMA ATR lower rail at bar close.")

Pineify syntax validation passed for this code. Syntax validation does not verify strategy profitability or agreement with another author's implementation.

Parameters, warm-up and failure modes

Input or conditionv1 behaviorWhat to verify
FRAMA length: 14Even integer from 4 to 500; odd values cause an error.Do not truncate one half or mix lengths in denominators.
Source: closeHigh/low windows still determine D.Match source before comparing two FRAMA lines.
First N barsCenter equals source; channel is hidden.First adaptive update is bar N + 1 in the loaded dataset.
Zero rangeRetain prior D; seed D = 1 before any valid estimate.A retained value contains no fresh roughness measurement.
ATR length: 14Rails wait for a non-missing ATR and FRAMA readiness.A larger ATR length can extend channel warm-up.
Multiplier: 1.5Nonnegative width; rails move with center and ATR.Width is not a confidence interval or a stop-loss guarantee.

Finite windows with gaps can produce D below 1: the full range may span a gap that neither half contains. The code bounds alpha instead of silently forcing D into a presumed interval. Inspect the raw dimension when the center suddenly follows the source exactly.

Small windows make the estimate sensitive to a few highs and lows. A changing extreme can alter D without a persistent trend change. D = 1.5 gives alpha about 0.100259 in this formula; it does not certify a random walk, and no universal D cutoff separates tradable trends from noise.

The live line and rails update as the current bar changes. Alerts use barstate.isconfirmed, which becomes true on the realtime bar's closing update. TradingView's bar-state reference explains that timing. Confirmation can remove a disappearing intrabar cross from the alert stream, but cannot prevent later price reversals.

A price cross, slope change or rail breakout is an observation, not a complete trading strategy. Entries still need explicit exits, position size, transaction costs and fill assumptions. Adding RSI or another price-based filter does not make the evidence independent or establish a better win rate.

Verify the values before adding trading rules

  1. Fix the symbol, timeframe, session and chart type. Use the same loaded data when comparing recursive filters.
  2. Start with the default 14-bar close version. After warm-up, inspect one completed bar's two 7-bar ranges, full range, D and alpha.
  3. Recalculate the center from its previous value. Then check ATR and both rails separately. Change one input at a time.
  4. Create an alert for the required crossing condition using a closing-bar frequency. Confirm whether the rule uses current rails, as v1 does, or a prior fixed rail.
  5. For a strategy experiment, specify exits, costs and position sizing before measuring results. Evaluate reserved data rather than selecting parameters from the best-looking chart.

Continue in Pineify's Pine Script AI Coding Agent

Give the agent the version contract and ask for inspectable values. For example: "Keep two equal high-low half-windows, reject odd lengths, retain D on zero range, and plot D and alpha in the Data Window. Add ATR rails with independent inputs and confirmed current-rail crossover alerts." Compare the generated output bar by bar before requesting strategy entries and exits.

Open Pine Script AI Coding Agent

FRAMA questions

FRAMA is an adaptive moving average developed by John Ehlers. It estimates price roughness from high-low ranges and changes the weight given to the current source value. It produces a center line; a channel needs an additional width rule.

A FRAMA center line does not specify channel width. Check each script's source, smoothing, range estimator, multiplier and alert rules. This page defines FRAMA + ATR channel v1, with upper and lower rails at FRAMA plus or minus 1.5 times ATR(14) by default.

No best settings are established here. The example uses a 14-bar even length and close source. Compare alternatives on the same instrument, timeframe and data, then reserve separate data for testing. ATR length and multiplier change the channel independently of the FRAMA length.

The current bar's source, high and low can change before close, so the live center and rails can move. The example alerts require barstate.isconfirmed. This confirms a closing-bar event; it does not freeze the plots during the open bar.

This example rejects odd lengths because its two non-overlapping half-windows must have equal integer sizes. It does not silently round 15 to 14 or 16. Other implementations may use different conventions and therefore produce different values.

If any required range is zero, this example skips the logarithms and retains the previous dimension. Before the first valid estimate it uses dimension 1. The Data Window makes the result visible; a stale dimension is not new evidence about market structure.

EMA uses a fixed smoothing coefficient for a chosen length. FRAMA changes that coefficient using its range-based dimension estimate. This difference alone does not establish lower lag, fewer losing trades or superior returns on a particular market.

Sources and related indicators

Sources reviewed October 17, 2026. The numeric example and ATR channel v1 are this page's demonstrations.