yahoo_finance_client 0.4.1 → 0.5.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/.rubocop.yml +1 -1
- data/CHANGELOG.md +4 -0
- data/README.md +19 -0
- data/lib/yahoo_finance_client/stock.rb +95 -0
- data/lib/yahoo_finance_client/version.rb +1 -1
- data/mise.toml +2 -0
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7e0827edebfc4f170f5a750a27e04cac4fb5dd158fcc85ab47d684a777d6dac8
|
|
4
|
+
data.tar.gz: 3922682a35baff70fb5492f6f21a8feca3ceb24cf549c7678caca26f922814bb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6b699a914a9e2b929b14180e0251ff4ab77ab41e53ec5cf7becff1abf0210fbd477d0f7a4b92f4a77015cf1b659f622d26eb3828e74fc8957edcf6d1f03449f8
|
|
7
|
+
data.tar.gz: 177c5c3577a4a7b31e480b9c85c097def09cdb1aa546da8dc82626239afd6b97b138bc5707f2a7df07c342015be3ad5cd3160f28df27e25ef55633afc1f11957
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## [0.5.0] - 2026-05-15
|
|
4
|
+
|
|
5
|
+
- Add `Stock.search(query, count:)` returning matching tickers from Yahoo's `v1/finance/search` autocomplete endpoint
|
|
6
|
+
|
|
3
7
|
## [0.4.1] - 2026-02-13
|
|
4
8
|
|
|
5
9
|
- Add `fifty_two_week_high` and `fifty_two_week_low` fields to quote data
|
data/README.md
CHANGED
|
@@ -55,6 +55,25 @@ YahooFinanceClient::Stock.get_quotes(["AAPL", "MSFT", "GOOG"])
|
|
|
55
55
|
# => { "AAPL" => { symbol: "AAPL", ... }, "MSFT" => { ... }, "GOOG" => { ... } }
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
+
### Search
|
|
59
|
+
|
|
60
|
+
Search the Yahoo Finance autocomplete index by ticker or company name:
|
|
61
|
+
```ruby
|
|
62
|
+
YahooFinanceClient::Stock.search("apple")
|
|
63
|
+
# => [
|
|
64
|
+
# { symbol: "AAPL", name: "Apple Inc.", exchange: "NasdaqGS", type: "EQUITY", type_display: "Equity" },
|
|
65
|
+
# { symbol: "AAPL.MX", name: "Apple Inc.", exchange: "Mexico", type: "EQUITY", type_display: "Equity" },
|
|
66
|
+
# ...
|
|
67
|
+
# ]
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The default result count is 10. Pass `count:` to override:
|
|
71
|
+
```ruby
|
|
72
|
+
YahooFinanceClient::Stock.search("apple", count: 5)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Search returns `[]` if the query is empty or the upstream request fails.
|
|
76
|
+
|
|
58
77
|
### Dividend History
|
|
59
78
|
|
|
60
79
|
Fetch historical dividend payments via the chart API:
|
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
require "httparty"
|
|
4
4
|
require "json"
|
|
5
|
+
require "uri"
|
|
5
6
|
|
|
6
7
|
module YahooFinanceClient
|
|
7
8
|
# This class provides methods to interact with Yahoo Finance API for stock data.
|
|
8
9
|
class Stock
|
|
9
10
|
QUOTE_PATH = "/v7/finance/quote"
|
|
10
11
|
CHART_PATH = "/v8/finance/chart"
|
|
12
|
+
SEARCH_PATH = "/v1/finance/search"
|
|
13
|
+
SEARCH_BASE_URL = "https://query1.finance.yahoo.com"
|
|
11
14
|
CACHE_TTL = 300
|
|
12
15
|
MAX_RETRIES = 2
|
|
13
16
|
BATCH_SIZE = 50
|
|
@@ -34,6 +37,19 @@ module YahooFinanceClient
|
|
|
34
37
|
fetch_from_cache(cache_key) || fetch_and_cache_dividend_history(cache_key, symbol, range)
|
|
35
38
|
end
|
|
36
39
|
|
|
40
|
+
# Search the Yahoo Finance autocomplete index for matching symbols.
|
|
41
|
+
#
|
|
42
|
+
# @param query [String] free-text query (ticker or company name)
|
|
43
|
+
# @param count [Integer] max number of results to return
|
|
44
|
+
# @return [Array<Hash>] each entry has symbol, name, exchange, type, type_display
|
|
45
|
+
def search(query, count: 10)
|
|
46
|
+
normalized = query.to_s.strip
|
|
47
|
+
return [] if normalized.empty?
|
|
48
|
+
|
|
49
|
+
cache_key = "search_#{normalized.downcase}_#{count}"
|
|
50
|
+
fetch_from_cache(cache_key) || fetch_and_cache_search(cache_key, normalized, count)
|
|
51
|
+
end
|
|
52
|
+
|
|
37
53
|
private
|
|
38
54
|
|
|
39
55
|
def partition_cached(symbols)
|
|
@@ -231,6 +247,85 @@ module YahooFinanceClient
|
|
|
231
247
|
{ date: date, amount: amount.round(4) }
|
|
232
248
|
end
|
|
233
249
|
|
|
250
|
+
def fetch_and_cache_search(cache_key, query, count)
|
|
251
|
+
data = fetch_search_data(query, count)
|
|
252
|
+
store_in_cache(cache_key, data) unless data.empty?
|
|
253
|
+
data
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Try an unauthenticated request first — the v1/finance/search endpoint is historically
|
|
257
|
+
# public and does not validate the crumb. Only fall through to the cookie+crumb flow if
|
|
258
|
+
# Yahoo actually returns an auth error.
|
|
259
|
+
def fetch_search_data(query, count)
|
|
260
|
+
url = build_search_url(query, count)
|
|
261
|
+
response = HTTParty.get(url, headers: { "User-Agent" => Session::USER_AGENT })
|
|
262
|
+
|
|
263
|
+
return fetch_authenticated_search(query, count) if auth_error?(response)
|
|
264
|
+
return [] unless response.success?
|
|
265
|
+
|
|
266
|
+
parse_search_response(response.body)
|
|
267
|
+
rescue StandardError
|
|
268
|
+
[]
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def fetch_authenticated_search(query, count)
|
|
272
|
+
retries = 0
|
|
273
|
+
begin
|
|
274
|
+
handle_authenticated_search_response(make_authenticated_search_request(query, count))
|
|
275
|
+
rescue AuthenticationError
|
|
276
|
+
retries += 1
|
|
277
|
+
retry if retries <= MAX_RETRIES
|
|
278
|
+
[]
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def handle_authenticated_search_response(response)
|
|
283
|
+
if auth_error?(response)
|
|
284
|
+
Session.instance.invalidate!
|
|
285
|
+
raise AuthenticationError, "Authentication failed"
|
|
286
|
+
end
|
|
287
|
+
response.success? ? parse_search_response(response.body) : []
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def make_authenticated_search_request(query, count)
|
|
291
|
+
session = Session.instance
|
|
292
|
+
session.ensure_authenticated
|
|
293
|
+
url = "#{build_search_url(query, count)}&crumb=#{session.crumb}"
|
|
294
|
+
HTTParty.get(url, headers: { "User-Agent" => Session::USER_AGENT, "Cookie" => session.cookie })
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def build_search_url(query, count)
|
|
298
|
+
"#{SEARCH_BASE_URL}#{SEARCH_PATH}?q=#{URI.encode_www_form_component(query)}" \
|
|
299
|
+
""esCount=#{count}&newsCount=0"
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def parse_search_response(body)
|
|
303
|
+
quotes = JSON.parse(body)["quotes"] || []
|
|
304
|
+
quotes.filter_map { |q| format_search_quote(q) }
|
|
305
|
+
rescue JSON::ParserError
|
|
306
|
+
[]
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def format_search_quote(quote)
|
|
310
|
+
symbol = quote["symbol"].to_s
|
|
311
|
+
return nil if symbol.empty?
|
|
312
|
+
|
|
313
|
+
{
|
|
314
|
+
symbol: symbol,
|
|
315
|
+
name: pick_search_name(symbol, quote["shortname"], quote["longname"]),
|
|
316
|
+
exchange: quote["exchDisp"] || quote["exchange"],
|
|
317
|
+
type: quote["quoteType"],
|
|
318
|
+
type_display: quote["typeDisp"]
|
|
319
|
+
}
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Mutual funds and some foreign listings report the symbol code as their `shortname`
|
|
323
|
+
# (e.g. Baelo Dividendo Creciente comes back with shortname="0P0001QYEF.F"); prefer the
|
|
324
|
+
# longname when shortname is missing or just echoes the symbol.
|
|
325
|
+
def pick_search_name(symbol, shortname, longname)
|
|
326
|
+
[shortname, longname, symbol].find { |n| !n.to_s.empty? && n != symbol } || symbol
|
|
327
|
+
end
|
|
328
|
+
|
|
234
329
|
def fetch_from_cache(key)
|
|
235
330
|
cached_entry = @cache[key]
|
|
236
331
|
return unless cached_entry && Time.now - cached_entry[:timestamp] < CACHE_TTL
|
data/mise.toml
ADDED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yahoo_finance_client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Francesc Leveque
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 2026-05-15 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: csv
|
|
@@ -57,6 +57,7 @@ files:
|
|
|
57
57
|
- lib/yahoo_finance_client/session.rb
|
|
58
58
|
- lib/yahoo_finance_client/stock.rb
|
|
59
59
|
- lib/yahoo_finance_client/version.rb
|
|
60
|
+
- mise.toml
|
|
60
61
|
- sig/yahoo_finance_client.rbs
|
|
61
62
|
homepage: https://github.com/fleveque/dividend-portfolio
|
|
62
63
|
licenses:
|
|
@@ -81,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
81
82
|
- !ruby/object:Gem::Version
|
|
82
83
|
version: '0'
|
|
83
84
|
requirements: []
|
|
84
|
-
rubygems_version: 3.6.
|
|
85
|
+
rubygems_version: 3.6.2
|
|
85
86
|
specification_version: 4
|
|
86
87
|
summary: Basic Yahoo! Finance API client
|
|
87
88
|
test_files: []
|