TRIX indicator: formula, Pine Script and limits
TRIX measures the one-bar rate of change after three EMA smoothing passes. This guide implements the percentage-change definition, so its output is in percent. Use the worked values and copyable script to check the calculation before interpreting zero crossings or adding trading rules.
Source → EMA1 → EMA2 → EMA3 → 1 bar % ROC
A signal line is a separate EMA of TRIX. Neither line is a complete trading strategy.
Three smoothing passes, then a percentage change
E1 = EMA(source, N)
E2 = EMA(E1, N)
E3 = EMA(E2, N)
TRIX = 100 × (E3 − E3[1]) / E3[1]
Signal = EMA(TRIX, M)
The [1] index means the previous chart bar. The denominator must exist and be nonzero. TradingView's TRIX documentation describes this sequence using an 18-period EMA. The sample below makes N and M editable.
Check which implementation you are comparing. A log-price variant calculates 10000 × change(EMA³(log(close))). That is a scaled difference of smoothed logarithms, not the exact percentage formula above. Matching length alone will not make the values match, and the logarithm requires positive input.
TEMA also uses three EMAs, but combines their levels as 3 × E1 − 3 × E2 + E3. It is a moving average in price units. Raw price ROC omits the three smoothing passes.
Worked example: price drops before TRIX crosses zero
Hypothetical inputs only. Set N = 3 and M = 3, so each EMA uses α = 2 / (3 + 1) = 0.5. Seed all three price EMAs at 100 on bar 0, then seed the signal at the first valid TRIX. Each following EMA is half its current input plus half its previous value. There are no missing observations; displayed percentages are rounded to six decimals.
| Bar | Source | EMA1 | EMA2 | EMA3 | TRIX % | Signal % |
|---|---|---|---|---|---|---|
| 0 | 100 | 100 | 100 | 100 | na | na |
| 1 | 108 | 104 | 102 | 101 | 1.000000 | 1.000000 |
| 2 | 108 | 106 | 104 | 102.5 | 1.485149 | 1.242574 |
| 3 | 108 | 107 | 105.5 | 104 | 1.463415 | 1.352994 |
| 4 | 100 | 103.5 | 104.5 | 104.25 | 0.240385 | 0.796690 |
| 5 | 100 | 101.75 | 103.125 | 103.6875 | -0.539568 | 0.128561 |
| 6 | 100 | 100.875 | 102 | 102.84375 | -0.813743 | -0.342591 |
At bar 4, source falls from 108 to 100, but EMA3 still rises from 104 to 104.25. TRIX is 100 × 0.25 / 104 = 0.240385%. It crosses below its signal on that bar while remaining positive. The zero crossing follows on bar 5. This one-bar separation belongs to this example; it is not a fixed lag estimate for other inputs or lengths.
Bar 0 has no previous EMA3, so its TRIX is unavailable. A nonzero constant input gives zero TRIX from the next bar. With N = 1, all three EMAs equal the source and the result becomes its one-bar percentage ROC.
Pine Script v6: TRIX with a signal line
Create a new indicator in TradingView's Pine Editor, replace its contents with this source, save it and select Add to chart. Blue is percentage TRIX; orange is its EMA signal. The triangles and alert conditions require the chart bar to close. Create an alert separately in TradingView if needed.
//@version=6
indicator("TRIX: percent ROC", overlay=false, precision=6)
length = input.int(18, "EMA length", minval=1)
signalLength = input.int(9, "Signal EMA length", minval=1)
source = input.source(close, "Source")
e1 = ta.ema(source, length)
e2 = ta.ema(e1, length)
e3 = ta.ema(e2, length)
valid = not na(source) and not na(e3) and not na(e3[1]) and e3[1] != 0
trix = valid ? 100 * (e3 - e3[1]) / e3[1] : na
signal = ta.ema(trix, signalLength)
crossUp = ta.crossover(trix, signal)
crossDown = ta.crossunder(trix, signal)
ready = valid and not na(trix[1]) and not na(signal[1])
confirmedUp = ready and crossUp and barstate.isconfirmed
confirmedDown = ready and crossDown and barstate.isconfirmed
plot(trix, "TRIX (%)", color=color.blue, linewidth=2, style=plot.style_linebr)
plot(valid ? signal : na, "Signal (%)", color=color.orange, style=plot.style_linebr)
hline(0, "Zero", color=color.gray)
plotshape(confirmedUp, title="Confirmed upward cross", style=shape.triangleup, location=location.bottom, color=color.blue, size=size.tiny)
plotshape(confirmedDown, title="Confirmed downward cross", style=shape.triangledown, location=location.top, color=color.orange, size=size.tiny)
alertcondition(confirmedUp, "TRIX upward cross", "TRIX crossed above its EMA signal at bar close.")
alertcondition(confirmedDown, "TRIX downward cross", "TRIX crossed below its EMA signal at bar close.")The lines can move while a bar is open. The confirmation condition only restricts markers and alerts. Missing source or a missing/zero previous EMA3 produces a gap. The signal EMA can retain its previous state across unavailable TRIX values; this script does not reset the entire history after a gap.
Parameters, initialization and comparison checks
| Input | Sample default | What to check |
|---|---|---|
| EMA length N | 18 | Applied to every smoothing stage, not the ROC interval. |
| Signal length M | 9 | An example choice. At M = 1 the signal equals TRIX, so strict crosses disappear. |
| Source | close | Match source and chart type when comparing scripts. |
ta.ema is recursive. A plotted value can appear before the effect of its starting history is negligible. Loading a longer history, using an SMA seed in another implementation or changing adjusted prices can alter early values. Do not treat 3 × N bars as a guaranteed convergence period.
- Match formula, units, symbol, timeframe, source and all lengths.
- Compare EMA1, EMA2 and EMA3 before comparing their ROC. A seed mismatch starts upstream.
- Load more history and compare overlapping closed bars against an explicit tolerance.
- Check flat inputs, N = 1, a zero denominator and missing data before testing trading conditions.
Read the condition before assigning a trade
With positive EMA3 values, TRIX above zero means EMA3 rose from the prior bar. Falling positive TRIX means that percentage rise is slowing. Neither statement requires the current source bar to rise, as bar 4 demonstrates.
A cross above the signal says TRIX has moved above its own EMA. It can happen below zero. Repeated crosses in sideways data are possible; smoothing does not establish a win rate or remove loss risk. Divergence also needs an explicit pivot rule and confirmation delay before it can be coded or tested consistently.
For negative inputs, the denominator can reverse the sign interpretation. Near zero, small changes can create extreme percentages. Inspect synthetic spreads or external indicator sources before applying price-based interpretations.
Educational calculation example, not investment advice. This indicator has no position sizing, exits, execution model or trading costs. A confirmed crossover does not establish profitability.
Take an explicit TRIX specification to Pineify
The Pine Script AI Coding Agent can help turn the calculation into an editable script. Include the percentage formula, source, both lengths, missing-value handling and closed-bar confirmation in your request. Ask for intermediate EMA plots when diagnosing differences.
First compare values bar by bar. If you later request a strategy, define the entry, exit, position size, fill timing, commission and slippage separately. Review the generated source and test it on TradingView.
Open the Pine Script AI Coding AgentTRIX questions
Sources and related guides
Official references checked October 17, 2026. The worked table is an independent calculation under its stated assumptions.
- TradingView: TRIX calculation
- TradingView: Triple EMA calculation
- TradingView: bar states
- TradingView: create a first indicator