yf_as_dataframe 0.4.1 → 0.4.2

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: ef9b7d363312088694d19ce68cd538579f9b3f2b93f57cf5e111f3247cd87b00
4
- data.tar.gz: 5bab2fa2aa65c4b6496025aa13f86c15d5df49deeeff2f6b60db07818d6fe1c8
3
+ metadata.gz: cb178f1a6feb462ac539fccad4d2440f2754b55b4ec0742a965b48bf4aa72fb1
4
+ data.tar.gz: 189dd9688dd80eeb85f8d2154f3a1d9f260f8fcb30ad7c3f086afb1485d0303a
5
5
  SHA512:
6
- metadata.gz: '0019c0c2f4293f3c1b3684bff81f2e0a78eb614c505031aaa77c4ba541c88def5189ed8d96310dc6b7217f3651f37f7ea9dbb64c05009a2286d12856027368b2'
7
- data.tar.gz: 39b3d46681bbc24409315878a8722e563266553e9b81592051404ef53df6aef397c0248ab1fc724ea6edfc5f6d647e2fb89de6bf675b975aeeb592ae7244f66c
6
+ metadata.gz: 042f92be7a2842fb89210a84415ab810cb3d9f96d902f2ba1aa4c10da646012f35dda9e257b02cb0dd2486a432817e489b4d041a054ca291d5a4f8a13f824544
7
+ data.tar.gz: 023f06de418a640ab2ae3b01997a0f1e8865d519cf0082d6bf48349350958437f40aa0087773800d9edd386ea9e907ae7949d00cb569ca0abc3801bd979c2bdf
@@ -81,8 +81,8 @@ class YfAsDataframe
81
81
  end
82
82
  cmd << url
83
83
 
84
- puts "DEBUG: curl-impersonate command: #{cmd.join(' ')}"
85
- puts "DEBUG: curl-impersonate timeout: #{timeout} seconds"
84
+ # puts "DEBUG: curl-impersonate command: #{cmd.join(' ')}"
85
+ # puts "DEBUG: curl-impersonate timeout: #{timeout} seconds"
86
86
 
87
87
  begin
88
88
  stdout_str = ''
@@ -95,7 +95,7 @@ class YfAsDataframe
95
95
  monitor = Thread.new do
96
96
  sleep(timeout + 10)
97
97
  unless done
98
- puts "DEBUG: Killing curl-impersonate PID \\#{pid} after timeout"
98
+ # puts "DEBUG: Killing curl-impersonate PID \\#{pid} after timeout"
99
99
  Process.kill('TERM', pid) rescue nil
100
100
  sleep(1)
101
101
  Process.kill('KILL', pid) rescue nil if wait_thr.alive?
@@ -107,23 +107,23 @@ class YfAsDataframe
107
107
  done = true
108
108
  monitor.kill
109
109
  end
110
- puts "DEBUG: curl-impersonate stdout: #{stdout_str[0..200]}..." if stdout_str && !stdout_str.empty?
111
- puts "DEBUG: curl-impersonate stderr: #{stderr_str}" if stderr_str && !stderr_str.empty?
112
- puts "DEBUG: curl-impersonate status: #{status.exitstatus}"
113
- if status.success?
114
- response = OpenStruct.new
115
- response.body = stdout_str
116
- response.code = 200
117
- response.define_singleton_method(:success?) { true }
118
- response.parsed_response = parse_json_if_possible(stdout_str)
119
- response
120
- else
110
+ # puts "DEBUG: curl-impersonate stdout: #{stdout_str[0..200]}..." if stdout_str && !stdout_str.empty?
111
+ # puts "DEBUG: curl-impersonate stderr: #{stderr_str}" if stderr_str && !stderr_str.empty?
112
+ # puts "DEBUG: curl-impersonate status: #{status.exitstatus}"
113
+ if status.success?
114
+ response = OpenStruct.new
115
+ response.body = stdout_str
116
+ response.code = 200
117
+ response.define_singleton_method(:success?) { true }
118
+ response.parsed_response = parse_json_if_possible(stdout_str)
119
+ response
120
+ else
121
+ # puts "DEBUG: curl-impersonate failed with error: \\#{error_message}"
121
122
  error_message = "curl failed with code \\#{status.exitstatus}: \\#{stderr_str}"
122
- puts "DEBUG: curl-impersonate failed with error: \\#{error_message}"
123
123
  nil
124
124
  end
125
125
  rescue => e
126
- puts "DEBUG: curl-impersonate exception: \\#{e.message}"
126
+ # puts "DEBUG: curl-impersonate exception: \\#{e.message}"
127
127
  nil
