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 +4 -4
- data/lib/yf_as_dataframe/curl_impersonate_integration.rb +16 -16
- data/lib/yf_as_dataframe/financials.rb +2 -2
- data/lib/yf_as_dataframe/holders.rb +2 -2
- data/lib/yf_as_dataframe/multi.rb +10 -9
- data/lib/yf_as_dataframe/price_history.rb +11 -11
- data/lib/yf_as_dataframe/quote.rb +1 -1
- data/lib/yf_as_dataframe/ticker.rb +5 -5
- data/lib/yf_as_dataframe/utils.rb +2 -2
- data/lib/yf_as_dataframe/version.rb +1 -1
- data/lib/yf_as_dataframe/yf_connection_minimal_patch.rb +12 -13
- metadata +2 -3
- data/smoke_test.rb +0 -64
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb178f1a6feb462ac539fccad4d2440f2754b55b4ec0742a965b48bf4aa72fb1
|
4
|
+
data.tar.gz: 189dd9688dd80eeb85f8d2154f3a1d9f260f8fcb30ad7c3f086afb1485d0303a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
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.
|
67
|
-
logger.level = Logger::
|
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
|
-
|
70
|
-
logger.level = Logger::CRITICAL
|
71
|
+
# logger.level = Logger::CRITICAL
|
71
72
|
end
|
72
73
|
|
73
|
-
if logger.debug?
|
74
|
-
|
75
|
-
|
76
|
-
|
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
|
-
|
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
|
-
|
395
|
+
# logger.formatter = MultiLineFormatter.new('%(levelname)-8s %(message)s')
|
396
396
|
end
|
397
397
|
|
398
398
|
def enable_debug_mode
|
@@ -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.
|
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
|
-
#
|
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
|
-
|
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
|
-
|
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.
|
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.
|
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
|