moving_average 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|