Weighted Moving Average (WMA)

Haiyue
9min

I. What is WMA

The Weighted Moving Average (WMA) is a moving average calculated using linearly increasing weights. Unlike SMA’s equal-weight method, WMA assigns the highest weight to the most recent price and the lowest weight to the oldest price, with weights decreasing in a linear proportion.

Historical Background

WMA is the most intuitive improvement over SMA. Its underlying idea comes from a simple observation: more recent data is more important for predicting the future. WMA was widely used in the early days of technical analysis development. Although there is no single “inventor,” it became a standard tool as technical analysis was formalized in the mid-20th century. WMA is also the core building block of the HMA (Hull Moving Average).

Indicator Classification

  • Type: Overlay indicator, plotted on the price chart
  • Category: Moving Averages
  • Default Parameters: Period n=20n = 20, data source is closing price (Close)

II. Mathematical Principles and Calculation

Core Formula

WMA uses linearly increasing weights. For a window of size nn:

WMAt=nPt+(n1)Pt1+(n2)Pt2++1Ptn+1n+(n1)+(n2)++1WMA_t = \frac{n \cdot P_t + (n-1) \cdot P_{t-1} + (n-2) \cdot P_{t-2} + \cdots + 1 \cdot P_{t-n+1}}{n + (n-1) + (n-2) + \cdots + 1}

The denominator is the sum of the first nn natural numbers:

i=1ni=n(n+1)2\sum_{i=1}^{n} i = \frac{n(n+1)}{2}

Therefore the formula can be simplified to:

WMAt=i=0n1(ni)Ptin(n+1)2WMA_t = \frac{\sum_{i=0}^{n-1} (n - i) \cdot P_{t-i}}{\frac{n(n+1)}{2}}

Weight Distribution

For a 5-day WMA, the weight assignment is as follows:

Time PointWeight CoefficientNormalized Weight
PtP_t (today)55/15 = 33.3%
Pt1P_{t-1} (yesterday)44/15 = 26.7%
Pt2P_{t-2}33/15 = 20.0%
Pt3P_{t-3}22/15 = 13.3%
Pt4P_{t-4}11/15 = 6.7%
Comparison with EMA Weights

WMA weights exhibit linear decay (arithmetic decrease), while EMA weights follow exponential decay. WMA has a hard cutoff to zero at the window boundary, whereas EMA weights are never truly zero but approach zero. WMA concentrates more weight on recent data compared to EMA.

Step-by-Step Calculation Example

Suppose a 5-day WMA with price sequence [10, 11, 12, 13, 14]:

WMA=5×14+4×13+3×12+2×11+1×105+4+3+2+1WMA = \frac{5 \times 14 + 4 \times 13 + 3 \times 12 + 2 \times 11 + 1 \times 10}{5 + 4 + 3 + 2 + 1}

=70+52+36+22+1015=1901512.67= \frac{70 + 52 + 36 + 22 + 10}{15} = \frac{190}{15} \approx 12.67

For comparison, SMA: (10+11+12+13+14)/5=12.0(10 + 11 + 12 + 13 + 14) / 5 = 12.0

The WMA value (12.67) is closer to the latest price (14), demonstrating the effect of assigning higher weight to recent prices.


III. Python Implementation

import numpy as np
import pandas as pd

def wma(close: pd.Series, period: int = 20) -> pd.Series:
    """
    Calculate the Weighted Moving Average (WMA)

    Parameters
    ----------
    close : pd.Series
        Closing price series
    period : int
        Calculation period, default is 20

    Returns
    -------
    pd.Series
        WMA value series
    """
    weights = np.arange(1, period + 1, dtype=float)

    def _wma(window):
        return np.dot(window, weights) / weights.sum()

    return close.rolling(window=period, min_periods=period).apply(_wma, raw=True)


def wma_vectorized(close: np.ndarray, period: int = 20) -> np.ndarray:
    """
    Vectorized WMA implementation (high-performance version)
    """
    n = len(close)
    result = np.full(n, np.nan)
    weights = np.arange(1, period + 1, dtype=float)
    denom = weights.sum()

    for i in range(period - 1, n):
        window = close[i - period + 1 : i + 1]
        result[i] = np.dot(window, weights) / denom

    return result