128
128
  end
129
129
  end
@@ -143,7 +143,7 @@ class YfAsDataframe
143
143
 
144
144
  df = Polars::DataFrame.new(df)
145
145
  timestamps.map{|ts| Time.at(ts).utc.to_date.to_s }.each do |t|
146
- puts t
146
+ # puts t
147
147
  df.replace(t, Polars::Series.new(df[t].cast(Polars::String)))
148
148
  end
149
149
  df
@@ -161,7 +161,7 @@ class YfAsDataframe
161
161
  statement = _create_financials_table(nam, timescale)
162
162
  return statement unless statement.nil?
163
163
  rescue Yfin::YfinDataException => e
164
- Logger.new(STDOUT).error {"#{@symbol}: Failed to create #{nam} financials table for reason: #{e}"}
164
+ # Logger.new(STDOUT).error {"#{@symbol}: Failed to create #{nam} financials table for reason: #{e}"}
165
165
  end
166
166
  Polars::DataFrame.new()
167
167
  end
@@ -100,7 +100,7 @@ class YfAsDataframe
100
100
  result = get_raw_json(QUOTE_SUMMARY_URL + "/#{symbol}", user_agent_headers=user_agent_headers, params=params_dict)
101
101
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} result = #{result.inspect}" }
102
102
  rescue Exception => e
103
- Logger.new(STDOUT).error("ERROR: #{e.message}")
103
+ # Logger.new(STDOUT).error("ERROR: #{e.message}")
104
104
  return nil
105
105
  end
106
106
  return result
@@ -136,7 +136,7 @@ class YfAsDataframe
136
136
 
137
137
  def _parse_result(result)
138
138
  data = result.parsed_response['quoteSummary']['result'].first #.dig('quoteSummary', 'result', 0)
139
- Logger.new(STDOUT).info { "#{__FILE__}:#{__LINE__} data = #{data.inspect}" }
139
+ # Logger.new(STDOUT).info { "#{__FILE__}:#{__LINE__} data = #{data.inspect}" }
140
140
  _parse_institution_ownership(data['institutionOwnership'])
141
141
  _parse_fund_ownership(data['fundOwnership'])
142
142
  _parse_major_holders_breakdown(data['majorHoldersBreakdown'])
@@ -62,19 +62,20 @@ class YfAsDataframe
62
62
  # """
63
63
  logger = Logger.new(STDOUT)
64
64
 
65
+ # YfAsDataframe::Utils.print_once("yfinance: download(show_errors=#{show_errors}) argument is deprecated and will be removed in future version. Do this instead: logging.getLogger('yfinance').setLevel(logging.ERROR)")
66
+
65
67
  if show_errors
66
- YfAsDataframe::Utils.print_once("yfinance: download(show_errors=#{show_errors}) argument is deprecated and will be removed in future version. Do this instead: logging.getLogger('yfinance').setLevel(logging.ERROR)")
67
- logger.level = Logger::ERROR
68
+ # YfAsDataframe::Utils.print_once("yfinance: download(show_errors=#{show_errors}) argument is deprecated and will be removed in future version. Do this instead to suppress error messages: logging.getLogger('yfinance').setLevel(logging.CRITICAL)")
69
+ # logger.level = Logger::CRITICAL
68
70
  else
69
- YfAsDataframe::Utils.print_once("yfinance: download(show_errors=#{show_errors}) argument is deprecated and will be removed in future version. Do this instead to suppress error messages: logging.getLogger('yfinance').setLevel(logging.CRITICAL)")
70
- logger.level = Logger::CRITICAL
71
+ # logger.level = Logger::CRITICAL
71
72
  end
72
73
 
73
- if logger.debug?
74
- threads = false if threads
75
- logger.debug('Disabling multithreading because DEBUG logging enabled')
76
- progress = false if progress
77
- end
74
+ # if logger.debug?
75
+ # threads = false if threads
76
+ # logger.debug('Disabling multithreading because DEBUG logging enabled')
77
+ # progress = false if progress
78
+ # end
78
79
 
79
80
  ignore_tz = interval[1..-1].match?(/[mh]/) ? false : true if ignore_tz.nil?
80
81
 
@@ -35,7 +35,7 @@ class YfAsDataframe
35
35
  def history(period: "1mo", interval: "1d", start: nil, fin: nil, prepost: false,
36
36
  actions: true, auto_adjust: true, back_adjust: false, repair: false, keepna: false,
37
37
  rounding: false, raise_errors: false, returns: false)
38
- logger = Logger.new(STDOUT) # Replace Rails.logger with standard Ruby logger
38
+ # logger = Logger.new(STDOUT) # Replace Rails.logger with standard Ruby logger
39
39
  start_user = start
