TheAlgorithms/Python · #11826

Streaming moving average

mjvakili · merged Oct 1, 20262 files · 92 + / 0 −
DIRECTORY.md1 + / 0 −
@@ -561,6 +561,7 @@   * [Sharpe Ratio](financial/sharpe_ratio.py)   * [Simple Moving Average](financial/simple_moving_average.py)   * [Straight Line Depreciation](financial/straight_line_depreciation.py)+  * [Streaming Moving Average](financial/streaming_moving_average.py)   * [Time And Half Pay](financial/time_and_half_pay.py)   * [Value At Risk](financial/value_at_risk.py) 
financial/streaming_moving_average.pyadded91 + / 0 −
@@ -0,0 +1,91 @@+"""This module contains a class that+calculates the moving average in real-time.++Reference+---------+https://en.wikipedia.org/wiki/Moving_average+"""++from collections import deque+++class StreamingMovingAverage:+    """Streaming Moving Average calculator that updates+    the average in real-time.++    Attributes+    ----------+    window_size : int+        The size of the moving average window.++    Methods+    -------+    update(new_value: float) -> None+        Update the moving average with a new data point.+    mov_avg() -> float+        Return the current moving average value.++    Raises+    ------+    ValueError+        If the window size is less than 1.+++    Examples+    --------+    >>> mov_avg_calculator = StreamingMovingAverage(3)+    >>> mov_avg_calculator.update(10.)+    >>> mov_avg_calculator.update(12.)+    >>> mov_avg_calculator.update(2.)+    >>> mov_avg_calculator.update(1.)+    >>> mov_avg_calculator.mov_avg+    5.0+    >>> mov_avg_calculator = StreamingMovingAverage(5)+    >>> mov_avg_calculator.update(2.)+    >>> mov_avg_calculator.update(3.)+    >>> mov_avg_calculator.mov_avg+    2.5+    """++    def __init__(self, window_size: int) -> None:+        if window_size < 1:+            raise ValueError("Window size must be a positive integer")+        self.window_size = window_size+        self.window: deque[float] = deque(maxlen=window_size)+        self._mov_avg: float = 0.0  # Placeholder for online moving average.++    def update(self, new_value: float) -> None:+        """Update the moving average with a new data point.++        Parameters+        ----------+        new_value : float+            The new data point to update the moving average.++        Raises+        ------+        TypeError+            If the type of new value is not float.+        """+        if not isinstance(new_value, float):+            raise TypeError("Type of new_value must be either float.")+        self.window.append(new_value)+        self._mov_avg = sum(self.window) / len(self.window)++    @property+    def mov_avg(self) -> float:+        """Return the current moving average value."""+        return self._mov_avg+++if __name__ == "__main__":+    import doctest+    import random++    doctest.testmod()+    moving_average_calculator = StreamingMovingAverage(window_size=3)+    example_data = [float(random.randint(a=1, b=10)) for _ in range(10)]+    for value in example_data:+        print(f"adding {value=} to streaming data.")+        moving_average_calculator.update(new_value=value)+        print(f"updated moving average={moving_average_calculator.mov_avg}")