# ========== Usage Example ==========
if __name__ == "__main__":
    # Generate simulated OHLCV data
    np.random.seed(42)
    dates = pd.date_range("2024-01-01", periods=100, freq="D")
    price = 100 + np.cumsum(np.random.randn(100) * 0.5)

    df = pd.DataFrame({
        "date": dates,
        "open":  price + np.random.randn(100) * 0.2,
        "high":  price + np.abs(np.random.randn(100) * 0.5),
        "low":   price - np.abs(np.random.randn(100) * 0.5),
        "close": price,
        "volume": np.random.randint(1000, 10000, size=100),
    })
    df.set_index("date", inplace=True)

    # Compare three moving averages
    df["SMA_20"] = df["close"].rolling(20).mean()
    df["EMA_20"] = df["close"].ewm(span=20, adjust=False).mean()
    df["WMA_20"] = wma(df["close"], period=20)

    print("=== SMA vs EMA vs WMA Comparison ===")
    print(df[["close", "SMA_20", "EMA_20", "WMA_20"]].tail(10))

    # Verify vectorized implementation
    wma_vals = wma_vectorized(df["close"].values, period=20)
    print("\n=== Vectorized Implementation Verification (last 5 rows) ===")
    for i in range(-5, 0):
        print(f"  pandas: {df['WMA_20'].iloc[i]:.4f}  numpy: {wma_vals[i]:.4f}")

IV. Problems the Indicator Solves

1. Addressing SMA’s Equal-Weight Flaw

SMA treats a price from 20 days ago the same as today’s price, which is unreasonable in fast-moving markets. WMA solves this problem with linear weights, making the moving average more reflective of the current market state.

2. More Responsive Trend Tracking

WMA’s responsiveness to trend changes falls between SMA and EMA (in most cases, WMA’s response speed is comparable to EMA). When price undergoes a directional change, WMA adjusts direction faster than SMA.

3. Foundation for HMA

WMA is the core building module of the Hull Moving Average (HMA). HMA combines WMAs of different periods to achieve an extremely low-lag smooth curve:

HMA=WMA(2WMA(P,n/2)WMA(P,n), n)HMA = WMA\big(2 \cdot WMA(P, n/2) - WMA(P, n),\ \sqrt{n}\big)

4. Trade Signal Generation

Similar to SMA/EMA, WMA can be used for:

  • Price-to-WMA crossovers (trend signals)
  • Crossovers between WMAs of different periods (Golden Cross / Death Cross)
  • As a stop-loss / take-profit reference line
Warning

Although WMA’s linear weights are more reasonable than SMA’s equal weights, it still has a hard cutoff at the window boundary — the weight for data beyond the nn-th day drops to zero abruptly. EMA avoids this issue through exponential decay.


V. Advantages, Disadvantages, and Use Cases

Advantages

AdvantageDescription
Recency biasLinear weights give the most influence to the latest price, aligning with trading intuition
Reduced lagResponds faster to price changes than SMA
Intuitive calculationWeight allocation logic is simple and easy to understand
HMA foundationServes as the base component for building HMA and other advanced moving averages

Disadvantages

DisadvantageDescription
Hard cutoffWeights drop to zero abruptly outside the window, potentially causing jumps
Higher computationEach calculation requires a weighted sum over the entire window; no O(1)O(1) recursion like EMA
Less smoothNoise filtering is weaker compared to SMA
Less commonly usedEMA is more mainstream in practice; WMA is rarely used on its own

Use Cases

  • Short-term trading: Scenarios requiring fast response to price changes
  • As a building component: Building HMA and other advanced indicators
  • Comparative analysis: Used alongside SMA and EMA to observe signal differences across weighting schemes

Comparison with Similar Indicators

FeatureSMAWMAEMA
Weight methodEqualLinear decayExponential decay
Window cutoffHardHardSoft decay
Response speedSlowestMediumMedium
SmoothnessHighestMediumMedium
Computational efficiencyCan be O(1)O(1)O(n)O(n)O(1)O(1)
Practical Advice
  1. WMA is rarely used in isolation, but understanding WMA is essential for learning HMA.
  2. If you need more responsiveness than SMA but prefer not to use EMA’s exponential decay, WMA is a reasonable middle ground.
  3. In quantitative backtesting frameworks, it is recommended to encapsulate WMA as a base function for reuse in HMA and other advanced indicator calculations.