quotr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ vendor/bundle
data/.rbenv-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.2-p290
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in quote.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2012 Dan Hodge
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,30 @@
1
+ quotr
2
+ =====
3
+
4
+ Retrieves historical stock & mutual fund quotes
5
+
6
+ what?
7
+ -----
8
+
9
+ This gem currenly does one thing only, retrieves historical closing prices for stocks, mutual funds, and ETFs.
10
+
11
+ where?
12
+ ------
13
+
14
+ It retrieves historical prices from the Yahoo! finance API
15
+
16
+ how?
17
+ ----
18
+
19
+ ```ruby
20
+ closing_price = Quotr.close(:GOOG, Date.new(2012, 5, 11)) # => BigDecimal("605.23")
21
+ ```
22
+
23
+ why?
24
+ ----
25
+
26
+ I couldn't find a gem that could retrieve historical quotes for stocks AND mutual funds
27
+
28
+ license
29
+ -------
30
+ MIT license © 2012 Dan Hodge
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'rspec/core'
2
+ require 'rspec/core/rake_task'
3
+
4
+ require 'bundler/gem_tasks'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
data/lib/quotr.rb ADDED
@@ -0,0 +1,11 @@
1
+ require "quotr/yahoo"
2
+ require "quotr/yahoo_parser"
3
+
4
+ module Quotr
5
+ class Error < StandardError; end
6
+
7
+ def self.close(symbol, date=Date.today)
8
+ results = YahooParser.parse(Yahoo.fetch(symbol, date))
9
+ results[date.to_date] || results.values.first
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module Quotr
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,28 @@
1
+ require 'net/http'
2
+
3
+ module Quotr
4
+ class Yahoo
5
+ URL = "http://ichart.finance.yahoo.com/table.csv".freeze
6
+ PARAMS = "s=%s&a=%02d&b=%d&c=%d&d=%02d&e=%d&f=%d&g=d&ignore=.csv".freeze
7
+
8
+ def self.fetch(symbol, date)
9
+ resp = Net::HTTP.get_response(uri(symbol, date - 7, date))
10
+ if resp.code.to_i == 200
11
+ resp.body
12
+ else
13
+ raise Error.new("Failure retrieving quote for #{symbol} on " +
14
+ "#{date.to_s}: #{resp.message} (#{resp.code})")
15
+ end
16
+ end
17
+
18
+ def self.uri(symbol, start_date, end_date)
19
+ params = [ symbol.to_s,
20
+ start_date.month-1, start_date.day, start_date.year,
21
+ end_date.month-1, end_date.day, end_date.year ]
22
+ param_str = PARAMS % params
23
+
24
+ URI("#{URL}?#{param_str}")
25
+ end
26
+ private_class_method :uri
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ require 'bigdecimal'
2
+ require 'csv'
3
+
4
+ module Quotr
5
+ class YahooParser
6
+ def self.parse(data)
7
+ result = {}
8
+ CSV.parse(data, :headers => true) do |row|
9
+ date = Date.strptime(row['Date'], '%Y-%m-%d')
10
+ result[date] = BigDecimal(row['Close'])
11
+ end
12
+
13
+ # return results sorted by date descending
14
+ Hash[result.sort.reverse]
15
+ end
16
+ end
17
+ end
data/quotr.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "quotr/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "quotr"
7
+ s.version = Quotr::VERSION
8
+ s.authors = ["Dan Hodge"]
9
+ s.email = ["danhodge@gmail.com"]
10
+ s.homepage = "https://github.com/danhodge/quotr"
11
+ s.summary = %q{Retrieves historical stock and mutual fund quotes}
12
+ s.description = %q{Retrieves historical stock and mutual fund quotes}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ # development dependencies
20
+ s.add_development_dependency "rspec"
21
+ s.add_development_dependency "vcr"
22
+ s.add_development_dependency "webmock"
23
+ end
data/quotr/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Quote
2
+ VERSION = "0.0.1"
3
+ end
data/quotr/yahoo.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'net/http'
2
+
3
+ module Quote
4
+ class Yahoo
5
+ URL = "http://ichart.finance.yahoo.com/table.csv".freeze
6
+ PARAMS = "s=%s&a=%02d&b=%d&c=%d&d=%02d&e=%d&f=%d&g=d&ignore=.csv".freeze
7
+
8
+ def self.fetch(symbol, date)
9
+ resp = Net::HTTP.get_response(uri(symbol, date - 7, date))
10
+ if resp.code.to_i == 200
11
+ resp.body
12
+ else
13
+ raise Error.new("Failure retrieving quote for #{symbol} on " +
14
+ "#{date.to_s}: #{resp.message} (#{resp.code})")
15
+ end
16
+ end
17
+
18
+ def self.uri(symbol, start_date, end_date)
19
+ params = [ symbol.to_s,
20
+ start_date.month-1, start_date.day, start_date.year,
21
+ end_date.month-1, end_date.day, end_date.year ]
22
+ param_str = PARAMS % params
23
+
24
+ URI("#{URL}?#{param_str}")
25
+ end
26
+ private_class_method :uri
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ require 'bigdecimal'
2
+ require 'csv'
3
+
4
+ module Quote
5
+ class YahooParser
6
+ def self.parse(data)
7
+ result = {}
8
+ CSV.parse(data, :headers => true) do |row|
9
+ date = Date.strptime(row['Date'], '%Y-%m-%d')
10
+ result[date] = BigDecimal(row['Close'])
11
+ end
12
+
13
+ # return results sorted by date descending
14
+ Hash[result.sort.reverse]
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,54 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://ichart.finance.yahoo.com/table.csv?a=03&b=13&c=2012&d=03&e=20&f=2012&g=d&ignore=.csv&s=vfinx
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - ! '*/*'
12
+ User-Agent:
13
+ - Ruby
14
+ response:
15
+ status:
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ Date:
20
+ - Sat, 12 May 2012 02:16:45 GMT
21
+ P3p:
22
+ - policyref="http://info.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV
23
+ TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY
24
+ ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV"
25
+ Vary:
26
+ - Accept-Encoding
27
+ Connection:
28
+ - close
29
+ Transfer-Encoding:
30
+ - chunked
31
+ Content-Type:
32
+ - text/csv
33
+ Cache-Control:
34
+ - private
35
+ body:
36
+ encoding: US-ASCII
37
+ string: ! 'Date,Open,High,Low,Close,Volume,Adj Close
38
+
39
+ 2012-04-20,127.14,127.14,127.14,127.14,000,127.14
40
+
41
+ 2012-04-19,126.98,126.98,126.98,126.98,000,126.98
42
+
43
+ 2012-04-18,127.74,127.74,127.74,127.74,000,127.74
44
+
45
+ 2012-04-17,128.26,128.26,128.26,128.26,000,128.26
46
+
47
+ 2012-04-16,126.30,126.30,126.30,126.30,000,126.30
48
+
49
+ 2012-04-13,126.36,126.36,126.36,126.36,000,126.36
50
+
51
+ '
52
+ http_version: !!null
53
+ recorded_at: Sat, 12 May 2012 02:16:45 GMT
54
+ recorded_with: VCR 2.1.1
@@ -0,0 +1,54 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://ichart.finance.yahoo.com/table.csv?a=03&b=13&c=2012&d=03&e=20&f=2012&g=d&ignore=.csv&s=vti
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - ! '*/*'
12
+ User-Agent:
13
+ - Ruby
14
+ response:
15
+ status:
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ Date:
20
+ - Sat, 12 May 2012 02:16:46 GMT
21
+ P3p:
22
+ - policyref="http://info.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV
23
+ TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY
24
+ ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV"
25
+ Vary:
26
+ - Accept-Encoding
27
+ Connection:
28
+ - close
29
+ Transfer-Encoding:
30
+ - chunked
31
+ Content-Type:
32
+ - text/csv
33
+ Cache-Control:
34
+ - private
35
+ body:
36
+ encoding: US-ASCII
37
+ string: ! 'Date,Open,High,Low,Close,Volume,Adj Close
38
+
39
+ 2012-04-20,71.06,71.29,70.80,70.82,1219600,70.82
40
+
41
+ 2012-04-19,71.08,71.47,70.37,70.71,2368300,70.71
42
+
43
+ 2012-04-18,71.13,71.35,70.98,71.12,1873500,71.12
44
+
45
+ 2012-04-17,70.78,71.56,70.72,71.37,1287900,71.37
46
+
47
+ 2012-04-16,70.75,70.85,70.04,70.30,1439000,70.30
48
+
49
+ 2012-04-13,71.05,71.05,70.33,70.37,1567400,70.37
50
+
51
+ '
52
+ http_version: !!null
53
+ recorded_at: Sat, 12 May 2012 02:16:46 GMT
54
+ recorded_with: VCR 2.1.1
@@ -0,0 +1,73 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://ichart.finance.yahoo.com/table.csv?a=04&b=17&c=2112&d=04&e=24&f=2112&g=d&ignore=.csv&s=vfinx
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - ! '*/*'
12
+ User-Agent:
13
+ - Ruby
14
+ response:
15
+ status:
16
+ code: 404
17
+ message: Not Found
18
+ headers:
19
+ Date:
20
+ - Fri, 25 May 2012 02:37:27 GMT
21
+ P3p:
22
+ - policyref="http://info.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV
23
+ TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY
24
+ ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV"
25
+ Vary:
26
+ - Accept-Encoding
27
+ Connection:
28
+ - close
29
+ Transfer-Encoding:
30
+ - chunked
31
+ Content-Type:
32
+ - text/html; charset=iso-8859-1
33
+ Cache-Control:
34
+ - private
35
+ body:
36
+ encoding: US-ASCII
37
+ string: ! "<!doctype html public \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html><head><title>Yahoo!
38
+ - 404 Not Found</title><style>\n/* nn4 hide */ \n/*/*/\nbody {font:small/1.2em
39
+ arial,helvetica,clean,sans-serif;font:x-small;text-align:center;}table {font-size:inherit;font:x-small;}\nhtml>body
40
+ {font:83%/1.2em arial,helvetica,clean,sans-serif;}input {font-size:100%;vertical-align:middle;}p,
41
+ form {margin:0;padding:0;}\np {padding-bottom:6px;margin-bottom:10px;}#doc
42
+ {width:48.5em;margin:0 auto;border:1px solid #fff;text-align:center;}#ygma
43
+ {text-align:right;margin-bottom:53px}\n#ygma img {float:left;}#ygma div {border-bottom:1px
44
+ solid #ccc;padding-bottom:8px;margin-left:152px;}#bd {clear:both;text-align:left;width:75%;margin:0
45
+ auto 20px;}\nh1 {font-size:135%;text-align:center;margin:0 0 15px;}legend
46
+ {display:none;}fieldset {border:0 solid #fff;padding:.8em 0 .8em 4.5em;}\nform
47
+ {position:relative;background:#eee;margin-bottom:15px;border:1px solid #ccc;border-width:1px
48
+ 0;}\n#s1p {width:15em;margin-right:.1em;}\nform span {position:absolute;left:70%;top:.8em;}form
49
+ a {font:78%/1.2em arial;display:block;padding-left:.8em;white-space:nowrap;background:
50
+ url(http://l.yimg.com/a/i/s/bullet.gif) no-repeat left center;} \nform .sep
51
+ {display:none;}.more {text-align:center;}#ft {padding-top:10px;border-top:1px
52
+ solid #999;}#ft p {text-align:center;font:78% arial;}\n/* end nn4 hide */\n</style></head>\n<body><div
53
+ id=\"doc\">\n<div id=\"ygma\"><a href=\"http://us.rd.yahoo.com/404/*http://www.yahoo.com\"><img\nsrc=http://l.yimg.com/a/i/yahoo.gif\nwidth=147
54
+ height=31 border=0 alt=\"Yahoo!\"></a><div><a\nhref=\"http://us.rd.yahoo.com/404/*http://www.yahoo.com\">Yahoo!</a>\n
55
+ - <a href=\"http://us.rd.yahoo.com/404/*http://help.yahoo.com\">Help</a></div></div>\n<div
56
+ id=\"bd\"><h1>Sorry, the page you requested was not found.</h1>\n<p>Please
57
+ check the URL for proper spelling and capitalization. If\nyou're having trouble
58
+ locating a destination on Yahoo!, try visiting the\n<strong><a\nhref=\"http://us.rd.yahoo.com/404/*http://www.yahoo.com\">Yahoo!
59
+ home\npage</a></strong> or look through a list of <strong><a\nhref=\"http://us.rd.yahoo.com/404/*http://docs.yahoo.com/docs/family/more/\">Yahoo!'s\nonline
60
+ services</a></strong>. Also, you may find what you're looking for\nif you
61
+ try searching below.</p>\n<form name=\"s1\" action=\"http://us.rd.yahoo.com/404/*-http://search.yahoo.com/search\"><fieldset>\n<legend><label
62
+ for=\"s1p\">Search the Web</label></legend>\n<input type=\"text\" size=30
63
+ name=\"p\" id=\"s1p\" title=\"enter search terms here\">\n<input type=\"submit\"
64
+ value=\"Search\">\n<span><a href=\"http://us.rd.yahoo.com/404/*http://search.yahoo.com/search/options?p=\">advanced
65
+ search</a> <span class=sep>|</span> <a href=\"http://us.rd.yahoo.com/404/*http://buzz.yahoo.com\">most
66
+ popular</a></span>\n</fieldset></form>\n<p class=\"more\">Please try <strong><a\nhref=\"http://us.rd.yahoo.com/404/*http://help.yahoo.com\">Yahoo!\nHelp
67
+ Central</a></strong> if you need more assistance.</p>\n</div><div id=\"ft\"><p>Copyright
68
+ &copy; 2012 Yahoo! Inc.\nAll rights reserved. <a\nhref=\"http://us.rd.yahoo.com/404/*http://privacy.yahoo.com\">Privacy\nPolicy</a>
69
+ - <a\nhref=\"http://us.rd.yahoo.com/404/*http://docs.yahoo.com/info/terms/\">Terms\nof
70
+ Service</a></p></div>\n</div></body></html>\n"
71
+ http_version: !!null
72
+ recorded_at: Fri, 25 May 2012 02:37:27 GMT
73
+ recorded_with: VCR 2.1.1
@@ -0,0 +1,52 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://ichart.finance.yahoo.com/table.csv?a=03&b=14&c=2012&d=03&e=21&f=2012&g=d&ignore=.csv&s=vfinx
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - ! '*/*'
12
+ User-Agent:
13
+ - Ruby
14
+ response:
15
+ status:
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ Date:
20
+ - Sat, 12 May 2012 02:16:45 GMT
21
+ P3p:
22
+ - policyref="http://info.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV
23
+ TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY
24
+ ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV"
25
+ Vary:
26
+ - Accept-Encoding
27
+ Connection:
28
+ - close
29
+ Transfer-Encoding:
30
+ - chunked
31
+ Content-Type:
32
+ - text/csv
33
+ Cache-Control:
34
+ - private
35
+ body:
36
+ encoding: US-ASCII
37
+ string: ! 'Date,Open,High,Low,Close,Volume,Adj Close
38
+
39
+ 2012-04-20,127.14,127.14,127.14,127.14,000,127.14
40
+
41
+ 2012-04-19,126.98,126.98,126.98,126.98,000,126.98
42
+
43
+ 2012-04-18,127.74,127.74,127.74,127.74,000,127.74
44
+
45
+ 2012-04-17,128.26,128.26,128.26,128.26,000,128.26
46
+
47
+ 2012-04-16,126.30,126.30,126.30,126.30,000,126.30
48
+
49
+ '
50
+ http_version: !!null
51
+ recorded_at: Sat, 12 May 2012 02:16:45 GMT
52
+ recorded_with: VCR 2.1.1
@@ -0,0 +1,73 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://ichart.finance.yahoo.com/table.csv?a=03&b=13&c=2012&d=03&e=20&f=2012&g=d&ignore=.csv&s=NACHOS
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - ! '*/*'
12
+ User-Agent:
13
+ - Ruby
14
+ response:
15
+ status:
16
+ code: 404
17
+ message: Not Found
18
+ headers:
19
+ Date:
20
+ - Sat, 12 May 2012 02:16:46 GMT
21
+ P3p:
22
+ - policyref="http://info.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV
23
+ TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY
24
+ ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV"
25
+ Vary:
26
+ - Accept-Encoding
27
+ Connection:
28
+ - close
29
+ Transfer-Encoding:
30
+ - chunked
31
+ Content-Type:
32
+ - text/html; charset=iso-8859-1
33
+ Cache-Control:
34
+ - private
35
+ body:
36
+ encoding: US-ASCII
37
+ string: ! "<!doctype html public \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html><head><title>Yahoo!
38
+ - 404 Not Found</title><style>\n/* nn4 hide */ \n/*/*/\nbody {font:small/1.2em
39
+ arial,helvetica,clean,sans-serif;font:x-small;text-align:center;}table {font-size:inherit;font:x-small;}\nhtml>body
40
+ {font:83%/1.2em arial,helvetica,clean,sans-serif;}input {font-size:100%;vertical-align:middle;}p,
41
+ form {margin:0;padding:0;}\np {padding-bottom:6px;margin-bottom:10px;}#doc
42
+ {width:48.5em;margin:0 auto;border:1px solid #fff;text-align:center;}#ygma
43
+ {text-align:right;margin-bottom:53px}\n#ygma img {float:left;}#ygma div {border-bottom:1px
44
+ solid #ccc;padding-bottom:8px;margin-left:152px;}#bd {clear:both;text-align:left;width:75%;margin:0
45
+ auto 20px;}\nh1 {font-size:135%;text-align:center;margin:0 0 15px;}legend
46
+ {display:none;}fieldset {border:0 solid #fff;padding:.8em 0 .8em 4.5em;}\nform
47
+ {position:relative;background:#eee;margin-bottom:15px;border:1px solid #ccc;border-width:1px
48
+ 0;}\n#s1p {width:15em;margin-right:.1em;}\nform span {position:absolute;left:70%;top:.8em;}form
49
+ a {font:78%/1.2em arial;display:block;padding-left:.8em;white-space:nowrap;background:
50
+ url(http://l.yimg.com/a/i/s/bullet.gif) no-repeat left center;} \nform .sep
51
+ {display:none;}.more {text-align:center;}#ft {padding-top:10px;border-top:1px
52
+ solid #999;}#ft p {text-align:center;font:78% arial;}\n/* end nn4 hide */\n</style></head>\n<body><div
53
+ id=\"doc\">\n<div id=\"ygma\"><a href=\"http://us.rd.yahoo.com/404/*http://www.yahoo.com\"><img\nsrc=http://l.yimg.com/a/i/yahoo.gif\nwidth=147
54
+ height=31 border=0 alt=\"Yahoo!\"></a><div><a\nhref=\"http://us.rd.yahoo.com/404/*http://www.yahoo.com\">Yahoo!</a>\n
55
+ - <a href=\"http://us.rd.yahoo.com/404/*http://help.yahoo.com\">Help</a></div></div>\n<div
56
+ id=\"bd\"><h1>Sorry, the page you requested was not found.</h1>\n<p>Please
57
+ check the URL for proper spelling and capitalization. If\nyou're having trouble
58
+ locating a destination on Yahoo!, try visiting the\n<strong><a\nhref=\"http://us.rd.yahoo.com/404/*http://www.yahoo.com\">Yahoo!
59
+ home\npage</a></strong> or look through a list of <strong><a\nhref=\"http://us.rd.yahoo.com/404/*http://docs.yahoo.com/docs/family/more/\">Yahoo!'s\nonline
60
+ services</a></strong>. Also, you may find what you're looking for\nif you
61
+ try searching below.</p>\n<form name=\"s1\" action=\"http://us.rd.yahoo.com/404/*-http://search.yahoo.com/search\"><fieldset>\n<legend><label
62
+ for=\"s1p\">Search the Web</label></legend>\n<input type=\"text\" size=30
63
+ name=\"p\" id=\"s1p\" title=\"enter search terms here\">\n<input type=\"submit\"
64
+ value=\"Search\">\n<span><a href=\"http://us.rd.yahoo.com/404/*http://search.yahoo.com/search/options?p=\">advanced
65
+ search</a> <span class=sep>|</span> <a href=\"http://us.rd.yahoo.com/404/*http://buzz.yahoo.com\">most
66
+ popular</a></span>\n</fieldset></form>\n<p class=\"more\">Please try <strong><a\nhref=\"http://us.rd.yahoo.com/404/*http://help.yahoo.com\">Yahoo!\nHelp
67
+ Central</a></strong> if you need more assistance.</p>\n</div><div id=\"ft\"><p>Copyright
68
+ &copy; 2012 Yahoo! Inc.\nAll rights reserved. <a\nhref=\"http://us.rd.yahoo.com/404/*http://privacy.yahoo.com\">Privacy\nPolicy</a>
69
+ - <a\nhref=\"http://us.rd.yahoo.com/404/*http://docs.yahoo.com/info/terms/\">Terms\nof
70
+ Service</a></p></div>\n</div></body></html>\n"
71
+ http_version: !!null
72
+ recorded_at: Sat, 12 May 2012 02:16:46 GMT
73
+ recorded_with: VCR 2.1.1
@@ -0,0 +1,54 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://ichart.finance.yahoo.com/table.csv?a=03&b=13&c=2012&d=03&e=20&f=2012&g=d&ignore=.csv&s=f
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - ! '*/*'
12
+ User-Agent:
13
+ - Ruby
14
+ response:
15
+ status:
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ Date:
20
+ - Sat, 12 May 2012 02:16:46 GMT
21
+ P3p:
22
+ - policyref="http://info.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV
23
+ TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY
24
+ ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV"
25
+ Vary:
26
+ - Accept-Encoding
27
+ Connection:
28
+ - close
29
+ Transfer-Encoding:
30
+ - chunked
31
+ Content-Type:
32
+ - text/csv
33
+ Cache-Control:
34
+ - private
35
+ body:
36
+ encoding: US-ASCII
37
+ string: ! 'Date,Open,High,Low,Close,Volume,Adj Close
38
+
39
+ 2012-04-20,11.71,11.72,11.39,11.41,52631000,11.36
40
+
41
+ 2012-04-19,11.81,11.88,11.58,11.66,48169200,11.61
42
+
43
+ 2012-04-18,11.81,11.85,11.72,11.79,32314000,11.74
44
+
45
+ 2012-04-17,11.98,12.00,11.88,11.91,35981200,11.86
46
+
47
+ 2012-04-16,12.01,12.05,11.83,11.88,31903500,11.83
48
+
49
+ 2012-04-13,11.98,12.03,11.84,11.92,39675000,11.87
50
+
51
+ '
52
+ http_version: !!null
53
+ recorded_at: Sat, 12 May 2012 02:16:46 GMT
54
+ recorded_with: VCR 2.1.1
@@ -0,0 +1,60 @@
1
+ require 'spec_helper.rb'
2
+ require 'vcr_helper.rb'
3
+
4
+ describe Quotr do
5
+ describe ".close" do
6
+ let(:sym) { :vfinx }
7
+ let(:invalid_sym) { "NACHOS" }
8
+ let(:date) { Date.new(2012, 4, 20) }
9
+ let(:future_date) { Date.new(2112, 5, 24) }
10
+ let(:expected_close) { BigDecimal("127.14") }
11
+
12
+ subject { Quotr }
13
+
14
+ it "retrieves a quote for a valid symbol on a valid day" do
15
+ VCR.use_cassette('all_valid_quote') do
16
+ subject.close(sym, date).should == expected_close
17
+ end
18
+ end
19
+
20
+ it "retrieves the quote from the previous day on a holiday" do
21
+ VCR.use_cassette('holiday_quote') do
22
+ subject.close(sym, date + 1).should == expected_close
23
+ end
24
+ end
25
+
26
+ it "fails for a valid symbol on a future day" do
27
+ VCR.use_cassette('future_quote') do
28
+ expect { subject.close(sym, future_date) }.to raise_error(Quotr::Error)
29
+ end
30
+ end
31
+
32
+ it "fails for an invalid symbol" do
33
+ VCR.use_cassette('invalid_symbol') do
34
+ expect { subject.close(invalid_sym, date) }.to raise_error(Quotr::Error)
35
+ end
36
+ end
37
+
38
+ context 'given a stock symbol' do
39
+ let(:sym) { :f }
40
+ let(:expected_close) { BigDecimal("11.41") }
41
+
42
+ it "retrieves a quote for a valid stock symbol" do
43
+ VCR.use_cassette('stock_symbol') do
44
+ subject.close(sym, date).should == expected_close
45
+ end
46
+ end
47
+ end
48
+
49
+ context 'given an ETF symbol' do
50
+ let(:sym) { :vti }
51
+ let(:expected_close) { BigDecimal("70.82") }
52
+
53
+ it "retrieves a quote for a valid ETF symbol" do
54
+ VCR.use_cassette('etf_symbol') do
55
+ subject.close(sym, date).should == expected_close
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Quotr::YahooParser do
4
+ describe ".parse" do
5
+ let(:result) { { Date.new(2012, 4, 4) => BigDecimal("128.12"),
6
+ Date.new(2012, 4, 3) => BigDecimal("130.99"),
7
+ Date.new(2012, 4, 2) => BigDecimal("130.76") } }
8
+
9
+ subject { Quotr::YahooParser }
10
+
11
+ context "given sorted data" do
12
+ let(:data) { "Date,Open,High,Low,Close,Volume,Adj Close\n" +
13
+ "2012-04-04,128.12,128.12,128.12,128.12,000,128.12\n" +
14
+ "2012-04-03,130.99,130.99,130.99,130.99,000,130.99\n" +
15
+ "2012-04-02,130.76,130.76,130.76,130.76,000,130.76\n" }
16
+
17
+ it { subject.parse(data).should == result }
18
+ end
19
+
20
+ context "given unsorted data" do
21
+ let(:data) { "Date,Open,High,Low,Close,Volume,Adj Close\n" +
22
+ "2012-04-02,130.76,130.76,130.76,130.76,000,130.76\n" +
23
+ "2012-04-04,128.12,128.12,128.12,128.12,000,128.12\n" +
24
+ "2012-04-03,130.99,130.99,130.99,130.99,000,130.99\n" }
25
+
26
+ it { subject.parse(data).should == result }
27
+ it { subject.parse(data).keys.should == result.keys }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Quotr::Yahoo do
4
+ describe ".fetch" do
5
+ let(:symbol) { :abcd }
6
+ let(:date) { Time.now }
7
+ let(:body) { "<CSV DATA>" }
8
+ let(:mock_resp) { mock(:code => 200, :body => body) }
9
+
10
+ before { Net::HTTP.should_receive(:get_response).and_return(mock_resp) }
11
+
12
+ subject { Quotr::Yahoo }
13
+
14
+ it { subject.fetch(symbol, date).should == body }
15
+ end
16
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Quotr do
4
+ let(:symbol) { :abcd }
5
+ let(:result) { { Date.new(2012, 4, 27) => BigDecimal('5.12'),
6
+ Date.new(2012, 4, 26) => BigDecimal('4.95'),
7
+ Date.new(2012, 4, 25) => BigDecimal('5.64') } }
8
+ before do
9
+ Quotr::Yahoo.should_receive(:fetch).and_return("<CSV>")
10
+ Quotr::YahooParser.should_receive(:parse).and_return(result)
11
+ end
12
+
13
+ describe '.close' do
14
+ subject { Quotr.close(symbol, date) }
15
+
16
+ context 'on a trade date' do
17
+ let(:date) { Date.new(2012, 4, 25) }
18
+
19
+ it 'gets the close on that date' do
20
+ should == result[date]
21
+ end
22
+ end
23
+
24
+ context 'on a non-trade date' do
25
+ let(:date) { Date.new(2012, 4, 28) }
26
+
27
+ it 'gets the most recent close' do
28
+ should == result[Date.new(2012, 4, 27)]
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,14 @@
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.rb"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ require 'quotr'
9
+
10
+ RSpec.configure do |config|
11
+ config.treat_symbols_as_metadata_keys_with_true_values = true
12
+ config.run_all_when_everything_filtered = true
13
+ config.filter_run :focus
14
+ end
@@ -0,0 +1,6 @@
1
+ require 'vcr'
2
+
3
+ VCR.configure do |c|
4
+ c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
5
+ c.hook_into :webmock
6
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: quotr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dan Hodge
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-25 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &2152939200 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *2152939200
25
+ - !ruby/object:Gem::Dependency
26
+ name: vcr
27
+ requirement: &2153294340 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2153294340
36
+ - !ruby/object:Gem::Dependency
37
+ name: webmock
38
+ requirement: &2156396960 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2156396960
47
+ description: Retrieves historical stock and mutual fund quotes
48
+ email:
49
+ - danhodge@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - .rbenv-version
56
+ - Gemfile
57
+ - LICENSE
58
+ - README.md
59
+ - Rakefile
60
+ - lib/quotr.rb
61
+ - lib/quotr/version.rb
62
+ - lib/quotr/yahoo.rb
63
+ - lib/quotr/yahoo_parser.rb
64
+ - quotr.gemspec
65
+ - quotr/version.rb
66
+ - quotr/yahoo.rb
67
+ - quotr/yahoo_parser.rb
68
+ - spec/fixtures/vcr_cassettes/all_valid_quote.yml
69
+ - spec/fixtures/vcr_cassettes/etf_symbol.yml
70
+ - spec/fixtures/vcr_cassettes/future_quote.yml
71
+ - spec/fixtures/vcr_cassettes/holiday_quote.yml
72
+ - spec/fixtures/vcr_cassettes/invalid_symbol.yml
73
+ - spec/fixtures/vcr_cassettes/stock_symbol.yml
74
+ - spec/integration/quotr_integration_spec.rb
75
+ - spec/lib/quotr/yahoo_parser_spec.rb
76
+ - spec/lib/quotr/yahoo_spec.rb
77
+ - spec/quotr_spec.rb
78
+ - spec/spec_helper.rb
79
+ - spec/vcr_helper.rb
80
+ homepage: https://github.com/danhodge/quotr
81
+ licenses: []
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ segments:
93
+ - 0
94
+ hash: -3506731071820815075
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ segments:
102
+ - 0
103
+ hash: -3506731071820815075
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 1.8.10
107
+ signing_key:
108
+ specification_version: 3
109
+ summary: Retrieves historical stock and mutual fund quotes
110
+ test_files:
111
+ - spec/fixtures/vcr_cassettes/all_valid_quote.yml
112
+ - spec/fixtures/vcr_cassettes/etf_symbol.yml
113
+ - spec/fixtures/vcr_cassettes/future_quote.yml
114
+ - spec/fixtures/vcr_cassettes/holiday_quote.yml
115
+ - spec/fixtures/vcr_cassettes/invalid_symbol.yml
116
+ - spec/fixtures/vcr_cassettes/stock_symbol.yml
117
+ - spec/integration/quotr_integration_spec.rb
118
+ - spec/lib/quotr/yahoo_parser_spec.rb
119
+ - spec/lib/quotr/yahoo_spec.rb
120
+ - spec/quotr_spec.rb
121
+ - spec/spec_helper.rb
122
+ - spec/vcr_helper.rb