market_beat 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,6 @@
1
+ 0.2.0
2
+ - Added support for fetching historical stock quotes.
3
+
1
4
  0.1.1
2
5
  - Include YAML files when building the gem.
3
6
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- market_beat (0.1.0)
4
+ market_beat (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 Michael Dvorkin
1
+ Copyright (c) 2011-12 Michael Dvorkin
2
2
  twitter.com/mid
3
3
  %w(mike dvorkin.net) * "@" || %w(mike fatfreecrm.com) * "@"
4
4
 
data/README.md CHANGED
@@ -31,6 +31,15 @@ Some methods return multiple values:
31
31
  >> MarketBeat.last_trade_with_time :IBM
32
32
  ["4:02pm", "181.47"]
33
33
 
34
+ Fetching historical quotes returns array of hashes where each hash represents
35
+ stock data for a given date:
36
+
37
+ >> MarketBeat.quotes(:AAPL, "2011-12-21", "2011-12-22")
38
+ [{:date=>#<Date: 2011-12-22 (4911835/2,0,2299161)>, :open=>"397.00",
39
+ :high=>"399.13", :low=>"396.10", :close=>"398.55", :volume=>"7227016"},
40
+ {:date=>#<Date: 2011-12-21 (4911833/2,0,2299161)>, :open=>"396.69",
41
+ :high=>"397.30", :low=>"392.01", :close=>"396.44", :volume=>"9390954"}]
42
+
34
43
  ### Available Methods (Real Time Data) ###
35
44
 
36
45
  MarketBeat.after_hours_change_real_time
@@ -133,6 +142,7 @@ Some methods return multiple values:
133
142
  MarketBeat.price_to_eps_estimate_current_year
134
143
  MarketBeat.price_to_eps_estimate_next_year
135
144
  MarketBeat.price_to_sales
145
+ MarketBeat.quotes
136
146
  MarketBeat.range_52_week
137
147
  MarketBeat.shares_owned
138
148
  MarketBeat.short_ratio
@@ -164,7 +174,7 @@ Some methods return multiple values:
164
174
  * Send me a pull request.
165
175
 
166
176
  ### License ###
167
- Copyright (c) 2011 Michael Dvorkin
177
+ Copyright (c) 2011-12 Michael Dvorkin
168
178
 
169
179
  twitter.com/mid
170
180
 
@@ -1,31 +1,42 @@
1
- # Copyright (c) 2011 Michael Dvorkin
1
+ # Copyright (c) 2011-12 Michael Dvorkin
2
2
  #
3
3
  # Market Beat is freely distributable under the terms of MIT license.
4
4
  # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
5
5
  #------------------------------------------------------------------------------
6
6
  require File.dirname(__FILE__) + '/market_beat/yahoo'
7
7
  require File.dirname(__FILE__) + '/market_beat/google'
8
+ require File.dirname(__FILE__) + '/market_beat/historical'
8
9
  require File.dirname(__FILE__) + "/market_beat/version"
9
10
 
10
11
  module MarketBeat
11
12
  # Pre-cache available methods so we could use them within
12
13
  # method_missing where respond_to? gives false positives.
14
+ @@methods = { :historical => [ :quotes ] }
13
15
  if RUBY_VERSION < '1.9.0'
14
- @@yahoo = (Yahoo.methods - Object.methods).map { |m| m.to_sym }
15
- @@google = (Google.methods - Object.methods).map { |m| m.to_sym }
16
+ @@methods[:yahoo] = (Yahoo.methods - Object.methods).map { |m| m.to_sym }
17
+ @@methods[:google] = (Google.methods - Object.methods).map { |m| m.to_sym }
16
18
  else
17
- @@yahoo = Yahoo.methods - Object.methods
18
- @@google = Google.methods - Object.methods
19
+ @@methods[:yahoo] = Yahoo.methods - Object.methods
20
+ @@methods[:google] = Google.methods - Object.methods
19
21
  end
20
22
 
21
23
  # Proxy MarketBeat methods to either Google or Yahoo providers.
22
24
  def self.method_missing(method, *args, &blk)
23
- if @@google.include?(method)
25
+ if @@methods[:google].include?(method)
24
26
  Google.send(method, *args)
25
- elsif @@yahoo.include?(method)
27
+ elsif @@methods[:yahoo].include?(method)
26
28
  Yahoo.send(method, *args)
29
+ elsif @@methods[:historical].include?(method)
30
+ Historical.send(method, *args)
27
31
  else
28
32
  super
29
33
  end
30
34
  end
35
+
36
+ if RUBY_VERSION > '1.9'
37
+ # Make MarketBeat.respond_to? return true for all the methods above.
38
+ def self.respond_to_missing?(method, include_private)
39
+ super(method, include_private) || @@methods.values.flatten.include?(method)
40
+ end
41
+ end
31
42
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2011 Michael Dvorkin
1
+ # Copyright (c) 2011-12 Michael Dvorkin
2
2
  #
3
3
  # Market Beat is freely distributable under the terms of MIT license.
4
4
  # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2011 Michael Dvorkin
1
+ # Copyright (c) 2011-12 Michael Dvorkin
2
2
  #
3
3
  # Market Beat is freely distributable under the terms of MIT license.
4
4
  # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
@@ -0,0 +1,56 @@
1
+ # Copyright (c) 2011-12 Michael Dvorkin
2
+ #
3
+ # Market Beat is freely distributable under the terms of MIT license.
4
+ # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
5
+ #------------------------------------------------------------------------------
6
+ require "csv"
7
+ require "date"
8
+
9
+ module MarketBeat
10
+ class Historical
11
+ URL = "http://www.google.com/finance/historical?q=%s&startdate=%s&enddate=%s&output=csv"
12
+
13
+ class << self
14
+ private
15
+ #
16
+ # Fetch historical quotes. Return nil on error or an array of hashes
17
+ # representing stock data. Empty array means no data is available.
18
+ # Start and end date parameters should be either YYYY-MM-DD strings
19
+ # or Date objects.
20
+ #
21
+ def quotes(ticker, start_date, end_date = Date.today)
22
+ csv = fetch(ticker, start_date, end_date)
23
+ return nil unless csv
24
+
25
+ quotes = CSV.parse(csv) # Parse comma-delimited data.
26
+ quotes[1..-1].map do |col| # Skip header line.
27
+ #
28
+ # I guess Google finance folks are tight on data so they return year
29
+ # as two digits, ex: 23-Dec-11 or Apr-26-99. With the tweak below we
30
+ # should be good till year 2042 ;-)
31
+ #
32
+ date = *col[0].split("-")
33
+ date[2] = ((date[2] <= "42" ? "20" : "19") + date[2]) if date[2].size == 2
34
+ { :date => Date.parse(date.join("-")),
35
+ :open => col[1],
36
+ :high => col[2],
37
+ :low => col[3],
38
+ :close => col[4],
39
+ :volume => col[5]
40
+ }
41
+ end
42
+ end
43
+ #
44
+ # Format the URL and fetch stock data.
45
+ #
46
+ def fetch(ticker, start_date, end_date)
47
+ uri = URI.parse(URL % [ ticker, start_date.to_s, end_date.to_s ])
48
+ response = Net::HTTP.get_response(uri)
49
+ response.body
50
+ rescue Exception => e
51
+ $stderr.puts "market_beat: error fetching quotes\n#{e.inspect}"
52
+ nil
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,10 +1,10 @@
1
- # Copyright (c) 2011 Michael Dvorkin
1
+ # Copyright (c) 2011-12 Michael Dvorkin
2
2
  #
3
3
  # Market Beat is freely distributable under the terms of MIT license.
4
4
  # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
5
5
  #------------------------------------------------------------------------------
6
6
  module MarketBeat
7
7
  def self.version
8
- '0.1.1'
8
+ '0.2.0'
9
9
  end
10
10
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2011 Michael Dvorkin
1
+ # Copyright (c) 2011-12 Michael Dvorkin
2
2
  #
3
3
  # Market Beat is freely distributable under the terms of MIT license.
4
4
  # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2011 Michael Dvorkin
1
+ # Copyright (c) 2011-12 Michael Dvorkin
2
2
  #
3
3
  # Market Beat is freely distributable under the terms of MIT license.
4
4
  # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2011 Michael Dvorkin
1
+ # Copyright (c) 2011-12 Michael Dvorkin
2
2
  #
3
3
  # Market Beat is freely distributable under the terms of MIT license.
4
4
  # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
@@ -0,0 +1,65 @@
1
+ # Copyright (c) 2011-12 Michael Dvorkin
2
+ #
3
+ # Market Beat is freely distributable under the terms of MIT license.
4
+ # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
5
+ #------------------------------------------------------------------------------
6
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
7
+ require "stringio"
8
+ require "date"
9
+
10
+ describe "MarketBeat::Historical" do
11
+ before(:all) do
12
+ @csv = File.read(File.dirname(__FILE__) + '/fixtures/AAPL.csv')
13
+ end
14
+
15
+ it "should return correct data when using strings as start/end dates" do
16
+ response = mock(:body => @csv)
17
+ Net::HTTP.should_receive(:get_response).once.and_return(response)
18
+ quotes = MarketBeat.quotes(:aapl, "2011-12-21", "2011-12-23")
19
+ quotes.size.should == 3
20
+ quotes[0].keys.map(&:to_s).sort.should == %w(close date high low open volume)
21
+ quotes[0][:open].should == "403.43"
22
+ quotes[0][:high].should == "403.43"
23
+ quotes[0][:low].should == "403.43"
24
+ quotes[0][:close].should == "403.43"
25
+ quotes[0][:volume].should == "0"
26
+ quotes[0][:date].to_s.should == "2011-12-23"
27
+ quotes[1][:date].to_s.should == "2011-12-22"
28
+ quotes[2][:date].to_s.should == "2011-12-21"
29
+ end
30
+
31
+ it "should return correct data when using Date as start/end dates" do
32
+ response = mock(:body => @csv)
33
+ Net::HTTP.should_receive(:get_response).once.and_return(response)
34
+ quotes = MarketBeat.quotes(:aapl, Date.parse("2011-12-21"), Date.parse("2011-12-23"))
35
+ quotes.size.should == 3
36
+ quotes[2].keys.map(&:to_s).sort.should == %w(close date high low open volume)
37
+ quotes[2][:open].should == "396.69"
38
+ quotes[2][:high].should == "397.30"
39
+ quotes[2][:low].should == "392.01"
40
+ quotes[2][:close].should == "396.44"
41
+ quotes[2][:volume].should == "9390954"
42
+ quotes[2][:date].to_s.should == "2011-12-21"
43
+ quotes[1][:date].to_s.should == "2011-12-22"
44
+ quotes[0][:date].to_s.should == "2011-12-23"
45
+ end
46
+
47
+ it "should return empty array when no data is available" do
48
+ response = mock(:body => @csv.split.first) # Just the header row.
49
+ Net::HTTP.should_receive(:get_response).once.and_return(response)
50
+ MarketBeat.quotes(:aapl, "2011-12-21", "2011-12-23").should == []
51
+ end
52
+
53
+ it "should return nil on error" do
54
+ begin
55
+ stderr, $stderr = $stderr, StringIO.new
56
+ response = mock(:body => "")
57
+ Net::HTTP.should_receive(:get_response).once.and_raise(SocketError)
58
+ MarketBeat.quotes(:aapl, "2011-12-21", "2011-12-23").should == nil
59
+ $stderr.string.should =~ /^market_beat: error fetching quotes/m
60
+ ensure
61
+ $stderr = stderr
62
+ end
63
+ end
64
+ end
65
+
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2011 Michael Dvorkin
1
+ # Copyright (c) 2011-12 Michael Dvorkin
2
2
  #
3
3
  # Market Beat is freely distributable under the terms of MIT license.
4
4
  # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
@@ -9,6 +9,12 @@ require 'yaml'
9
9
  describe "MarketBeat Google Proxy" do
10
10
  metrics = YAML.load_file(File.dirname(__FILE__) + '/../lib/market_beat/google.yml')
11
11
  metrics.values.each do |method|
12
+ if RUBY_VERSION > '1.9'
13
+ it "MarketBeat should respond to :#{method}" do
14
+ MarketBeat.respond_to?(method).should == true
15
+ end
16
+ end
17
+
12
18
  it "Google.#{method}" do
13
19
  MarketBeat::Google.should_receive(method).once
14
20
  MarketBeat::Yahoo.should_not_receive(method)
@@ -21,6 +27,12 @@ describe "MarketBeat Yahoo Proxy" do
21
27
  yahoo_metrics = YAML.load_file(File.dirname(__FILE__) + '/../lib/market_beat/yahoo.yml')
22
28
  google_metrics = YAML.load_file(File.dirname(__FILE__) + '/../lib/market_beat/google.yml')
23
29
  yahoo_metrics.values.each do |method|
30
+ if RUBY_VERSION > '1.9'
31
+ it "MarketBeat should respond to :#{method}" do
32
+ MarketBeat.respond_to?(method).should == true
33
+ end
34
+ end
35
+
24
36
  it "Yahoo.#{method}" do # If Yahoo and Google have the same method Google takes precedence.
25
37
  if google_metrics.values.include?(method)
26
38
  MarketBeat::Google.should_receive(method).once
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2011 Michael Dvorkin
1
+ # Copyright (c) 2011-12 Michael Dvorkin
2
2
  #
3
3
  # Market Beat is freely distributable under the terms of MIT license.
4
4
  # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2011 Michael Dvorkin
1
+ # Copyright (c) 2011-12 Michael Dvorkin
2
2
  #
3
3
  # Market Beat is freely distributable under the terms of MIT license.
4
4
  # See LICENSE file or http://www.opensource.org/licenses/mit-license.php
metadata CHANGED
@@ -1,34 +1,37 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: market_beat
3
- version: !ruby/object:Gem::Version
4
- version: 0.1.1
3
+ version: !ruby/object:Gem::Version
5
4
  prerelease:
5
+ version: 0.2.0
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Michael Dvorkin
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-21 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
12
+
13
+ date: 2012-01-15 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
15
16
  name: rspec
16
- requirement: &70119385118060 !ruby/object:Gem::Requirement
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
17
19
  none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
21
23
  version: 2.6.0
22
24
  type: :development
23
- prerelease: false
24
- version_requirements: *70119385118060
25
- description: Fetch real-time and delayed stock quotes and 100+ other financial and
26
- market indicaors from publicly available sources.
25
+ version_requirements: *id001
26
+ description: Fetch real-time and delayed stock quotes and 100+ other financial and market indicaors from publicly available sources.
27
27
  email: mike@dvorkin.net
28
28
  executables: []
29
+
29
30
  extensions: []
31
+
30
32
  extra_rdoc_files: []
31
- files:
33
+
34
+ files:
32
35
  - CHANGELOG
33
36
  - Gemfile
34
37
  - Gemfile.lock
@@ -36,42 +39,48 @@ files:
36
39
  - Rakefile
37
40
  - README.md
38
41
  - lib/market_beat/google.rb
42
+ - lib/market_beat/historical.rb
39
43
  - lib/market_beat/version.rb
40
44
  - lib/market_beat/yahoo.rb
41
45
  - lib/market_beat.rb
42
46
  - lib/market_beat/google.yml
43
47
  - lib/market_beat/yahoo.yml
44
48
  - spec/google_spec.rb
49
+ - spec/historical_spec.rb
45
50
  - spec/market_beat_spec.rb
46
51
  - spec/spec_helper.rb
47
52
  - spec/yahoo_spec.rb
48
53
  - .gitignore
49
54
  homepage: http://github.com/michaeldv/market_beat
50
55
  licenses: []
56
+
51
57
  post_install_message:
52
58
  rdoc_options: []
53
- require_paths:
59
+
60
+ require_paths:
54
61
  - lib
55
- required_ruby_version: !ruby/object:Gem::Requirement
62
+ required_ruby_version: !ruby/object:Gem::Requirement
56
63
  none: false
57
- requirements:
58
- - - ! '>='
59
- - !ruby/object:Gem::Version
60
- version: '0'
61
- required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
69
  none: false
63
- requirements:
64
- - - ! '>='
65
- - !ruby/object:Gem::Version
66
- version: '0'
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
67
74
  requirements: []
75
+
68
76
  rubyforge_project: market_beat
69
- rubygems_version: 1.8.11
77
+ rubygems_version: 1.8.5
70
78
  signing_key:
71
79
  specification_version: 3
72
80
  summary: Fetch up-to-date stock quotes and 100+ financial and market indicators.
73
- test_files:
81
+ test_files:
74
82
  - spec/google_spec.rb
83
+ - spec/historical_spec.rb
75
84
  - spec/market_beat_spec.rb
76
85
  - spec/spec_helper.rb
77
86
  - spec/yahoo_spec.rb