The Weighted Moving Average assigns linearly increasing weights to more recent prices.
The denominator is the triangle number — the sum of weights 1 + 2 + … + N.
WMA falls between SMA and EMA in responsiveness. Less common in practice than EMA, but useful when you want linear rather than exponential decay of older data.
Weights 1 to 5, newest heaviest. Day 15: (1×104 + 2×102 + 3×99 + 4×101 + 5×104) / 15 = 1529 / 15 = 101.93. On day 8, at the end of the rally, it led the SMA by 0.67 (107.47 against 106.80): the heavy weights sit on the latest prices.
The example data: 15 days, used in every indicator here
| Day | High | Low | Close | Volume |
|---|---|---|---|---|
| 1 | 101 | 99 | 100 | 50,000 |
| 2 | 103 | 100 | 102 | 62,000 |
| 3 | 103 | 100 | 101 | 48,000 |
| 4 | 105 | 101 | 104 | 70,000 |
| 5 | 108 | 104 | 107 | 85,000 |
| 6 | 108 | 105 | 106 | 60,000 |
| 7 | 110 | 106 | 109 | 90,000 |
| 8 | 110 | 107 | 108 | 72,000 |
| 9 | 108 | 104 | 105 | 80,000 |
| 10 | 105 | 102 | 103 | 66,000 |
| 11 | 105 | 102 | 104 | 55,000 |
| 12 | 104 | 101 | 102 | 75,000 |
| 13 | 102 | 98 | 99 | 95,000 |
| 14 | 102 | 99 | 101 | 64,000 |
| 15 | 105 | 101 | 104 | 71,000 |
- The weights drop to zero at the edge of the window, so a price leaving it still makes the line jump a little.
- Linear weights are a choice, not a finding — there is no evidence they beat exponential ones. Pick by how quickly you want old data to fade.
- Like every average, it confirms a turn rather than predicting it.
w = np.arange(1, 6) # weights 1..5, newest heaviest df['wma5'] = df['close'].rolling(5).apply(lambda x: (x * w).sum() / w.sum(), raw=True)
Assumes import numpy as np, import pandas as pd, and a DataFrame df with columns high, low, close and volume — the 15 days above.
- Trading Systems and Methods (5th ed.), P. J. Kaufman, Wiley, 2013 — the moving-average family compared
- Technical Analysis of the Financial Markets, J. J. Murphy, New York Institute of Finance, 1999
Last reviewed October 2026 · How this site checks its content · Report a mistake