yquotes 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/yquotes/version.rb +1 -1
- data/lib/yquotes/yahoo.rb +89 -96
- data/lib/yquotes.rb +41 -47
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0ff917e8a8aac81d7a0cda637da8e8501c71c76
|
4
|
+
data.tar.gz: 1f20150900e8382b0c9e9800615d81b5db7729b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 044d0ecf6eff1d86b792c12cfb718a823a57eb138f71b69f6dd5a36875b6b262b0a33a7f963f75ab9e1fc2388fdc9b2ba8e4a8f2fa346f2fc02f1654408abc50
|
7
|
+
data.tar.gz: 4173e954a531ce60e70004dcfcdaa9d1671b117d5f26408f224452bb47c68e17623c60648ad9da021132d55e152c03ecef8eb84213f578bcfd0d404893acb192
|
data/lib/yquotes/version.rb
CHANGED
data/lib/yquotes/yahoo.rb
CHANGED
@@ -3,100 +3,93 @@ require 'csv'
|
|
3
3
|
require 'date'
|
4
4
|
require 'nokogiri'
|
5
5
|
|
6
|
-
|
7
6
|
module YQuotes
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
end
|
101
|
-
|
102
|
-
end
|
7
|
+
COOKIE_URL = 'https://finance.yahoo.com/quote/AAPL/history?p=AAPL'.freeze
|
8
|
+
CRUMB_PATTERN = /\"CrumbStore\":{\"crumb\":\"(?<crumb>[^"]+)/
|
9
|
+
QUOTE_ENDPOINT = 'https://query1.finance.yahoo.com/v7/finance/download/%{symbol}?'.freeze
|
10
|
+
|
11
|
+
class Yahoo
|
12
|
+
# Get cookie and crumb
|
13
|
+
def initialize
|
14
|
+
fetch_credentials
|
15
|
+
end
|
16
|
+
|
17
|
+
# fetch_csv: fetch historical quotes in csv format
|
18
|
+
def fetch_csv(ticker, start_date = nil, end_date = nil, period = 'd')
|
19
|
+
connection = nil
|
20
|
+
|
21
|
+
# retry 3-times in case it sends unauthorized
|
22
|
+
3.times do |_i|
|
23
|
+
begin
|
24
|
+
url = build_url(ticker, start_date, end_date, period)
|
25
|
+
connection = open(url, 'Cookie' => @cookie)
|
26
|
+
break
|
27
|
+
rescue OpenURI::HTTPError => e
|
28
|
+
fetch_credentials
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
data = CSV.parse(connection.read, converters: :numeric)
|
33
|
+
|
34
|
+
raise 'Yahoo.fetch_csv unable to fetch data' unless data.is_a? Array
|
35
|
+
data
|
36
|
+
end
|
37
|
+
|
38
|
+
alias get_csv fetch_csv
|
39
|
+
alias get_data fetch_csv
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def fetch_credentials
|
44
|
+
# get cookie
|
45
|
+
page = open(COOKIE_URL)
|
46
|
+
@cookie = page.meta['set-cookie'].split('; ', 2).first
|
47
|
+
|
48
|
+
# get crumb
|
49
|
+
scripts = Nokogiri::HTML(page).css('script')
|
50
|
+
scripts.each do |s|
|
51
|
+
next unless s.text.include? 'CrumbStore'
|
52
|
+
pattern = s.text.match(CRUMB_PATTERN)
|
53
|
+
@crumb = pattern['crumb']
|
54
|
+
break
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# build_params: build parameters for get query
|
59
|
+
def build_url(ticker, start_date = nil, end_date = nil, period = 'd')
|
60
|
+
url = QUOTE_ENDPOINT
|
61
|
+
url = format(url, symbol: URI.escape(ticker.upcase))
|
62
|
+
|
63
|
+
params = {
|
64
|
+
crumb: URI.escape(@crumb),
|
65
|
+
events: 'history',
|
66
|
+
interval: '1d'
|
67
|
+
}
|
68
|
+
|
69
|
+
# sanitize date
|
70
|
+
params[:period1] = get_date(start_date).to_i unless start_date.nil?
|
71
|
+
params[:period2] = get_date(end_date).to_i unless end_date.nil?
|
72
|
+
|
73
|
+
params[:interval] = '1d' if period == 'd'
|
74
|
+
params[:interval] = '1mo' if period == 'm'
|
75
|
+
params[:interval] = '1wk' if period == 'w'
|
76
|
+
|
77
|
+
url + params.map { |k, v| "#{k}=#{v}" }.join('&').to_s
|
78
|
+
end
|
79
|
+
|
80
|
+
# get_date: get date from String
|
81
|
+
def get_date(d)
|
82
|
+
return nil if d.nil?
|
83
|
+
return d.to_time if d.is_a? DateTime
|
84
|
+
|
85
|
+
if d.is_a? String
|
86
|
+
|
87
|
+
begin
|
88
|
+
dt = DateTime.parse(d).to_time
|
89
|
+
rescue Exception => e
|
90
|
+
raise "invalid param #{d} - date should be in yyyy-mm-dd format"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/yquotes.rb
CHANGED
@@ -1,65 +1,59 @@
|
|
1
1
|
require 'csv'
|
2
2
|
require 'daru'
|
3
3
|
require 'tmpdir'
|
4
|
-
require
|
5
|
-
require
|
4
|
+
require 'yquotes/version'
|
5
|
+
require 'yquotes/yahoo'
|
6
6
|
|
7
7
|
module YQuotes
|
8
|
+
class Client
|
9
|
+
def initialize
|
10
|
+
@yahoo_client = Yahoo.new
|
11
|
+
end
|
8
12
|
|
9
|
-
|
13
|
+
# get_quote: returns Daru::DataFrame of the quote with volume and close
|
14
|
+
def get_quote(ticker, args = {})
|
15
|
+
if args.is_a? Hash
|
16
|
+
start_date = args[:start_date] if args[:start_date]
|
17
|
+
start_date ||= args[:s] if args[:s]
|
10
18
|
|
11
|
-
|
12
|
-
|
13
|
-
end
|
19
|
+
end_date = args[:end_date] if args[:end_date]
|
20
|
+
end_date ||= args[:e] if args[:e]
|
14
21
|
|
15
|
-
|
16
|
-
|
22
|
+
period = args[:period] if args[:period]
|
23
|
+
period ||= args[:p] if args[:p]
|
24
|
+
end
|
17
25
|
|
18
|
-
|
19
|
-
|
20
|
-
|
26
|
+
csv = @yahoo_client.get_csv(ticker, start_date, end_date, period)
|
27
|
+
create_from_csv(csv)
|
28
|
+
end
|
21
29
|
|
22
|
-
|
23
|
-
|
30
|
+
alias historical_data get_quote
|
31
|
+
alias historical_quote get_quote
|
24
32
|
|
25
|
-
|
26
|
-
period ||= args[:p] if args[:p]
|
27
|
-
end
|
33
|
+
private
|
28
34
|
|
29
|
-
|
30
|
-
|
31
|
-
end
|
35
|
+
def create_from_csv(data)
|
36
|
+
file_path = Dir.tmpdir + "/#{Time.now.to_i}"
|
32
37
|
|
33
|
-
|
34
|
-
|
38
|
+
CSV.open(file_path, 'w') do |out|
|
39
|
+
data.each do |row|
|
40
|
+
out << row
|
41
|
+
end
|
42
|
+
end
|
35
43
|
|
36
|
-
|
44
|
+
df = nil
|
37
45
|
|
38
|
-
|
46
|
+
df = Daru::DataFrame.from_csv(file_path, converters: :numeric)
|
47
|
+
File.delete(file_path) if File.exist?(file_path)
|
39
48
|
|
40
|
-
|
41
|
-
|
42
|
-
CSV.open(file_path, 'w') do |out|
|
43
|
-
data.each do |row|
|
44
|
-
out << row
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
df = nil
|
49
|
-
|
50
|
-
df = Daru::DataFrame.from_csv(file_path, :converters => :numeric)
|
51
|
-
File.delete(file_path) if File.exists?(file_path)
|
52
|
-
|
53
|
-
#sort from earlier to latest
|
54
|
-
df = df.sort ['Date']
|
55
|
-
|
56
|
-
# strip columns and create index
|
57
|
-
df.index = Daru::Index.new(df['Date'].to_a)
|
58
|
-
df.rename_vectors 'Volume' => :volume, 'Adj Close' => :adj_close, 'Open' => :open, 'Close' => :close, 'High' => :high, 'Low' => :low
|
59
|
-
df.delete_vector 'Date'
|
60
|
-
d = df.filter(:row) { |row| row[:volume] > 0}
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
49
|
+
# sort from earlier to latest
|
50
|
+
df = df.sort ['Date']
|
64
51
|
|
52
|
+
# strip columns and create index
|
53
|
+
df.index = Daru::Index.new(df['Date'].to_a)
|
54
|
+
df.rename_vectors 'Volume' => :volume, 'Adj Close' => :adj_close, 'Open' => :open, 'Close' => :close, 'High' => :high, 'Low' => :low
|
55
|
+
df.delete_vector 'Date'
|
56
|
+
d = df.filter(:row) { |row| row[:volume] > 0 }
|
57
|
+
end
|
58
|
+
end
|
65
59
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yquotes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- P Choudhary
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|