yahoo_finance_client 0.2.1 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3e431bef79d59f2f41862b78bae97b9b0935d764c2772dd34d64185c55a1bfac
4
- data.tar.gz: 244e81d428f6db8662943c978fca0bc8849657cb6272f5cf9d6e86703bc9586d
3
+ metadata.gz: e0ac5c76c098d2bed0c2960381c799e4669a5e6bfac74d223c1f7dceadc650af
4
+ data.tar.gz: a3738e2f466198761b923b4f3293e887a6de856e9cdcaca30fd6c473d55fd606
5
5
  SHA512:
6
- metadata.gz: e5515556391d51378e7a483efa7dbc01bbfe899c4040cf25c2b0f51ec15c2c506e61cdb91add0297e2746681dd073fb29e199c9c0c6ef54bc1083326e62940e8
7
- data.tar.gz: 1b42eaaeaa692b2449710cbd291bf432b8ba4e8b82f1754319da81a441bb18bb1a2cd4149f5a5e4e3ac0774b8e7af23d800b5b114e79a7b5e355fa927527e286
6
+ metadata.gz: 195bcd6094858a5df15ca67424aeddc8564c11ac2f3871608d1e6fdd6275e0622d1570158960befa9260f5d187ff6c83c7f36af3ab6144f3692d3e641bebc547
7
+ data.tar.gz: 1e910b49a4b0147b87d464c34b5e9d525b48e9ec1150b56eefcf929cca3957b965fce221ac7b2c57c6f3e4fbdf5f4dae66fc133b3f0fec4a0e21f8b4f83f16ce
data/.rubocop.yml CHANGED
@@ -10,6 +10,9 @@ Lint/EmptyClass:
10
10
  Metrics/AbcSize:
11
11
  Max: 25
12
12
 
13
+ Metrics/ClassLength:
14
+ Max: 150
15
+
13
16
  Metrics/MethodLength:
14
17
  Max: 11
15
18
 
@@ -9,6 +9,7 @@ module YahooFinanceClient
9
9
  QUOTE_PATH = "/v7/finance/quote"
10
10
  CACHE_TTL = 300
11
11
  MAX_RETRIES = 2
12
+ BATCH_SIZE = 50
12
13
  AUTH_ERROR_PATTERNS = [/invalid cookie/i, /invalid crumb/i, /unauthorized/i].freeze
13
14
 
14
15
  @cache = {}
@@ -19,8 +20,35 @@ module YahooFinanceClient
19
20
  fetch_from_cache(cache_key) || fetch_and_cache(cache_key, symbol)
20
21
  end
21
22
 
23
+ def get_quotes(symbols)
24
+ return {} if symbols.nil? || symbols.empty?
25
+
26
+ results, uncached = partition_cached(symbols)
27
+ fetch_uncached_quotes(uncached, results)
28
+ results
29
+ end
30
+
22
31
  private
23
32
 
33
+ def partition_cached(symbols)
34
+ results = {}
35
+ uncached = []
36
+ symbols.each do |symbol|
37
+ cached = fetch_from_cache("quote_#{symbol}")
38
+ cached ? results[symbol] = cached : uncached << symbol
39
+ end
40
+ [results, uncached]
41
+ end
42
+
43
+ def fetch_uncached_quotes(uncached, results)
44
+ uncached.each_slice(BATCH_SIZE) do |batch|
45
+ fetch_quotes_data(batch).each do |sym, data|
46
+ store_in_cache("quote_#{sym}", data)
47
+ results[sym] = data
48
+ end
49
+ end
50
+ end
51
+
24
52
  def fetch_and_cache(cache_key, symbol)
25
53
  data = fetch_quote_data(symbol)
26
54
  store_in_cache(cache_key, data) if data[:error].nil?
@@ -39,6 +67,19 @@ module YahooFinanceClient
39
67
  end
40
68
  end
41
69
 
70
+ def fetch_quotes_data(symbols)
71
+ retries = 0
72
+ symbols_param = symbols.join(",")
73
+ begin
74
+ response = make_authenticated_request(symbols_param)
75
+ handle_batch_response(response, symbols)
76
+ rescue AuthenticationError
77
+ retries += 1
78
+ retry if retries <= MAX_RETRIES
79
+ symbols.each_with_object({}) { |s, h| h[s] = { error: "Authentication failed after #{MAX_RETRIES} retries" } }
80
+ end
81
+ end
82
+
42
83
  def make_authenticated_request(symbol)
43
84
  session = Session.instance
44
85
  session.ensure_authenticated
@@ -54,6 +95,20 @@ module YahooFinanceClient
54
95
  response.success? ? parse_response(response.body, symbol) : { error: "Yahoo Finance connection failed" }
55
96
  end
56
97
 
98
+ def handle_batch_response(response, symbols)
99
+ if auth_error?(response)
100
+ Session.instance.invalidate!
101
+ raise AuthenticationError, "Authentication failed"
102
+ end
103
+ unless response.success?
104
+ return symbols.each_with_object({}) do |s, h|
105
+ h[s] = { error: "Yahoo Finance connection failed" }
106
+ end
107
+ end
108
+
109
+ parse_batch_response(response.body, symbols)
110
+ end
111
+
57
112
  def auth_error?(response)
58
113
  response.code == 401 || AUTH_ERROR_PATTERNS.any? { |p| response.body.to_s.match?(p) }
59
114
  end
@@ -63,6 +118,18 @@ module YahooFinanceClient
63
118
  quote ? format_quote(quote) : { error: "No data was found for #{symbol}" }
64
119
  end
65
120
 
121
+ def parse_batch_response(body, symbols)
122
+ results = JSON.parse(body).dig("quoteResponse", "result") || []
123
+ found = results.each_with_object({}) do |quote, hash|
124
+ formatted = format_quote(quote)
125
+ hash[formatted[:symbol]] = formatted
126
+ end
127
+
128
+ symbols.each_with_object(found) do |symbol, hash|
129
+ hash[symbol] ||= { error: "No data was found for #{symbol}" }
130
+ end
131
+ end
132
+
66
133
  def format_quote(quote)
67
134
  price = quote["regularMarketPrice"]
68
135
  dividend = quote["dividendRate"]
@@ -78,7 +145,9 @@ module YahooFinanceClient
78
145
  volume: quote["regularMarketVolume"], pe_ratio: quote["trailingPE"], eps: eps,
79
146
  dividend: dividend, dividend_yield: calculate_yield(dividend, price),
80
147
  payout_ratio: calculate_payout(dividend, eps),
81
- ma50: quote["fiftyDayAverage"], ma200: quote["twoHundredDayAverage"]
148
+ ma50: quote["fiftyDayAverage"], ma200: quote["twoHundredDayAverage"],
149
+ ex_dividend_date: parse_unix_date(quote["exDividendDate"]),
150
+ dividend_date: parse_unix_date(quote["dividendDate"])
82
151
  }
83
152
  end
84
153
 
@@ -94,6 +163,12 @@ module YahooFinanceClient
94
163
  (dividend / eps * 100).round(2)
95
164
  end
96
165
 
166
+ def parse_unix_date(value)
167
+ return nil unless value.is_a?(Numeric) && value.positive?
168
+
169
+ Time.at(value).utc.to_date
170
+ end
171
+
97
172
  def fetch_from_cache(key)
98
173
  cached_entry = @cache[key]
99
174
  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.2.1"
4
+ VERSION = "0.3.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yahoo_finance_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Francesc Leveque