yahoo-finance 0.2.0 → 1.2.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.
- checksums.yaml +13 -5
- data/HISTORY +11 -1
- data/README.md +58 -12
- data/lib/yahoo-finance/finance-utils.rb +29 -0
- data/lib/yahoo-finance/version.rb +4 -0
- data/lib/yahoo-finance.rb +245 -1
- metadata +64 -7
- data/lib/yahoo_finance.rb +0 -231
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZjBkYTA4YjE1ZDQ5ODNhMTJiYmQ5YWM2ZDRhMTdkOTlhMmJkYzY5Yw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NDAyNTI1YWQ5ZWNhNDJhMTAyYjNjMzQ5OWJmZWI5MTdjMWE2NGQ2NQ==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ODUwYTM3YjI3OGNhYzFmZjRiZjFjMDYyMGU5N2M3YmJjMDZjNGQxZTc5OTg3
|
10
|
+
NDM2ZjRiNWI5YjNiYjU0ODRiZDRlZTkwMzJiNzM2ZmQ4MWI4M2I1ZTRhODM5
|
11
|
+
NzAxYmJiZGU1ZTJmZGMzZDA3OTFlYzZhN2ZmZTRjMDJiNDE1Njg=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NjFjZWY4MTc5YzMxNTIyMDU2ZGJhODc1ZTE2NDQ0ZDc2NzQ5NTU4MmJjNTA1
|
14
|
+
Y2FjZDFjMzYyYWRhZWM5YzBiZDFkYmUyNTFlNWQ2NDQ1NjJmNWI5YzEzYjAz
|
15
|
+
NjFjYWM0ZWQ1M2Q3ODIwMDZjZGVhZTI1YTk4MDBjMDk2YWZlODM=
|
data/HISTORY
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
1.2.0 - Feb 04, 2017
|
2
|
+
====================
|
3
|
+
* Fixed support for { raw: false }
|
4
|
+
* Symbols that are not found will now not return (instead of returning a struct with an empty :symbol field and a bunch of "N/A"s)
|
5
|
+
* The returned quotes now will always include the :symbol name
|
6
|
+
|
7
|
+
0.3.0 - Aug 16, 2015
|
8
|
+
====================
|
9
|
+
* Refactorings & support for US companies data (via NASDAQ's Apis) - by Eric D. Santos Sosa
|
10
|
+
|
1
11
|
0.2.0 - Nov 24, 2014
|
2
12
|
====================
|
3
13
|
* Allow fetching a single symbol with the `quote` method
|
@@ -16,4 +26,4 @@
|
|
16
26
|
|
17
27
|
0.0.1 - Aug 04, 2007
|
18
28
|
===============================
|
19
|
-
* Initial implementation - no bells, no
|
29
|
+
* Initial implementation - no bells, no whistles :)
|
data/README.md
CHANGED
@@ -3,11 +3,10 @@ A dead simple wrapper for yahoo finance quotes end-point.
|
|
3
3
|
|
4
4
|
## Installation:
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
Just add it to your `Gemfile`:
|
7
|
+
|
8
|
+
`gem 'yahoo-finance'`
|
8
9
|
|
9
|
-
If using bundler:
|
10
|
-
`gem 'yahoo-finance', require: 'yahoo_finance'`
|
11
10
|
|
12
11
|
## Usage:
|
13
12
|
|
@@ -16,7 +15,8 @@ If using bundler:
|
|
16
15
|
Pass an array of valid symbols (stock names, indexes, exchange rates) and a list of fields you want:
|
17
16
|
|
18
17
|
```ruby
|
19
|
-
|
18
|
+
yahoo_client = YahooFinance::Client.new
|
19
|
+
data = yahoo_client.quotes(["BVSP", "NATU3.SA", "USDJPY=X"], [:ask, :bid, :last_trade_date])
|
20
20
|
```
|
21
21
|
|
22
22
|
Data is now an array of results. You now have accessor methods to retrieve the data, with the return results being strings:
|
@@ -28,13 +28,28 @@ puts data[0].symbol + " value is: " + data[0].ask
|
|
28
28
|
Passing `raw: false` will return numerical values
|
29
29
|
|
30
30
|
```ruby
|
31
|
-
|
32
|
-
data[
|
31
|
+
yahoo_client = YahooFinance::Client.new
|
32
|
+
data = yahoo_client.quotes(["BVSP", "NATU3.SA", "USDJPY=X"], [:ask, :bid, :last_trade_date], { raw: false } )
|
33
|
+
data[0].ask # This is now a BigDecimal
|
34
|
+
```
|
35
|
+
|
36
|
+
Passing `na_as_nil: true` will convert "N/A" responses to `nil`
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
yahoo_client = YahooFinance::Client.new
|
40
|
+
|
41
|
+
data = yahoo_client.quotes(["BVSP"], [:ask] )
|
42
|
+
data[0].ask
|
43
|
+
> "N/A"
|
44
|
+
|
45
|
+
data = yahoo_client.quotes(["BVSP"], [:ask], { na_as_nil: true } )
|
46
|
+
data[0].ask
|
47
|
+
> nil
|
33
48
|
```
|
34
49
|
|
35
50
|
The full list of fields follows:
|
36
51
|
|
37
|
-
```
|
52
|
+
```ruby
|
38
53
|
:after_hours_change_real_time
|
39
54
|
:annualized_gain
|
40
55
|
:ask
|
@@ -112,6 +127,8 @@ The full list of fields follows:
|
|
112
127
|
:price_paid
|
113
128
|
:price_per_book
|
114
129
|
:price_per_sales
|
130
|
+
:revenue
|
131
|
+
:shares_outstanding
|
115
132
|
:shares_owned
|
116
133
|
:short_ratio
|
117
134
|
:stock_exchange
|
@@ -123,6 +140,30 @@ The full list of fields follows:
|
|
123
140
|
:weeks_range_52
|
124
141
|
```
|
125
142
|
|
143
|
+
### Getting symbols by stock market (beta)
|
144
|
+
|
145
|
+
Create a YahooFinance::Client instance
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
yahoo_client = YahooFinance::Client.new
|
149
|
+
```
|
150
|
+
|
151
|
+
Calling symbols_by_market method (symbols_by_market(country, stock_market))
|
152
|
+
|
153
|
+
Note: Can only be called with US Stock Markets for now.
|
154
|
+
|
155
|
+
*Important: This data comes directly from NASDAQ's CSV endpoints, NOT Yahoo Finance*. It might be extracted into a different Gem in the future.
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
yahoo_client.symbols_by_market('us', 'nyse') # Only US Stock Markets For Now
|
159
|
+
```
|
160
|
+
|
161
|
+
This method returns an array of symbols that can be used with the quotes method
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
data = yahoo_client.quotes(yahoo_client.symbols_by_market('us', 'nyse'), [:ask, :bid, :last_trade_date])
|
165
|
+
```
|
166
|
+
|
126
167
|
### Getting historical quotes
|
127
168
|
|
128
169
|
Here you can specify a date range and a symbol, and retrieve historical data for it.
|
@@ -130,19 +171,22 @@ The last parameter (options) can include, besides the "raw" option, a "period" o
|
|
130
171
|
The period can be specified as :daily, :monthly, :weekly or :dividends_only
|
131
172
|
|
132
173
|
```ruby
|
133
|
-
|
174
|
+
yahoo_client = YahooFinance::Client.new
|
175
|
+
data = yahoo_client.historical_quotes("AAPL") # entire historical data
|
134
176
|
```
|
135
177
|
|
136
178
|
or
|
137
179
|
|
138
180
|
```ruby
|
139
|
-
|
181
|
+
yahoo_client = YahooFinance::Client.new
|
182
|
+
data = yahoo_client.historical_quotes("AAPL", { start_date: Time::now-(24*60*60*10), end_date: Time::now }) # 10 days worth of data
|
140
183
|
```
|
141
184
|
|
142
185
|
or
|
143
186
|
|
144
187
|
``` ruby
|
145
|
-
|
188
|
+
yahoo_client = YahooFinance::Client.new
|
189
|
+
data = yahoo_client.historical_quotes("AAPL", { raw: false, period: :monthly })
|
146
190
|
```
|
147
191
|
|
148
192
|
### Getting splits
|
@@ -150,7 +194,8 @@ data = YahooFinance.historical_quotes("AAPL", { raw: false, period: :monthly })
|
|
150
194
|
You can also retrieve split data.
|
151
195
|
|
152
196
|
```ruby
|
153
|
-
|
197
|
+
yahoo_client = YahooFinance::Client.new
|
198
|
+
data = yahoo_client.splits('AAPL', :start_date => Date.today - 10*365)
|
154
199
|
data[0].date # Date<2014-06-09>
|
155
200
|
data[0].before # 1
|
156
201
|
data[0].after # 7
|
@@ -160,3 +205,4 @@ data[0].after # 7
|
|
160
205
|
Enjoy! :-)
|
161
206
|
|
162
207
|
- Herval (hervalfreire@gmail.com)
|
208
|
+
- Eric D. Santos Sosa (eric.santos@cometa.works)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# YahooFinance Module for YahooFinance gem
|
2
|
+
module YahooFinance
|
3
|
+
# FinanceUtils Module
|
4
|
+
module FinanceUtils
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(self)
|
7
|
+
end
|
8
|
+
|
9
|
+
MARKETS = OpenStruct.new(
|
10
|
+
us: OpenStruct.new(
|
11
|
+
nasdaq: OpenStruct.new(
|
12
|
+
url: "http://www.nasdaq.com/screening/companies-by-name.aspx?letter=0&exchange=nasdaq&render=download"),
|
13
|
+
nyse: OpenStruct.new(
|
14
|
+
url: "http://www.nasdaq.com/screening/companies-by-name.aspx?letter=0&exchange=nyse&render=download"),
|
15
|
+
amex: OpenStruct.new(
|
16
|
+
url: "http://www.nasdaq.com/screening/companies-by-name.aspx?letter=0&exchange=amex&render=download")))
|
17
|
+
|
18
|
+
def symbols_by_market(country, market)
|
19
|
+
symbols = []
|
20
|
+
market = MARKETS.send(country).send(market)
|
21
|
+
return symbols if market.nil?
|
22
|
+
CSV.foreach(open(market.url)) do |row|
|
23
|
+
next if row.first == "Symbol"
|
24
|
+
symbols.push(row.first.gsub(" ", ""))
|
25
|
+
end
|
26
|
+
symbols
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/yahoo-finance.rb
CHANGED
@@ -1 +1,245 @@
|
|
1
|
-
require
|
1
|
+
require "open-uri"
|
2
|
+
require "ostruct"
|
3
|
+
require "json"
|
4
|
+
require "yahoo-finance/version"
|
5
|
+
require "yahoo-finance/finance-utils"
|
6
|
+
require "csv"
|
7
|
+
require 'bigdecimal'
|
8
|
+
|
9
|
+
module YahooFinance
|
10
|
+
# Client for Yahoo Finance Queries
|
11
|
+
class Client
|
12
|
+
include YahooFinance::FinanceUtils
|
13
|
+
|
14
|
+
COLUMNS = {
|
15
|
+
:ask => ["a", BigDecimal],
|
16
|
+
:average_daily_volume => ["a2", BigDecimal],
|
17
|
+
:ask_size => ["a5", BigDecimal],
|
18
|
+
:bid => ["b", BigDecimal],
|
19
|
+
:ask_real_time => ["b2", Time],
|
20
|
+
:bid_real_time => ["b3", BigDecimal],
|
21
|
+
:book_value => ["b4", BigDecimal],
|
22
|
+
:bid_size => ["b6", BigDecimal],
|
23
|
+
:chance_and_percent_change => ["c", String],
|
24
|
+
:change => ["c1", BigDecimal],
|
25
|
+
:comission => ["c3", String],
|
26
|
+
:change_real_time => ["c6", BigDecimal],
|
27
|
+
:after_hours_change_real_time => ["c8", String],
|
28
|
+
:dividend_per_share => ["d", BigDecimal],
|
29
|
+
:last_trade_date => ["d1", DateTime],
|
30
|
+
:trade_date => ["d2", String],
|
31
|
+
:earnings_per_share => ["e", BigDecimal],
|
32
|
+
:error_indicator => ["e1", String],
|
33
|
+
:eps_estimate_current_year => ["e7", BigDecimal],
|
34
|
+
:eps_estimate_next_year => ["e8", BigDecimal],
|
35
|
+
:eps_estimate_next_quarter => ["e9", BigDecimal],
|
36
|
+
:float_shares => ["f6", BigDecimal],
|
37
|
+
:low => ["g", BigDecimal],
|
38
|
+
:high => ["h", BigDecimal],
|
39
|
+
:low_52_weeks => ["j", BigDecimal],
|
40
|
+
:high_52_weeks => ["k", BigDecimal],
|
41
|
+
:holdings_gain_percent => ["g1", BigDecimal],
|
42
|
+
:annualized_gain => ["g3", BigDecimal],
|
43
|
+
:holdings_gain => ["g4", BigDecimal],
|
44
|
+
:holdings_gain_percent_realtime => ["g5", BigDecimal],
|
45
|
+
:holdings_gain_realtime => ["g6", BigDecimal],
|
46
|
+
:more_info => ["i", String],
|
47
|
+
:order_book => ["i5", BigDecimal],
|
48
|
+
:market_capitalization => ["j1", BigDecimal],
|
49
|
+
:shares_outstanding => ["j2", BigDecimal],
|
50
|
+
:market_cap_realtime => ["j3", BigDecimal],
|
51
|
+
:ebitda => ["j4", BigDecimal],
|
52
|
+
:change_From_52_week_low => ["j5", BigDecimal],
|
53
|
+
:percent_change_from_52_week_low => ["j6", BigDecimal],
|
54
|
+
:last_trade_realtime_withtime => ["k1", String],
|
55
|
+
:change_percent_realtime => ["k2", String],
|
56
|
+
:last_trade_size => ["k3", BigDecimal],
|
57
|
+
:change_from_52_week_high => ["k4", BigDecimal],
|
58
|
+
:percent_change_from_52_week_high => ["k5", BigDecimal],
|
59
|
+
:last_trade_with_time => ["l", String],
|
60
|
+
:last_trade_price => ["l1", BigDecimal],
|
61
|
+
:close => ["l1", BigDecimal], # same as :last_trade_price
|
62
|
+
:high_limit => ["l2", BigDecimal],
|
63
|
+
:low_limit => ["l3", BigDecimal],
|
64
|
+
:days_range => ["m", BigDecimal],
|
65
|
+
:days_range_realtime => ["m2", BigDecimal],
|
66
|
+
:moving_average_50_day => ["m3", BigDecimal],
|
67
|
+
:moving_average_200_day => ["m4", BigDecimal],
|
68
|
+
:change_from_200_day_moving_average => ["m5", BigDecimal],
|
69
|
+
:percent_change_from_200_day_moving_average => ["m6", BigDecimal],
|
70
|
+
:change_from_50_day_moving_average => ["m7", BigDecimal],
|
71
|
+
:percent_change_from_50_day_moving_average => ["m8", BigDecimal],
|
72
|
+
:name => ["n", String],
|
73
|
+
:notes => ["n4", String],
|
74
|
+
:open => ["o", BigDecimal],
|
75
|
+
:previous_close => ["p", BigDecimal],
|
76
|
+
:price_paid => ["p1", BigDecimal],
|
77
|
+
:change_in_percent => ["p2", BigDecimal],
|
78
|
+
:price_per_sales => ["p5", BigDecimal],
|
79
|
+
:price_per_book => ["p6", BigDecimal],
|
80
|
+
:ex_dividend_date => ["q", DateTime],
|
81
|
+
:pe_ratio => ["p5", BigDecimal],
|
82
|
+
:dividend_pay_date => ["r1", String],
|
83
|
+
:pe_ratio_realtime => ["r2", BigDecimal],
|
84
|
+
:peg_ratio => ["r5", BigDecimal],
|
85
|
+
:price_eps_estimate_current_year => ["r6", BigDecimal],
|
86
|
+
:price_eps_Estimate_next_year => ["r7", BigDecimal],
|
87
|
+
:symbol => ["s", String],
|
88
|
+
:shares_owned => ["s1", BigDecimal],
|
89
|
+
:revenue => ["s6", BigDecimal],
|
90
|
+
:short_ratio => ["s7", BigDecimal],
|
91
|
+
:last_trade_time => ["t1", Time],
|
92
|
+
:trade_links => ["t6", String],
|
93
|
+
:ticker_trend => ["t7", String],
|
94
|
+
:one_year_target_price => ["t8", BigDecimal],
|
95
|
+
:volume => ["v", BigDecimal],
|
96
|
+
:holdings_value => ["v1", String],
|
97
|
+
:holdings_value_realtime => ["v7", String],
|
98
|
+
:weeks_range_52 => ["w", BigDecimal],
|
99
|
+
:day_value_change => ["w1", BigDecimal],
|
100
|
+
:day_value_change_realtime => ["w4", String],
|
101
|
+
:stock_exchange => ["x", String],
|
102
|
+
:dividend_yield => ["y", BigDecimal],
|
103
|
+
:adjusted_close => [nil, BigDecimal] # this one only comes in historical quotes
|
104
|
+
}
|
105
|
+
|
106
|
+
HISTORICAL_MODES = {
|
107
|
+
daily: "d",
|
108
|
+
weekly: "w",
|
109
|
+
monthly: "m",
|
110
|
+
dividends_only: "v"
|
111
|
+
}
|
112
|
+
|
113
|
+
SYMBOLS_PER_REQUEST = 50
|
114
|
+
|
115
|
+
# retrieve the quote data (an OpenStruct per quote)
|
116
|
+
# the options param can be used to specify the following attributes:
|
117
|
+
# :raw - if true, each column will be converted (to numbers, dates, etc)
|
118
|
+
def quotes(symbols_array, columns_array = [:symbol, :last_trade_price, :last_trade_date, :change, :previous_close], options = {})
|
119
|
+
# remove invalid keys
|
120
|
+
columns_array.reject! { |c| !COLUMNS.key?(c) }
|
121
|
+
columns_array << :symbol if columns_array.index(:symbol).nil?
|
122
|
+
|
123
|
+
# "N/A" is never present if { raw = false }
|
124
|
+
options[:na_as_nil] = true if options[:raw] == false
|
125
|
+
|
126
|
+
ret = []
|
127
|
+
symbols_array.each_slice(SYMBOLS_PER_REQUEST) do |symbols|
|
128
|
+
read_quotes(symbols.join("+"), columns_array).map do |row|
|
129
|
+
data = row.to_hash
|
130
|
+
if options[:na_as_nil]
|
131
|
+
data.each { |key, value| data[key] = nil if value == 'N/A' }
|
132
|
+
end
|
133
|
+
if options[:raw] == false
|
134
|
+
data.each { |key, value| data[key] = format(value, COLUMNS[key][1]) }
|
135
|
+
end
|
136
|
+
ret << OpenStruct.new(data)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
ret
|
140
|
+
end
|
141
|
+
|
142
|
+
def quote(symbol, columns_array = [:symbol, :last_trade_price, :last_trade_date, :change, :previous_close], options = {})
|
143
|
+
options[:raw] ||= true
|
144
|
+
quotes([symbol], columns_array, options).first
|
145
|
+
end
|
146
|
+
|
147
|
+
def historical_quotes(symbol, options = {})
|
148
|
+
options[:raw] ||= true
|
149
|
+
options[:period] ||= :daily
|
150
|
+
read_historical(symbol, options).map do |row|
|
151
|
+
OpenStruct.new(row.to_hash.merge(symbol: symbol))
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def symbols(query)
|
156
|
+
ret = []
|
157
|
+
read_symbols(query).each do |row|
|
158
|
+
ret << OpenStruct.new(row)
|
159
|
+
end
|
160
|
+
ret
|
161
|
+
end
|
162
|
+
|
163
|
+
def splits(symbol, options = {})
|
164
|
+
rows = read_splits(symbol, options).select { |row| row[0] == "SPLIT" }
|
165
|
+
rows.map do |type, date, value|
|
166
|
+
after, before = value.split(":")
|
167
|
+
OpenStruct.new(symbol: symbol, date: Date.strptime(date.strip, "%Y%m%d"), before: before.to_i, after: after.to_i)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def format(str, type)
|
172
|
+
if str.nil?
|
173
|
+
str
|
174
|
+
elsif type == BigDecimal
|
175
|
+
BigDecimal.new(str)
|
176
|
+
elsif type == DateTime
|
177
|
+
DateTime.parse(str)
|
178
|
+
elsif type == Time
|
179
|
+
Time.parse(str)
|
180
|
+
else
|
181
|
+
str
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
def read_quotes(symb_str, cols)
|
188
|
+
columns = "#{cols.map { |col| COLUMNS[col][0] }.join("")}"
|
189
|
+
conn = open("https://download.finance.yahoo.com/d/quotes.csv?s=#{URI.escape(symb_str)}&f=#{columns}")
|
190
|
+
CSV.parse(conn.read, headers: cols)
|
191
|
+
end
|
192
|
+
|
193
|
+
def read_historical(symbol, options)
|
194
|
+
params = { s: URI.escape(symbol), g: HISTORICAL_MODES[options[:period]], ignore: ".csv" }
|
195
|
+
if options[:start_date]
|
196
|
+
params[:a] = options[:start_date].month-1
|
197
|
+
params[:b] = options[:start_date].day
|
198
|
+
params[:c] = options[:start_date].year
|
199
|
+
end
|
200
|
+
if options[:end_date]
|
201
|
+
params[:d] = options[:end_date].month-1
|
202
|
+
params[:e] = options[:end_date].day
|
203
|
+
params[:f] = options[:end_date].year
|
204
|
+
end
|
205
|
+
|
206
|
+
url = "https://ichart.finance.yahoo.com/table.csv?#{params.map{|k, v| "#{k}=#{v}"}.join("&")}"
|
207
|
+
conn = open(url)
|
208
|
+
cols = if options[:period] == :dividends_only
|
209
|
+
[:dividend_pay_date, :dividend_yield]
|
210
|
+
else
|
211
|
+
[:trade_date, :open, :high, :low, :close, :volume, :adjusted_close]
|
212
|
+
end
|
213
|
+
result = CSV.parse(conn.read, headers: cols)
|
214
|
+
#:first_row, :header_converters => :symbol)
|
215
|
+
result.delete(0) # drop returned header
|
216
|
+
result
|
217
|
+
end
|
218
|
+
|
219
|
+
def read_splits(symbol, options)
|
220
|
+
params = { s: URI.escape(symbol), g: "v" }
|
221
|
+
if options[:start_date]
|
222
|
+
params[:a] = options[:start_date].month-1
|
223
|
+
params[:b] = options[:start_date].day
|
224
|
+
params[:c] = options[:start_date].year
|
225
|
+
end
|
226
|
+
if options[:end_date]
|
227
|
+
params[:d] = options[:end_date].month-1
|
228
|
+
params[:e] = options[:end_date].day
|
229
|
+
params[:f] = options[:end_date].year
|
230
|
+
end
|
231
|
+
|
232
|
+
url = "https://ichart.finance.yahoo.com/x?#{params.map{|k, v| "#{k}=#{v}"}.join("&")}"
|
233
|
+
conn = open(url)
|
234
|
+
CSV.parse(conn.read)
|
235
|
+
end
|
236
|
+
|
237
|
+
def read_symbols(query)
|
238
|
+
conn = open("http://d.yimg.com/autoc.finance.yahoo.com/autoc?query=#{query}®ion=US&lang=en-US&callback=YAHOO.Finance.SymbolSuggest.ssCallback")
|
239
|
+
result = conn.read
|
240
|
+
result.sub!("YAHOO.Finance.SymbolSuggest.ssCallback(", "").chomp!(");")
|
241
|
+
json_result = JSON.parse(result)
|
242
|
+
json_result["ResultSet"]["Result"]
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yahoo-finance
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Herval Freire
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
11
|
+
date: 2017-02-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: test-unit
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
13
69
|
description:
|
14
70
|
email: herval@hervalicio.us
|
15
71
|
executables: []
|
@@ -21,7 +77,8 @@ files:
|
|
21
77
|
- HISTORY
|
22
78
|
- README.md
|
23
79
|
- lib/yahoo-finance.rb
|
24
|
-
- lib/
|
80
|
+
- lib/yahoo-finance/finance-utils.rb
|
81
|
+
- lib/yahoo-finance/version.rb
|
25
82
|
homepage: http://hervalicio.us/blog
|
26
83
|
licenses: []
|
27
84
|
metadata: {}
|
@@ -31,17 +88,17 @@ require_paths:
|
|
31
88
|
- lib
|
32
89
|
required_ruby_version: !ruby/object:Gem::Requirement
|
33
90
|
requirements:
|
34
|
-
- -
|
91
|
+
- - ! '>='
|
35
92
|
- !ruby/object:Gem::Version
|
36
93
|
version: '0'
|
37
94
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
95
|
requirements:
|
39
|
-
- -
|
96
|
+
- - ! '>='
|
40
97
|
- !ruby/object:Gem::Version
|
41
98
|
version: '0'
|
42
99
|
requirements: []
|
43
100
|
rubyforge_project:
|
44
|
-
rubygems_version: 2.
|
101
|
+
rubygems_version: 2.4.8
|
45
102
|
signing_key:
|
46
103
|
specification_version: 4
|
47
104
|
summary: A wrapper to Yahoo! Finance market data (quotes and exchange rates) feed
|
data/lib/yahoo_finance.rb
DELETED
@@ -1,231 +0,0 @@
|
|
1
|
-
require 'open-uri'
|
2
|
-
require 'ostruct'
|
3
|
-
require 'json'
|
4
|
-
|
5
|
-
if RUBY_VERSION >= "1.9"
|
6
|
-
require 'csv'
|
7
|
-
else
|
8
|
-
require 'rubygems'
|
9
|
-
require 'fastercsv'
|
10
|
-
class Object
|
11
|
-
CSV = FCSV
|
12
|
-
alias_method :CSV, :FCSV
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class YahooFinance
|
17
|
-
|
18
|
-
VERSION = '0.2.0'
|
19
|
-
|
20
|
-
COLUMNS = {
|
21
|
-
:ask => "a",
|
22
|
-
:average_daily_volume => "a2",
|
23
|
-
:ask_size => "a5",
|
24
|
-
:bid => "b",
|
25
|
-
:ask_real_time => "b2",
|
26
|
-
:bid_real_time => "b3",
|
27
|
-
:book_value => "b4",
|
28
|
-
:bid_size => "b6",
|
29
|
-
:change_and_percent_change => "c",
|
30
|
-
:change => "c1",
|
31
|
-
:comission => "c3",
|
32
|
-
:change_real_time => "c6",
|
33
|
-
:after_hours_change_real_time => "c8",
|
34
|
-
:dividend_per_share => "d",
|
35
|
-
:last_trade_date => "d1",
|
36
|
-
:trade_date => "d2",
|
37
|
-
:earnings_per_share => "e",
|
38
|
-
:error_indicator => "e1",
|
39
|
-
:eps_estimate_current_year => "e7",
|
40
|
-
:eps_estimate_next_year => "e8",
|
41
|
-
:eps_estimate_next_quarter => "e9",
|
42
|
-
:float_shares => "f6",
|
43
|
-
:low => "g",
|
44
|
-
:high => "h",
|
45
|
-
:low_52_weeks => "j",
|
46
|
-
:high_52_weeks => "k",
|
47
|
-
:holdings_gain_percent => "g1",
|
48
|
-
:annualized_gain => "g3",
|
49
|
-
:holdings_gain => "g4",
|
50
|
-
:holdings_gain_percent_realtime => "g5",
|
51
|
-
:holdings_gain_realtime => "g6",
|
52
|
-
:more_info => "i",
|
53
|
-
:order_book => "i5",
|
54
|
-
:market_capitalization => "j1",
|
55
|
-
:market_cap_realtime => "j3",
|
56
|
-
:ebitda => "j4",
|
57
|
-
:change_From_52_week_low => "j5",
|
58
|
-
:percent_change_from_52_week_low => "j6",
|
59
|
-
:last_trade_realtime_withtime => "k1",
|
60
|
-
:change_percent_realtime => "k2",
|
61
|
-
:last_trade_size => "k3",
|
62
|
-
:change_from_52_week_high => "k4",
|
63
|
-
:percent_change_from_52_week_high => "k5",
|
64
|
-
:last_trade_with_time => "l",
|
65
|
-
:last_trade_price => "l1",
|
66
|
-
:close => "l1",
|
67
|
-
:high_limit => "l2",
|
68
|
-
:low_limit => "l3",
|
69
|
-
:days_range => "m",
|
70
|
-
:days_range_realtime => "m2",
|
71
|
-
:moving_average_50_day => "m3",
|
72
|
-
:moving_average_200_day => "m4",
|
73
|
-
:change_from_200_day_moving_average => "m5",
|
74
|
-
:percent_change_from_200_day_moving_average => "m6",
|
75
|
-
:change_from_50_day_moving_average => "m7",
|
76
|
-
:percent_change_from_50_day_moving_average => "m8",
|
77
|
-
:name => "n",
|
78
|
-
:notes => "n4",
|
79
|
-
:open => "o",
|
80
|
-
:previous_close => "p",
|
81
|
-
:price_paid => "p1",
|
82
|
-
:change_in_percent => "p2",
|
83
|
-
:price_per_sales => "p5",
|
84
|
-
:price_per_book => "p6",
|
85
|
-
:ex_dividend_date => "q",
|
86
|
-
:pe_ratio => "r",
|
87
|
-
:dividend_pay_date => "r1",
|
88
|
-
:pe_ratio_realtime => "r2",
|
89
|
-
:peg_ratio => "r5",
|
90
|
-
:price_eps_estimate_current_year => "r6",
|
91
|
-
:price_eps_Estimate_next_year => "r7",
|
92
|
-
:symbol => "s",
|
93
|
-
:shares_owned => "s1",
|
94
|
-
:short_ratio => "s7",
|
95
|
-
:last_trade_time => "t1",
|
96
|
-
:trade_links => "t6",
|
97
|
-
:ticker_trend => "t7",
|
98
|
-
:one_year_target_price => "t8",
|
99
|
-
:volume => "v",
|
100
|
-
:holdings_value => "v1",
|
101
|
-
:holdings_value_realtime => "v7",
|
102
|
-
:weeks_range_52 => "w",
|
103
|
-
:day_value_change => "w1",
|
104
|
-
:day_value_change_realtime => "w4",
|
105
|
-
:stock_exchange => "x",
|
106
|
-
:dividend_yield => "y",
|
107
|
-
:adjusted_close => nil # this one only comes in historical quotes
|
108
|
-
}
|
109
|
-
|
110
|
-
HISTORICAL_MODES = {
|
111
|
-
:daily => "d",
|
112
|
-
:weekly => "w",
|
113
|
-
:monthly => "m",
|
114
|
-
:dividends_only => "v"
|
115
|
-
}
|
116
|
-
|
117
|
-
SYMBOLS_PER_REQUEST = 50
|
118
|
-
|
119
|
-
# retrieve the quote data (an OpenStruct per quote)
|
120
|
-
# the options param can be used to specify the following attributes:
|
121
|
-
# :raw - if true, each column will be converted (to numbers, dates, etc)
|
122
|
-
def self.quotes(symbols_array, columns_array = [:symbol, :last_trade_price, :last_trade_date, :change, :previous_close], options = { })
|
123
|
-
options[:raw] ||= true
|
124
|
-
|
125
|
-
ret = []
|
126
|
-
symbols_array.each_slice(SYMBOLS_PER_REQUEST) do |symbols|
|
127
|
-
read_quotes(symbols.join("+"), columns_array).map do |row|
|
128
|
-
ret << OpenStruct.new(row.to_hash)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
ret
|
132
|
-
end
|
133
|
-
|
134
|
-
def self.quote(symbol, columns_array = [:symbol, :last_trade_price, :last_trade_date, :change, :previous_close], options = { })
|
135
|
-
options[:raw] ||= true
|
136
|
-
quotes([symbol], columns_array, options).first
|
137
|
-
end
|
138
|
-
|
139
|
-
def self.historical_quotes(symbol, options = {})
|
140
|
-
options[:raw] ||= true
|
141
|
-
options[:period] ||= :daily
|
142
|
-
read_historical(symbol, options).map do |row|
|
143
|
-
OpenStruct.new(row.to_hash.merge(:symbol => symbol))
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
def self.symbols(query)
|
148
|
-
ret = []
|
149
|
-
read_symbols(query).each do |row|
|
150
|
-
ret << OpenStruct.new(row)
|
151
|
-
end
|
152
|
-
ret
|
153
|
-
end
|
154
|
-
|
155
|
-
def self.splits(symbol, options = {})
|
156
|
-
rows = read_splits(symbol, options).select{|row| row[0] == 'SPLIT'}
|
157
|
-
rows.map do |row|
|
158
|
-
type, date, value = row
|
159
|
-
after, before = value.split(':')
|
160
|
-
OpenStruct.new(:symbol => symbol, :date => Date.strptime(date.strip, '%Y%m%d'), :before => before.to_i, :after => after.to_i)
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
private
|
165
|
-
|
166
|
-
def self.read_quotes(symb_str, cols)
|
167
|
-
columns = "#{cols.map {|col| COLUMNS[col] }.join('')}"
|
168
|
-
conn = open("http://download.finance.yahoo.com/d/quotes.csv?s=#{URI.escape(symb_str)}&f=#{columns}")
|
169
|
-
CSV.parse(conn.read, :headers => cols)
|
170
|
-
end
|
171
|
-
|
172
|
-
def self.read_historical(symbol, options)
|
173
|
-
params = {
|
174
|
-
:s => URI.escape(symbol),
|
175
|
-
:g => HISTORICAL_MODES[options[:period]],
|
176
|
-
:ignore => '.csv',
|
177
|
-
}
|
178
|
-
if options[:start_date]
|
179
|
-
params[:a] = options[:start_date].month-1
|
180
|
-
params[:b] = options[:start_date].day
|
181
|
-
params[:c] = options[:start_date].year
|
182
|
-
end
|
183
|
-
if options[:end_date]
|
184
|
-
params[:d] = options[:end_date].month-1
|
185
|
-
params[:e] = options[:end_date].day
|
186
|
-
params[:f] = options[:end_date].year
|
187
|
-
end
|
188
|
-
|
189
|
-
url = "http://ichart.finance.yahoo.com/table.csv?#{params.map{|k, v| "#{k}=#{v}"}.join('&')}"
|
190
|
-
conn = open(url)
|
191
|
-
cols =
|
192
|
-
if options[:period] == :dividends_only
|
193
|
-
[:dividend_pay_date, :dividend_yield]
|
194
|
-
else
|
195
|
-
[:trade_date, :open, :high, :low, :close, :volume, :adjusted_close]
|
196
|
-
end
|
197
|
-
result = CSV.parse(conn.read, :headers => cols) #:first_row, :header_converters => :symbol)
|
198
|
-
result.delete(0) # drop returned header
|
199
|
-
result
|
200
|
-
end
|
201
|
-
|
202
|
-
def self.read_splits(symbol, options)
|
203
|
-
params = {
|
204
|
-
:s => URI.escape(symbol),
|
205
|
-
:g => 'v'
|
206
|
-
}
|
207
|
-
if options[:start_date]
|
208
|
-
params[:a] = options[:start_date].month-1
|
209
|
-
params[:b] = options[:start_date].day
|
210
|
-
params[:c] = options[:start_date].year
|
211
|
-
end
|
212
|
-
if options[:end_date]
|
213
|
-
params[:d] = options[:end_date].month-1
|
214
|
-
params[:e] = options[:end_date].day
|
215
|
-
params[:f] = options[:end_date].year
|
216
|
-
end
|
217
|
-
|
218
|
-
url = "http://ichart.finance.yahoo.com/x?#{params.map{|k, v| "#{k}=#{v}"}.join('&')}"
|
219
|
-
conn = open(url)
|
220
|
-
CSV.parse(conn.read)
|
221
|
-
end
|
222
|
-
|
223
|
-
def self.read_symbols(query)
|
224
|
-
conn = open("http://d.yimg.com/autoc.finance.yahoo.com/autoc?query=#{query}&callback=YAHOO.Finance.SymbolSuggest.ssCallback")
|
225
|
-
result = conn.read
|
226
|
-
result.sub!('YAHOO.Finance.SymbolSuggest.ssCallback(', '').chomp!(')')
|
227
|
-
json_result = JSON.parse(result)
|
228
|
-
json_result["ResultSet"]["Result"]
|
229
|
-
end
|
230
|
-
|
231
|
-
end
|