moving_average 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in moving_average.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # MovingAverage
2
+
3
+ This gem adds methods to the Array class to compute different types of moving
4
+ averages.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'moving_average'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install moving_average
19
+
20
+ ## Usage
21
+
22
+ To compute a simple moving average (SMA), you can use
23
+
24
+ a = [1, 2, 3, 4, 5]
25
+ a.simple_moving_average(3, 4) => 2.5
26
+
27
+ or
28
+
29
+ a.sma(3, 4) => 2.5
30
+
31
+ An exponential moving average (EMA) and a weighted moving average (WMA) may be
32
+ computed in the same way.
33
+
34
+ ## Contributing
35
+
36
+ 1. Fork it
37
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
38
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
39
+ 4. Push to the branch (`git push origin my-new-feature`)
40
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,25 @@
1
+ module MovingAverage
2
+
3
+ module Errors
4
+
5
+ class InvalidIndexError < IndexError
6
+ def message
7
+ 'Given idx is outside the Array.'
8
+ end
9
+ end
10
+
11
+ class InvalidTailError < RangeError
12
+ def message
13
+ 'Given tail is <= 0.'
14
+ end
15
+ end
16
+
17
+ class NotEnoughDataError < ArgumentError
18
+ def message
19
+ 'Given tail is too large for idx.'
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,58 @@
1
+ class Array
2
+
3
+ def valid_for_ma(idx, tail)
4
+ unless idx >= 0 && idx < self.size
5
+ raise MovingAverage::Errors::InvalidIndexError
6
+ end
7
+ unless tail > 0
8
+ raise MovingAverage::Errors::InvalidTailError
9
+ end
10
+ unless idx - tail >= -1
11
+ raise MovingAverage::Errors::NotEnoughDataError
12
+ end
13
+ true
14
+ end; private :valid_for_ma
15
+
16
+ def exponential_moving_average(idx, tail)
17
+ valid_for_ma(idx, tail)
18
+ # Taken from
19
+ # http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
20
+ # p_1 + (1 - alpha)p_2 + (1 - alpha)^2p_3 + ...
21
+ # -----------------------------------------------------
22
+ # 1 + (1 - alpha) + (1 - alpha)^2 + (1 - alpha)^3 + ...
23
+ alpha = 2.0 / (tail + 1)
24
+ n = (1..tail).to_a.map{|tidx| (1 - alpha) ** (tidx - 1) * self[idx - tidx + 1]}.sum
25
+ d = (1..tail).to_a.map{|tidx| (1 - alpha) ** (tidx - 1)}.sum
26
+ n / d
27
+ end
28
+ alias_method :ema, :exponential_moving_average
29
+
30
+ def simple_moving_average(idx, tail)
31
+ valid_for_ma(idx, tail)
32
+ self[idx-tail+1..idx].sum.to_f / tail
33
+ end
34
+ alias_method :sma, :simple_moving_average
35
+
36
+ def weighted_moving_average(idx, tail)
37
+ valid_for_ma(idx, tail)
38
+ # Taken from
39
+ # http://en.wikipedia.org/wiki/Moving_average#Weighted_moving_average
40
+ # np_M + (n - 1)p_(M - 1) + (n - 2)p_(M - 3) + ...
41
+ # ------------------------------------------------
42
+ # n + (n - 1) + (n - 2) + ...
43
+ # The denominator is a triangle number of the form
44
+ # n(n + 1)
45
+ # --------
46
+ # 2
47
+ n = (0..tail-1).to_a.map{|tidx| (tail - tidx) * self[idx - tidx]}.sum
48
+ d = (tail * (tail + 1)) / 2.0
49
+ n / d
50
+ end
51
+ alias_method :wma, :weighted_moving_average
52
+
53
+ unless method_defined?(:sum)
54
+ def sum
55
+ inject(0){|s, n| s += n}
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module MovingAverage
2
+ VERSION = '0.0.2'
3
+ end
@@ -0,0 +1,6 @@
1
+ require 'moving_average/errors'
2
+ require 'moving_average/moving_average'
3
+ require 'moving_average/version'
4
+
5
+ module MovingAverage
6
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/moving_average/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Brad Cater"]
6
+ gem.email = ["bradcater@gmail.com"]
7
+ gem.description = %q{This gem adds methods to the Array class to compute different types of moving averages.}
8
+ gem.summary = %q{This gem adds methods to the Array class to compute different types of moving averages.}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "moving_average"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = MovingAverage::VERSION
17
+
18
+ gem.add_development_dependency "rspec", "~> 2.13"
19
+
20
+ end
@@ -0,0 +1,47 @@
1
+ require 'moving_average'
2
+
3
+ describe MovingAverage do
4
+
5
+ it "exponential moving average should work for valid arguments" do
6
+ # Example taken from
7
+ # http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages
8
+ a = [22.27, 22.19, 22.08, 22.17, 22.18, 22.13, 22.23, 22.43, 22.24, 22.29]
9
+ a.exponential_moving_average(9, 10).round(3).should eql(22.247)
10
+ a.ema(9, 10).round(3).should eql(22.247)
11
+ end
12
+
13
+ it "exponential moving average should raise NotEnoughDataError for invalid arguments" do
14
+ expect { [1, 2, 3].exponential_moving_average(-1, 3) }.to raise_exception(MovingAverage::Errors::InvalidIndexError, "Given idx is outside the Array.")
15
+ expect { [1, 2, 3].exponential_moving_average(3, 3) }.to raise_exception(MovingAverage::Errors::InvalidIndexError, "Given idx is outside the Array.")
16
+ expect { [1, 2, 3].exponential_moving_average(1, -1) }.to raise_exception(MovingAverage::Errors::InvalidTailError, "Given tail is <= 0.")
17
+ expect { [1, 2, 3].exponential_moving_average(1, 3) }.to raise_exception(MovingAverage::Errors::NotEnoughDataError, "Given tail is too large for idx.")
18
+ end
19
+
20
+ it "simple moving average should work" do
21
+ (1..5).to_a.simple_moving_average(4, 5).should ==(3)
22
+ (1..5).to_a.sma(4, 5).should ==(3)
23
+ end
24
+
25
+ it "simple moving average should raise proper errors for invalid arguments" do
26
+ expect { [1, 2, 3].simple_moving_average(-1, 3) }.to raise_exception(MovingAverage::Errors::InvalidIndexError, "Given idx is outside the Array.")
27
+ expect { [1, 2, 3].simple_moving_average(3, 3) }.to raise_exception(MovingAverage::Errors::InvalidIndexError, "Given idx is outside the Array.")
28
+ expect { [1, 2, 3].simple_moving_average(1, -1) }.to raise_exception(MovingAverage::Errors::InvalidTailError, "Given tail is <= 0.")
29
+ expect { [1, 2, 3].simple_moving_average(1, 3) }.to raise_exception(MovingAverage::Errors::NotEnoughDataError, "Given tail is too large for idx.")
30
+ end
31
+
32
+ it "weighted moving average should work" do
33
+ # Example taken from
34
+ # http://daytrading.about.com/od/indicators/a/MovingAverages.htm
35
+ vals = [1.2900, 1.2900, 1.2903, 1.2904]
36
+ vals.weighted_moving_average(3, 4).should eql(1.29025)
37
+ vals.wma(3, 4).should eql(1.29025)
38
+ end
39
+
40
+ it "weighted moving average should raise proper errors for invalid arguments" do
41
+ expect { [1, 2, 3].weighted_moving_average(-1, 3) }.to raise_exception(MovingAverage::Errors::InvalidIndexError, "Given idx is outside the Array.")
42
+ expect { [1, 2, 3].weighted_moving_average(3, 3) }.to raise_exception(MovingAverage::Errors::InvalidIndexError, "Given idx is outside the Array.")
43
+ expect { [1, 2, 3].weighted_moving_average(1, -1) }.to raise_exception(MovingAverage::Errors::InvalidTailError, "Given tail is <= 0.")
44
+ expect { [1, 2, 3].weighted_moving_average(1, 3) }.to raise_exception(MovingAverage::Errors::NotEnoughDataError, "Given tail is too large for idx.")
45
+ end
46
+
47
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: moving_average
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - Brad Cater
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-03-16 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 25
30
+ segments:
31
+ - 2
32
+ - 13
33
+ version: "2.13"
34
+ type: :development
35
+ version_requirements: *id001
36
+ description: This gem adds methods to the Array class to compute different types of moving averages.
37
+ email:
38
+ - bradcater@gmail.com
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - .gitignore
47
+ - Gemfile
48
+ - LICENSE
49
+ - README.md
50
+ - Rakefile
51
+ - lib/moving_average.rb
52
+ - lib/moving_average/errors.rb
53
+ - lib/moving_average/moving_average.rb
54
+ - lib/moving_average/version.rb
55
+ - moving_average.gemspec
56
+ - spec/moving_average_spec.rb
57
+ has_rdoc: true
58
+ homepage: ""
59
+ licenses: []
60
+
61
+ post_install_message:
62
+ rdoc_options: []
63
+
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ hash: 3
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ requirements: []
85
+
86
+ rubyforge_project:
87
+ rubygems_version: 1.6.2
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: This gem adds methods to the Array class to compute different types of moving averages.
91
+ test_files:
92
+ - spec/moving_average_spec.rb