quotr 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/.rbenv-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +30 -0
- data/Rakefile +6 -0
- data/lib/quotr.rb +11 -0
- data/lib/quotr/version.rb +3 -0
- data/lib/quotr/yahoo.rb +28 -0
- data/lib/quotr/yahoo_parser.rb +17 -0
- data/quotr.gemspec +23 -0
- data/quotr/version.rb +3 -0
- data/quotr/yahoo.rb +28 -0
- data/quotr/yahoo_parser.rb +17 -0
- data/spec/fixtures/vcr_cassettes/all_valid_quote.yml +54 -0
- data/spec/fixtures/vcr_cassettes/etf_symbol.yml +54 -0
- data/spec/fixtures/vcr_cassettes/future_quote.yml +73 -0
- data/spec/fixtures/vcr_cassettes/holiday_quote.yml +52 -0
- data/spec/fixtures/vcr_cassettes/invalid_symbol.yml +73 -0
- data/spec/fixtures/vcr_cassettes/stock_symbol.yml +54 -0
- data/spec/integration/quotr_integration_spec.rb +60 -0
- data/spec/lib/quotr/yahoo_parser_spec.rb +30 -0
- data/spec/lib/quotr/yahoo_spec.rb +16 -0
- data/spec/quotr_spec.rb +32 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/vcr_helper.rb +6 -0
- metadata +122 -0
data/.gitignore
ADDED
data/.rbenv-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.2-p290
|
data/Gemfile
ADDED
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
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
|
data/lib/quotr/yahoo.rb
ADDED
@@ -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
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
|
+
© 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
|
+
© 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
|
data/spec/quotr_spec.rb
ADDED
@@ -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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|
data/spec/vcr_helper.rb
ADDED
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
|