edgar-stocks 1.0.0

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.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NDMzODMwZGU3YTQxNDQ5MzIzZTRkYTg3YTEyNWVjOWViZTI0NGU4NQ==
5
+ data.tar.gz: !binary |-
6
+ MGEwODcyYTBkYjY1MTNkYTM4ZDllODk3NzhiZjBkZWNiNTJiN2ZlMw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ ZTU5YmMzODE2OWVjZWI3N2YwYTE0ZjRkYWMwNzM5N2NjNzczMDdmOGQ5NzQz
10
+ MGQ4MmRjN2YyNDlkMjI1NmZhZDQzYjViMmY3YjYwYWI0MzM5ODRmMGJlMThl
11
+ NDI3NDIxZDNlODIxNzQyNmUzZDhjN2U4NWE1MDQ2OTVlMjA0Njc=
12
+ data.tar.gz: !binary |-
13
+ MDIxNDk0MjU3YjIzOGJlZGVkNTg0ZDQzYzI4OWNmNjUzOWUxYTI2NmM1YWRm
14
+ MDZkZjFmOWVhN2JhM2RlMzhjZTdiMWRmZmNjMDQ5NGQ3YTQwNmIxZWNmMTVh
15
+ NTM5ZDAwYjBiNTYzZDUxMjM1YWY1YTY3ZGM1NTBlNmZjYWYzNDA=
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .idea/
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in edgar.gemspec
4
+ gemspec
5
+
6
+ gem 'rspec'
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Andy Schrage
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.
@@ -0,0 +1,55 @@
1
+ # Edgar-Stocks
2
+
3
+ Edgar-Stocks is a Ruby gem that provides access to historical stock data in a simple, configurable way.
4
+
5
+ Edgar provides the following info for a stock:
6
+ - Opening price
7
+ - Closing price
8
+ - Daily high
9
+ - Daily low
10
+ - Adjusted close
11
+ - Volume
12
+
13
+ In addition to the above, Edgar can calculate the rolling average for a given date for a particular stock.
14
+
15
+ Have more ideas how I can improve the gem? Leave me a message!
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ gem 'edgar'
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install edgar
30
+
31
+ ## Usage
32
+
33
+ Simply create a new Edgar object for each stock you care about:
34
+
35
+ stock = Edgar::Edgar.new('INTU')
36
+
37
+ Then query it!
38
+
39
+ stock.closing_price # Returns today's closing price
40
+
41
+ Or ask for a date in the past.
42
+
43
+ stock.closing_price(DateTime.yesterday) # Obviously get yesterday's closing price
44
+
45
+ You can even get running averages
46
+
47
+ stock.closing_price(DateTime.now, 5) # Get the five day average closing price starting with today's closing.
48
+
49
+ ## Contributing
50
+
51
+ 1. Fork it
52
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
53
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
54
+ 4. Push to the branch (`git push origin my-new-feature`)
55
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'edgar/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "edgar-stocks"
8
+ spec.version = Edgar::VERSION
9
+ spec.authors = ["Andy Schrage"]
10
+ spec.email = ["ajschrag@mtu.edu"]
11
+ spec.description = %q{Edgar-Stocks is a Ruby gem that provides access to historical stock data in a simple, configurable way.}
12
+ spec.summary = %q{Stock data since the beginning of time!}
13
+ spec.homepage = "https://github.com/Swimminschrage/edgar"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency 'rspec'
24
+ end
@@ -0,0 +1,116 @@
1
+ require 'edgar/version'
2
+ require 'net/http'
3
+ require 'csv'
4
+ require 'time'
5
+
6
+ module Edgar
7
+
8
+ class Edgar
9
+ attr_reader :symbol
10
+
11
+ # Configuration defaults
12
+ @@config = {
13
+ :lookup_offset => -1,
14
+ :round_to => 2
15
+ }
16
+
17
+ @@valid_config_keys = @@config.keys
18
+
19
+ def self.configure(opts = {})
20
+ opts.each {|k,v| @@config[k.to_sym] = v if @@valid_config_keys.include? k.to_sym}
21
+ end
22
+
23
+ def self.config
24
+ @@config
25
+ end
26
+
27
+ def initialize(symbol)
28
+ @symbol = symbol
29
+
30
+ # Perform the actual lookup of historical data and parse it into arrays that
31
+ # are cached in memory
32
+ @data = CSV.parse(lookup)
33
+ end
34
+
35
+ def closing_price(date = DateTime.now, running = 1)
36
+ lookup_by_column(running, date, 4)
37
+ end
38
+
39
+ def opening_price(date = DateTime.now, running = 1)
40
+ lookup_by_column(running, date, 1)
41
+ end
42
+
43
+ def high_price(date = DateTime.now, running = 1)
44
+ lookup_by_column(running, date, 2)
45
+ end
46
+
47
+ def low_price(date = DateTime.now, running = 1)
48
+ lookup_by_column(running, date, 3)
49
+ end
50
+
51
+ def volume(date = DateTime.now, running = 1)
52
+ lookup_by_column(running, date, 5)
53
+ end
54
+
55
+ private
56
+
57
+ def lookup
58
+ @content ||= get_historical_data
59
+ end
60
+
61
+ def get_historical_data
62
+ uri = URI("http://ichart.finance.yahoo.com/table.csv?s=#{@symbol}")
63
+ response = Net::HTTP.get_response(uri)
64
+
65
+ raise InvalidSymbolError.new("Unable to lookup '#{symbol}'") unless response.code == "200"
66
+ response.body
67
+ end
68
+
69
+ def lookup_by_column(running, date, column)
70
+ return nil if date > DateTime.now()
71
+
72
+ running = 1 if running < 1
73
+
74
+ formatted_date = date.strftime('%Y-%m-%d')
75
+
76
+ @data[1..@data.size].each_index do |index|
77
+ row = @data[index+1]
78
+
79
+ return sum_and_average(index+1, running, column) if row[0] == formatted_date
80
+
81
+ if DateTime.parse(row[0]) < date
82
+ if Edgar.config[:lookup_offset] < 0
83
+ return sum_and_average(index+1, running, column)
84
+ else
85
+ return sum_and_average(index, running, column)
86
+ end
87
+ end
88
+
89
+ end
90
+ return nil
91
+ end
92
+
93
+ def sum_and_average(start, days, column)
94
+ total = @data[start, days].inject(0) do |sum, row|
95
+ sum + row[column.to_i].to_f
96
+ end
97
+
98
+ # Round off to at most two digits
99
+ round_to = Edgar.config[:round_to]
100
+ round_to = 2 if round_to < 0
101
+
102
+ denom = @data[start, days].size
103
+ (total / denom).round(round_to)
104
+ end
105
+ end
106
+
107
+ class InvalidSymbolError < ArgumentError
108
+ def initialize(message)
109
+ @message = message
110
+ end
111
+
112
+ def to_s
113
+ @message
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,3 @@
1
+ module Edgar
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,109 @@
1
+ require 'spec_helper'
2
+ require_relative '../lib/edgar'
3
+
4
+ describe 'Edgar' do
5
+ let(:stock) {Edgar::Edgar.new('INTU')}
6
+ let(:firstday) {DateTime.new(2013,10,1)}
7
+ let(:weekend_day) {DateTime.new(2013,9,21)}
8
+ let(:future_day) {DateTime.new(2020,1,1)}
9
+ subject {stock}
10
+
11
+ it 'should have a reference to the symbol' do
12
+ expect(stock.symbol).to eq('INTU')
13
+ end
14
+
15
+ it 'should be able to lookup valid stock symbols' do
16
+ expect{Edgar::Edgar.new('INTU')}.to_not raise_error Edgar::InvalidSymbolError
17
+ end
18
+
19
+ it 'should not be able to lookup invalid stock symbols' do
20
+ expect{Edgar::Edgar.new('LALALALALA')}.to raise_error(Edgar::InvalidSymbolError)
21
+ end
22
+
23
+ it 'can get closing price for October 1, 2013' do
24
+ expect(stock.closing_price(firstday)).to eq(66.45)
25
+ end
26
+
27
+ it 'can get the opening price for October 1, 2013' do
28
+ expect(stock.opening_price(firstday)).to eq(66.53)
29
+ end
30
+
31
+ it 'can get the high price for October 1, 2013' do
32
+ expect(stock.high_price(firstday)).to eq(67.09)
33
+ end
34
+
35
+ it 'can get the low price for a stock' do
36
+ expect(stock.low_price(firstday)).to eq(66.19)
37
+ end
38
+
39
+ it 'can get the volume traded for a stock' do
40
+ expect(stock.volume(firstday)).to eq(2095700)
41
+ end
42
+
43
+ describe 'when configured to look to the next day' do
44
+ before (:all) do
45
+ Edgar::Edgar.configure({:lookup_offset => 1})
46
+ end
47
+
48
+ it 'should go to monday when a weekend date is specified' do
49
+ expect(stock.opening_price(weekend_day)).to eq(66.59)
50
+ end
51
+ end
52
+
53
+ describe 'when configured to look to the prev day' do
54
+ before (:all) do
55
+ Edgar::Edgar.configure({:lookup_offset => -1})
56
+ end
57
+
58
+ it 'should go to friday when a weekend date is specified' do
59
+ expect(stock.opening_price(weekend_day)).to eq(66.64)
60
+ end
61
+ end
62
+
63
+ describe 'when a future date is provided' do
64
+ let(:future_day) {DateTime.new(2020,1,1)}
65
+ it 'should return nil' do
66
+ expect(stock.opening_price(future_day)).to be_nil
67
+ end
68
+ end
69
+
70
+ describe 'when an old date is provided' do
71
+ let(:past_day) {DateTime.new(1919,1,1)}
72
+ it 'should return nil' do
73
+ expect(stock.opening_price(past_day)).to be_nil
74
+ end
75
+
76
+ it 'should return the average using any valid dates when all are valid' do
77
+ expect(stock.opening_price(DateTime.new(1993, 3, 23), 2)).to eq(29.50)
78
+ end
79
+
80
+ it 'should return the average using any valid dates when some are invalid' do
81
+ expect(stock.opening_price(DateTime.new(1993, 3, 23), 6)).to eq(29.50)
82
+ end
83
+ end
84
+
85
+ describe 'when providing a range' do
86
+ let(:firstday) {DateTime.new(2013, 9, 27)}
87
+ it 'should return the running avg for opening price' do
88
+ expect(stock.opening_price(firstday, 10)).to eq(66.28)
89
+ end
90
+
91
+ describe 'and rounding to 4 decimal points' do
92
+ it 'should return the running avg to 4 decimal points' do
93
+ Edgar::Edgar.configure({:round_to => 4})
94
+ expect(stock.opening_price(firstday, 10)).to eq(66.278)
95
+ end
96
+
97
+ it 'should return the running avg to 0 decimal points' do
98
+ Edgar::Edgar.configure({:round_to => 0})
99
+ expect(stock.opening_price(firstday, 10)).to eq(66)
100
+ end
101
+
102
+ it 'should return the running avg to 3 decimal points' do
103
+ Edgar::Edgar.configure({:round_to => 3})
104
+ expect(stock.opening_price(firstday, 10)).to eq(66.278)
105
+ end
106
+ end
107
+ end
108
+
109
+ end
@@ -0,0 +1,17 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = 'random'
17
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: edgar-stocks
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Andy Schrage
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Edgar-Stocks is a Ruby gem that provides access to historical stock data
56
+ in a simple, configurable way.
57
+ email:
58
+ - ajschrag@mtu.edu
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - .gitignore
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - edgar.gemspec
69
+ - lib/edgar.rb
70
+ - lib/edgar/version.rb
71
+ - spec/edgar_spec.rb
72
+ - spec/spec_helper.rb
73
+ homepage: https://github.com/Swimminschrage/edgar
74
+ licenses:
75
+ - MIT
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 2.1.8
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Stock data since the beginning of time!
97
+ test_files:
98
+ - spec/edgar_spec.rb
99
+ - spec/spec_helper.rb