MADeviation — MA Deviation
The signed distance between price and its simple moving average, in price units. Positive means price is above the average, negative means below.
MADeviation is the identifier a strategy writes; MA Deviation is the label the chart’s indicator picker shows. Single value — .value is the only accessor.
Signature
MADeviation(period, on=<source>)| Argument | Type | Required | Notes |
|---|---|---|---|
period |
int Param or literal | Yes | Length of the moving average. Default 20, bounds 2–200. |
on= |
symbol, OHLCV field, or indicator | No | Source. Defaults to the trade symbol’s close. |
Formula
$$ \text{MADeviation}t = \text{close}t - \frac{1}{N} \sum{i=0}^{N-1} \text{close}{t-i} $$
No scaling, no floor, no absolute value — just the subtraction. The result is in the source’s units, which is why it is unbounded and instrument-specific.
Warmup
period bars. Before the window fills the indicator returns 0, which on this scale reads as “price is exactly on its average”. A strategy never observes it (execute() waits until every indicator is ready); it is what the chart plots on the leading bars.
Reading the value
dev.value # price units, signeddev.value_at(1)dev > 0 # price above its averagedev.crossed_above(0) # the bar price reclaims the averagedev.value / self.trade.close * 100 # the same thing as a percentageExample
class DeviationFade(Strategy): """Fade price when it stretches too far below its own average.""" period = Param(20, min=2, max=200) trade = Symbol() sizing = FixedCapital()
def execute(self): dev = MADeviation(self.period, on=self.trade) self.stop_loss(3.0)
stretch = dev.value / self.trade.close * 100
if stretch < -3 and self.trade.is_flat: self.buy(self.trade, reason=f"Price {stretch:.1f}% under its average")
if stretch > 0 and self.trade.is_long: self.sell(self.trade, self.trade.position, reason="Back at the average")Notes
- Unbounded and price-scaled.
dev.value > 2means something entirely different on a $15 stock and a $5,000 index. Normalize by price, as the example does — or useTrendIntensity, which is this measure already divided by the average. - The sign alone is a complete trend filter:
dev > 0is exactlyclose > SMA(period). Everything the sign can tell you, anSMAcomparison tells you too; the magnitude is what this indicator adds. - It is the raw material of a band system —
SMA ± k · StdDevisBollingerBands, anddev.valueis the numerator of the position inside those bands. - Useful chained:
SMA(5, on=dev)smooths the stretch into something closer to a slow oscillator.