Skip to content
Open RaamTrade

TRIMA — Triangular Moving Average

An average whose weights rise to a peak at the window’s centre and fall away again — equivalently, an SMA of an SMA. Smoother than an SMA of the same length, and laggier by about half the window.

Signature

TRIMA(period, on=<source>)
Argument Type Required Notes
period int Param or literal Yes Window. Default 20, bounds 1–400.
on= symbol, OHLCV field, or indicator No Source. Defaults to the trade symbol’s close.

Formula

$$ w_i = \min(i+1,\ n-i), \quad \text{TRIMA} = \frac{\sum_i w_i C_i}{\sum_i w_i} $$

Weights are symmetric and peak at the middle of the window.

Warmup

period bars; during the lead-in the triangle is built over the bars available.

Reading the value

trima.value
trima.crossed_above(fast)

Example

class TrimaBaseline(Strategy):
"""Use the smoothest baseline available as a regime filter."""
trade = Symbol()
sizing = FixedCapital()
def execute(self):
trima = TRIMA(30, on=self.trade)
fast = EMA(10, on=self.trade)
if fast.crossed_above(trima) and self.trade.is_flat:
self.buy(self.trade, reason="EMA over TRIMA")
if fast.crossed_below(trima) and self.trade.is_long:
self.sell(self.trade, self.trade.position, reason="EMA under TRIMA")

Notes

  • Standard triangular weighting (TA-Lib TRIMA).
  • Proven by an assert-via-trade run on SPY daily (matched a strategy-side triangular-weight reference to 1e-3 on every bar; zero alarm trades).
  • Use it where smoothness matters more than timing — as a baseline, not a trigger.
  • A different recipe from pandas_ta’s trima(10), not a different scale: measured on a 300-bar tape ours stays about 2.3 % away and never converges to it, because the construction (window offset, seed, weight normalisation) is its own.