TradingView indicators

Triangular moving average: weights and centered versions

A triangular moving average (TMA) gives the middle observations of a price window more weight than its ends. Two simple moving averages with carefully chosen lengths produce these weights. A causal TMA uses only the current and earlier bars. A centered version assigns the result to an earlier time and needs later prices to finish the calculation.

Five observations, one checkable result

100, 102, 101, 105, 107 → weights 1, 2, 3, 2, 1

TMA = 924 / 9 = 102.6667. In a causal calculation, this value belongs to the bar with price 107.

Inspect the Pine Script example

Odd and even lengths have different peaks

Let N be the total number of observations, a = ceil(N/2), and b = floor(N/2) + 1. Then TMA = SMA(SMA(source, a), b). Combining the windows covers a + b − 1 = N observations. Odd N has one peak weight; even N has two equal peak weights. Divide the weighted sum by a × b.

Formula reference: Sierra Chart triangular moving average.

TMA lengths, weights and denominators for a complete price series
NSMA lengthsWeights: oldest to newestDivisorObservations
11 then 1111
42 then 31, 2, 2, 164
53 then 31, 2, 3, 2, 195
63 then 41, 2, 3, 3, 2, 1126
2010 then 111, 2, …, 9, 10, 10, 9, …, 2, 111020

Odd example, N=5. For 100, 102, 101, 105, 107, the three inner SMA(3) values are 101, 102.6667 and 104.3333. Their average is 102.6667. Equivalently, (100 + 2×102 + 3×101 + 2×105 + 107) / 9 = 924/9.

Even example, N=6. Add 110 as the sixth price. SMA(3) now produces 101, 102.6667, 104.3333 and 107.3333. Averaging these four values gives 103.8333. The weighted calculation is (100 + 2×102 + 3×101 + 3×105 + 2×107 + 110) / 12 = 1246/12. Calculations use unrounded intermediate values.

These are hypothetical prices, not a backtest. Two SMA(20) passes cover 39 observations, so they do not produce the 20-observation TMA in this table.

Why a centered TMA changes at the right edge

Center the five-price window on the bar with price 101. Its final value of 102.6667 needs prices 105 and 107, which arrive one and two bars later. A complete centered line can leave the last two bars empty and fill them later. A version that draws estimates into that gap can revise those estimates as prices arrive. Moving a finished line two bars left does not make its value available two bars earlier.

For a concrete example, suppose a centered implementation omits unavailable future prices and divides by the weights available so far. The same historical bar then changes as follows. This is an illustrative endpoint rule; other centered scripts use different estimates.

Hypothetical revisions to the centered value assigned to the bar with price 101
When observedCalculation at that same barValue
Bar 101 closes(100 + 2×102 + 3×101) / 6101.1667 (partial)
Next bar closes at 105(607 + 2×105) / 8102.1250 (partial)
Next bar closes at 107(817 + 107) / 9102.6667 (complete)

A hypothetical threshold at 102 would not be exceeded by the initial estimate, yet would be exceeded on the finished chart. Treating that revised value as an entry known at the original bar introduces future information. For even N, the weight center lies between bars, so inspect the script's alignment convention as well as its endpoint calculation.

Mladen Rakic's explanation of his centered TMA describes the right-edge estimation issue. TradingView's repainting documentation distinguishes open-bar changes from misleading plots placed in the past.

Causal TMA in Pine Script v6

Paste this indicator into TradingView's Pine Editor, save it, and add it to a chart. Length means the total observation window. The line has no offset and uses no future bars. Its crossover marker and alert condition wait for the current bar to close; the line itself still updates during that bar.

Pine Script v6 · indicator
//@version=6
indicator("Causal triangular moving average", overlay=true)

length = input.int(20, "TMA length", minval=1)
source = input.source(close, "Source")
firstLength = int(math.ceil(length / 2.0))
secondLength = int(math.floor(length / 2.0)) + 1
tma = ta.sma(ta.sma(source, firstLength), secondLength)

crossedAbove = ta.crossover(source, tma)
confirmedCross = barstate.isconfirmed and crossedAbove

plot(tma, "TMA", color=color.blue, linewidth=2)
plotshape(confirmedCross, title="Confirmed cross above", style=shape.triangleup, location=location.belowbar, color=color.blue, size=size.tiny)
alertcondition(confirmedCross, "Confirmed cross above TMA", "Source crossed above TMA on a closed bar.")

Copy code

  • For continuous valid prices, the first TMA needs N observations. The crossover also needs a previous TMA value.
  • The two SMA calls ignore missing source values. An external series with gaps may span more than N chart bars and will not follow the contiguous-bar examples above.
  • Choose a price source such as close when checking these examples. A repainting external indicator remains a repainting input even if the TMA waits for bar close.
  • Historical data corrections can alter old values. Close confirmation does not protect against data revisions.

The marker is a calculation example, not an order or a complete trading strategy. Creating an alert in TradingView is a separate step.

Compare weights before comparing lag

TMA concentrates weight in the middle; SMA spreads weight equally; linear WMA gives the newest price the largest weight. For a complete N-observation window, both TMA and SMA have weighted average age (N − 1)/2 bars because both weight profiles are symmetric. At N=20 that is 9.5 bars. It is a property of the weights, not a promise that either crossover will arrive exactly 9.5 bars after a price turn.

A new price has weight 1/110 in a 20-observation TMA versus 1/20 in SMA. If a constant price series jumps by 10 on its newest bar, the first TMA change is 10/110 = 0.0909, versus 0.5 for SMA. Later responses depend on subsequent prices and the bars leaving the window. Neither this example nor double smoothing establishes fewer false signals or a better return.

Before testing a trading rule, fix the source, timeframe, total window length, confirmation timing and transaction costs. Compare signals using values actually available at the decision time. Educational information only; this is not investment advice.

Specify the TMA you want Pineify to draft

Pine Script AI Coding Agent can help draft or revise a script from explicit rules. Use a request that fixes the ambiguity:

Create a Pine Script v6 TMA with total length N, using SMA(SMA(close, ceil(N/2)), floor(N/2)+1). Add a length input, no backward plot offset, and close-confirmed crossover alerts. Explain warm-up and verify the weights for N=5 and N=6.

Inspect the output and test it on TradingView. Code generation and syntax checks do not establish trading performance or prove every data source is free of repainting.

Explore Pine Script AI Coding Agent

TMA questions

Sources and related calculations

References checked October 17, 2026. Numeric examples are derived from the stated weights.

Compare the SMA calculation and linear WMA weights, or return to TradingView indicators.