yfinrb 0.1.0 → 0.2.15

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: ae85dede3894ef988f67e2ad11cbade387915950c3387e4f593c34eb172e4d27
4
- data.tar.gz: ff90bb244a371653b94696e1137cdeecc2a955f1acd0f355c54068073c439f06
3
+ metadata.gz: 9316643665488097dfb09a3823315a062252b9647588c8af42a194c9e8c787d4
4
+ data.tar.gz: fa9cfd71619b493736744a406aa7f3bbe0d65fb1ae84d7fd64a0bb6f65c68ebf
5
5
  SHA512:
6
- metadata.gz: a5be1264d728ab72e778062b430162a27e6bf40b970893495e2db61c1760434401440b6bda8ca982088c2e9254e9452a2585d5a6e9dd5ad6d3b8157da03d0000
7
- data.tar.gz: f40d51d8164b62fb3edcd04f98011f9450c8523460e22abfe1e052cedaa11c7edc9c8a5ce94a44602acc421e8eec822dc50c763e4a04aa43a90c02c28422f941
6
+ metadata.gz: 5c8f803f68ca2354e995fa5c709d27e399b35c1aa5e516c34498cb4782ddb01fb587d950f87a905e85e7def09fbe1fd7e9f970c4ce58fb92a74061c72b1c9093
7
+ data.tar.gz: 520fa67a0ebfe33ad861cce25d58f769e7ea923b5928987d21a0290ad1227d36fba4e15d7dae50f082280331b894110120d03596c58afc19079cd56928bfabc2
data/README.md CHANGED
@@ -26,20 +26,22 @@ Yahoo! finance API is intended for personal use only.**
26
26
 
27
27
  ---
28
28
 
29
- ## Quick Start
29
+ ## Purpose
30
30
 
31
- ### The Ticker module
31
+ This package provides for pulling data from Yahoo!'s unofficial API, and providing that data using using [Polars](https://github.com/ankane/ruby-polars?tab=readme-ov-file) dataframes in ruby. Data in those dataframes can then be easily post-processed using technical indicators provided by [Tulip](https://tulipindicators.org/) via [Tulirb's](https://www.rubydoc.info/github/ozone4real/tulirb/main/Tulirb) ruby bindings, and visualized using [Vega](https://github.com/ankane/vega-ruby).
32
32
 
33
- The `Ticker` class, which allows you to access ticker data:
33
+ ### Quick Start: The Ticker module
34
+
35
+ The `Ticker` class, which allows you to access ticker data from Yahoo!'s unofficial API:
34
36
 
35
37
  ```ruby
36
38
 
37
- msft = Yfinrb::Ticker("MSFT")
39
+ msft = Yfinrb::Ticker.new("MSFT")
38
40
 
39
41
  # get all stock info
40
42
  msft.info
41
43
 
42
- # get historical market data
44
+ # get historical market data as a dataframe
43
45
  hist = msft.history(period: "1mo")
44
46
  hist2 = msft.history(start: '2020-01-01', fin: '2021-12-31')
45
47
 
@@ -95,8 +97,161 @@ msft.news
95
97
  # get option chain for specific expiration
96
98
  opt = msft.option_chain('2026-12-18')
97
99
  # data available via: opt.calls, opt.puts
100
+
101
+
102
+ # technical operations, using the Tulirb gem, which provides bindings to
103
+ # the Tulip technical indicators library
104
+ h = msft.history(period: '2y', interval: '1d')
105
+ Yfinrb.ad(h)
106
+
107
+ # then
108
+ h.insert_at_idx(h.columns.length, Yfinrb.ad(h))
109
+ h['ad_results'] = Yfinrb.ad(h)
110
+
98
111
  ```
99
112
 
113
+ Most of the indicators are found [here](https://tulipindicators.org/) and [here](https://www.rubydoc.info/github/ozone4real/tulirb/main/Tulirb). Indicator parameters in [Tulirb](https://www.rubydoc.info/github/ozone4real/tulirb/main/Tulirb) called, e.g., "period" or "short_period" are renamed as "window" or "short_window", respectively. There are a few other variants that are affected. Default values are shown below.
114
+
115
+ ```ruby
116
+
117
+ df = msft.history(period: '3y', interval: '1d') # for example
118
+
119
+ Yfinrb.ad(df)
120
+ Yfinrb.adosc(df, short_window: 2, long_window: 5)
121
+ Yfinrb.adx(df, column: 'Adj Close', window: 5)
122
+ Yfinrb.adxr(df, column: 'Adj Close', window: 5)
123
+ Yfinrb.avg_daily_trading_volume(df, window: 20)
124
+ Yfinrb.ao(df)
125
+ Yfinrb.apo(df, column: 'Adj Close', short_window: 12, long_window: 29)
126
+ Yfinrb.aroon(df, window: 20)
127
+ Yfinrb.aroonosc(df, window: 20)
128
+ Yfinrb.avg_price(df)
129
+ Yfinrb.atr(df, window: 20)
130
+ Yfinrb.bbands(df, column: 'Adj Close', window: 20, stddev: 1 )
131
+ Yfinrb.bop(df)
132
+ Yfinrb.cci(df, window: 20)
133
+ Yfinrb.cmo(df, column: 'Adj Close', window: 20)
134
+ Yfinrb.cvi(df, window: 20)
135
+ Yfinrb.dema(df, column: 'Adj Close', window: 20)
136
+ Yfinrb.di(df, window: 20)
137
+ Yfinrb.dm(df, window: 20)
138
+ Yfinrb.dpo(df, column: 'Adj Close', window: 20)
139
+ Yfinrb.dx(df, window: 20)
140
+ Yfinrb.ema(df, column: 'Adj Close', window: 5)
141
+ Yfinrb.emv(df)
142
+ Yfinrb.fisher(df, window: 20)
143
+ Yfinrb.fosc(df, window: 20)
144
+ Yfinrb.hma(df, column: 'Adj Close', window: 5)
145
+ Yfinrb.kama(df, column: 'Adj Close', window: 5)
146
+ Yfinrb.kvo(df, short_window: 5, long_window: 20)
147
+ Yfinrb.linreg(df, column: 'Adj Close', window: 20)
148
+ Yfinrb.linregintercept(df, column: 'Adj Close', window: 20)
149
+ Yfinrb.linregslope(df, column: 'Adj Close', window: 20)
150
+ Yfinrb.macd(df, column: 'Adj Close', short_window: 12, long_window: 26, signal_window: 9)
151
+ Yfinrb.marketfi(df)
152
+ Yfinrb.mass(df, window: 20)
153
+ Yfinrb.max(df, column: 'Adj Close', window: 20)
154
+ Yfinrb.md(df, column: 'Adj Close', window: 20)
155
+ Yfinrb.median_price(df)
156
+ Yfinrb.mfi(df, window: 20)
157
+ Yfinrb.min(df, column: 'Adj Close', window: 20)
158
+ Yfinrb.mom(df, column: 'Adj Close', window: 5)
159
+ Yfinrb.moving_avgs(df, window: 20)
160
+ Yfinrb.natr(df, window: 20)
161
+ Yfinrb.nvi(df)
162
+ Yfinrb.obv(df)
163
+ Yfinrb.ppo(df, column: 'Adj Close', short_window: 12, long_window: 26)
164
+ Yfinrb.psar(df, acceleration_factor_step: 0.2, acceleration_factor_maximum: 2)
165
+ Yfinrb.pvi(df)
166
+ Yfinrb.qstick(df, window: 20)
167
+ Yfinrb.roc(df, column: 'Adj Close', window: 20)
168
+ Yfinrb.rocr(df, column: 'Adj Close', window: 20)
169
+ Yfinrb.rsi(df, window: 20)
170
+ Yfinrb.sma(df, column: 'Adj Close', window: 20)
171
+ Yfinrb.stddev(df, column: 'Adj Close', window: 20)
172
+ Yfinrb.stderr(df, column: 'Adj Close', window: 20)
173
+ Yfinrb.stochrsi(df, column: 'Adj Close', window: 20)
174
+ Yfinrb.sum(df, column: 'Adj Close', window: 20)
175
+ Yfinrb.tema(df, column: 'Adj Close', window: 20)
176
+ Yfinrb.tr(df, column: 'Adj Close')
177
+ Yfinrb.trima(df, column: 'Adj Close', window: 20)
178
+ Yfinrb.trix(df, column: 'Adj Close', window: 20)
179
+ Yfinrb.trima(df, column: 'Adj Close', window: 20)
180
+ Yfinrb.tsf(df, column: 'Adj Close', window: 20)
181
+ Yfinrb.typical_price(df)
182
+ Yfinrb.ultosc(df, short_window: 5, medium_window: 12, long_window: 26)
183
+ Yfinrb.weighted_close_price(df)
184
+ Yfinrb.var(df, column: 'Adj Close', window: 20)
185
+ Yfinrb.vhf(df, column: 'Adj Close', window: 20)
186
+ Yfinrb.vidya(df, column: 'Adj Close', short_window: 5, long_window: 20, alpha: 0.2)
187
+ Yfinrb.volatility(df, column: 'Adj Close', window: 20)
188
+ Yfinrb.vosc(df, column: 'Adj Close', short_window: 5, long_window: 20)
189
+ Yfinrb.vol_weighted_moving_avg(df, window: 20)
190
+ Yfinrb.wad(df)
191
+ Yfinrb.wcprice(df)
192
+ Yfinrb.wilders(df, column: 'Adj Close', window: 20)
193
+ Yfinrb.willr(df, window: 20)
194
+ Yfinrb.wma(df, column: 'Adj Close', window: 5)
195
+ Yfinrb.zlema(df, column: 'Adj Close', window: 5)
196
+ ```
197
+
198
+ ---
199
+
200
+ ## Graphing
201
+
202
+ To graph any of the series using [Vega](https://github.com/ankane/vega-ruby), per the information [here](https://github.com/ankane/vega-ruby#exporting-charts-experimental), you will need to run
203
+
204
+ ```sh
205
+ yarn add vega-cli vega-lite
206
+ ```
207
+
208
+ Then, from within irb, you can generate charts, e.g.,
209
+
210
+ ```ruby
211
+ > msft = Yfinrb::Ticker.new("MSFT")
212
+ # =>
213
+ # #<Yfinrb::Ticker:0x000000011e6d50a0
214
+ # ...
215
+
216
+ > df = msft.history(period: '3y', interval: '1d')
217
+ # =>
218
+ # shape: (754, 10)
219
+ # ...
220
+
221
+ > df.insert_at_idx(df.columns.length, Yfinrb.ema(df, column: 'Adj Close', window: 5))
222
+ # =>
223
+ # shape: (753, 11)
224
+ # ┌────────────┬────────────┬────────────┬────────────┬───┬───────────┬───────────────┬──────────────┬──────────────────────┐
225
+ # │ Timestamps ┆ Open ┆ High ┆ Low ┆ … ┆ Dividends ┆ Capital Gains ┆ Stock Splits ┆ EMA(5) for Adj Close │
226
+ # │ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
227
+ # │ date ┆ f64 ┆ f64 ┆ f64 ┆ ┆ f64 ┆ f64 ┆ f64 ┆ f64 │
228
+ # ╞════════════╪════════════╪════════════╪════════════╪═══╪═══════════╪═══════════════╪══════════════╪══════════════════════╡
229
+ # │ 2021-07-12 ┆ 279.160004 ┆ 279.769989 ┆ 276.579987 ┆ … ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 270.325745 │
230
+ # │ 2021-07-13 ┆ 277.519989 ┆ 282.850006 ┆ 277.390015 ┆ … ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 271.514984 │
231
+ # │ 2021-07-14 ┆ 282.350006 ┆ 283.660004 ┆ 280.549988 ┆ … ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 272.804932 │
232
+ # │ 2021-07-15 ┆ 282.0 ┆ 282.51001 ┆ 279.829987 ┆ … ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 273.184001 │
233
+ # │ 2021-07-16 ┆ 282.070007 ┆ 284.100006 ┆ 279.459991 ┆ … ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 273.345751 │
234
+ # │ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │
235
+ # │ 2024-07-02 ┆ 453.200012 ┆ 459.589996 ┆ 453.109985 ┆ … ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 454.288375 │
236
+ # │ 2024-07-03 ┆ 458.190002 ┆ 461.019989 ┆ 457.880005 ┆ … ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 456.448913 │
237
+ # │ 2024-07-05 ┆ 459.609985 ┆ 468.350006 ┆ 458.970001 ┆ … ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 460.152608 │
238
+ # │ 2024-07-08 ┆ 466.549988 ┆ 467.700012 ┆ 464.459991 ┆ … ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 462.181735 │
239
+ # │ 2024-07-09 ┆ 467.0 ┆ 467.329987 ┆ 458.0 ┆ … ┆ 0.0 ┆ 0.0 ┆ 0.0 ┆ 461.30116 │
240
+ # └────────────┴────────────┴────────────┴────────────┴───┴───────────┴───────────────┴──────────────┴──────────────────────┘
241
+
242
+ > File.binwrite('/tmp/chart.png',df.plot("Timestamps", "EMA(5) for Adj Close", type: "line", width:800, height:500).to_png)
243
+ # => 44913
244
+
245
+ ```
246
+
247
+ Then the following image should be saved at the specified location.
248
+
249
+ ![A chart generated with Yfinrb using Vega](./chart.png?raw=true)
250
+
251
+ PNG, SVG, and PDF output formats are supported directly. See [this page](https://github.com/ankane/vega-ruby) for more information in constructing supported charts.
252
+
253
+ While it _has not been tested yet_, images _should_ be able to be produced interactively using [iruby](https://github.com/SciRuby/iruby) operating in a [Jupyter environment](https://github.com/jupyterlab).
254
+
100
255
  ---
101
256
 
102
257
  ## Installation
data/chart.png ADDED
Binary file
@@ -1,4 +1,4 @@
1
- class Yfin
1
+ class Yfinrb
2
2
  module Analysis
3
3
  extend ActiveSupport::Concern
4
4
 
@@ -1,4 +1,6 @@
1
- class Yfin
1
+ require 'polars-df'
2
+
3
+ class Yfinrb
2
4
  module Financials
3
5
  include ActiveSupport::Inflector
4
6
 
@@ -54,7 +56,7 @@ class Yfin
54
56
 
55
57
  if pretty
56
58
  # data = data.dup
57
- # data.index = Utils.camel2title(data.index, sep: ' ', acronyms: ["PPE"])
59
+ # data.index = Yfinrb::Utils.camel2title(data.index, sep: ' ', acronyms: ["PPE"])
58
60
  end
59
61
 
60
62
  as_dict ? data.to_h : data
@@ -65,7 +67,7 @@ class Yfin
65
67
 
66
68
  if pretty
67
69
  # data = data.dup
68
- # data.index = Utils.camel2title(data.index, sep: ' ', acronyms: ["EBIT", "EBITDA", "EPS", "NI"])
70
+ # data.index = Yfinrb::Utils.camel2title(data.index, sep: ' ', acronyms: ["EBIT", "EBITDA", "EPS", "NI"])
69
71
  end
70
72
 
71
73
  as_dict ? data.to_h : data
@@ -77,7 +79,7 @@ class Yfin
77
79
 
78
80
  if pretty
79
81
  # data = data.dup
80
- # data.index = Utils.camel2title(data.index, sep: ' ', acronyms: ["PPE"])
82
+ # data.index = Yfinrb::Utils.camel2title(data.index, sep: ' ', acronyms: ["PPE"])
81
83
  end
82
84
 
83
85
  as_dict ? data.to_h : data
@@ -1,5 +1,4 @@
1
-
2
- class Yfin
1
+ class Yfinrb
3
2
  module Fundamentals
4
3
  extend ActiveSupport::Concern
5
4
 
@@ -1,11 +1,4 @@
1
-
2
- require'date'
3
- require 'open-uri'
4
- require 'json'
5
- require 'csv'
6
-
7
-
8
- class Yfin
1
+ class Yfinrb
9
2
  module Holders
10
3
  extend ActiveSupport::Concern
11
4
  # include YfConnection
data/lib/yfinrb/multi.rb CHANGED
@@ -1,6 +1,6 @@
1
+ require 'polars-df'
1
2
 
2
-
3
- class Yfin
3
+ class Yfinrb
4
4
  class Multi
5
5
 
6
6
  def download(tickers, start: nil, fin: nil, actions: false, threads: true,
@@ -62,10 +62,10 @@ class Yfin
62
62
  logger = Rails.logger
63
63
 
64
64
  if show_errors
65
- 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)")
65
+ Yfinrb::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
66
  logger.level = Logger::ERROR
67
67
  else
68
- 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)")
68
+ Yfinrb::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
69
  logger.level = Logger::CRITICAL
70
70
  end
71
71
 
@@ -80,9 +80,9 @@ class Yfin
80
80
  tickers = tickers.is_a?(Array) ? tickers : tickers.gsub(',', ' ').split
81
81
  _tickers_ = []
82
82
  tickers.each do |ticker|
83
- if Utils.is_isin(ticker)
83
+ if Yfinrb::Utils.is_isin(ticker)
84
84
  isin = ticker
85
- ticker = Utils.get_ticker_by_isin(ticker, proxy, session: session)
85
+ ticker = Yfinrb::Utils.get_ticker_by_isin(ticker, proxy, session: session)
86
86
  # @shared::_ISINS[ticker] = isin
87
87
  end
88
88
  _tickers_ << ticker
@@ -187,7 +187,7 @@ class Yfin
187
187
  begin
188
188
  @shared::_DFS[key] = Polars::DataFrame.new(index: idx, data: df).drop_duplicates
189
189
  rescue
190
- @shared::_DFS[key] = Polars.concat([Utils.empty_df(idx), df.dropna], axis: 0, sort: true)
190
+ @shared::_DFS[key] = Polars.concat([Yfinrb::Utils.empty_df(idx), df.dropna], axis: 0, sort: true)
191
191
  end
192
192
 
193
193
  @shared::_DFS[key] = @shared::_DFS[key].loc[!@shared::_DFS[key].index.duplicated(keep: 'last')]
@@ -223,7 +223,7 @@ class Yfin
223
223
  raise_errors: true
224
224
  )
225
225
  rescue Exception => e
226
- @shared::_DFS[ticker.upcase] = Utils.empty_df
226
+ @shared::_DFS[ticker.upcase] = Yfinrb::Utils.empty_df
227
227
  @shared::_ERRORS[ticker.upcase] = e.to_s
228
228
  @shared::_TRACEBACKS[ticker.upcase] = e.backtrace.join("\n")
229
229
  else
@@ -1,5 +1,7 @@
1
+ require 'polars'
2
+ require 'polars-df'
1
3
 
2
- class Yfin
4
+ class Yfinrb
3
5
  module PriceHistory
4
6
  extend ActiveSupport::Concern
5
7
  include ActionView::Helpers::NumberHelper
@@ -35,8 +37,10 @@ class Yfin
35
37
  rounding: false, raise_errors: false, returns: false)
36
38
  logger = Rails.logger # Yfin.get_yf_logger
37
39
  start_user = start
40
+ # Rails.logger.info { "#{__FILE__}:#{__LINE__} here" }
38
41
  end_user = fin || DateTime.now
39
42
 
43
+ # Rails.logger.info { "#{__FILE__}:#{__LINE__} here" }
40
44
  params = _preprocess_params(start, fin, interval, period, prepost, raise_errors)
41
45
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} params=#{params.inspect}" }
42
46
 
@@ -47,11 +51,11 @@ class Yfin
47
51
  end
48
52
 
49
53
  data = _get_data(ticker, params, fin, raise_errors)
54
+ # Rails.logger.info { "#{__FILE__}:#{__LINE__} data = #{data.inspect}" }
50
55
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} data[chart][result].first.keys = #{data['chart']['result'].first.keys.inspect}" }
51
56
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} data[chart][result].first[events] = #{data['chart']['result'].first['events'].inspect}" }
52
57
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} data[chart][result].first[events][dividends] = #{data['chart']['result'].first['events']['dividends'].inspect}" }
53
58
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} data[chart][result].first[events][splits] = #{data['chart']['result'].first['events']['splits'].inspect}" }
54
- # Rails.logger.info { "#{__FILE__}:#{__LINE__} data = #{data.inspect}" }
55
59
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} @history = #{@history.inspect}" }
56
60
 
57
61
  @history_metadata = data["chart"]["result"][0]["meta"] rescue {}
@@ -76,7 +80,7 @@ class Yfin
76
80
  if @reconstruct_start_interval && @reconstruct_start_interval == interval
77
81
  @reconstruct_start_interval = nil
78
82
  end
79
- return Utils.empty_df
83
+ return Yfinrb::Utils.empty_df
80
84
  end
81
85
 
82
86
  # begin
@@ -556,22 +560,25 @@ class Yfin
556
560
  private
557
561
 
558
562
  def _preprocess_params(start, fin, interval, period, prepost, raise_errors)
559
- # Rails.logger.info { "#{__FILE__}:#{__LINE__} start = #{start.inspect}, end_date = #{fin.inspect}, interval = #{interval}, period = #{period}, tz = #{tz}, prepost = #{prepost}, raise_errors = #{raise_errors}" }
563
+ # Rails.logger.info { "#{__FILE__}:#{__LINE__} start = #{start.inspect}, end_date = #{fin.inspect}, interval = #{interval}, period = #{period}, tz = #{tz}, prepost = #{prepost}, raise_errors = #{raise_errors}" }
560
564
 
565
+ # Rails.logger.info { "#{__FILE__}:#{__LINE__} here start = #{fin}, period = #{period}" }
561
566
  if start || period.nil? || period.downcase == "max"
567
+ # Rails.logger.info { "#{__FILE__}:#{__LINE__} here fin = #{fin}" }
562
568
  if tz.nil?
563
569
  err_msg = "No timezone found, symbol may be delisted"
564
- # Yfin.shared_DFS[@ticker] = Utils.empty_df
570
+ # Yfin.shared_DFS[@ticker] = Yfinrb::Utils.empty_df
565
571
  # Yfin.shared_ERRORS[@ticker] = err_msg
566
572
  if raise_errors
567
573
  raise Exception.new("#{@ticker}: #{err_msg}")
568
574
  else
569
575
  Rails.logger.error("#{@ticker}: #{err_msg}")
570
576
  end
571
- return Utils.empty_df
577
+ return Yfinrb::Utils.empty_df
572
578
  end
573
579
 
574
- fin = fin.nil? ? Time.now.to_i : Utils.parse_user_dt(fin, tz)
580
+ # Rails.logger.info { "#{__FILE__}:#{__LINE__} here fin = #{fin}" }
581
+ fin = fin.nil? ? Time.now.to_i : Yfinrb::Utils.parse_user_dt(fin, tz)
575
582
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} fin = #{fin.inspect}" }
576
583
 
577
584
  if start.nil?
@@ -582,7 +589,7 @@ class Yfin
582
589
  start = max_start_datetime.to_i
583
590
  end
584
591
  else
585
- start = Utils.parse_user_dt(start, tz)
592
+ start = Yfinrb::Utils.parse_user_dt(start, tz)
586
593
  end
587
594
 
588
595
  params = { "period1" => start, "period2" => fin }
@@ -592,7 +599,8 @@ class Yfin
592
599
  period = period.downcase
593
600
  # params = { "range" => period }
594
601
  fin = DateTime.now.to_i
595
- start = (fin - Utils.interval_to_timedelta(period)).to_i
602
+ # Rails.logger.info { "#{__FILE__}:#{__LINE__} here fin= #{fin}, period = #{period}" }
603
+ start = (fin - Yfinrb::Utils.interval_to_timedelta(period)).to_i
596
604
  params = { "period1" => start, "period2" => fin }
597
605
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} params = #{params.inspect}" }
598
606
  end
@@ -607,7 +615,7 @@ class Yfin
607
615
  end
608
616
 
609
617
  def _get_data(ticker, params, fin, raise_errors)
610
- url = "https://query2.finance.yahoo.com/v8/finance/chart/#{ticker}"
618
+ url = "https://query2.finance.yahoo.com/v8/finance/chart/#{CGI.escape ticker}"
611
619
  # url = "https://query1.finance.yahoo.com/v7/finance/download/#{ticker}" ... Deprecated
