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.
Source Code
Copy the following code into your Apps Script editor (Extensions > Apps Script) to use the WMA function in your spreadsheet.
/**
* 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;
}