Skip to content
← Back to Functions
Code

Moving Average Calculator

Computes moving averages for a numeric series with configurable window size.

Function signature

ogCalculateMovingAverageSeries(values = array(), options = array())

Categories

  • Analytics and Reports

Parameters

valuesNumeric values in chronological order.optionsOptional keys: window, allow_partial. Recognized keys: `allow_partial`, `window`.

Return value

Short public-safe status message.

  • window
  • allow_partial
  • series

Compatibility

Existing function name and call order preserved; metadata signature corrected to source.

Minimum PHP version: 7.4

Security notes

Validate request method, identity, permissions, and caller-owned allowlists before use; keep secrets and internal paths out of public output.

Code

<?php

/*
 * Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
 * Free for personal and internal use. Paid project use requires visible credit
 * to Jeffery L. Paris. Corporate use requires a paid license fee unless a
 * separate written license states otherwise.
 */

/**
 * Computes moving averages for a numeric series with configurable window size.
 *
 * @param array $values Numeric values in chronological order.
 * @param array $options Optional keys: window, allow_partial.
 * @return array Moving-average rows with index, value, average, and window count.
 */
function ogCalculateMovingAverageSeries($values = array(), $options = array()) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

	if (!is_array($values)) {
		$result['message'] = 'Values must be an array.';
		return $result;
	}

	if (!is_array($options)) {
		$options = array();
	}

	$window = 3;
	if (!empty($options['window'])) {
		$window = (int)$options['window'];
	}
	if ($window < 1) {
		$window = 1;
	}

	$allow_partial = false;
	if (!empty($options['allow_partial'])) {
		$allow_partial = true;
	}

	$numeric_values = array();
	foreach ($values as $value) {
		if (is_numeric($value)) {
			$numeric_values[] = (float)$value;
		}
	}

	if (count($numeric_values) < 1) {
		$result['message'] = 'No numeric values were supplied.';
		return $result;
	}

	if (!$allow_partial && count($numeric_values) < $window) {
		$result['message'] = 'Window is larger than the available series.';
		return $result;
	}

	$rows = array();
	for ($index = 0; $index < count($numeric_values); $index++) {
		$start = $index - $window + 1;
		if ($start < 0) {
			$start = 0;
		}

		$window_values = array_slice($numeric_values, $start, ($index - $start + 1));
		if (!$allow_partial && count($window_values) < $window) {
			continue;
		}

		$average = array_sum($window_values) / count($window_values);
		$rows[] = array(
			'index' => $index,
			'value' => $numeric_values[$index],
			'average' => $average,
			'window_count' => count($window_values)
		);
	}

	$result['success'] = true;
	$result['message'] = 'Moving average series calculated.';
	$result['data'] = array(
		'window' => $window,
		'allow_partial' => $allow_partial,
		'series' => $rows
	);

	return $result;
}