612
620
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} url = #{url}" }
613
621
  data = nil
@@ -702,7 +710,7 @@ class Yfin
702
710
  # startDt = quotes.index[0].floor('D')
703
711
  startDt = quotes['Timestamps'].to_a.map(&:to_date).min
704
712
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} startDt = #{startDt.inspect}" }
705
- endDt = fin.present? ? fin : Time.at(DateTime.now.tomorrow).to_i
713
+ endDt = fin.present? ? fin.to_date : Time.at(DateTime.now.tomorrow).to_i
706
714
 
707
715
  # Rails.logger.info { "#{__FILE__}:#{__LINE__} @history[events][dividends] = #{@history['events']["dividends"].inspect}" }
708
716
  # divi = {}
@@ -1111,7 +1119,7 @@ class Yfin
1111
1119
 
1112
1120
  def _reconstruct_intervals_batch(df, interval, prepost, tag=-1)
1113
1121
  # # Reconstruct values in df using finer-grained price data. Delimiter marks what to reconstruct
1114
- # logger = Rails.logger # Utils.get_yf_logger
1122
+ # logger = Rails.logger # Yfinrb::Utils.get_yf_logger
1115
1123
 
1116
1124
  # # raise Exception.new("'df' must be a Polars DataFrame not", type(df)) unless df.is_a?(Polars::DataFrame)
