indicators 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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