40
40
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} here" }
41
41
  end_user = fin || Time.now
@@ -75,7 +75,7 @@ class YfAsDataframe
75
75
  if raise_errors
76
76
  raise Exception.new("#{ticker}: #{err_msg}")
77
77
  else
78
- logger.error("#{ticker}: #{err_msg}")
78
+ # logger.error("#{ticker}: #{err_msg}")
79
79
  end
80
80
  if @reconstruct_start_interval && @reconstruct_start_interval == interval
81
81
  @reconstruct_start_interval = nil
@@ -572,7 +572,7 @@ class YfAsDataframe
572
572
  if raise_errors
573
573
  raise Exception.new("#{@ticker}: #{err_msg}")
574
574
  else
575
- Logger.new(STDOUT).error("#{@ticker}: #{err_msg}")
575
+ # Logger.new(STDOUT).error("#{@ticker}: #{err_msg}")
576
576
  end
577
577
  return YfAsDataframe::Utils.empty_df
578
578
  end
@@ -617,8 +617,8 @@ class YfAsDataframe
617
617
  def _get_data(ticker, params, fin, raise_errors)
618
618
  url = "https://query2.finance.yahoo.com/v8/finance/chart/#{CGI.escape ticker}"
619
619
  # url = "https://query1.finance.yahoo.com/v7/finance/download/#{ticker}" ... Deprecated
620
- logger = Logger.new(STDOUT)
621
- logger.info { "#{__FILE__}:#{__LINE__} url = #{url}" }
620
+ # logger = Logger.new(STDOUT)
621
+ # logger.info { "#{__FILE__}:#{__LINE__} url = #{url}" }
622
622
  data = nil
623
623
  # get_fn = @data.method(:get)
624
624
 
@@ -631,9 +631,9 @@ class YfAsDataframe
631
631
  end
632
632
 
633
633
  begin
634
- logger.info { "#{__FILE__}:#{__LINE__} url = #{url}, params = #{params.inspect}" }
634
+ # logger.info { "#{__FILE__}:#{__LINE__} url = #{url}, params = #{params.inspect}" }
635
635
  data = get(url, nil, params).parsed_response
636
- logger.info { "#{__FILE__}:#{__LINE__} data = #{data.inspect}" }
636
+ # logger.info { "#{__FILE__}:#{__LINE__} data = #{data.inspect}" }
637
637
 
638
638
  # Validate response before processing
639
639
  unless validate_yahoo_response(data)
@@ -647,10 +647,10 @@ class YfAsDataframe
647
647
 
648
648
  # Use standard Ruby Hash
649
649
  data = data.is_a?(Hash) ? data : JSON.parse(data.to_s) rescue data
650
- logger.info { "#{__FILE__}:#{__LINE__} data = #{data.inspect}" }
650
+ # logger.info { "#{__FILE__}:#{__LINE__} data = #{data.inspect}" }
651
651
  rescue Exception => e
652
- logger.error { "#{__FILE__}:#{__LINE__} Exception caught: #{e.message}" }
653
- logger.error { "#{__FILE__}:#{__LINE__} Exception backtrace: #{e.backtrace.first(5).join("\n")}" }
652
+ # logger.error { "#{__FILE__}:#{__LINE__} Exception caught: #{e.message}" }
653
+ # logger.error { "#{__FILE__}:#{__LINE__} Exception backtrace: #{e.backtrace.first(5).join("\n")}" }
654
654
  raise if raise_errors
655
655
  end
656
656
 
@@ -1085,7 +1085,7 @@ class YfAsDataframe
1085
1085
  # quotes.sort_index!(inplace: true)
1086
1086
 
1087
1087
  if interval.downcase == "30m"
1088
- logger.debug("#{ticker}: resampling 30m OHLC from 15m")
1088
+ # logger.debug("#{ticker}: resampling 30m OHLC from 15m")
1089
1089
  quotes2 = quotes.resample('30T')
1090
1090
  quotes = Polars::DataFrame.new(index: quotes2.last.index, data: {
1091
1091
  'Open' => quotes2['Open'].first,
@@ -130,7 +130,7 @@ class YfAsDataframe
130
130
  result = get_raw_json(QUOTE_SUMMARY_URL + "/#{symbol}", user_agent_headers=user_agent_headers, params=params_dict)
131
131
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} result = #{result.inspect}" }
132
132
  rescue Exception => e
133
- Logger.new(STDOUT).error("ERROR: #{e.message}")
133
+ # Logger.new(STDOUT).error("ERROR: #{e.message}")
134
134
  return nil
135
135
  end
136
136
  return result
@@ -47,7 +47,7 @@ class YfAsDataframe
47
47
  def symbol; @ticker; end
48
48
 
49
49
  def shares_full(start: nil, fin: nil)
50
- logger = Logger.new(STDOUT)
50
+ # logger = Logger.new(STDOUT)
51
51
 
52
52
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} start = #{start.inspect}, fin = #{fin.inspect}" }
53
53
 
