advanced_math 0.0.5 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt CHANGED
@@ -1,8 +1,13 @@
1
- advanced_math-0.0.4.gem
2
1
  advanced_math.gemspec
2
+ gem_publish.sh
3
3
  History.txt
4
+ lib/advanced_math/rsi.rb
5
+ lib/advanced_math/sma.rb
4
6
  lib/advanced_math.rb
5
7
  Manifest.txt
6
8
  PostInstall.txt
7
9
  README.rdoc
10
+ test/rsi.pl
11
+ test/RSI.pm
12
+ test/test_rsi.rb
8
13
  test/test_simple_moving_average.rb
@@ -1,16 +1,37 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
1
4
  # -*- encoding: utf-8 -*-
2
5
 
3
6
  Gem::Specification.new do |s|
4
7
  s.name = %q{advanced_math}
5
- s.version = "0.0.5"
8
+ s.version = "0.0.7"
6
9
 
7
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
11
  s.authors = [%q{Glenn Nagel}]
9
12
  s.date = %q{2011-08-28}
10
13
  s.description = %q{A simple gem for advanced and financial math calcualtions.}
11
14
  s.email = [%q{glenn@mercury-wireless.com}]
12
- s.extra_rdoc_files = ["History.txt", "Manifest.txt", "PostInstall.txt"]
13
- s.files = ["History.txt", "Manifest.txt", "PostInstall.txt", "README.rdoc", "advanced_math-0.0.4.gem", "advanced_math.gemspec", "lib/advanced_math.rb", "test/test_simple_moving_average.rb"]
15
+ s.extra_rdoc_files = [
16
+ "History.txt",
17
+ "Manifest.txt",
18
+ "PostInstall.txt"
19
+ ]
20
+ s.files = [
21
+ "History.txt",
22
+ "Manifest.txt",
23
+ "PostInstall.txt",
24
+ "README.rdoc",
25
+ "advanced_math.gemspec",
26
+ "gem_publish.sh",
27
+ "lib/advanced_math.rb",
28
+ "lib/advanced_math/rsi.rb",
29
+ "lib/advanced_math/sma.rb",
30
+ "test/RSI.pm",
31
+ "test/rsi.pl",
32
+ "test/test_rsi.rb",
33
+ "test/test_simple_moving_average.rb"
34
+ ]
14
35
  s.homepage = %q{https://github.com/gnagel/mercury-wireless-public/tree/master/ruby/advanced_math}
15
36
  s.post_install_message = %q{PostInstall.txt}
16
37
  s.rdoc_options = [%q{--main}, %q{README.rdoc}]
@@ -18,7 +39,7 @@ Gem::Specification.new do |s|
18
39
  s.rubyforge_project = %q{advanced_math}
19
40
  s.rubygems_version = %q{1.8.6}
20
41
  s.summary = %q{A simple gem for advanced and financial math calcualtions.}
21
- s.test_files = [%q{test/test_simple_moving_average.rb}]
42
+ s.test_files = [%q{test/test_rsi.rb}, %q{test/test_simple_moving_average.rb}]
22
43
 
23
44
  if s.respond_to? :specification_version then
24
45
  s.specification_version = 3
@@ -32,3 +53,4 @@ Gem::Specification.new do |s|
32
53
  s.add_dependency(%q<hoe>, ["~> 2.9"])
33
54
  end
34
55
  end
56
+
data/gem_publish.sh ADDED
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+
3
+ rm *.gem;
4
+ rake gemspec:generate &&
5
+ gem build ./*gemspec &&
6
+ gem push ./*gemspec
@@ -0,0 +1,113 @@
1
+ require File.dirname(__FILE__) + "/sma.rb"
2
+
3
+ module AdvancedMath
4
+ ###
5
+ # Relative Strength Index (RSI) calculator
6
+ # Created: 2011-08-28
7
+ # Author: G Nagel
8
+ # Company: Mercury Wireless Software LLC
9
+ # Source: http://en.wikipedia.org/wiki/Relative_Strength_Index#Cutler.27s_RSI
10
+ # Source: http://www.aspenres.com/Documents/AspenGraphics4.0/Aspen_Graphics_4.htm#CutlersRSI.htm
11
+ # Source: http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:relative_strength_index_rsi
12
+ ###
13
+ class RelativeStrengthIndex
14
+ attr_accessor :values_up, :values_down, :range, :last_value
15
+ attr_accessor :verbose
16
+ ###
17
+ # Initialize the members
18
+ ###
19
+ def initialize(range)
20
+ raise ArgumentError, "Range is nil" unless (range)
21
+ raise ArgumentError, "Range must be > 1" unless range.to_i > 1
22
+
23
+ @verbose = false
24
+ @values_up = []
25
+ @values_down = []
26
+ @range = range.to_i()
27
+ @last_value = nil
28
+ end
29
+
30
+ ###
31
+ # Add a value to the list.
32
+ # If the list is < @range, then return nil.
33
+ # Otherwise compute the RSI and return the value.
34
+ ###
35
+ def add(value)
36
+ raise ArgumentError, "Value is nil" unless (value)
37
+ puts "==================" if verbose()
38
+ puts "value = #{value}" if verbose()
39
+
40
+ if (nil == @last_value)
41
+ @last_value = value.to_f()
42
+ puts "Setting intial last_value = #{@last_value}" if verbose()
43
+ return nil
44
+ end
45
+
46
+ @values_up.shift() if (range() == @values_up.length())
47
+ @values_down.shift() if (range() == @values_down.length())
48
+
49
+ diff = value.to_f - @last_value
50
+ @last_value = value.to_f()
51
+ if (0 > diff)
52
+ @values_up << 0
53
+ @values_down << diff.abs()
54
+ elsif (0 < diff)
55
+ @values_up << diff
56
+ @values_down << 0
57
+ else
58
+ @values_up << 0
59
+ @values_down << 0
60
+ end
61
+ puts "diff = #{diff}, values_up = #{@values_up.inspect()}, values_down = #{@values_down.inspect()}" if verbose()
62
+
63
+ if (@values_up.length() < range())
64
+ puts "#{@values_up.length()} < #{range()}" if verbose()
65
+ return nil
66
+ end
67
+ if (@values_up.length() > range())
68
+ puts "#{@values_up.length()} > #{range()}" if verbose()
69
+ @values_up.shift()
70
+ @values_down.shift()
71
+ else
72
+ puts "#{@values_up.length()} == #{range()}" if verbose()
73
+ end
74
+
75
+ sum = {:up => 0, :down => 0, :i_up => 0, :i_down => 0}
76
+ @values_up.each() { |value| sum[:up] = sum[:up] + value }
77
+ @values_down.each() { |value| sum[:down] = sum[:down] + value }
78
+
79
+ rs = (0 == sum[:down]) ? 100.0 : (sum[:up] / sum[:down])
80
+ puts "rs = #{rs}" if verbose()
81
+
82
+ rsi = 100.0 - (100.0 / (1.0 + rs))
83
+ puts "rsi = #{rsi}" if verbose()
84
+ return rsi
85
+ end
86
+
87
+ ###
88
+ # Compute the RSI values for an array
89
+ # Return an array with the RSI values
90
+ ###
91
+ def add_array(values)
92
+ raise ArgumentError, "Value is nil" unless (values);
93
+ raise ArgumentError, "Value is not an array" unless values.kind_of?(Array);
94
+
95
+ output = []
96
+
97
+ # Calculate the sum of the array
98
+ values.each() { |value| output << add(value) }
99
+
100
+ # Return the RSI array
101
+ return output
102
+ end
103
+ end
104
+
105
+ ###
106
+ # RSI is just an alias to RelativeStrengthIndex
107
+ ###
108
+ class RSI < RelativeStrengthIndex
109
+ def initialize(range)
110
+ super(range)
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,74 @@
1
+ module AdvancedMath
2
+ # Simple Moving Average (SMA) calculator
3
+ # Created: 2011-06-24
4
+ # Author: G Nagel
5
+ # Company: Mercury Wireless Software LLC
6
+ class SimpleMovingAverage
7
+ ###
8
+ # Initialize the members:
9
+ # range:
10
+ # number of values to average
11
+ # sum:
12
+ # current sum of all values in the array
13
+ # values:
14
+ # array of values used as temporary storage
15
+ ###
16
+ def initialize(range)
17
+ raise ArgumentError, "Range is nil" unless (range);
18
+ raise ArgumentError, "Range must be >= 1" unless range.to_i >= 1;
19
+ @range = range.to_i;
20
+ @sum = 0;
21
+ @values = Array.new();
22
+ end
23
+
24
+ ###
25
+ # Add a value to the list.
26
+ # If the list is < @range, then return nil.
27
+ # Otherwise compute the SMA and return the value.
28
+ ###
29
+ def add(value)
30
+ raise ArgumentError, "Value is nil" unless (value);
31
+
32
+ # add the value to the end of the array.
33
+ @values.push(value);
34
+
35
+ # Calculate the sum of the array
36
+ @sum += value.to_f;
37
+
38
+ # Is the array less than the range?
39
+ return nil if (@values.length() < @range)
40
+
41
+ # Is the array larger than the range?
42
+ @sum -= @values.shift.to_f() if (@values.length() > @range)
43
+
44
+ # Compute the average
45
+ return @sum.to_f / @range.to_f;
46
+ end
47
+
48
+ ###
49
+ # Compute the SMA values for an array
50
+ # Return an array with the SMA values
51
+ ###
52
+ def add_array(values)
53
+ raise ArgumentError, "Value is nil" unless (values);
54
+ raise ArgumentError, "Value is not an array" unless values.kind_of?(Array);
55
+
56
+ output = []
57
+
58
+ # Calculate the sum of the array
59
+ values.each() { |value| output << add(value) }
60
+
61
+ # Return the SMA array
62
+ return output
63
+ end
64
+ end
65
+
66
+ ###
67
+ # SMA is just an alias to SimpleMovingAverage
68
+ ###
69
+ class SMA < SimpleMovingAverage
70
+ def initialize(range)
71
+ super(range)
72
+ end
73
+ end
74
+ end
data/lib/advanced_math.rb CHANGED
@@ -1,59 +1,6 @@
1
-
2
1
  module AdvancedMath
3
- VERSION = '0.0.5'
4
-
5
-
6
- # Simple Moving Average (SMA) calculator
7
- # Created: 2011-06-24
8
- # Author: G Nagel
9
- # Company: Mercury Wireless Software LLC
10
- class SimpleMovingAverage
11
- ###
12
- # Initialize the members:
13
- # range:
14
- # number of values to average
15
- # sum:
16
- # current sum of all values in the array
17
- # values:
18
- # array of values used as temporary storage
19
- ###
20
- def initialize(range)
21
- raise ArgumentError, "Range is nil" unless (range);
22
- raise ArgumentError, "Range must be >= 1" unless range.to_i >= 1;
23
- @range = range.to_i;
24
- @sum = 0;
25
- @values = Array.new();
26
- end
27
-
28
- ###
29
- # Add a value to the list.
30
- # If the list is < @range, then return nil.
31
- # Otherwise compute the SMA and return the value.
32
- ###
33
- def add(value)
34
- raise ArgumentError, "Value is nil" unless (value);
35
-
36
- # add the value to the end of the array.
37
- @values.push(value);
38
-
39
- # Calculate the sum of the array
40
- @sum += value.to_f;
41
-
42
- # Is the array less than the range?
43
- return nil if (@values.length() < @range)
44
-
45
- # Is the array larger than the range?
46
- @sum -= @values.shift.to_f() if (@values.length() > @range)
47
-
48
- # Compute the average
49
- return @sum.to_f / @range.to_f;
50
- end
51
- end
52
-
53
- ###
54
- # SMA is just an alias to SimpleMovingAverage
55
- ###
56
- class SMA < SimpleMovingAverage
57
- end
58
-
2
+ VERSION = '0.0.7'
59
3
  end
4
+
5
+ require File.dirname(__FILE__) + "/advanced_math/sma.rb"
6
+ require File.dirname(__FILE__) + "/advanced_math/rsi.rb"
data/test/RSI.pm ADDED
@@ -0,0 +1,247 @@
1
+ package Math::Business::RSI;
2
+
3
+ use strict;
4
+ use warnings;
5
+ use Carp;
6
+
7
+ our $VERSION = 2.5; # local revision: b
8
+
9
+ use Math::Business::SMA;
10
+ use Math::Business::EMA;
11
+
12
+ 1;
13
+
14
+ sub recommended {
15
+ my $class = shift;
16
+
17
+ $class->new(14);
18
+ }
19
+
20
+ sub new {
21
+ my $class = shift;
22
+ my $this = bless {
23
+ U => Math::Business::EMA->new,
24
+ D => Math::Business::EMA->new,
25
+ RSI => undef,
26
+ cy => undef,
27
+ }, $class;
28
+
29
+ my $alpha = shift;
30
+ if( defined $alpha ) {
31
+ $this->set_alpha( $alpha );
32
+ }
33
+
34
+ return $this;
35
+ }
36
+
37
+ sub set_alpha {
38
+ my $this = shift;
39
+ my $alpha = shift;
40
+
41
+ # NOTE: this alpha is different than you might think ... it's really inverse alpha
42
+ # Wilder uses alpha=14 instead of alpha=(1/14) like you might expect
43
+
44
+ my $days = 2*$alpha - 1; # so days is 2*$alpha-1 instead of the expected 2*(1/$alpha)-1
45
+
46
+ eval { $this->set_days( $days ) };
47
+ croak "set_alpha() is basically set_days(2*$alpha-1), which complained: $@" if $@;
48
+ }
49
+
50
+ sub set_standard {
51
+ my $this = shift;
52
+ my $rm = ref $this->{U};
53
+
54
+ if( $rm =~ m/SMA/ ) {
55
+ $this->{U} = Math::Business::EMA->new;
56
+ $this->{D} = Math::Business::EMA->new;
57
+
58
+ if( my $d = $this->{days} ) {
59
+ $this->set_days($d);
60
+ }
61
+ }
62
+ }
63
+
64
+ sub set_cutler {
65
+ my $this = shift;
66
+ my $rm = ref $this->{U};
67
+
68
+ if( $rm =~ m/EMA/ ) {
69
+ $this->{U} = Math::Business::SMA->new;
70
+ $this->{D} = Math::Business::SMA->new;
71
+
72
+ if( my $d = $this->{days} ) {
73
+ $this->set_days($d);
74
+ }
75
+ }
76
+ }
77
+
78
+ sub set_days {
79
+ my $this = shift;
80
+ my $arg = int(shift);
81
+
82
+ croak "days must be a positive non-zero integer" if $arg <= 0;
83
+
84
+ $this->{U}->set_days($this->{days} = $arg);
85
+ $this->{D}->set_days($arg);
86
+ delete $this->{cy};
87
+ delete $this->{RSI};
88
+ }
89
+
90
+ sub insert {
91
+ my $this = shift;
92
+ my $close_yesterday = $this->{cy};
93
+
94
+ my $EMA_U = $this->{U};
95
+ my $EMA_D = $this->{D};
96
+
97
+ croak "You must set the number of days before you try to insert" if not $this->{days};
98
+ while( defined( my $close_today = shift ) ) {
99
+ if( defined $close_yesterday ) {
100
+ my $delta = $close_today - $close_yesterday;
101
+
102
+ my ($U,$D) = (0,0);
103
+ if( $delta > 0 ) {
104
+ $U = $delta;
105
+ $D = 0;
106
+
107
+ } elsif( $delta < 0 ) {
108
+ $U = 0;
109
+ $D = abs $delta;
110
+ }
111
+
112
+ $EMA_U->insert($U);
113
+ $EMA_D->insert($D);
114
+ }
115
+
116
+ if( defined(my $eu = $EMA_U->query) ) {
117
+ my $ed = $EMA_D->query;
118
+ my $rs = (($ed == 0) ? 100 : $eu/$ed ); # NOTE: This is by definition apparently.
119
+
120
+ $this->{RSI} = 100 - 100/(1+$rs);
121
+ }
122
+
123
+ $close_yesterday = $close_today;
124
+ }
125
+
126
+ $this->{cy} = $close_yesterday;
127
+ }
128
+
129
+ sub query {
130
+ my $this = shift;
131
+
132
+ return $this->{RSI};
133
+ }
134
+
135
+ __END__
136
+
137
+ =head1 NAME
138
+
139
+ Math::Business::RSI - Technical Analysis: Relative Strength Index
140
+
141
+ =head1 SYNOPSIS
142
+
143
+ use Math::Business::RSI;
144
+
145
+ my $rsi = new Math::Business::RSI;
146
+ $rsi->set_alpha(14); # issues a set days of 2*14-1
147
+ $rsi->set_days(27); # equivilent to set_alpha(14)
148
+
149
+ # equivelent to set_days(27)/set_alpha(14):
150
+ my $rsi = new Math::Business::RSI(14);
151
+
152
+ # or to just get the recommended model ... set_alpha(14)
153
+ my $rsi = Math::Business::RSI->recommended;
154
+
155
+ my @closing_values = qw(
156
+ 3 4 4 5 6 5 6 5 5 5 5
157
+ 6 6 6 6 7 7 7 8 8 8 8
158
+ );
159
+
160
+ # choose one:
161
+ $rsi->insert( @closing_values );
162
+ $rsi->insert( $_ ) for @closing_values;
163
+
164
+ if( defined(my $q = $rsi->query) ) {
165
+ print "RSI: $q.\n";
166
+
167
+ } else {
168
+ print "RSI: n/a.\n";
169
+ }
170
+
171
+ =head1 RESEARCHER
172
+
173
+ The RSI was designed by J. Welles Wilder Jr in 1978.
174
+
175
+ According to Wilder, a security is "overbought" it the RSI reaches an upper
176
+ bound of 70 and is "oversold" when it moves below 30. Some sources also
177
+ use thresholds of 80 and 20.
178
+
179
+ Therefore, moving above the upper threshold is a selling signal, whlie moving
180
+ below the lower threshold is a signal to buy.
181
+
182
+ Oddly, RSI(14) uses a "smoothing period" of 14 days -- referring to an alpha of
183
+ 1/14. This means the EMA[N]u/EMA[N]d has N set to 27. This also means the
184
+ alpha is upside of other alpha you might see. RSI(14) actually uses an alpha
185
+ of ~0.0714, but set_alpha() takes the inverse to make C<$rsi->set_alpha(14)>
186
+ work.
187
+
188
+ If all of the above seems really confusing, no worries: RSI(14) means
189
+ C<set_alpha(14)> (or C<new(14)> and is equivelent to C<set_days(27)>.
190
+
191
+ =head2 Cutler
192
+
193
+ There are differing schools of thought on how to calculate this and how
194
+ important it is to stick to precisely the formula Wilder used. Cutler used
195
+ simple moving averages instead of exponential moving averages.
196
+
197
+ You can switch between Wilder and Cutler mode with these:
198
+
199
+ $rsi->set_cutler; # for simple moving averages
200
+ $rsi->set_standard; # for exponential moving averages
201
+
202
+ WARNING: Both of these clear out the value queue! If you need to track
203
+ both, you'll need two objects.
204
+
205
+ =head1 THANKS
206
+
207
+ Todd Litteken C<< <cl@xganon.com> >>
208
+
209
+ Amit Dutt C<< <amit_dutt@hotmail.com> >>
210
+
211
+ =head1 AUTHOR
212
+
213
+ Paul Miller C<< <jettero@cpan.org> >>
214
+
215
+ I am using this software in my own projects... If you find bugs, please please
216
+ please let me know.
217
+
218
+ I normally hang out on #perl on freenode, so you can try to get immediate
219
+ gratification there if you like. L<irc://irc.freenode.net/perl>
220
+
221
+ There is also a mailing list with very light traffic that you might want to
222
+ join: L<http://groups.google.com/group/stockmonkey/>.
223
+
224
+ =head1 COPYRIGHT
225
+
226
+ Copyright (c) 2010 Paul Miller
227
+
228
+ =head1 LICENSE
229
+
230
+ This module is free software. You can redistribute it and/or
231
+ modify it under the terms of the Artistic License 2.0.
232
+
233
+ This program is distributed in the hope that it will be useful,
234
+ but without any warranty; without even the implied warranty of
235
+ merchantability or fitness for a particular purpose.
236
+
237
+ [This software may have had previous licenses, of which the current maintainer
238
+ is completely unaware. If this is so, it is possible the above license is
239
+ incorrect or invalid.]
240
+
241
+ =head1 SEE ALSO
242
+
243
+ perl(1), L<Math::Business::StockMonkey>, L<Math::Business::StockMonkey::FAQ>, L<Math::Business::StockMonkey::CookBook>
244
+
245
+ L<http://en.wikipedia.org/wiki/Relative_Strength_Index>
246
+
247
+ =cut
data/test/rsi.pl ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env perl
2
+ use Math::Business::RSI;
3
+
4
+ my $rsi = new Math::Business::RSI(shift @ARGV);
5
+ $rsi->set_cutler;
6
+ $rsi->insert( $_ ) for @ARGV;
7
+ $rsi = int($rsi->query);
8
+ print "$rsi\n";
data/test/test_rsi.rb ADDED
@@ -0,0 +1,127 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + "/../lib/advanced_math.rb"
3
+
4
+ module AdvancedMath
5
+ class RelativeStrengthIndexTest < Test::Unit::TestCase
6
+ # Verify the constructor raises an ArgumentError if the "range" is invalid
7
+ def test_sma_initialize_nil
8
+ assert_raise(ArgumentError) { RelativeStrengthIndex.new(nil) }
9
+ end
10
+
11
+ # Verify the constructor raises an ArgumentError if the "range" is invalid
12
+ def test_sma_initialize_negative
13
+ assert_raise(ArgumentError) { RelativeStrengthIndex.new(-1) }
14
+ (-1...-1000).each do |i|
15
+ assert_raise(ArgumentError) { RelativeStrengthIndex.new(i) }
16
+ end
17
+ end
18
+
19
+ # Verify the constructor raises an ArgumentError if the "range" is invalid
20
+ def test_sma_initialize_zero
21
+ assert_raise(ArgumentError) { RelativeStrengthIndex.new(0) }
22
+ end
23
+
24
+ # Verify the constructor raises an ArgumentError if the "range" is invalid
25
+ def test_sma_initialize_one
26
+ assert_raise(ArgumentError) { RelativeStrengthIndex.new(1) }
27
+ end
28
+
29
+ # Verify the constructor doesn't raise an exception if the value is positive
30
+ def test_sma_initialize_positive
31
+ (2...1000).each do |i|
32
+ assert_nothing_raised(ArgumentError) { RelativeStrengthIndex.new(i) }
33
+ end
34
+ end
35
+
36
+ # Verify "add" raises an ArgumentError if the "value" is invalid
37
+ def test_sma_add_nil
38
+ assert_raise(ArgumentError) { RelativeStrengthIndex.new(1).add(nil) }
39
+ end
40
+
41
+ # # Verify SMA of 1, always returns the same value
42
+ # def test_sma_add_0
43
+ # sma = RelativeStrengthIndex.new(2)
44
+ # assert_nil(value = sma.add(0))
45
+ # assert_nil(value = sma.add(0))
46
+ # assert_not_nil(value = sma.add(0))
47
+ # assert_equal(50, value)
48
+ # (0...1000).each { |i| assert_equal(50, sma.add(0)) }
49
+ # end
50
+
51
+ def test_sma_add_range
52
+ sma = RelativeStrengthIndex.new(2)
53
+ (0...1000).each do |i|
54
+ value = sma.add(i)
55
+ if (i < 2)
56
+ assert_nil(value, "#{i}")
57
+ else
58
+ assert_not_nil(value, "#{i}")
59
+ assert_equal(99, sma.add(i).to_i(), "#{i}")
60
+ end
61
+ end
62
+ end
63
+
64
+ def RelativeStrengthIndexTest.rsi_values(period, values)
65
+ cmd = "#{File.dirname(__FILE__)}/rsi.pl #{period} #{values.join(" ")}"
66
+ cmd = `#{cmd}`.strip()
67
+ return cmd.to_i()
68
+ end
69
+
70
+ def RelativeStrengthIndexTest.rsi_range(period, prefix, range)
71
+ values = []
72
+ prefix.each() { |i| values << i }
73
+ range.each() { |i| values << i }
74
+ return RelativeStrengthIndexTest.rsi_values(period, values)
75
+ end
76
+
77
+ # Verify SMA of 2, always returns the same value - 0.5
78
+ def test_sma_add_2
79
+ sma = RelativeStrengthIndex.new(2)
80
+ assert_equal(nil, sma.add(0))
81
+ assert_equal(nil, sma.add(0))
82
+ assert_equal(99, sma.add(0).to_i())
83
+ (1...1000).each do |i|
84
+ value = sma.add(i).to_i()
85
+ cmp = RelativeStrengthIndexTest.rsi_range(sma.range(), [0, 0, 0], Range.new(0, i+1))
86
+ assert_equal(cmp, value, "#{i}")
87
+ assert_equal(99, value, "#{i}")
88
+ end
89
+
90
+ # (0..1000).to_a().each() do |i|
91
+ # sma = RelativeStrengthIndex.new(2)
92
+ # value = sma.add(i)
93
+ # assert_nil(value, i)
94
+ #
95
+ # value = sma.add(i+1)
96
+ # assert_not_nil(value = sma.add(i+1), i)
97
+ # assert_equal(99, sma.add(i).to_i(), "#{i}")
98
+ # end
99
+ end
100
+
101
+ def test_sma_array
102
+ assert_raise(ArgumentError) { RelativeStrengthIndex.new(2).add_array(nil) }
103
+ assert_raise(ArgumentError) { RelativeStrengthIndex.new(2).add_array("") }
104
+ assert_raise(ArgumentError) { RelativeStrengthIndex.new(2).add_array(1) }
105
+ assert_nothing_raised(ArgumentError) { RelativeStrengthIndex.new(2).add_array(Array.new) }
106
+ assert_not_nil( RelativeStrengthIndex.new(2).add_array(Array.new) )
107
+ assert_not_nil( RelativeStrengthIndex.new(2).add_array([]) )
108
+ assert_equal( 0, RelativeStrengthIndex.new(2).add_array([]).length() )
109
+ assert_equal( 1, RelativeStrengthIndex.new(2).add_array([1]).length() )
110
+ assert_equal( 2, RelativeStrengthIndex.new(2).add_array((1..2).to_a).length() )
111
+ assert_equal( 1000, RelativeStrengthIndex.new(2).add_array((1..1000).to_a).length() )
112
+
113
+ values = RelativeStrengthIndex.new(2).add_array((0..1000).to_a)
114
+ assert_nil(values[0])
115
+ assert_nil(values[1])
116
+ 2.upto(values.length() -1) do |i|
117
+ assert_not_nil(values[i])
118
+ assert_equal(99, values[i].to_i())
119
+ end
120
+
121
+ values = RelativeStrengthIndex.new(14).add_array((0..14000).to_a)
122
+ values.slice!(0, 14).each() { |value| assert_nil(value) }
123
+
124
+ values.each() { |value| assert_not_nil(value); assert_equal(99, value.to_i()) }
125
+ end
126
+ end
127
+ end
@@ -5,48 +5,88 @@ module AdvancedMath
5
5
  class SimpleMovingAverageTest < Test::Unit::TestCase
6
6
  # Verify the constructor raises an ArgumentError if the "range" is invalid
7
7
  def test_sma_initialize_nil
8
- assert_raise(ArgumentError) { SimpleMovingAverage.new(nil); }
8
+ assert_raise(ArgumentError) { SimpleMovingAverage.new(nil) }
9
9
  end
10
10
 
11
11
  # Verify the constructor raises an ArgumentError if the "range" is invalid
12
12
  def test_sma_initialize_negative
13
- assert_raise(ArgumentError) { SimpleMovingAverage.new(-1); }
13
+ assert_raise(ArgumentError) { SimpleMovingAverage.new(-1) }
14
14
  (-1...-1000).each do |i|
15
- assert_raise(ArgumentError) { SimpleMovingAverage.new(i); }
15
+ assert_raise(ArgumentError) { SimpleMovingAverage.new(i) }
16
16
  end
17
17
  end
18
18
 
19
19
  # Verify the constructor raises an ArgumentError if the "range" is invalid
20
20
  def test_sma_initialize_zero
21
- assert_raise(ArgumentError) { SimpleMovingAverage.new(0); }
21
+ assert_raise(ArgumentError) { SimpleMovingAverage.new(0) }
22
22
  end
23
23
 
24
24
  # Verify the constructor doesn't raise an exception if the value is positive
25
25
  def test_sma_initialize_positive
26
26
  (1...1000).each do |i|
27
- assert_nothing_raised(ArgumentError) { SimpleMovingAverage.new(i); }
27
+ assert_nothing_raised(ArgumentError) { SimpleMovingAverage.new(i) }
28
28
  end
29
29
  end
30
30
 
31
31
  # Verify "add" raises an ArgumentError if the "value" is invalid
32
32
  def test_sma_add_nil
33
- assert_raise(ArgumentError) { SimpleMovingAverage.new(1).add(nil); }
33
+ assert_raise(ArgumentError) { SimpleMovingAverage.new(1).add(nil) }
34
34
  end
35
35
 
36
36
  # Verify SMA of 1, always returns the same value
37
37
  def test_sma_add_1
38
- sma = SimpleMovingAverage.new(1);
38
+ sma = SimpleMovingAverage.new(1)
39
39
  (1...1000).each do |i|
40
- assert_equal(i, sma.add(i));
40
+ assert_equal(i, sma.add(i))
41
41
  end
42
42
  end
43
43
 
44
44
  # Verify SMA of 2, always returns the same value - 0.5
45
45
  def test_sma_add_2
46
- sma = SimpleMovingAverage.new(2);
47
- assert_equal(nil, sma.add(1));
46
+ sma = SimpleMovingAverage.new(2)
47
+ assert_equal(nil, sma.add(1))
48
48
  (2...1000).each do |i|
49
- assert_equal(i - 0.5, sma.add(i));
49
+ assert_equal(i - 0.5, sma.add(i))
50
+ end
51
+
52
+ (0..1000).to_a().each() do |i|
53
+ sma = SimpleMovingAverage.new(2)
54
+ assert_nil(value = sma.add(i))
55
+ assert_not_nil(value = sma.add(i+1))
56
+ assert_equal(i+0.5, value)
57
+ end
58
+ end
59
+
60
+ def test_sma_array
61
+ assert_raise(ArgumentError) { SimpleMovingAverage.new(2).add_array(nil) }
62
+ assert_raise(ArgumentError) { SimpleMovingAverage.new(2).add_array("") }
63
+ assert_raise(ArgumentError) { SimpleMovingAverage.new(2).add_array(1) }
64
+ assert_nothing_raised(ArgumentError) { SimpleMovingAverage.new(2).add_array(Array.new) }
65
+ assert_not_nil( SimpleMovingAverage.new(2).add_array(Array.new) )
66
+ assert_not_nil( SimpleMovingAverage.new(2).add_array([]) )
67
+ assert_equal( 0, SimpleMovingAverage.new(2).add_array([]).length() )
68
+ assert_equal( 1, SimpleMovingAverage.new(2).add_array([1]).length() )
69
+ assert_equal( 2, SimpleMovingAverage.new(2).add_array((1..2).to_a).length() )
70
+ assert_equal( 1000, SimpleMovingAverage.new(2).add_array((1..1000).to_a).length() )
71
+
72
+ values = SimpleMovingAverage.new(2).add_array((0..1000).to_a)
73
+ assert_nil(values[0])
74
+ 1.upto(values.length() -1) do |i|
75
+ assert_not_nil(values[i])
76
+ assert_equal(i - 0.5, values[i])
77
+ end
78
+
79
+ values = SimpleMovingAverage.new(14).add_array((0..14000).to_a)
80
+ 0.upto(12) { |i| assert_nil(values[i], "#{i}") }
81
+
82
+ 13.upto(values.length() -1) do |i|
83
+ assert_not_nil(values[i], "#{i}")
84
+
85
+ sum = 0.0
86
+ Range.new(i-13, i).each() { |value| sum = sum + value.to_f}
87
+ sum = sum / 14
88
+
89
+ assert_equal(sum, values[i], "#{i}")
50
90
  end
51
91
  end
52
92
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: advanced_math
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 17
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 5
10
- version: 0.0.5
9
+ - 7
10
+ version: 0.0.7
11
11
  platform: ruby
12
12
  authors:
13
13
  - Glenn Nagel
@@ -48,9 +48,14 @@ files:
48
48
  - Manifest.txt
49
49
  - PostInstall.txt
50
50
  - README.rdoc
51
- - advanced_math-0.0.4.gem
52
51
  - advanced_math.gemspec
52
+ - gem_publish.sh
53
53
  - lib/advanced_math.rb
54
+ - lib/advanced_math/rsi.rb
55
+ - lib/advanced_math/sma.rb
56
+ - test/RSI.pm
57
+ - test/rsi.pl
58
+ - test/test_rsi.rb
54
59
  - test/test_simple_moving_average.rb
55
60
  homepage: https://github.com/gnagel/mercury-wireless-public/tree/master/ruby/advanced_math
56
61
  licenses: []
@@ -87,4 +92,5 @@ signing_key:
87
92
  specification_version: 3
88
93
  summary: A simple gem for advanced and financial math calcualtions.
89
94
  test_files:
95
+ - test/test_rsi.rb
90
96
  - test/test_simple_moving_average.rb
Binary file