quotr 0.0.1

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 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