moving_average 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -67,6 +67,47 @@ class Array
67
67
  end
68
68
  alias_method :sma, :simple_moving_average
69
69
 
70
+ # Compute the smoothed moving average of the values of an Array.
71
+ #
72
+ # Formally, given that the first value for the SMMA is the SMA, subsequent
73
+ # values can be computed as
74
+ #
75
+ # (sma – smma_i-1 + a[i])
76
+ # -----------------------
77
+ # n
78
+ #
79
+ # where
80
+ #
81
+ # smma_i-1
82
+ #
83
+ # is the smoothed moving average of the previous index.
84
+ #
85
+ # Formula taken from
86
+ # https://mahifx.com/indicators/smoothed-moving-average-smma
87
+ #
88
+ # ==== Parameters
89
+ #
90
+ # * +idx+ - Optional, the index of the last datum to consider.
91
+ # * +tail+ - Optional, the number of data to consider.
92
+ def smoothed_moving_average(idx=nil, tail=nil)
93
+ # Set these manually here since we need the leading SMA.
94
+ if tail.nil?
95
+ idx = self.size - 1 if idx.nil?
96
+ tail = idx / 2
97
+ tail += 1 if idx.odd?
98
+ end
99
+ idx, tail = idx_and_tail_or_defaults(idx, tail)
100
+ valid_for_ma(idx, tail)
101
+ valid_for_ma(idx - tail, tail)
102
+ smma1 = self[idx - 2 * tail + 1..idx - tail].sma
103
+ (idx - tail + 1..idx).to_a.each do |tidx|
104
+ prevsum = self[tidx - tail + 1..tidx].sum
105
+ smma1 = (prevsum - smma1 + self[idx - (idx - tidx)]) / tail
106
+ end
107
+ smma1
108
+ end
109
+ alias_method :smma, :smoothed_moving_average
110
+
70
111
  # Compute the weighted moving average of the values of an Array.
71
112
  #
72
113
  # Formally, the WMA can be computed as n / d, where
@@ -1,3 +1,3 @@
1
1
  module MovingAverage
2
- VERSION = '0.0.4'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -52,6 +52,33 @@ describe MovingAverage do
52
52
  expect { [1, 2, 3].simple_moving_average(1, -1) }.to raise_exception(MovingAverage::Errors::InvalidTailError, "Given tail is <= 0.")
53
53
  expect { [1, 2, 3].simple_moving_average(1, 3) }.to raise_exception(MovingAverage::Errors::NotEnoughDataError, "Given tail is too large for idx.")
54
54
  end
55
+
56
+ end
57
+
58
+ describe "smoothed moving average" do
59
+
60
+ SMMA_DATA = (1..10).to_a.freeze
61
+ SMMA = 8.5
62
+
63
+ it "should work for missing arguments" do
64
+ SMMA_DATA.smoothed_moving_average.round(1).should ==(SMMA)
65
+ SMMA_DATA.smma.round(1).should ==(SMMA)
66
+ SMMA_DATA.smoothed_moving_average(9).round(1).should ==(SMMA)
67
+ SMMA_DATA.smma(9).round(1).should ==(SMMA)
68
+ end
69
+
70
+ it "should work for valid arguments" do
71
+ SMMA_DATA.smoothed_moving_average(9, 5).round(1).should ==(SMMA)
72
+ SMMA_DATA.smma(9, 5).round(1).should ==(SMMA)
73
+ end
74
+
75
+ it "should raise proper errors for invalid arguments" do
76
+ expect { [1, 2, 3].smoothed_moving_average(-1, 3) }.to raise_exception(MovingAverage::Errors::InvalidIndexError, "Given idx is outside the Array.")
77
+ expect { [1, 2, 3].smoothed_moving_average(3, 3) }.to raise_exception(MovingAverage::Errors::InvalidIndexError, "Given idx is outside the Array.")
78
+ expect { [1, 2, 3].smoothed_moving_average(1, -1) }.to raise_exception(MovingAverage::Errors::InvalidTailError, "Given tail is <= 0.")
79
+ expect { [1, 2, 3].smoothed_moving_average(1, 3) }.to raise_exception(MovingAverage::Errors::NotEnoughDataError, "Given tail is too large for idx.")
80
+ end
81
+
55
82
  end
56
83
 
57
84
  describe "weighted moving average" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moving_average
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-17 00:00:00.000000000 Z
12
+ date: 2013-03-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec