indicators 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ .DS_Store
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in indicators.gemspec
4
4
  gemspec
5
+ gem 'guard'
6
+ gem 'guard-rspec'
7
+ gem 'guard-bundler'
8
+ gem 'growl'
@@ -0,0 +1,30 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'bundler' do
5
+ watch('Gemfile')
6
+ # Uncomment next line if Gemfile contain `gemspec' command
7
+ # watch(/^.+\.gemspec/)
8
+ end
9
+
10
+ guard 'rspec', :version => 2 do
11
+ watch(%r{^spec/.+_spec\.rb$})
12
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
13
+ watch('spec/spec_helper.rb') { "spec" }
14
+
15
+ # Rails example
16
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
17
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
18
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
19
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
20
+ watch('config/routes.rb') { "spec/routing" }
21
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
22
+
23
+ # Capybara request specs
24
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
25
+
26
+ # Turnip features and steps
27
+ watch(%r{^spec/acceptance/(.+)\.feature$})
28
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
29
+ end
30
+
data/README.md CHANGED
@@ -4,7 +4,7 @@ A gem for calculating technical analysis indicators.
4
4
 
5
5
  Current functionality demo of Indicators and Securities gems synergy can be tested at http://strangemuseum.heroku.com.
6
6
 
7
- [![Build Status](https://secure.travis-ci.org/Nedomas/indicators.png)](http://travis-ci.org/Nedomas/indicators)
7
+ [![Build Status](https://secure.travis-ci.org/Nedomas/indicators.png)](http://travis-ci.org/Nedomas/indicators)[![Dependency Status](https://gemnasium.com/Nedomas/indicators.png)](https://gemnasium.com/Nedomas/indicators)
8
8
 
9
9
  ## Installation
10
10
 
@@ -32,11 +32,9 @@ Then it returns data as an array with indicator values in index places:
32
32
 
33
33
  # Securities gem hash
34
34
 
35
- my_data = Indicators::Data.new(Securities::Stock.new(["aapl", "yhoo"]).history(:start_date => '2012-08-25', :end_date => '2012-08-30').results)
35
+ my_data = Indicators::Data.new(Securities::Stock.new(:symbol => 'AAPL', :start_date => '2012-08-25', :end_date => '2012-08-30').output)
36
36
 
37
- Then it returns a hash so it can be quite powerful at calculating multiple stock indicators at once:
38
-
39
- {"aapl"=>[nil, 675.24, 674.0600000000001], "yhoo"=>[nil, 14.785, 14.821666666666667]}
37
+ my_data.calc(:type => :sma, :params => 3)
40
38
 
41
39
  ## Output
42
40
 
@@ -91,7 +89,6 @@ Variables have to be specified as an array [lookback period, the number of perio
91
89
 
92
90
  ## To Do
93
91
 
94
- * Write specs.
95
92
  * A strategy backtesting tool.
96
93
 
97
94
  # Indicators:
@@ -16,6 +16,6 @@ Gem::Specification.new do |gem|
16
16
  gem.version = Indicators::VERSION
17
17
 
18
18
  gem.add_dependency 'rails'
19
- gem.add_development_dependency 'securities'
19
+ gem.add_development_dependency 'securities', ">= 2.0.0", "< 3.0.0"
20
20
  gem.add_development_dependency 'rspec'
21
21
  end
@@ -3,8 +3,7 @@ module Indicators
3
3
  class Helper
4
4
 
5
5
  # Error handling.
6
- class HelperException < StandardError
7
- end
6
+ class HelperException < StandardError ; end
8
7
 
9
8
  def self.validate_data data, column, parameters
10
9
  # If this is a hash, choose which column of values to use for calculations.
@@ -14,12 +13,6 @@ module Indicators
14
13
  valid_data = data
15
14
  end
16
15
 
17
- # Make output more friendly
18
- # if parameters.is_a?(Array)
19
- # parameters_array = parameters
20
- # parameters = parameters.sum
21
- # end
22
-
23
16
  if valid_data.length < parameters
24
17
  raise HelperException, "Data point length (#{valid_data.length}) must be greater than or equal to the required indicator periods (#{parameters})."
25
18
  end
@@ -29,6 +22,7 @@ module Indicators
29
22
  # Indicators::Helper.get_parameters([12, 1, 1], 0, 15)
30
23
  def self.get_parameters parameters, i=0, default=0
31
24
 
25
+ # Single parameter is to choose from.
32
26
  if parameters.is_a?(Integer) || parameters.is_a?(NilClass)
33
27
 
34
28
  # Set all other to default if only one integer is given instead of an array.
@@ -40,11 +34,12 @@ module Indicators
40
34
  if default != 0
41
35
  return default
42
36
  else
43
- raise HelperException, "There were no parameters specified and there is no default for it."
37
+ raise HelperException, 'There were no parameters specified and there is no default for it.'
44
38
  end
45
39
  else
46
40
  return parameters
47
41
  end
42
+ # Multiple parameters to choose from.
48
43
  elsif parameters.is_a?(Array)
49
44
  # In case array is given not like [1, 2] but like this ["1", "2"]. This usually happens when getting data from input forms.
50
45
  parameters = parameters.map(&:to_i)
@@ -52,13 +47,13 @@ module Indicators
52
47
  if default != 0
53
48
  return default
54
49
  else
55
- raise HelperException, "There were no parameters specified and there is no default for it."
50
+ raise HelperException, 'There were no parameters specified and there is no default for it.'
56
51
  end
57
52
  else
58
53
  return parameters[i]
59
54
  end
60
55
  else
61
- raise HelperException, "Parameters have to be a integer, an array or nil."
56
+ raise HelperException, 'Parameters have to be a integer, an array or nil.'
62
57
  end
63
58
 
64
59
  end
@@ -4,30 +4,27 @@ module Indicators
4
4
  attr_reader :data, :results
5
5
  INDICATORS = [:sma, :ema, :bb, :macd, :rsi, :sto]
6
6
  # Error handling
7
- class DataException < StandardError
8
- end
7
+ class DataException < StandardError ; end
9
8
 
10
9
  def initialize parameters
11
10
  @data = parameters
12
11
 
13
12
  # Check if data usable.
14
13
  if @data.nil? || @data.empty?
15
- raise DataException, "There is no data to work on."
14
+ raise DataException, 'There is no data to work on.'
16
15
  end
17
- unless @data.is_a?(Array) or @data.is_a?(Hash)
18
- raise DataException, "Alien data. Given data must be an array or a hash (got #{@data.class})."
16
+ unless @data.is_a?(Array)
17
+ raise DataException, "Alien data. Given data must be an array (got #{@data.class})."
19
18
  end
20
19
 
21
- if @data.is_a?(Hash)
22
- # Hacky, but a fast way to check if this is a dividends hash without the extra hassle.
23
- raise DataException, "Cannot use dividends values for technical analysis." if @data.to_s.include?(':dividends')
24
- end
20
+ # Hacky, but a fast way to check if this is a dividends hash.
21
+ raise DataException, 'Cannot use dividends values for technical analysis.' if @data.to_s.include?(':dividends')
25
22
  end
26
23
 
27
24
  def calc parameters
28
25
  # Check is parameters are usable.
29
26
  unless parameters.is_a?(Hash)
30
- raise DataException, 'Given parameters have to be a hash. FORMAT: .calc(:type => :ema, :params => 12)'
27
+ raise DataException, 'Given parameters have to be a hash.'
31
28
  end
32
29
 
33
30
  # If not specified, set default :type to :sma.
@@ -4,63 +4,53 @@ module Indicators
4
4
 
5
5
  attr_reader :output, :abbr, :params
6
6
  # Error handling.
7
- class MainException < StandardError
8
- end
7
+ class MainException < StandardError ; end
9
8
 
10
9
  def initialize data, parameters
11
10
  type = parameters[:type]
12
11
  all_params = parameters[:params]
13
12
  @abbr = type.to_s.upcase
14
- if type == :sma
13
+ case type
14
+ when :sma
15
15
  @params = Indicators::Helper.get_parameters(all_params, 0, 20)
16
- elsif type == :ema
16
+ when :ema
17
17
  @params = Indicators::Helper.get_parameters(all_params, 0, 20)
18
- elsif type == :bb
18
+ when :bb
19
19
  @params = Array.new
20
- @params[0] = Indicators::Helper.get_parameters(all_params, 0, 20)
21
- @params[1] = Indicators::Helper.get_parameters(all_params, 1, 2)
22
- elsif type == :macd
20
+ @params << Indicators::Helper.get_parameters(all_params, 0, 20)
21
+ @params << Indicators::Helper.get_parameters(all_params, 1, 2)
22
+ when :macd
23
23
  @params = Array.new
24
- @params[0] = Indicators::Helper.get_parameters(all_params, 0, 12)
25
- @params[1] = Indicators::Helper.get_parameters(all_params, 1, 26)
26
- @params[2] = Indicators::Helper.get_parameters(all_params, 2, 9)
27
- elsif type == :rsi
24
+ @params << Indicators::Helper.get_parameters(all_params, 0, 12)
25
+ @params << Indicators::Helper.get_parameters(all_params, 1, 26)
26
+ @params << Indicators::Helper.get_parameters(all_params, 2, 9)
27
+ when :rsi
28
28
  @params = Indicators::Helper.get_parameters(all_params, 0, 14)
29
- elsif type == :sto
29
+ when :sto
30
30
  @params = Array.new
31
- @params[0] = Indicators::Helper.get_parameters(all_params, 0, 14)
32
- @params[1] = Indicators::Helper.get_parameters(all_params, 1, 3)
33
- @params[2] = Indicators::Helper.get_parameters(all_params, 2, 3)
31
+ @params << Indicators::Helper.get_parameters(all_params, 0, 14)
32
+ @params << Indicators::Helper.get_parameters(all_params, 1, 3)
33
+ @params << Indicators::Helper.get_parameters(all_params, 2, 3)
34
34
  end
35
35
 
36
- if data.is_a?(Hash)
37
- @output = Hash.new
38
- data.each do |symbol, stock_data|
39
- # Check if this symbol was empty and don't go further with it.
40
- if stock_data.length == 0
41
- @output[symbol] = []
42
- else
43
- @output[symbol] = case type
44
- when :sma then Indicators::Sma.calculate(Indicators::Parser.parse_data(stock_data), @params)
45
- when :ema then Indicators::Ema.calculate(Indicators::Parser.parse_data(stock_data), @params)
46
- when :bb then Indicators::Bb.calculate(Indicators::Parser.parse_data(stock_data), @params)
47
- when :macd then Indicators::Macd.calculate(Indicators::Parser.parse_data(stock_data), @params)
48
- when :rsi then Indicators::Rsi.calculate(Indicators::Parser.parse_data(stock_data), @params)
49
- when :sto then Indicators::Sto.calculate(Indicators::Parser.parse_data(stock_data), @params)
50
- end
51
- # Parser returns in {:date=>[2012.0, 2012.0, 2012.0], :open=>[409.4, 410.0, 414.95],} format
52
- end
53
- end
36
+ # This is a Securities gem hash.
37
+ if data[0].is_a?(Hash)
38
+ data = Indicators::Parser.parse_data(data)
39
+ # Parser returns in {:date=>[2012.0, 2012.0, 2012.0], :open=>[409.4, 410.0, 414.95],} format
54
40
  else
55
- @output = case type
56
- when :sma then Indicators::Sma.calculate(data, @params)
57
- when :ema then Indicators::Ema.calculate(data, @params)
58
- when :bb then Indicators::Bb.calculate(data, @params)
59
- when :macd then Indicators::Macd.calculate(data, @params)
60
- when :rsi then Indicators::Rsi.calculate(data, @params)
61
- when :sto then raise MainException, "You cannot calculate Stochastic Oscillator on array. Highs and lows are needed. Feel free Securities gem hash instead."
62
- end
63
- end
41
+ # Don't let calculation start on a standard array for few instruments cause it needs more specific data.
42
+ if type == :sto
43
+ raise MainException, 'You cannot calculate Stochastic Oscillator on array. Highs and lows are needed. Feel free Securities gem hash instead.'
44
+ end
45
+ end
46
+ @output = case type
47
+ when :sma then Indicators::Sma.calculate(data, @params)
48
+ when :ema then Indicators::Ema.calculate(data, @params)
49
+ when :bb then Indicators::Bb.calculate(data, @params)
50
+ when :macd then Indicators::Macd.calculate(data, @params)
51
+ when :rsi then Indicators::Rsi.calculate(data, @params)
52
+ when :sto then Indicators::Sto.calculate(data, @params)
53
+ end
64
54
  return @output
65
55
  end
66
56
 
@@ -4,8 +4,7 @@ module Indicators
4
4
  class Parser
5
5
 
6
6
  # Error handling.
7
- class ParserException < StandardError
8
- end
7
+ class ParserException < StandardError ; end
9
8
 
10
9
  def self.parse_data parameters
11
10
 
@@ -18,7 +17,7 @@ module Indicators
18
17
  transposed_hash = a
19
18
  }
20
19
  usable_data = transposed_hash
21
- # usable data is are {:close => [1, 2, 3], :open => []}
20
+ # usable data is {:close => [1, 2, 3], :open => []}
22
21
 
23
22
  return usable_data
24
23
  end
@@ -1,3 +1,3 @@
1
1
  module Indicators
2
- VERSION = "1.0.2"
2
+ VERSION = "1.0.3"
3
3
  end
@@ -1,28 +1,73 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Data do
4
-
5
- context "should raise an exception if" do
6
- it "nil or empty" do
7
- expect { Indicators::Data.new(nil) }.to raise_error
8
- expect { Indicators::Data.new('') }.to raise_error
9
- end
10
- it "not an array or hash" do
11
- expect { Indicators::Data.new('some string') }.to raise_error
12
- end
13
- it "contains dividends hash from securities gem" do
14
- expect { Indicators::Data.new(Securities::Stock.new(["aapl"]).history(:start_date => '2012-08-01', :end_date => '2012-08-10', :periods => :dividends)) }.to raise_error
3
+ describe Indicators::Data do
4
+
5
+ describe ".new" do
6
+ context "should raise an exception if parameter" do
7
+
8
+ it "is nil or empty" do
9
+ expect { Indicators::Data.new(nil) }.to raise_error('There is no data to work on.')
10
+ expect { Indicators::Data.new('') }.to raise_error('There is no data to work on.')
11
+ end
12
+ it "is not an array" do
13
+ expect { Indicators::Data.new('some string') }.to raise_error(Indicators::Data::DataException, /Alien data. Given data must be an array/)
14
+ end
15
+ it "contains dividends hash from Securities gem" do
16
+ expect { Indicators::Data.new(Securities::Stock.new(:symbol => 'AAPL', :start_date => '2012-08-01', :end_date => '2012-08-10', :type => :dividends).output) }.to raise_error('Cannot use dividends values for technical analysis.')
17
+ end
18
+ end
19
+
20
+ context "should not raise an exception if parameter" do
21
+
22
+ it "is an array" do
23
+ expect { Indicators::Data.new([1, 2, 3]) }.not_to raise_error
24
+ end
25
+ it "is a hash" do
26
+ expect { Indicators::Data.new(Securities::Stock.new(:symbol => 'AAPL', :start_date => '2012-08-01', :end_date => '2012-08-03', :type => :daily).output) }.not_to raise_error
27
+ end
28
+
15
29
  end
16
30
  end
17
31
 
18
- context "should not raise an exception if" do
19
- it "is an array" do
20
- expect { Indicators::Data.new([1, 2, 3]) }.not_to raise_error
32
+ describe ".calc" do
33
+ before :all do
34
+ @my_data = Indicators::Data.new(Securities::Stock.new(:symbol => 'AAPL', :start_date => '2012-08-01', :end_date => '2012-08-20', :type => :daily).output)
21
35
  end
22
- it "is a hash" do
23
- expect { Indicators::Data.new(Securities::Stock.new(["aapl"]).history(:start_date => '2012-08-01', :end_date => '2012-08-03', :periods => :daily)) }.not_to raise_error
36
+
37
+ context "should raise an exception if parameter" do
38
+ it "is not a hash" do
39
+ expect { @my_data.calc('some string') }.to raise_error('Given parameters have to be a hash.')
40
+ end
41
+ it ":type is invalid" do
42
+ expect { @my_data.calc(:type => :invalid_type, :params => 5) }.to raise_error(Indicators::Data::DataException, /Invalid indicator type specified/)
43
+ end
24
44
  end
25
45
 
46
+ context "should not raise an exception if parameter" do
47
+ it ":type is not specified (should default to :sma)" do
48
+ expect { @my_data.calc(:params => 5) }.not_to raise_error
49
+ # Can't get this test to work for some reason.
50
+ # @my_data.calc(:params => 5).abbr.downcase.to_sym should eq(:sma)
51
+ end
52
+ it "good SMA params are specified" do
53
+ expect { @my_data.calc(:type => :sma, :params => 5) }.not_to raise_error
54
+ end
55
+ it "good EMA params are specified" do
56
+ expect { @my_data.calc(:type => :ema, :params => 5) }.not_to raise_error
57
+ end
58
+ it "good BB params are specified" do
59
+ expect { @my_data.calc(:type => :bb, :params => [10, 2]) }.not_to raise_error
60
+ end
61
+ it "good MACD params are specified" do
62
+ expect { @my_data.calc(:type => :macd, :params => [2, 5, 4]) }.not_to raise_error
63
+ end
64
+ it "good RSI params are specified" do
65
+ expect { @my_data.calc(:type => :rsi, :params => 5) }.not_to raise_error
66
+ end
67
+ it "good STO params are specified" do
68
+ expect { @my_data.calc(:type => :sto, :params => [3, 5, 4]) }.not_to raise_error
69
+ end
70
+ end
26
71
  end
27
72
 
28
73
  end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Indicators::Helper do
4
+
5
+ context "should raise an exception if" do
6
+ before :all do
7
+ @my_data = Indicators::Data.new([1, 2, 3, 4, 5])
8
+ end
9
+ it "there was not enough data for specified periods" do
10
+ expect { @my_data.calc(:type => :sma, :params => 6) }.to raise_error('Data point length (5) must be greater than or equal to the required indicator periods (6).')
11
+ end
12
+ it "unknown type is given for parameters" do
13
+ expect { @my_data.calc(:type => :sma, :params => 'unknown_type') }.to raise_error('Parameters have to be a integer, an array or nil.')
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Indicators::Main do
4
+
5
+ context "should raise an exception if" do
6
+ it "there was no data to work on" do
7
+ @my_data = Indicators::Data.new([1, 2, 3, 4, 5])
8
+ expect { @my_data.calc(:type => :sto, :params => 2) }.to raise_error('You cannot calculate Stochastic Oscillator on array. Highs and lows are needed. Feel free Securities gem hash instead.')
9
+ end
10
+ end
11
+
12
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: indicators
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
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: 2012-09-04 00:00:00.000000000 Z
12
+ date: 2012-09-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -34,7 +34,10 @@ dependencies:
34
34
  requirements:
35
35
  - - ! '>='
36
36
  - !ruby/object:Gem::Version
37
- version: '0'
37
+ version: 2.0.0
38
+ - - <
39
+ - !ruby/object:Gem::Version
40
+ version: 3.0.0
38
41
  type: :development
39
42
  prerelease: false
40
43
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +45,10 @@ dependencies:
42
45
  requirements:
43
46
  - - ! '>='
44
47
  - !ruby/object:Gem::Version
45
- version: '0'
48
+ version: 2.0.0
49
+ - - <
50
+ - !ruby/object:Gem::Version
51
+ version: 3.0.0
46
52
  - !ruby/object:Gem::Dependency
47
53
  name: rspec
48
54
  requirement: !ruby/object:Gem::Requirement
@@ -70,6 +76,7 @@ files:
70
76
  - .rspec
71
77
  - .travis.yml
72
78
  - Gemfile
79
+ - Guardfile
73
80
  - LICENSE
74
81
  - README.md
75
82
  - Rakefile
@@ -87,6 +94,8 @@ files:
87
94
  - lib/indicators/parser.rb
88
95
  - lib/indicators/version.rb
89
96
  - spec/data_spec.rb
97
+ - spec/helper_spec.rb
98
+ - spec/main_spec.rb
90
99
  - spec/spec_helper.rb
91
100
  homepage: http://github.com/Nedomas/indicators
92
101
  licenses: []
@@ -102,7 +111,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
102
111
  version: '0'
103
112
  segments:
104
113
  - 0
105
- hash: -937322617127678675
114
+ hash: 399426522861495545
106
115
  required_rubygems_version: !ruby/object:Gem::Requirement
107
116
  none: false
108
117
  requirements:
@@ -111,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
120
  version: '0'
112
121
  segments:
113
122
  - 0
114
- hash: -937322617127678675
123
+ hash: 399426522861495545
115
124
  requirements: []
116
125
  rubyforge_project:
117
126
  rubygems_version: 1.8.24
@@ -120,4 +129,6 @@ specification_version: 3
120
129
  summary: A gem for calculating technical analysis indicators.
121
130
  test_files:
122
131
  - spec/data_spec.rb
132
+ - spec/helper_spec.rb
133
+ - spec/main_spec.rb
123
134
  - spec/spec_helper.rb