@@ -71,7 +71,7 @@ class YfAsDataframe
71
71
  start ||= Time.new(fin.year, fin.month, fin.day) - 548*24*60*60
72
72
 
73
73
  if start >= fin
74
- logger.error("Start date (#{start}) must be before end (#{fin})")
74
+ # logger.error("Start date (#{start}) must be before end (#{fin})")
75
75
  return nil
76
76
  end
77
77
 
@@ -81,13 +81,13 @@ class YfAsDataframe
81
81
  begin
82
82
  json_data = get(shares_url).parsed_response
83
83
  rescue #_json.JSONDecodeError, requests.exceptions.RequestException
84
- logger.error("#{@ticker}: Yahoo web request for share count failed")
84
+ # logger.error("#{@ticker}: Yahoo web request for share count failed")
85
85
  return nil
86
86
  end
87
87
 
88
88
  fail = json_data["finance"]["error"]["code"] == "Bad Request" rescue false
89
89
  if fail
90
- logger.error("#{@ticker}: Yahoo web request for share count failed")
90
+ # logger.error("#{@ticker}: Yahoo web request for share count failed")
91
91
  return nil
92
92
  end
93
93
 
@@ -153,7 +153,7 @@ class YfAsDataframe
153
153
  # """
154
154
  return @earnings_dates[limit] if @earnings_dates && @earnings_dates[limit]
155
155
 
156
- logger = Logger.new(STDOUT)
156
+ # logger = Logger.new(STDOUT)
157
157
 
158
158
  page_size = [limit, 100].min # YF caps at 100, don't go higher
159
159
  page_offset = 0
@@ -379,7 +379,7 @@ def attributes(obj)
379
379
  end
380
380
 
381
381
  def print_once(msg)
382
- puts msg
382
+ # puts msg
383
383
  end
384
384
 
385
385
  def get_yf_logger
@@ -392,7 +392,7 @@ def setup_debug_formatting
392
392
 
393
393
  return unless logger.level == Logger::DEBUG
394
394
 
395
- logger.formatter = MultiLineFormatter.new('%(levelname)-8s %(message)s')
395
+ # logger.formatter = MultiLineFormatter.new('%(levelname)-8s %(message)s')
396
396
  end
397
397
 
398
398
  def enable_debug_mode
@@ -1,3 +1,3 @@
1
1
  class YfAsDataframe
2
- VERSION = "0.4.1"
2
+ VERSION = "0.4.2"
3
3
  end
@@ -12,12 +12,12 @@ class YfAsDataframe
12
12
  # Override get method to use curl-impersonate by default
13
13
  def get(url, headers=nil, params=nil)
14
14
  # Debug output
15
- puts "DEBUG: curl_impersonate_enabled = #{CurlImpersonateIntegration.curl_impersonate_enabled}"
16
- puts "DEBUG: curl_impersonate_fallback = #{CurlImpersonateIntegration.curl_impersonate_fallback}"
15
+ # puts "DEBUG: curl_impersonate_enabled = #{CurlImpersonateIntegration.curl_impersonate_enabled}"
16
+ # puts "DEBUG: curl_impersonate_fallback = #{CurlImpersonateIntegration.curl_impersonate_fallback}"
17
17
 
18
18
  # Try curl-impersonate first if enabled
19
19
  if CurlImpersonateIntegration.curl_impersonate_enabled
20
- puts "DEBUG: Trying curl-impersonate..."
20
+ # puts "DEBUG: Trying curl-impersonate..."
21
21
  begin
22
22
  # Prepare headers and params as in original method
23
23
  headers ||= {}
@@ -55,28 +55,27 @@ class YfAsDataframe
55
55
  retries: CurlImpersonateIntegration.curl_impersonate_retries
56
56
  )
57
57
 
58
- if response && response.success?
59
- puts "DEBUG: curl-impersonate succeeded"
58
+ if response && !response.empty?
59
+ # puts "DEBUG: curl-impersonate succeeded"
60
60
  return response
61
61
  else
62
- puts "DEBUG: curl-impersonate returned nil or failed"
62
+ # puts "DEBUG: curl-impersonate returned nil or failed"
63
63
  end
