yahoo_finance_lib 0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +51 -0
- data/Rakefile +1 -0
- data/lib/yahoo_finance.rb +8 -0
- data/lib/yahoo_finance/analyst_opinion.rb +88 -0
- data/lib/yahoo_finance/company_events.rb +41 -0
- data/lib/yahoo_finance/key_statistics.rb +122 -0
- data/lib/yahoo_finance/stock.rb +232 -0
- data/lib/yahoo_finance/version.rb +3 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/yahoo_analyst_opinion_spec.rb +20 -0
- data/spec/yahoo_company_events_spec.rb +26 -0
- data/spec/yahoo_finance_spec.rb +91 -0
- data/spec/yahoo_key_stats_spec.rb +21 -0
- data/yahoo_finance.gemspec +26 -0
- metadata +155 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9afd058d869ba5ada9ed3379d38e22eabe9efad5
|
4
|
+
data.tar.gz: 7e17d093ac49cf799c3a7b1c4aced1b3fbd2ff8a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b6de89a90b27f851f7d85af6ca8ce0e08722022919c3d402eeb0d356b59feb847c2c30230d4cd70127cc4764df67bb672563f93a61bb4e279e5ab89479f4080d
|
7
|
+
data.tar.gz: 67127365095889c951d9250f2c3eda19a506b34f8b191e7e45f983f694cc56c9f996171f7fd2d9ea4caeb21d11fd0e8bbd2de1737641d0d13731f5a885eb9945
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Takis Mercouris
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# YahooFinanceStock
|
2
|
+
|
3
|
+
YahooFinance lib is a gem that fetches stock quotes, key statistics, company events, and analyst opinion from Yahoo (TM) API and financial HTML pages. The loading of stock quotes uses the excellent nas/yahoo_stock gem. This gem provides a 'unified' attribute based interface, and abstracts the source of the information, i.e. the user only needs to specify an attribute without the need to specify the page source of the attribute. This gem leverages to the highest extend possible the YahooStock (yahoo_stock_nas) gem for all the attributes provided by that gem, and fails over to HTML scraping when the data is unavailable there. Naturally, this has an implication on performance; YahooStock queries bundle 50 stocks in each query, whereas HTML scraping happens one page per stock at a time.
|
4
|
+
|
5
|
+
#####This gem is currently still in development. HTML scraping now supports many attributes from Key Statistics, supports earnings announcements from the Company Events page, and most attributes from Analyst Opinion -- additional pages will be added as I find time.
|
6
|
+
|
7
|
+
#####Caveat: HTML parsing is susceptible to HTML encoding of Yahoo Finance pages; when these pages change, parsing will break. Core Yahoo API attributes from YahooStock will entirely depend on YahooStock continuing to support the Yahoo APIs.
|
8
|
+
|
9
|
+
#####Use the code entirely at your own risk, and subject to copyright & trademark restrictions on Yahoo Finance(TM). I am quite sure that are additional Yahoo restrictions which you will need to investigate (http://finance.yahoo.com/badges/tos). From past experience I know you cannot redistribute Yahoo Finance data, or use it for commercial purposes.
|
10
|
+
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
gem 'yahoo_finance_lib'
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle update
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install yahoo_finance_lib
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
Note that
|
29
|
+
|
30
|
+
Example:
|
31
|
+
irb
|
32
|
+
require 'rubygems'
|
33
|
+
require 'yahoo_finance'
|
34
|
+
|
35
|
+
stock = YahooFinance::Stock.new(['AAPL', 'YHOO'], [:market_cap, :bid, :brokers_count, :upgrades_downgrades_history])
|
36
|
+
# look at available fields you could fetch with this library
|
37
|
+
stock.available_fields
|
38
|
+
|
39
|
+
stock.add_field(:last_trade_price_only)
|
40
|
+
|
41
|
+
results = stock.fetch
|
42
|
+
aapl_bid = results["AAPL"][:bid]
|
43
|
+
yhoo_last = results["YHOO"][:last_trade_price_only]
|
44
|
+
|
45
|
+
!-- ## Contributing
|
46
|
+
|
47
|
+
1. Fork it
|
48
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
49
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
50
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
51
|
+
5. Create new Pull Request -->
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module YahooFinance
|
5
|
+
module AnalystOpinion
|
6
|
+
AVL_KEY_STATS = {
|
7
|
+
:mean_recommendation_this_week => ['Mean Recommendation (this week):', "Mean Recommendation (this week):"],
|
8
|
+
:mean_recommendation_last_week => ['Mean Recommendation (last week):', "Mean Recommendation (last week):"],
|
9
|
+
:price_target_mean => ['Mean Target:', 'Mean Price Target'],
|
10
|
+
:price_target_median => ['Median Target:', 'Meadian Price Target'],
|
11
|
+
:price_target_high => ['High Target:', 'High Price Target'],
|
12
|
+
:price_target_low => ['Low Target:', 'Low Price Target'],
|
13
|
+
:brokers_count => ['No. of Brokers:', 'Number of Brokers with recommendations'],
|
14
|
+
:upgrades_downgrades_history => ["", 'Upgrades/Downgrades History'],
|
15
|
+
:recommendation_trends => ["", "Recommendation Trends - current, 1 month ago, 2 months ago, and 3 months ago"]
|
16
|
+
}
|
17
|
+
def AnalystOpinion.key_events_available
|
18
|
+
return AVL_KEY_STATS.keys;
|
19
|
+
end
|
20
|
+
|
21
|
+
class AnalystOpinionPage
|
22
|
+
@symbol
|
23
|
+
|
24
|
+
def initialize symbol
|
25
|
+
@symbol = symbol
|
26
|
+
end
|
27
|
+
|
28
|
+
def fetch
|
29
|
+
url = "http://finance.yahoo.com/q/ao?s=#{@symbol}"
|
30
|
+
open(url) do |stream|
|
31
|
+
@doc = Nokogiri::HTML(stream)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def value_for key_stat
|
36
|
+
begin
|
37
|
+
if key_stat == :upgrades_downgrades_history
|
38
|
+
ret = []
|
39
|
+
tbl = @doc.xpath("//th[text() = 'Upgrades & Downgrades History']")[0].parent.parent.parent.children[1].xpath("tr")
|
40
|
+
for i in 1..(tbl.size-1) do
|
41
|
+
r = {}
|
42
|
+
r[:date] = YahooFinance.parse_yahoo_field(tbl[i].children[0].text)
|
43
|
+
r[:firm] = tbl[i].children[1].text
|
44
|
+
r[:action] = tbl[i].children[2].text
|
45
|
+
r[:from] = tbl[i].children[3].text
|
46
|
+
r[:to] = tbl[i].children[4].text
|
47
|
+
ret << r
|
48
|
+
end
|
49
|
+
return ret
|
50
|
+
end
|
51
|
+
if key_stat == :recommendation_trends
|
52
|
+
ret = {}
|
53
|
+
tbl1 = @doc.xpath("//th[text() = 'Recommendation Trends']")[0].parent.parent
|
54
|
+
elem = tbl1.parent
|
55
|
+
sibling_idx = elem.children.index(tbl1)+1
|
56
|
+
sibling = elem.children[sibling_idx]
|
57
|
+
# now get all the subnodes...
|
58
|
+
table_rows = sibling.xpath(".//table//tr") # really contained within a subtable
|
59
|
+
for i in 1..(table_rows.size-1) do
|
60
|
+
r = table_rows[i]
|
61
|
+
header = r.xpath(".//th")
|
62
|
+
symbol = header[0].text.gsub(' ','').to_sym
|
63
|
+
cells = r.xpath(".//td")
|
64
|
+
ar = []
|
65
|
+
cells.each do |cell|
|
66
|
+
begin
|
67
|
+
ar << YahooFinance.parse_yahoo_field(cell.text)
|
68
|
+
rescue
|
69
|
+
puts " COULD NOT PARSE NUMERIC TREND CELL"
|
70
|
+
ar << " "
|
71
|
+
end
|
72
|
+
end
|
73
|
+
ret[symbol] = ar
|
74
|
+
# THIS IS NOT WORKING YET. THE LOGIC IS FALSE
|
75
|
+
end
|
76
|
+
return ret
|
77
|
+
end
|
78
|
+
if [:upgrades_downgrades_history, :recommendation_trends].include?(key_stat) == false
|
79
|
+
value = @doc.xpath("//td[text() = '#{AVL_KEY_STATS[key_stat][0]}']")[0].parent.children[1].text
|
80
|
+
return YahooFinance.parse_yahoo_field(value)
|
81
|
+
end
|
82
|
+
rescue
|
83
|
+
end
|
84
|
+
return nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module YahooFinance
|
5
|
+
module CompanyEvents
|
6
|
+
COMPANY_EVENTS_STATS = {
|
7
|
+
:next_earnings_announcement_date => ['Earnings announcement', "Next earnings call date"]
|
8
|
+
}
|
9
|
+
def CompanyEvents.key_events_available
|
10
|
+
return YahooFinance::CompanyEvents::COMPANY_EVENTS_STATS.keys;
|
11
|
+
end
|
12
|
+
|
13
|
+
class CompanyEventsPage
|
14
|
+
@symbol
|
15
|
+
|
16
|
+
def initialize symbol
|
17
|
+
@symbol = symbol
|
18
|
+
end
|
19
|
+
|
20
|
+
def fetch
|
21
|
+
url = "http://finance.yahoo.com/q/ce?s=#{@symbol}"
|
22
|
+
open(url) do |stream|
|
23
|
+
@doc = Nokogiri::HTML(stream)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def value_for key_stat
|
28
|
+
begin
|
29
|
+
if key_stat == :next_earnings_announcement_date
|
30
|
+
if @doc.css('table#yfncsumtab//table.yfnc_datamodoutline1//table//td.yfnc_tabledata1')[1].text == "Earnings announcement"
|
31
|
+
return YahooFinance.parse_yahoo_field(@doc.css('table#yfncsumtab//table.yfnc_datamodoutline1//table//td.yfnc_tabledata1')[0].text)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
rescue
|
35
|
+
end
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module YahooFinance
|
5
|
+
module KeyStatistics
|
6
|
+
AVL_KEY_STATS = {
|
7
|
+
# String_to_parse, Description, Source Value format factor (some values are in % but dont't show %)
|
8
|
+
:market_cap => ['Market Cap ', "Market Cap, intraday"],
|
9
|
+
:enterprise_value => ['Enterprise Value ', "Enterprise Value"],
|
10
|
+
:trailing_pe => ['Trailing P\/E \(ttm\, intraday\)\:', "Trailing PE, trailing twelve months, intraday (based on price)"],
|
11
|
+
:forward_pe => ['Forward P\/E ', "Forward P/E"],
|
12
|
+
:peg_ratio => ['PEG Ratio ', "PEG Ratio (5 year expected (forward looking))"],
|
13
|
+
:price_to_sales_ttm => ['Price\/Sales \(ttm\)\:', "Price/Sales, trailing 12 months"],
|
14
|
+
:price_to_book_mrq => ['Price\/Book \(mrq\):', "Price/Book, most recent quarter"],
|
15
|
+
:roa_ttm => ['Return on Assets \(ttm\)\:', "Return on Assets, trailing twelve months"],
|
16
|
+
:roe_ttm => ['Return on Equity \(ttm\)\:', "Return on Equity, trailing twelve months"],
|
17
|
+
:book_value_per_share_mrq => ['Book Value Per Share \(mrq\):', "Book Value per share, most recent quarter"],
|
18
|
+
# Income Statement
|
19
|
+
:revenue_ttm => ['Revenue \(ttm\)\:', "Revenue, trailing twelve months"],
|
20
|
+
:revenue_per_share_ttm => ['Revenue Per Share \(ttm\)\:', "Revenue per share, trailing twelve months"],
|
21
|
+
:qtrly_revenue_growth_yoy => ['Qtrly Revenue Growth \(yoy\)\:', "Quarterly Revenue Growth, year on year"],
|
22
|
+
:diluted_eps_ttm => ['Diluted EPS \(ttm\)\:', "Diluted Earnings per share, trailing twelve months"],
|
23
|
+
:qtrly_earnings_growth_yoy => ['Qtrly Earnings Growth \(yoy\)\:', "Quarterly Earnings Growth, year on year"],
|
24
|
+
# Balance Sheet
|
25
|
+
:total_cash_mrq => ['Total Cash \(mrq\)\:', "Total Cash, most recent quarter"],
|
26
|
+
:total_cash_per_share_mrq => ['Total Cash Per Share \(mrq\)\:', "Total Cash per Share, most recent quarter"],
|
27
|
+
:total_debt_mrq => ['Total Debt (mrq):', "Total Debt, most recent quarter"],
|
28
|
+
:total_debt_to_equity_mrq => ['Total Debt/Equity \(mrq\)\:', "Total Debt/Equity (expressed as a percentage), most recent quarter", 0.01],
|
29
|
+
:current_ratio_mrq => ['Current Ratio \(mrq\)\:', "Total Current Assets / Total Current Liabilities, most recent quarter"],
|
30
|
+
:book_value_per_share_mrq => ['Book Value Per Share \(mrq\)\:', "Total Common Equity / Total Common Shares Outstanding, most recent quarter"],
|
31
|
+
# Trading additional info:
|
32
|
+
:beta => ['Beta\:', "Equity monthly beta relative to S&P500. Uses 36 months when available."],
|
33
|
+
# Share Statistics
|
34
|
+
:shares_outstanding => ['Shares Outstanding', "Number of outstanding shares"],
|
35
|
+
:pcnt_held_by_insiders => ['\% Held by Insiders', "Percent of shares held by insiders (returned as a fraction of 1)"],
|
36
|
+
:pcnt_held_by_institutions => ['\% Held by Institutions', "Percent of shares held by institutions (returned as a fraction of 1)"],
|
37
|
+
:pcnt_short_of_float => ['Short % of Float \(', "Percent of shares shorted relative to total (returned as a fraction of 1)"],
|
38
|
+
# Cash Flow
|
39
|
+
:operating_cash_flow_ttm => ['Operating Cash Flow \(ttm\)\:', "Operating cash flow, trailing twelve months"],
|
40
|
+
:levered_cash_flow_ttm => ['Levered Free Cash Flow \(ttm\)\:', "Levered Free Cash Flow, trailing 12 months: (EBIT + Interest Expense) x (1 x Tax Rate) + Depreciation & Amort., Total + Other Amortization + Capital Expenditure + Sale (Purchase) of Intangible assets - Change in Net Working Capital + Pref. Dividends Paid + Total Debt Repaid + Total Debt Issued + Repurchase of Preferred + Issuance of Preferred Stock"]
|
41
|
+
# ,
|
42
|
+
# # Profitability
|
43
|
+
# :Profit_Margin,
|
44
|
+
# :Operating_Margin,
|
45
|
+
# # Mgt Effectiveness
|
46
|
+
# :Return_on_Assets,
|
47
|
+
# :Return_on_Equity,
|
48
|
+
# # Income Stmt
|
49
|
+
# :Qtrly_Revenue_Growth_yoy,
|
50
|
+
# :EBITDA,
|
51
|
+
# :Qtrly_Earnings_Growth_yoy,
|
52
|
+
# # Balance Sheet
|
53
|
+
# :Total_Cash_mrq,
|
54
|
+
# :Total_Debt_mrq,
|
55
|
+
# :Total_Debt_to_Equity_mrq,
|
56
|
+
# :Book_Value_per_share_mrq,
|
57
|
+
# :Total_Assets_to_Total_Liabilities,
|
58
|
+
# # Shares
|
59
|
+
# :Shares_Outstanding,
|
60
|
+
# :Pcnt_Shares_Held_by_Insiders,
|
61
|
+
# :Pcnt_Shares_Held_by_Institutions,
|
62
|
+
# :Shares_Short,
|
63
|
+
# :Shares_Short_Date,
|
64
|
+
# :Short_Ratio,
|
65
|
+
# :Shares_Short_prior_month,
|
66
|
+
# # Dividends
|
67
|
+
# :Fwd_Annual_Dividend_Yield,
|
68
|
+
# :Trailing_Annual_Dividend_Yield,
|
69
|
+
# :Five_Year_Average_Dividend_Yield,
|
70
|
+
# :Next_Ex_Dividend_Date,
|
71
|
+
# :Next_Dividend_Date
|
72
|
+
}
|
73
|
+
def KeyStatistics.key_stats_available
|
74
|
+
return AVL_KEY_STATS.keys;
|
75
|
+
end
|
76
|
+
|
77
|
+
class StatsPage
|
78
|
+
@page_keys = []
|
79
|
+
@page_values = []
|
80
|
+
@symbol
|
81
|
+
|
82
|
+
def initialize symbol
|
83
|
+
@symbol = symbol
|
84
|
+
end
|
85
|
+
|
86
|
+
def fetch
|
87
|
+
url = "http://finance.yahoo.com/q/ks?s=#{@symbol}"
|
88
|
+
begin
|
89
|
+
tries ||= 3
|
90
|
+
open(url) do |stream|
|
91
|
+
doc = Nokogiri::HTML(stream)
|
92
|
+
# puts "DATA IS: #{data}"
|
93
|
+
@page_keys = doc.xpath('//td[@class="yfnc_tablehead1"]')
|
94
|
+
@page_values = doc.xpath('//td[@class="yfnc_tabledata1"]')
|
95
|
+
end
|
96
|
+
rescue Exception => e
|
97
|
+
puts "Failed to open and parse key stats for #{@symbol} because of #{e.message}. #{(tries > 0) ? 'retrying' : ''}"
|
98
|
+
if (tries -= 1) > 0
|
99
|
+
retry
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def value_for key_stat
|
105
|
+
return nil if !@page_keys
|
106
|
+
|
107
|
+
matchstr = "#{AVL_KEY_STATS[key_stat][0]}"
|
108
|
+
@page_keys.each_with_index do |key, i|
|
109
|
+
if key.text.match(/^#{AVL_KEY_STATS[key_stat][0]}/)
|
110
|
+
value = YahooFinance.parse_yahoo_field @page_values[i].text.to_s
|
111
|
+
if AVL_KEY_STATS[key_stat][2]
|
112
|
+
value *= AVL_KEY_STATS[key_stat][2]
|
113
|
+
end
|
114
|
+
return value
|
115
|
+
end
|
116
|
+
end
|
117
|
+
return nil
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
|
2
|
+
require 'yahoo_stock'
|
3
|
+
require 'yahoo_finance/key_statistics'
|
4
|
+
require 'yahoo_finance/company_events'
|
5
|
+
require 'yahoo_finance/analyst_opinion'
|
6
|
+
|
7
|
+
|
8
|
+
module YahooFinance
|
9
|
+
AVL_FIELDS = {
|
10
|
+
:YAHOO_STOCK_FIELDS => YahooStock::Quote.new(:stock_symbols => ['AAPL']).valid_parameters,
|
11
|
+
:KEY_STATISTICS => YahooFinance::KeyStatistics.key_stats_available,
|
12
|
+
:COMPANY_EVENTS => YahooFinance::CompanyEvents.key_events_available,
|
13
|
+
:ANALYST_OPINION => YahooFinance::AnalystOpinion.key_events_available
|
14
|
+
}
|
15
|
+
DRIVERS = {
|
16
|
+
:KEY_STATISTICS => YahooFinance::KeyStatistics::StatsPage,
|
17
|
+
:COMPANY_EVENTS => YahooFinance::CompanyEvents::CompanyEventsPage,
|
18
|
+
:ANALYST_OPINION => YahooFinance::AnalystOpinion::AnalystOpinionPage
|
19
|
+
}
|
20
|
+
|
21
|
+
# We are not interested parsing every type of field
|
22
|
+
# Key Fields: number (that may include , for 000s separator, NOT SUPPORTED YET), scaled number
|
23
|
+
# percentage, date
|
24
|
+
def YahooFinance.parse_yahoo_field aField
|
25
|
+
# we really need to oarse numbers, dates, and strings %%% STUB ALERT %%%%
|
26
|
+
|
27
|
+
aField.strip!
|
28
|
+
|
29
|
+
if aField.match /^([\-\+]{,1})([\d\,])*(\.[\d]+)*$/
|
30
|
+
# it's a number as far as we care; let's strip the commas....
|
31
|
+
aField.gsub! /\,/, ''
|
32
|
+
end
|
33
|
+
|
34
|
+
m=aField.match /^([\-\+]{0,1})([\d]*)(\.[\d]{1,})([KMB\%]{0,1})$/
|
35
|
+
if m # && (m.size == 3)
|
36
|
+
num = ((m[1] || "")+(m[2] || "")+(m[3] || "")).to_f
|
37
|
+
|
38
|
+
case m[4]
|
39
|
+
when "K" then
|
40
|
+
num *= 1000
|
41
|
+
# puts "NUM got K = #{num.to_s}"
|
42
|
+
when "M" then
|
43
|
+
num *= 1000000
|
44
|
+
# puts "NUM got B = #{num.to_s}"
|
45
|
+
when "B" then
|
46
|
+
num *= 1000000000
|
47
|
+
# puts "NUM got B = #{num.to_s}"
|
48
|
+
when '%' then
|
49
|
+
num /= 100
|
50
|
+
# puts "NUM got % = #{num.to_s}"
|
51
|
+
end
|
52
|
+
return num
|
53
|
+
end
|
54
|
+
|
55
|
+
if aField.match /^([\-\+]*[0-9]*)(\.[0-9]*)*$/
|
56
|
+
# simple number
|
57
|
+
return aField.to_f
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
m=aField.match /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[\s]+([\d]{1,2})\,[\s]*([\d]{4})$/
|
62
|
+
if m
|
63
|
+
# got a date
|
64
|
+
dt = nil
|
65
|
+
begin
|
66
|
+
dt = Date.strptime aField, '%b %d, %Y'
|
67
|
+
rescue
|
68
|
+
end
|
69
|
+
return dt if dt
|
70
|
+
end
|
71
|
+
|
72
|
+
#else make an attempt to parse as date
|
73
|
+
dt = nil
|
74
|
+
begin
|
75
|
+
dt = Date.parse(aField)
|
76
|
+
rescue
|
77
|
+
end
|
78
|
+
return dt if dt
|
79
|
+
|
80
|
+
aField
|
81
|
+
end
|
82
|
+
|
83
|
+
class Stock
|
84
|
+
@@available_fields = (AVL_FIELDS[:YAHOO_STOCK_FIELDS] + AVL_FIELDS[:KEY_STATISTICS] + AVL_FIELDS[:COMPANY_EVENTS] + AVL_FIELDS[:ANALYST_OPINION])
|
85
|
+
@@insert_variable_delays = true
|
86
|
+
@@insert_variable_delay = 4
|
87
|
+
@@retry_times = 3
|
88
|
+
@@retry_variable_delay = 30
|
89
|
+
@symbols = []
|
90
|
+
@fields = []
|
91
|
+
@fields_hash = {}
|
92
|
+
@results_hash = {}
|
93
|
+
|
94
|
+
def self.insert_variable_delays
|
95
|
+
@@insert_variable_delays
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.insert_variable_delays= trueFalse
|
99
|
+
@@insert_variable_delays = trueFalse
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.insert_variable_delay
|
103
|
+
@@insert_variable_delay
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.insert_variable_delay= aDelay
|
107
|
+
@@insert_variable_delay = aDelay
|
108
|
+
end
|
109
|
+
|
110
|
+
def initialize(symbols, fields = nil)
|
111
|
+
@symbols = symbols
|
112
|
+
@fields = []
|
113
|
+
if fields
|
114
|
+
fields.each do |aField|
|
115
|
+
add_field aField
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def symbols
|
121
|
+
return @symbols
|
122
|
+
end
|
123
|
+
|
124
|
+
def fields
|
125
|
+
return @fields
|
126
|
+
end
|
127
|
+
|
128
|
+
def available_fields
|
129
|
+
@@available_fields
|
130
|
+
end
|
131
|
+
|
132
|
+
# NOTE -- UPDATE THIS WHEN YOU ADD A NEW PAGE %%
|
133
|
+
def available_fields_and_descriptions
|
134
|
+
ysh = {}; YahooFinance::AVL_FIELDS[:YAHOO_STOCK_FIELDS].each { |field| ysh[field] = "" }
|
135
|
+
ysh.merge(YahooFinance::KeyStatistics::AVL_KEY_STATS).merge(YahooFinance::CompanyEvents::AVL_KEY_STATS)
|
136
|
+
end
|
137
|
+
|
138
|
+
def add_symbol(aSymbol)
|
139
|
+
aSymbol = aSymbol.strip || ""
|
140
|
+
@symbols << aSymbol if (aSymbol != "" && (@symbols.include?(aSymbol) == false))
|
141
|
+
end
|
142
|
+
|
143
|
+
def add_field(aField)
|
144
|
+
if @@available_fields.include? aField
|
145
|
+
@fields << aField
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def fetch
|
150
|
+
allocate_fields_to_connections
|
151
|
+
# initialize symbol rows
|
152
|
+
@results_hash = {}
|
153
|
+
@symbols.each do |aSymbol|
|
154
|
+
@results_hash[aSymbol.upcase] = {} # we do this to avoid problems with symbols misstyped with mixed upper/lower case
|
155
|
+
end
|
156
|
+
|
157
|
+
# First we fetch symbols under YAHOO_STOCK_FIELDS
|
158
|
+
if @fields_hash[:YAHOO_STOCK_FIELDS].size > 0
|
159
|
+
# puts "SYMBOLS ARE: #{@symbols.to_s} AND PARAMETERS: #{@fields_hash[:YAHOO_STOCK_FIELDS].to_s}"
|
160
|
+
|
161
|
+
# Yahoo Stock API has some limits, therefore, we need to chunk the symbols
|
162
|
+
@symbols.each_slice(50).to_a.each do |symbol_slice|
|
163
|
+
|
164
|
+
qt = YahooStock::Quote.new(:stock_symbols => symbol_slice)
|
165
|
+
qt.add_parameters(:symbol)
|
166
|
+
@fields_hash[:YAHOO_STOCK_FIELDS].each do |aField|
|
167
|
+
qt.add_parameters(aField)
|
168
|
+
end
|
169
|
+
|
170
|
+
yshs = qt.results(:to_hash).output
|
171
|
+
@fields_hash[:YAHOO_STOCK_FIELDS].each do |aField|
|
172
|
+
yshs.each do |aSymbolRow|
|
173
|
+
symbol = aSymbolRow[:symbol]
|
174
|
+
value = aSymbolRow[aField]
|
175
|
+
begin
|
176
|
+
@results_hash[symbol][aField] = YahooFinance.parse_yahoo_field(value)
|
177
|
+
rescue Exception => e
|
178
|
+
puts "Failed in symbol #{symbol.to_s} field #{aField.to_s} value #{(value || "NULL").to_s}"
|
179
|
+
puts "RESULT ROW: #{aSymbolRow.to_s}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
sleep(Random.new(Random.new_seed).rand*@@insert_variable_delay) if @@insert_variable_delays
|
184
|
+
end
|
185
|
+
end
|
186
|
+
# Then we fetch fields from KEY STATISTICS
|
187
|
+
DRIVERS.keys.each do |driver|
|
188
|
+
# puts "CHECKING #{driver.to_s}"
|
189
|
+
if @fields_hash[driver].size > 0
|
190
|
+
# puts "FETCHING FIELDS FOR #{driver.to_s}"
|
191
|
+
@symbols.each do |aSymbol|
|
192
|
+
tries = 0
|
193
|
+
begin
|
194
|
+
stp = DRIVERS[driver].new(aSymbol)
|
195
|
+
stp.fetch
|
196
|
+
@fields_hash[driver].each do |aField|
|
197
|
+
value = stp.value_for(aField) # this already parses the numbers
|
198
|
+
@results_hash[aSymbol][aField] = value
|
199
|
+
end
|
200
|
+
sleep(Random.new(Random.new_seed).rand*@@insert_variable_delay) if @@insert_variable_delays
|
201
|
+
rescue
|
202
|
+
tries += 1
|
203
|
+
sleep(@@retry_variable_delay)
|
204
|
+
retry if tries <= @@retry_times
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
@results_hash
|
210
|
+
end
|
211
|
+
|
212
|
+
def allocate_fields_to_connections
|
213
|
+
@fields_hash = {}
|
214
|
+
AVL_FIELDS.keys.each do |driver|
|
215
|
+
@fields_hash[driver] = []
|
216
|
+
end
|
217
|
+
|
218
|
+
@fields.each do |aField|
|
219
|
+
if AVL_FIELDS[:YAHOO_STOCK_FIELDS].include? aField
|
220
|
+
@fields_hash[:YAHOO_STOCK_FIELDS] << aField
|
221
|
+
else
|
222
|
+
DRIVERS.keys.each do |driver|
|
223
|
+
# puts "CHECKING DRIVER: #{driver} for field #{aField}"
|
224
|
+
if AVL_FIELDS[driver].include? aField
|
225
|
+
@fields_hash[driver] << aField
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe YahooFinance::AnalystOpinion do
|
4
|
+
# before(:each) do
|
5
|
+
# @tsymbols = ['AAPL', 'DDD']
|
6
|
+
# @page = YahooFinance::Page.new(@tsymbols)
|
7
|
+
# end
|
8
|
+
|
9
|
+
describe "Analyst Opinion" do
|
10
|
+
it "available stats should include things like :brokers_count" do
|
11
|
+
YahooFinance::AnalystOpinion.key_events_available.include?(:brokers_count).should == true
|
12
|
+
end
|
13
|
+
it "should fetch a stat like :brokers_count for AAPL and should greater than zero" do
|
14
|
+
pg = YahooFinance::AnalystOpinion::AnalystOpinionPage.new('AAPL')
|
15
|
+
pg.fetch
|
16
|
+
aapl_brokers_count = pg.value_for :brokers_count
|
17
|
+
aapl_brokers_count.should > 0
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe YahooFinance::CompanyEvents do
|
4
|
+
# before(:each) do
|
5
|
+
# @tsymbols = ['AAPL', 'DDD']
|
6
|
+
# @page = YahooFinance::Page.new(@tsymbols)
|
7
|
+
# end
|
8
|
+
|
9
|
+
describe "Company Events" do
|
10
|
+
it "available stats should include things like :next_earnings_announcement_date" do
|
11
|
+
YahooFinance::CompanyEvents.key_events_available.include?(:next_earnings_announcement_date).should == true
|
12
|
+
end
|
13
|
+
it "should fetch a stat like :next_earnings_announcement_date for AAPL and should be either Date or String" do
|
14
|
+
pg = YahooFinance::CompanyEvents::CompanyEventsPage.new('AAPL')
|
15
|
+
pg.fetch
|
16
|
+
aapl_next_earnings_date = pg.value_for :next_earnings_announcement_date
|
17
|
+
case aapl_next_earnings_date.class.name
|
18
|
+
when "Date" then aapl_next_earnings_date.class.name.should == "Date"
|
19
|
+
when "String" then aapl_next_earnings_date.class.name.should == "String"
|
20
|
+
else
|
21
|
+
aapl_next_earnings_date.class.name.should == "Date" #force a failure
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe YahooFinance do
|
4
|
+
describe "Parsing Yahoo Fields" do
|
5
|
+
it "should parse an int correctly, such as \"3\"" do
|
6
|
+
YahooFinance.parse_yahoo_field("3").should == 3
|
7
|
+
end
|
8
|
+
it "should parse a float correctly, such as \"3.25\"" do
|
9
|
+
YahooFinance.parse_yahoo_field("3.25").should == 3.25
|
10
|
+
end
|
11
|
+
it "should parse a float with comma separated 000s correctly, such as \"3,245.25\"" do
|
12
|
+
YahooFinance.parse_yahoo_field("3,245.25").should == 3245.25
|
13
|
+
end
|
14
|
+
it "should parse a negative float with comma separated 000s correctly, such as \"-3,245.25\"" do
|
15
|
+
YahooFinance.parse_yahoo_field("-3,245.25").should == -3245.25
|
16
|
+
end
|
17
|
+
it "should parse a scaled float correctly, such as \"3.25K\"" do
|
18
|
+
YahooFinance.parse_yahoo_field("3.25K").should == 3250.0
|
19
|
+
end
|
20
|
+
it "should parse a scaled float correctly, such as \"3.25B\"" do
|
21
|
+
YahooFinance.parse_yahoo_field("3.25B").should == 3250000000.0
|
22
|
+
end
|
23
|
+
it "should parse a date, such as 'Feb 3, 2009'" do
|
24
|
+
dt = YahooFinance.parse_yahoo_field("Feb 3, 2009")
|
25
|
+
dt.class.name.should == "Date"
|
26
|
+
dt.month.should == 2
|
27
|
+
dt.day.should == 3
|
28
|
+
dt.year.should == 2009
|
29
|
+
end
|
30
|
+
it "should recognize that a string like 'hello 1, 2000' is a string and neither a number or a date" do
|
31
|
+
str = YahooFinance.parse_yahoo_field("hello 1, 2000")
|
32
|
+
str.class.name.should == "String"
|
33
|
+
str.should == "hello 1, 2000"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe YahooFinance::Stock do
|
39
|
+
before(:each) do
|
40
|
+
@tsymbols = ['AAPL', 'DDD']
|
41
|
+
@stock = YahooFinance::Stock.new(@tsymbols)
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "initialization" do
|
45
|
+
it "should remember the symbols it was initialized with" do
|
46
|
+
@stock.symbols.uniq.sort.should == @tsymbols
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should allow you to add a symbol" do
|
50
|
+
@stock.add_symbol('TEST')
|
51
|
+
@stock.symbols.size == 3
|
52
|
+
# puts "#{@page.symbols.to_s}"
|
53
|
+
@stock.symbols.uniq.sort.should == @tsymbols
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "execution - fetching yahoo_stock outputs" do
|
58
|
+
it "should return value for a field such as :p_e_ratio, and it should be of type float" do
|
59
|
+
@stock.add_field(:p_e_ratio)
|
60
|
+
results = @stock.fetch
|
61
|
+
# puts "GOT RESULTS: #{results[0][:p_e_ratio]}"
|
62
|
+
# let's parse the output
|
63
|
+
pe_ratio = results['AAPL'][:p_e_ratio]
|
64
|
+
case pe_ratio.class.name
|
65
|
+
when "Float" then pe_ratio.class.name.should == "Float"
|
66
|
+
when "String" then pe_ratio.should == "N/A"
|
67
|
+
else
|
68
|
+
pe_ratio.class.name.should == "Float" #force a failure
|
69
|
+
end
|
70
|
+
end
|
71
|
+
it "should return value for a field such as :bid and it should be of type float, or should return 'N/A'" do
|
72
|
+
@stock.add_field(:bid)
|
73
|
+
results = @stock.fetch
|
74
|
+
# puts "GOT RESULTS: #{results[0][:p_e_ratio]}"
|
75
|
+
# let's parse the output
|
76
|
+
bid = results['AAPL'][:bid]
|
77
|
+
case bid.class.name
|
78
|
+
when "Float" then bid.class.name.should == "Float"
|
79
|
+
when "String" then bid.should == "N/A"
|
80
|
+
else
|
81
|
+
bid.class.name.should == "Float" #force a failure
|
82
|
+
end
|
83
|
+
end
|
84
|
+
it "should return value for a field such as :brokers_count and it should be > 0 for AAPL" do
|
85
|
+
@stock.add_field(:brokers_count)
|
86
|
+
results = @stock.fetch
|
87
|
+
brokers_count = results['AAPL'][:brokers_count]
|
88
|
+
brokers_count.should > 0
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe YahooFinance::KeyStatistics do
|
4
|
+
# before(:each) do
|
5
|
+
# @tsymbols = ['AAPL', 'DDD']
|
6
|
+
# @page = YahooFinance::Page.new(@tsymbols)
|
7
|
+
# end
|
8
|
+
|
9
|
+
describe "key statistics" do
|
10
|
+
it "available stats should include things like total_debt_to_equity_mrq" do
|
11
|
+
YahooFinance::KeyStatistics::key_stats_available.include?(:price_to_sales_ttm).should == true
|
12
|
+
end
|
13
|
+
it "should fetch a key stat like :total_debt_to_equity_mrq for AAPL" do
|
14
|
+
pg = YahooFinance::KeyStatistics::StatsPage.new('AAPL')
|
15
|
+
pg.fetch
|
16
|
+
aapl_total_debt_to_equity = pg.value_for :total_debt_to_equity_mrq
|
17
|
+
aapl_total_debt_to_equity.class.name.should == "Float"
|
18
|
+
aapl_total_debt_to_equity.should >= 0.0
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'yahoo_finance/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "yahoo_finance_lib"
|
8
|
+
spec.version = YahooFinance::VERSION
|
9
|
+
spec.authors = ["Takis Mercouris"]
|
10
|
+
spec.email = ["tm@polymechanus.com"]
|
11
|
+
spec.description = %q{Unified library to stock quotes and various pages in yahoo finance, including key statistics, company events, and analyst opinion}
|
12
|
+
spec.summary = %q{Fetch stock information from yahoo finance API and HTML pages}
|
13
|
+
spec.homepage = "http://polymechanus.com/yahoo_finance-ruby-gem-tutorial/"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "nas-yahoo_stock", "~> 1.0.8", ">= 1.0.8"
|
22
|
+
spec.add_runtime_dependency "nokogiri", "~> 1.6.1", ">= 1.6.1"
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake", "~> 0"
|
25
|
+
spec.add_development_dependency "rspec", "~> 2.14.1", '>= 2.14.1'
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yahoo_finance_lib
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.5'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Takis Mercouris
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nas-yahoo_stock
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.8
|
20
|
+
- - '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.0.8
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.0.8
|
30
|
+
- - '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.0.8
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: nokogiri
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ~>
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 1.6.1
|
40
|
+
- - '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.6.1
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ~>
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 1.6.1
|
50
|
+
- - '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.6.1
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: bundler
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '1.3'
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ~>
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '1.3'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: rake
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ~>
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ~>
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: rspec
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ~>
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 2.14.1
|
88
|
+
- - '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 2.14.1
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ~>
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 2.14.1
|
98
|
+
- - '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: 2.14.1
|
101
|
+
description: Unified library to stock quotes and various pages in yahoo finance, including
|
102
|
+
key statistics, company events, and analyst opinion
|
103
|
+
email:
|
104
|
+
- tm@polymechanus.com
|
105
|
+
executables: []
|
106
|
+
extensions: []
|
107
|
+
extra_rdoc_files: []
|
108
|
+
files:
|
109
|
+
- .gitignore
|
110
|
+
- Gemfile
|
111
|
+
- LICENSE.txt
|
112
|
+
- README.md
|
113
|
+
- Rakefile
|
114
|
+
- lib/yahoo_finance.rb
|
115
|
+
- lib/yahoo_finance/analyst_opinion.rb
|
116
|
+
- lib/yahoo_finance/company_events.rb
|
117
|
+
- lib/yahoo_finance/key_statistics.rb
|
118
|
+
- lib/yahoo_finance/stock.rb
|
119
|
+
- lib/yahoo_finance/version.rb
|
120
|
+
- spec/spec_helper.rb
|
121
|
+
- spec/yahoo_analyst_opinion_spec.rb
|
122
|
+
- spec/yahoo_company_events_spec.rb
|
123
|
+
- spec/yahoo_finance_spec.rb
|
124
|
+
- spec/yahoo_key_stats_spec.rb
|
125
|
+
- yahoo_finance.gemspec
|
126
|
+
homepage: http://polymechanus.com/yahoo_finance-ruby-gem-tutorial/
|
127
|
+
licenses:
|
128
|
+
- MIT
|
129
|
+
metadata: {}
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options: []
|
132
|
+
require_paths:
|
133
|
+
- lib
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
requirements: []
|
145
|
+
rubyforge_project:
|
146
|
+
rubygems_version: 2.4.1
|
147
|
+
signing_key:
|
148
|
+
specification_version: 4
|
149
|
+
summary: Fetch stock information from yahoo finance API and HTML pages
|
150
|
+
test_files:
|
151
|
+
- spec/spec_helper.rb
|
152
|
+
- spec/yahoo_analyst_opinion_spec.rb
|
153
|
+
- spec/yahoo_company_events_spec.rb
|
154
|
+
- spec/yahoo_finance_spec.rb
|
155
|
+
- spec/yahoo_key_stats_spec.rb
|