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 +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
|
+

|
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?")
|