64
64
  rescue => e
65
- # Log error but continue to fallback
66
- puts "DEBUG: curl-impersonate exception: #{e.message}"
65
+ # puts "DEBUG: curl-impersonate exception: #{e.message}"
67
66
  # warn "curl-impersonate request failed: #{e.message}" if $VERBOSE
68
67
  end
69
68
  else
70
- puts "DEBUG: curl-impersonate is disabled, skipping to fallback"
69
+ # puts "DEBUG: curl-impersonate is disabled, skipping to fallback"
71
70
  end
72
71
 
73
72
  # Fallback to original HTTParty method
74
73
  if CurlImpersonateIntegration.curl_impersonate_fallback
75
- puts "DEBUG: Using HTTParty fallback"
76
- get_original(url, headers, params)
74
+ # puts "DEBUG: Using HTTParty fallback"
75
+ return HTTParty.get(url, headers: headers).body
77
76
  else
78
- puts "DEBUG: Fallback is disabled, but forcing fallback anyway"
79
- get_original(url, headers, params)
77
+ # puts "DEBUG: Fallback is disabled, but forcing fallback anyway"
78
+ return HTTParty.get(url, headers: headers).body
80
79
  end
81
80
  end
82
81
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yf_as_dataframe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bill McKinnon
@@ -156,7 +156,6 @@ files:
156
156
  - lib/yf_as_dataframe/yf_connection.rb
157
157
  - lib/yf_as_dataframe/yf_connection_minimal_patch.rb
158
158
  - lib/yf_as_dataframe/yfinance_exception.rb
159
- - smoke_test.rb
160
159
  homepage: https://www.github.com/bmck/yf_as_dataframe
161
160
  licenses:
162
161
  - MIT
@@ -179,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
179
178
  - !ruby/object:Gem::Version
180
179
  version: '0'
181
180
  requirements: []
182
- rubygems_version: 3.5.22
181
+ rubygems_version: 3.1.6
183
182
  signing_key:
184
183
  specification_version: 4
185
184
  summary: A shameless port of python's yfinance module to ruby
data/smoke_test.rb DELETED
@@ -1,64 +0,0 @@
1
- # require "bundler/setup"
2
- require "yf_as_dataframe"
3
-
4
- def print_section(title)
5
- puts "\n=== #{title} ==="
6
- end
7
-
8
- begin
9
- print_section("Ticker Creation")
10
- msft = YfAsDataframe::Ticker.new("MSFT")
11
- puts "Ticker created: #{msft.ticker}"
12
-
13
- print_section("Price History")
14
- hist = msft.history(period: "1mo")
15
- puts "History DataFrame shape: #{hist.shape}" if hist
16
-
17
- print_section("Meta Information")
18
- meta = msft.history_metadata
19
- puts "Meta: #{meta.inspect}"
20
-
21
- print_section("Actions")
22
- puts "Dividends: #{msft.dividends.inspect}"
23
- puts "Splits: #{msft.splits.inspect}"
24
-
25
- print_section("Share Count")
26
- shares = msft.shares_full(start: "2022-01-01", fin: nil)
27
- puts "Shares DataFrame shape: #{shares.shape}" if shares
28
-
29
- print_section("Financials")
30
- puts "Income Statement: #{msft.income_stmt.inspect}"
31
- puts "Balance Sheet: #{msft.balance_sheet.inspect}"
32
- puts "Cash Flow: #{msft.cashflow.inspect}"
33
-
34
- print_section("Holders")
35
- puts "Major Holders: #{msft.major_holders.inspect}"
36
- puts "Institutional Holders: #{msft.institutional_holders.inspect}"
37
-
38
- print_section("Recommendations")
39
- puts "Recommendations: #{msft.recommendations.inspect}"
40
-
41
- print_section("Earnings Dates")
42
- puts "Earnings Dates: #{msft.earnings_dates.inspect}"
43
-
44
- print_section("ISIN")
45
- puts "ISIN: #{msft.isin.inspect}"
46
-
47
- print_section("Options")
48
- puts "Options: #{msft.options.inspect}"
49
-
50
- print_section("News")
51
- puts "News: #{msft.news.inspect}"
52
-
53
- print_section("Technical Indicator Example")
54
- if hist
55
- ad = YfAsDataframe.ad(hist)
56
- puts "AD indicator: #{ad.inspect}"
57
- end
58
-
59
- puts "\nAll tests completed successfully!"
60
-
61
- rescue => e
62
- puts "\nTest failed: #{e.class} - #{e.message}"
63
- puts e.backtrace.first(10)
64
- end