moving_average 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/README.md +9 -1
- data/lib/moving_average/errors.rb +1 -1
- data/lib/moving_average/moving_average.rb +51 -16
- data/lib/moving_average/version.rb +1 -1
- metadata +1 -1
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -22,10 +22,18 @@ Or install it yourself as:
|
|
22
22
|
To compute a simple moving average (SMA), you can use
|
23
23
|
|
24
24
|
a = [1, 2, 3, 4, 5]
|
25
|
-
a.simple_moving_average
|
25
|
+
a.simple_moving_average => 3
|
26
26
|
|
27
27
|
or
|
28
28
|
|
29
|
+
a.sma => 3
|
30
|
+
|
31
|
+
You could also find the SMA of the 3-element slice [1, 2, 3] of the Array using
|
32
|
+
|
33
|
+
a.sma(2, 3) => 2
|
34
|
+
|
35
|
+
or the 4-element slice [1, 2, 3, 4] by using
|
36
|
+
|
29
37
|
a.sma(3, 4) => 2.5
|
30
38
|
|
31
39
|
An exponential moving average (EMA) and a weighted moving average (WMA) may be
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class Array
|
2
2
|
|
3
|
-
def idx_and_tail_or_defaults(idx, tail)
|
3
|
+
def idx_and_tail_or_defaults(idx, tail) #:nodoc:
|
4
4
|
if tail.nil?
|
5
5
|
tail = self.size
|
6
6
|
if idx.nil?
|
@@ -10,7 +10,7 @@ class Array
|
|
10
10
|
[idx, tail]
|
11
11
|
end; private :idx_and_tail_or_defaults
|
12
12
|
|
13
|
-
def valid_for_ma(idx, tail)
|
13
|
+
def valid_for_ma(idx, tail) #:nodoc:
|
14
14
|
unless idx >= 0 && idx < self.size
|
15
15
|
raise MovingAverage::Errors::InvalidIndexError
|
16
16
|
end
|
@@ -23,14 +23,30 @@ class Array
|
|
23
23
|
true
|
24
24
|
end; private :valid_for_ma
|
25
25
|
|
26
|
+
# Compute the exponential moving average (EMA) of the values of an Array.
|
27
|
+
#
|
28
|
+
# Formally, the EMA can be computed as n / d, where
|
29
|
+
#
|
30
|
+
# n = p_1 + (1 - alpha)p_2 + (1 - alpha)^2p_3 + ... + (1 - alpha)^zp_(z + 1)
|
31
|
+
#
|
32
|
+
# and
|
33
|
+
#
|
34
|
+
# d = 1 + (1 - alpha) + (1 - alpha)^2 + (1 - alpha)^3 + ... + (1 - alpha)^z
|
35
|
+
#
|
36
|
+
# where
|
37
|
+
#
|
38
|
+
# alpha = 2 / (z + 1)
|
39
|
+
#
|
40
|
+
# Formula taken from
|
41
|
+
# http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
|
42
|
+
#
|
43
|
+
# ==== Parameters
|
44
|
+
#
|
45
|
+
# * +idx+ - Optional, the index of the last datum to consider.
|
46
|
+
# * +tail+ - Optional, the number of data to consider.
|
26
47
|
def exponential_moving_average(idx=nil, tail=nil)
|
27
48
|
idx, tail = idx_and_tail_or_defaults(idx, tail)
|
28
49
|
valid_for_ma(idx, tail)
|
29
|
-
# Taken from
|
30
|
-
# http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
|
31
|
-
# p_1 + (1 - alpha)p_2 + (1 - alpha)^2p_3 + ...
|
32
|
-
# -----------------------------------------------------
|
33
|
-
# 1 + (1 - alpha) + (1 - alpha)^2 + (1 - alpha)^3 + ...
|
34
50
|
alpha = 2.0 / (tail + 1)
|
35
51
|
n = (1..tail).to_a.map{|tidx| (1 - alpha) ** (tidx - 1) * self[idx - tidx + 1]}.sum
|
36
52
|
d = (1..tail).to_a.map{|tidx| (1 - alpha) ** (tidx - 1)}.sum
|
@@ -38,6 +54,12 @@ class Array
|
|
38
54
|
end
|
39
55
|
alias_method :ema, :exponential_moving_average
|
40
56
|
|
57
|
+
# Compute the simple moving average (SMA) of the values of an Array.
|
58
|
+
#
|
59
|
+
# ==== Parameters
|
60
|
+
#
|
61
|
+
# * +idx+ - Optional, the index of the last datum to consider.
|
62
|
+
# * +tail+ - Optional, the number of data to consider.
|
41
63
|
def simple_moving_average(idx=nil, tail=nil)
|
42
64
|
idx, tail = idx_and_tail_or_defaults(idx, tail)
|
43
65
|
valid_for_ma(idx, tail)
|
@@ -45,18 +67,30 @@ class Array
|
|
45
67
|
end
|
46
68
|
alias_method :sma, :simple_moving_average
|
47
69
|
|
70
|
+
# Compute the weighted moving average of the values of an Array.
|
71
|
+
#
|
72
|
+
# Formally, the WMA can be computed as n / d, where
|
73
|
+
#
|
74
|
+
# n = zp_M + (z - 1)p_(M - 1) + (z - 2)p_(M - 3) + ...
|
75
|
+
#
|
76
|
+
# and
|
77
|
+
#
|
78
|
+
# d = z + (z - 1) + (z - 2) + ...
|
79
|
+
#
|
80
|
+
# The denominator is a triangle number of the form
|
81
|
+
#
|
82
|
+
# z(z + 1) / 2
|
83
|
+
#
|
84
|
+
# Formula taken from
|
85
|
+
# http://en.wikipedia.org/wiki/Moving_average#Weighted_moving_average
|
86
|
+
#
|
87
|
+
# ==== Parameters
|
88
|
+
#
|
89
|
+
# * +idx+ - Optional, the index of the last datum to consider.
|
90
|
+
# * +tail+ - Optional, the number of data to consider.
|
48
91
|
def weighted_moving_average(idx=nil, tail=nil)
|
49
92
|
idx, tail = idx_and_tail_or_defaults(idx, tail)
|
50
93
|
valid_for_ma(idx, tail)
|
51
|
-
# Taken from
|
52
|
-
# http://en.wikipedia.org/wiki/Moving_average#Weighted_moving_average
|
53
|
-
# np_M + (n - 1)p_(M - 1) + (n - 2)p_(M - 3) + ...
|
54
|
-
# ------------------------------------------------
|
55
|
-
# n + (n - 1) + (n - 2) + ...
|
56
|
-
# The denominator is a triangle number of the form
|
57
|
-
# n(n + 1)
|
58
|
-
# --------
|
59
|
-
# 2
|
60
94
|
n = (0..tail-1).to_a.map{|tidx| (tail - tidx) * self[idx - tidx]}.sum
|
61
95
|
d = (tail * (tail + 1)) / 2.0
|
62
96
|
n / d
|
@@ -64,6 +98,7 @@ class Array
|
|
64
98
|
alias_method :wma, :weighted_moving_average
|
65
99
|
|
66
100
|
unless method_defined?(:sum)
|
101
|
+
# Compute the sum of the values of an Array.
|
67
102
|
def sum
|
68
103
|
inject(0){|s, n| s += n}
|
69
104
|
end
|