yfinrb 0.1.0 → 0.2.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +160 -5
- data/chart.png +0 -0
- data/lib/yfinrb/analysis.rb +1 -1
- data/lib/yfinrb/financials.rb +6 -4
- data/lib/yfinrb/fundamentals.rb +1 -2
- data/lib/yfinrb/holders.rb +1 -8
- data/lib/yfinrb/multi.rb +8 -8
- data/lib/yfinrb/price_history.rb +22 -14
- data/lib/yfinrb/price_technical.rb +579 -0
- data/lib/yfinrb/quote.rb +4 -3
- data/lib/yfinrb/ticker.rb +11 -12
- data/lib/yfinrb/tickers.rb +1 -3
- data/lib/yfinrb/utils.rb +26 -31
- data/lib/yfinrb/version.rb +2 -4
- data/lib/yfinrb/yf_connection.rb +15 -11
- data/lib/yfinrb/yfinance_exception.rb +1 -2
- data/lib/yfinrb.rb +18 -12
- data/yfinrb-0.2.13.gem +0 -0
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9316643665488097dfb09a3823315a062252b9647588c8af42a194c9e8c787d4
|
4
|
+
data.tar.gz: fa9cfd71619b493736744a406aa7f3bbe0d65fb1ae84d7fd64a0bb6f65c68ebf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
##
|
29
|
+
## Purpose
|
30
30
|
|
31
|
-
|
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
|
-
|
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
|
data/lib/yfinrb/analysis.rb
CHANGED
data/lib/yfinrb/financials.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
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
|
data/lib/yfinrb/fundamentals.rb
CHANGED
data/lib/yfinrb/holders.rb
CHANGED
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
|
data/lib/yfinrb/price_history.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
require 'polars'
|
2
|
+
require 'polars-df'
|
1
3
|
|
2
|
-
class
|
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
|
-
|
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
|
-
|
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
|
-
|
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?")
|