Weighted Moving Average (WMA)


The Weighted Moving Average (WMA) is a technical analysis tool that smooths price data to help identify the underlying trend by giving greater significance to more recent data points. Unlike a Simple Moving Average (SMA) which assigns equal weight to all prices, the WMA applies a linear weighting. This means the most recent price receives the highest weight, the second most recent receives the second highest, and so on, in a straight-line progression. This method results in an average that responds more quickly to recent price action than an SMA, making it a valuable tool for traders focused on short- to medium-term momentum.

WMA

=WMA(data, period)

Example Usage

=WMA(A2:F500, 14)

Parameters

Parameter Type Description Status
data
Range
Range of columns containing the date, Open, high, Low, close, volume data.
Required
period
Number
Number of periods (days) over which to calculate the WMA.
Required

Returns

A two-column array of dates and their corresponding WMA values.

WMA Formula Result in Google Sheets

Source Code

Copy the following code into your Apps Script editor (Extensions > Apps Script) to use the WMA function in your spreadsheet.

wma.js
/**
 * Calculates the Weighted Moving Average (WMA) for a given dataset and period.
 *
 * @param {array} data - An array of historical stock data. Can be a single column of prices or a multi-column array from GOOGLEFINANCE.
 * @param {number} period - The number of periods for the WMA.
 * @returns {array} - A 2D array with headers: Date, WMA.
 * @customfunction
 */
function WMA(data, period) {
  // Argument validation
  if (arguments.length !== 2) {
    throw new Error(`Wrong number of arguments. Expected 2, but got ${arguments.length}.`);
  }
  if (typeof period !== 'number' || period <= 0 || !Number.isInteger(period)) {
    throw new Error(`Invalid period. The period must be a positive integer. Got: ${period}`);
  }

  const processedData = getData(data);

  // --- NEW: Function-level validation ---
  const columnCount = processedData[0].length;
  if (columnCount > 2 && columnCount < 5) {
      throw new Error(`Invalid data structure for WMA. For multi-column data, expected at least 5 columns (Date, O, H, L, C), but got ${columnCount}. For simple data, expected 2 columns (Date, Value).`);
  }
  // --- END of validation ---

  const dates = processedData.slice(1).map(row => row[0]);
  const values = getValues(processedData);

  if (period > values.length) {
    throw new Error(`Invalid period. The period (${period}) cannot be greater than the number of data points (${values.length}).`);
  }

  const results = [["Date", `WMA(${period})`]];

  // Calculate weights
  const weights = Array.from({ length: period }, (_, i) => period - i); // [n, n-1, ..., 1]
  const totalWeight = weights.reduce((sum, weight) => sum + weight, 0); // Sum of weights

  // Calculate WMA for the given period
  for (let i = period - 1; i < values.length; i++) {
    let weightedSum = 0;

    // Calculate weighted sum for the current period
    for (let j = 0; j < period; j++) {
      weightedSum += values[i - j] * weights[j];
    }

    const wma = weightedSum / totalWeight;
    results.push([dates[i], wma]);
  }

  return results;
}