yahoo_finance_client 0.4.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30839cb8e628ac9ed9d0f2b62b84c070deec2c0e34b2ebfa847e1f96ead57b66
4
- data.tar.gz: edf5c2cfd5da659d3d133970209beab1520172609ba5ef3e62103f8632b94580
3
+ metadata.gz: 7e0827edebfc4f170f5a750a27e04cac4fb5dd158fcc85ab47d684a777d6dac8
4
+ data.tar.gz: 3922682a35baff70fb5492f6f21a8feca3ceb24cf549c7678caca26f922814bb
5
5
  SHA512:
6
- metadata.gz: 2a1b56270a9f16516c23aeeb68726e44597696f6decd6099feea133be43f812d2512955ad314de75423460ae45ff99ead67b649868037ec99c02c2bec9ad7f77
7
- data.tar.gz: 45f41b601b87201eb3dfe5af834826268806ece7b4ac572e095f6489168c3e8579134a030ebad89570317922e96a5b52cd526ce87d7b644f07fa0233ce100676
6
+ metadata.gz: 6b699a914a9e2b929b14180e0251ff4ab77ab41e53ec5cf7becff1abf0210fbd477d0f7a4b92f4a77015cf1b659f622d26eb3828e74fc8957edcf6d1f03449f8
7
+ data.tar.gz: 177c5c3577a4a7b31e480b9c85c097def09cdb1aa546da8dc82626239afd6b97b138bc5707f2a7df07c342015be3ad5cd3160f28df27e25ef55633afc1f11957
data/.rubocop.yml CHANGED
@@ -11,7 +11,7 @@ Metrics/AbcSize:
11
11
  Max: 25
12
12
 
13
13
  Metrics/ClassLength:
14
- Max: 200
14
+ Max: 280
15
15
 
16
16
  Metrics/MethodLength:
17
17
  Max: 11
data/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
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
+
7
+ ## [0.4.1] - 2026-02-13
8
+
9
+ - Add `fifty_two_week_high` and `fifty_two_week_low` fields to quote data
10
+
11
+ ## [0.4.0] - 2026-02-12
12
+
13
+ - Add dividend history fetching via chart API (`get_dividend_history`)
14
+ - Update README with bulk quotes, dividend history, and caching docs
15
+
16
+ ## [0.3.1] - 2026-02-12
17
+
18
+ - Add `ex_dividend_date` and `dividend_date` fields to quote data
19
+
20
+ ## [0.3.0] - 2026-02-10
21
+
22
+ - Add bulk quotes support with `get_quotes` method
23
+
24
+ ## [0.2.1] - 2026-01-29
25
+
26
+ - Add extended stock information fields (EPS, PE ratio, dividend data, moving averages)
27
+
28
+ ## [0.2.0] - 2026-01-27
29
+
30
+ - Add multi-strategy authentication with retry logic
31
+ - Add CLAUDE.md with project instructions
32
+
3
33
  ## [0.1.6] - 2025-02-18
4
34
 
5
35
  - Adding a simple cache
data/README.md CHANGED
@@ -32,11 +32,65 @@ gem install yahoo_finance_client
32
32
 
33
33
  ## Usage
34
34
 
35
- You should be able to get stock data by calling this method and passing a string with the stock ticker:
35
+ ### Single Quote
36
+
37
+ Fetch stock data by passing a ticker symbol:
36
38
  ```ruby
37
39
  YahooFinanceClient::Stock.get_quote("AAPL")
40
+ # => {
41
+ # symbol: "AAPL", name: "Apple Inc.", price: 182.52,
42
+ # change: 1.25, percent_change: 0.69, volume: 48123456,
43
+ # pe_ratio: 28.5, eps: 6.40,
44
+ # dividend: 0.96, dividend_yield: 0.53, payout_ratio: 15.0,
45
+ # ma50: 178.30, ma200: 172.15,
46
+ # ex_dividend_date: #<Date: 2025-02-07>, dividend_date: #<Date: 2025-02-15>
47
+ # }
48
+ ```
49
+
50
+ ### Bulk Quotes
51
+
52
+ Fetch multiple quotes at once (batched in groups of 50):
53
+ ```ruby
54
+ YahooFinanceClient::Stock.get_quotes(["AAPL", "MSFT", "GOOG"])
55
+ # => { "AAPL" => { symbol: "AAPL", ... }, "MSFT" => { ... }, "GOOG" => { ... } }
56
+ ```
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
+
77
+ ### Dividend History
78
+
79
+ Fetch historical dividend payments via the chart API:
80
+ ```ruby
81
+ YahooFinanceClient::Stock.get_dividend_history("AAPL")
82
+ # => [{ date: #<Date: 2024-02-09>, amount: 0.24 }, ...]
38
83
  ```
39
84
 
85
+ The default range is `"2y"`. You can pass a different range:
86
+ ```ruby
87
+ YahooFinanceClient::Stock.get_dividend_history("AAPL", range: "5y")
88
+ ```
89
+
90
+ ### Caching
91
+
92
+ All responses are cached for 5 minutes (300 seconds). The cache is shared across `get_quote`, `get_quotes`, and `get_dividend_history`.
93
+
40
94
  ## Development
41
95
 
42
96
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -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)
@@ -152,6 +168,7 @@ module YahooFinanceClient
152
168
  dividend: dividend, dividend_yield: calculate_yield(dividend, price),
153
169
  payout_ratio: calculate_payout(dividend, eps),
154
170
  ma50: quote["fiftyDayAverage"], ma200: quote["twoHundredDayAverage"],
171
+ fifty_two_week_high: quote["fiftyTwoWeekHigh"], fifty_two_week_low: quote["fiftyTwoWeekLow"],
155
172
  ex_dividend_date: parse_unix_date(quote["exDividendDate"]),
156
173
  dividend_date: parse_unix_date(quote["dividendDate"])
157
174
  }
@@ -230,6 +247,85 @@ module YahooFinanceClient
230
247
  { date: date, amount: amount.round(4) }
231
248
  end
232
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
+ "&quotesCount=#{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
+
233
329
  def fetch_from_cache(key)
234
330
  cached_entry = @cache[key]
235
331
  return unless cached_entry && Time.now - cached_entry[:timestamp] < CACHE_TTL
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module YahooFinanceClient
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.0"
5
5
  end
data/mise.toml ADDED
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ ruby = "3.4.1"
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.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: 1980-01-02 00:00:00.000000000 Z
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.7
85
+ rubygems_version: 3.6.2
85
86
  specification_version: 4
86
87
  summary: Basic Yahoo! Finance API client
87
88
  test_files: []