1117
1125
  # return df if interval == "1m"
@@ -1130,7 +1138,7 @@ class Yfin
1130
1138
  # # If interval is weekly then can construct with daily. But if smaller intervals then
1131
1139
  # # restricted to recent times:
1132
1140
  # intervals = ["1wk", "1d", "1h", "30m", "15m", "5m", "2m", "1m"]
1133
- # itds = intervals.map { |i| [i, Utils.interval_to_timedelta(interval)] }.to_h
1141
+ # itds = intervals.map { |i| [i, Yfinrb::Utils.interval_to_timedelta(interval)] }.to_h
1134
1142
  # nexts = intervals.each_cons(2).to_h
1135
1143
  # min_lookbacks = {"1wk" => nil, "1d" => nil, "1h" => 730.days }
1136
1144
  # ["30m", "15m", "5m", "2m"].each { |i| min_lookbacks[i] = 60.days }
@@ -1561,7 +1569,7 @@ class Yfin
1561
1569
  # return df if df.empty?
1562
1570
 
1563
1571
  # # Easy to detect and fix, just look for outliers = ~100x local median
1564
- # logger = Rails.logger # Utils.get_yf_logger
1572
+ # logger = Rails.logger # Yfinrb::Utils.get_yf_logger
1565
1573
 
1566
1574
  # if df.shape[0] == 0
1567
1575
  # df["Repaired?"] = false if !df.columns.include?("Repaired?")