What Is an SMA Moving Average? Pine Script v6 Guide to Simple Moving Averages
When analyzing price charts, raw candlestick data can appear noisy and difficult to interpret — the Simple Moving Average (SMA) is one of the most fundamental mathematical tools used to smooth that noise and reveal the underlying directional trend of a market.
1. What Is a Simple Moving Average (SMA)?
A Simple Moving Average is a statistical calculation that computes the arithmetic mean of a price series over a fixed number of periods. At each bar, the SMA sums the most recent N closing prices and divides by N, producing a single smoothed value that "rolls" forward with each new bar.
Mathematical Definition
For a window of length $N$, the SMA at time $t$ is defined as:
$$\text{SMA}_t = \frac{1}{N} \sum_{i=0}^{N-1} P_{t-i}$$
Where $P_{t-i}$ is the price at bar $t - i$. Every observation within the window receives an equal weight of $\frac{1}{N}$.
Numerical Example
Consider 5 consecutive closing prices: 10, 12, 11, 13, 14. The 5-period SMA is:
$$\text{SMA}_5 = \frac{10 + 12 + 11 + 13 + 14}{5} = \frac{60}{5} = 12.0$$
As the next bar arrives with price 15, the oldest value (10) is dropped and the window shifts:
$$\text{SMA}_5 = \frac{12 + 11 + 13 + 14 + 15}{5} = \frac{65}{5} = 13.0$$
2. Why Does SMA Smooth Price Data?
The smoothing effect of the SMA comes directly from averaging. A single anomalous price spike — caused by a news event or low-liquidity moment — contributes only $\frac{1}{N}$ of the total weight. As $N$ increases, the influence of any single bar diminishes further, producing a flatter, slower-moving line.
| SMA Period (N) | Responsiveness | Smoothness | Lag | Common Use |
|---|---|---|---|---|
| 5 | Very High | Low | Minimal | Short-term noise filter |
| 20 | Moderate | Moderate | Moderate | Monthly trend reference |
| 50 | Low | High | Significant | Medium-term trend |
| 200 | Very Low | Very High | Large | Long-term trend baseline |
3. SMA Warm-Up Period
Because the SMA requires a full window of N bars before it can produce a valid result, the function ta.sma() returns na for the first N − 1 bars. The first non-na value appears at bar_index == N - 1.
For example, a 20-period SMA will have na on bars 0 through 18, and its first valid value on bar 19.
4. Implementing SMA in Pine Script v6
Pine Script v6 provides the built-in function ta.sma() to compute the Simple Moving Average. The length parameter accepts a series int, meaning it can be dynamically computed at runtime — a key advantage over functions like ta.ema() which require a simple int length.
Basic SMA Indicator
🔽 [Click to expand] View Full Pine Script Code — Basic SMA Indicator
//@version=6
indicator(title = "SMA Moving Average Demo", overlay = true)
// --- Inputs ---
// User-configurable SMA period; input.int returns input int, which satisfies simple int
int smaLength = input.int(defval = 20, title = "SMA Length", minval = 1, maxval = 500)
// --- Calculation ---
// ta.sma() accepts series int for length — dynamic lengths are fully supported
// Returns na for the first (smaLength - 1) bars
float smaValue = ta.sma(close, smaLength)
// --- Visualization ---
// Plot the SMA line on the main chart pane (overlay = true)
plot(
series = smaValue,
title = "SMA",
color = color.new(color.blue, 0),
linewidth = 2,
style = plot.style_line
)
Multi-Period SMA Comparison
A common technique is to plot multiple SMAs with different periods simultaneously to observe how shorter and longer windows interact with price.
🔽 [Click to expand] View Full Pine Script Code — Multi-Period SMA
//@version=6
indicator(title = "Multi-Period SMA Comparison", overlay = true)
// --- Inputs ---
// Three independently configurable SMA periods
int fastLen = input.int(defval = 10, title = "Fast SMA Length", minval = 1)
int medLen = input.int(defval = 50, title = "Medium SMA Length", minval = 1)
int slowLen = input.int(defval = 200, title = "Slow SMA Length", minval = 1)
// --- Calculations ---
// ta.sma() natively accepts series int — all three calls are fully legal
float fastSma = ta.sma(close, fastLen)
float medSma = ta.sma(close, medLen)
float slowSma = ta.sma(close, slowLen)
// --- Visualization ---
// Fast SMA: responsive, plotted in green
plot(
series = fastSma,
title = "Fast SMA",
color = color.new(color.green, 0),
linewidth = 1,
style = plot.style_line
)
// Medium SMA: balanced, plotted in orange
plot(
series = medSma,
title = "Medium SMA",
color = color.new(color.orange, 0),
linewidth = 2,
style = plot.style_line
)
// Slow SMA: smooth trend baseline, plotted in red
plot(
series = slowSma,
title = "Slow SMA",
color = color.new(color.red, 0),
linewidth = 2,
style = plot.style_line
)
5. SMA with Dynamic Length (Series Int)
One of the key technical advantages of ta.sma() in Pine Script v6 is that its length parameter accepts a series int. This means the window size can be computed dynamically on each bar — for example, derived from a volatility measure or another indicator output.
🔽 [Click to expand] View Full Pine Script Code — Dynamic Length SMA
//@version=6
indicator(title = "Dynamic Length SMA", overlay = true)
// --- Base length from user input ---
int baseLen = input.int(defval = 20, title = "Base SMA Length", minval = 2)
// --- Dynamic length: scale base length by a volatility proxy ---
// math.round() returns series float; int() cast produces series int
// ta.sma() accepts series int for length — this is fully legal
float volatilityRatio = ta.sma(high - low, baseLen) / ta.sma(close, baseLen)
// Guard against na on early bars and ensure minimum length of 2
int dynLen = na(volatilityRatio) ? baseLen : int(math.max(2.0, math.round(baseLen * (1.0 + volatilityRatio * 10.0))))
// --- Dynamic SMA calculation ---
// ta.sma() natively supports series int length — no compile error
float dynSma = ta.sma(close, dynLen)
// --- Static reference SMA for comparison ---
float staticSma = ta.sma(close, baseLen)
// --- Visualization ---
plot(dynSma, title = "Dynamic SMA", color = color.new(color.purple, 0), linewidth = 2)
plot(staticSma, title = "Static SMA", color = color.new(color.gray, 0), linewidth = 1)
6. SMA vs. Other Moving Averages — Key Differences
Understanding what makes the SMA unique requires comparing it to other common moving average types at the mathematical level.
| Property | SMA | EMA | WMA |
|---|---|---|---|
| Weight distribution | Equal ($\frac{1}{N}$ each) | Exponentially decaying | Linearly decreasing |
| Oldest bar weight | $\frac{1}{N}$ (same as newest) | Near zero (never exactly 0) | $\frac{1}{N(N+1)/2}$ (smallest) |
| Pine Script length qualifier | series int ✅ | simple int ⚠️ | series int ✅ |
| Warm-up bars | N − 1 bars return na | Starts from bar 0 (no na warm-up) | N − 1 bars return na |
| Reaction to price spike | Gradual (diluted by N) | Fast (high recent weight) | Moderate |
Important Pine Script v6 note: ta.ema() requires a simple int length — passing a series int (such as a dynamically computed value) to ta.ema() will cause a compile error. ta.sma() does not have this restriction and accepts series int lengths natively.
7. Practical Considerations
The Lag Property
Because the SMA averages past prices, it always lags behind the current price. The lag is approximately $\frac{N-1}{2}$ bars. For a 20-period SMA, the center of mass of the window is roughly 9.5 bars in the past. This is a mathematical property, not a flaw — it is precisely what produces the smoothing effect.
$$\text{Approximate Lag} = \frac{N - 1}{2} \text{ bars}$$
Handling na Values
When using SMA output in further calculations, always guard against na during the warm-up period using na() checks or nz():
//@version=6
indicator("SMA na Guard Example", overlay = true)
int len = input.int(20, "Length")
float smaVal = ta.sma(close, len)
// Safe downstream use: replace na with 0.0 using nz()
float safeVal = nz(smaVal, 0.0)
// Or use na() to conditionally skip logic during warm-up
float result = na(smaVal) ? na : close - smaVal // distance from price to SMA
plot(result, title = "Price - SMA", color = color.blue)
8. Conclusion
- The Simple Moving Average computes the arithmetic mean of the last $N$ prices, assigning equal weight $\frac{1}{N}$ to every bar in the window. It returns
nafor the first $N - 1$ bars and produces its first valid value atbar_index == N - 1. - In Pine Script v6,
ta.sma()uniquely accepts a series int for itslengthparameter, enabling fully dynamic window sizes computed at runtime — unliketa.ema()which is restricted to simple int lengths. - The SMA's smoothing power and lag are both direct mathematical consequences of averaging: larger $N$ produces a smoother line with greater lag ($\approx \frac{N-1}{2}$ bars), while smaller $N$ tracks price more closely at the cost of retaining more noise.
Ideas for Further Development
- SMA Ribbon: Plot 8–12 SMAs with incrementally increasing periods (e.g., 10, 20, 30, … 100) to create a visual "ribbon" that expands during trending markets and compresses during consolidation.
- SMA Deviation Band: Compute the standard deviation of price around the SMA using
ta.stdev()and plot upper/lower bands at ±1σ and ±2σ to quantify how far price has deviated from its mean — a foundation for mean-reversion analysis.
Comments
Post a Comment