1from __future__ import division
2
3
4class SimpleMovingAverage(object):
5    """
6    Simple Moving Average implementation.
7    """
8
9    __slots__ = (
10        "size",
11        "index",
12        "counts",
13        "totals",
14        "sum_count",
15        "sum_total",
16    )
17
18    def __init__(self, size):
19        # type: (int) -> None
20        """
21        Constructor for SimpleMovingAverage.
22
23        :param size: The size of the window to calculate the moving average.
24        :type size: :obj:`int`
25        """
26        if size < 1:
27            raise ValueError
28
29        self.index = 0
30        self.size = size
31
32        self.sum_count = 0
33        self.sum_total = 0
34
35        self.counts = [0] * self.size
36        self.totals = [0] * self.size
37
38    def get(self):
39        # type: () -> float
40        """
41        Get the current SMA value.
42        """
43        if self.sum_total == 0:
44            return 0.0
45
46        return float(self.sum_count) / self.sum_total
47
48    def set(self, count, total):
49        # type: (int, int) -> None
50        """
51        Set the value of the next bucket and update the SMA value.
52
53        :param count: The valid quantity of the next bucket.
54        :type count: :obj:`int`
55        :param total: The total quantity of the next bucket.
56        :type total: :obj:`int`
57        """
58        if count > total:
59            raise ValueError
60
61        self.sum_count += count - self.counts[self.index]
62        self.sum_total += total - self.totals[self.index]
63
64        self.counts[self.index] = count
65        self.totals[self.index] = total
66
67        self.index = (self.index + 1) % self.size
68