yf_as_dataframe 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6a690bd699a50d934c069b980e828d6449d114bd479170a84aff874d19f9d8e5
4
+ data.tar.gz: baca5e7d7e51ffb00c377f0a9af4bbb0d8c96ecb59ee0bd32c198f9a19b833f3
5
+ SHA512:
6
+ metadata.gz: 7ee7591b73bbde0fc295b1c0d55be234dbffe3728e260e7cc27f535f83bfddad29ed2664ee5a29efd8ed819b053e9e3e529e4acafb7614b00ff583ab71cfd1a3
7
+ data.tar.gz: 6ec2462ffb10cc9a99f8c44fbb79915cb68b6c8291a7bb794a5aaf8a87c7db2dc937cfb833b8dda3127dc0e03038ea3c4c18deb470ddac40f1b1a54b62f5c7e4
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: double_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: double_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
data/CHANGELOG.rst ADDED
File without changes
@@ -0,0 +1,15 @@
1
+ # Code of Conduct
2
+
3
+ ## Submitting a new issue
4
+
5
+ * Search through existing Issues and Discussions, in case your issue already exists and a solution is being developed.
6
+ * Ensure you read & follow the template form.
7
+ * Consider you may be the best person to investigate and fix.
8
+
9
+ ## Contributing to an existing Issue
10
+
11
+ * Read the entire thread.
12
+ * Ensure your comment is contributing something new/useful. Remember you can simply react to other comments.
13
+ * Be concise:
14
+ - use the formatting options
15
+ - if replying to a big comment, instead of quoting it, link to it
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in yf_as_dataframe.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rubocop", "~> 1.21"
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 TODO: Write your name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,299 @@
1
+ # YfAsDataframe
2
+
3
+ # Download market data from Yahoo! Finance's API
4
+
5
+ <table border=1 cellpadding=10><tr><td>
6
+
7
+ #### \*\*\* IMPORTANT LEGAL DISCLAIMER \*\*\*
8
+
9
+ ---
10
+
11
+ **Yahoo!, Y!Finance, and Yahoo! finance are registered trademarks of
12
+ Yahoo, Inc.**
13
+
14
+ yf_as_dataframe is **not** affiliated, endorsed, or vetted by Yahoo, Inc. It is
15
+ an open-source tool that uses Yahoo's publicly available APIs, and is
16
+ intended for research and educational purposes.
17
+
18
+ **You should refer to Yahoo!'s terms of use**
19
+ ([here](https://policies.yahoo.com/us/en/yahoo/terms/product-atos/apiforydn/index.htm),
20
+ [here](https://legal.yahoo.com/us/en/yahoo/terms/otos/index.html), and
21
+ [here](https://policies.yahoo.com/us/en/yahoo/terms/index.htm)) **for
22
+ details on your rights to use the actual data downloaded. Remember - the
23
+ Yahoo! finance API is intended for personal use only.**
24
+
25
+ </td></tr></table>
26
+
27
+ ---
28
+
29
+ ## Purpose
30
+
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
+
33
+ ### Quick Start: The Ticker module
34
+
35
+ The `Ticker` class, which allows you to access ticker data from Yahoo!'s unofficial API:
36
+
37
+ ```ruby
38
+
39
+ msft = YfAsDataframe::Ticker.new("MSFT")
40
+
41
+ # get all stock info
42
+ msft.info
43
+
44
+ # get historical market data as a dataframe
45
+ hist = msft.history(period: "1mo")
46
+ hist2 = msft.history(start: '2020-01-01', fin: '2021-12-31')
47
+
48
+ # show meta information about the history (requires history() to be called first)
49
+ msft.history_metadata
50
+
51
+ # show actions (dividends, splits, capital gains)
52
+ msft.actions
53
+ msft.dividends
54
+ msft.splits
55
+ msft.capital_gains # only for mutual funds & etfs
56
+
57
+ # show share count
58
+ msft.shares_full(start: "2022-01-01", fin: nil)
59
+
60
+ # show financials:
61
+ # - income statement
62
+ msft.income_stmt
63
+ msft.quarterly_income_stmt
64
+ # - balance sheet
65
+ msft.balance_sheet
66
+ msft.quarterly_balance_sheet
67
+ # - cash flow statement
68
+ msft.cashflow
69
+ msft.quarterly_cashflow
70
+
71
+ # show holders
72
+ msft.major_holders
73
+ msft.institutional_holders
74
+ msft.mutualfund_holders
75
+ msft.insider_transactions
76
+ msft.insider_purchases
77
+ msft.insider_roster_holders
78
+
79
+ # show recommendations
80
+ msft.recommendations
81
+ msft.recommendations_summary
82
+ msft.upgrades_downgrades
83
+
84
+ # Show future and historic earnings dates, returns at most next 4 quarters and last 8 quarters by default.
85
+ msft.earnings_dates
86
+
87
+ # show ISIN code
88
+ # ISIN = International Securities Identification Number
89
+ msft.isin
90
+
91
+ # show options expirations
92
+ msft.options
93
+
94
+ # show news
95
+ msft.news
96
+
97
+ # get option chain for specific expiration
98
+ opt = msft.option_chain('2026-12-18')
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
+ YfAsDataframe.ad(h)
106
+
107
+ # then
108
+ h.insert_at_idx(h.columns.length, YfAsDataframe.ad(h))
109
+ h['ad_results'] = YfAsDataframe.ad(h)
110
+
111
+ ```
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
+ YfAsDataframe.ad(df)
120
+ YfAsDataframe.adosc(df, short_window: 2, long_window: 5)
121
+ YfAsDataframe.adx(df, column: 'Adj Close', window: 5)
122
+ YfAsDataframe.adxr(df, column: 'Adj Close', window: 5)
123
+ YfAsDataframe.avg_daily_trading_volume(df, window: 20)
124
+ YfAsDataframe.ao(df)
125
+ YfAsDataframe.apo(df, column: 'Adj Close', short_window: 12, long_window: 29)
126
+ YfAsDataframe.aroon(df, window: 20)
127
+ YfAsDataframe.aroonosc(df, window: 20)
128
+ YfAsDataframe.avg_price(df)
129
+ YfAsDataframe.atr(df, window: 20)
130
+ YfAsDataframe.bbands(df, column: 'Adj Close', window: 20, stddev: 1 )
131
+ YfAsDataframe.bop(df)
132
+ YfAsDataframe.cci(df, window: 20)
133
+ YfAsDataframe.cmo(df, column: 'Adj Close', window: 20)
134
+ YfAsDataframe.cvi(df, window: 20)
135
+ YfAsDataframe.dema(df, column: 'Adj Close', window: 20)
136
+ YfAsDataframe.di(df, window: 20)
137
+ YfAsDataframe.dm(df, window: 20)
138
+ YfAsDataframe.dpo(df, column: 'Adj Close', window: 20)
139
+ YfAsDataframe.dx(df, window: 20)
140
+ YfAsDataframe.ema(df, column: 'Adj Close', window: 5)
141
+ YfAsDataframe.emv(df)
142
+ YfAsDataframe.fisher(df, window: 20)
143
+ YfAsDataframe.fosc(df, window: 20)
144
+ YfAsDataframe.hma(df, column: 'Adj Close', window: 5)
145
+ YfAsDataframe.kama(df, column: 'Adj Close', window: 5)
146
+ YfAsDataframe.kvo(df, short_window: 5, long_window: 20)
147
+ YfAsDataframe.linreg(df, column: 'Adj Close', window: 20)
148
+ YfAsDataframe.linregintercept(df, column: 'Adj Close', window: 20)
149
+ YfAsDataframe.linregslope(df, column: 'Adj Close', window: 20)
150
+ YfAsDataframe.macd(df, column: 'Adj Close', short_window: 12, long_window: 26, signal_window: 9)
151
+ YfAsDataframe.marketfi(df)
152
+ YfAsDataframe.mass(df, window: 20)
153
+ YfAsDataframe.max(df, column: 'Adj Close', window: 20)
154
+ YfAsDataframe.md(df, column: 'Adj Close', window: 20)
155
+ YfAsDataframe.median_price(df)
156
+ YfAsDataframe.mfi(df, window: 20)
157
+ YfAsDataframe.min(df, column: 'Adj Close', window: 20)
158
+ YfAsDataframe.mom(df, column: 'Adj Close', window: 5)
159
+ YfAsDataframe.moving_avgs(df, window: 20)
160
+ YfAsDataframe.natr(df, window: 20)
161
+ YfAsDataframe.nvi(df)
162
+ YfAsDataframe.obv(df)
163
+ YfAsDataframe.ppo(df, column: 'Adj Close', short_window: 12, long_window: 26)
164
+ YfAsDataframe.psar(df, acceleration_factor_step: 0.2, acceleration_factor_maximum: 2)
165
+ YfAsDataframe.pvi(df)
166
+ YfAsDataframe.qstick(df, window: 20)
167
+ YfAsDataframe.roc(df, column: 'Adj Close', window: 20)
168
+ YfAsDataframe.rocr(df, column: 'Adj Close', window: 20)
169
+ YfAsDataframe.rsi(df, window: 20)
170
+ YfAsDataframe.sma(df, column: 'Adj Close', window: 20)
171
+ YfAsDataframe.stddev(df, column: 'Adj Close', window: 20)
172
+ YfAsDataframe.stderr(df, column: 'Adj Close', window: 20)
173
+ YfAsDataframe.stochrsi(df, column: 'Adj Close', window: 20)
174
+ YfAsDataframe.sum(df, column: 'Adj Close', window: 20)
175
+ YfAsDataframe.tema(df, column: 'Adj Close', window: 20)
176
+ YfAsDataframe.tr(df, column: 'Adj Close')
177
+ YfAsDataframe.trima(df, column: 'Adj Close', window: 20)
178
+ YfAsDataframe.trix(df, column: 'Adj Close', window: 20)
179
+ YfAsDataframe.trima(df, column: 'Adj Close', window: 20)
180
+ YfAsDataframe.tsf(df, column: 'Adj Close', window: 20)
181
+ YfAsDataframe.typical_price(df)
182
+ YfAsDataframe.ultosc(df, short_window: 5, medium_window: 12, long_window: 26)
183
+ YfAsDataframe.weighted_close_price(df)
184
+ YfAsDataframe.var(df, column: 'Adj Close', window: 20)
185
+ YfAsDataframe.vhf(df, column: 'Adj Close', window: 20)
186
+ YfAsDataframe.vidya(df, column: 'Adj Close', short_window: 5, long_window: 20, alpha: 0.2)
187
+ YfAsDataframe.volatility(df, column: 'Adj Close', window: 20)
188
+ YfAsDataframe.vosc(df, column: 'Adj Close', short_window: 5, long_window: 20)
189
+ YfAsDataframe.vol_weighted_moving_avg(df, window: 20)
190
+ YfAsDataframe.wad(df)
191
+ YfAsDataframe.wcprice(df)
192
+ YfAsDataframe.wilders(df, column: 'Adj Close', window: 20)
193
+ YfAsDataframe.willr(df, window: 20)
194
+ YfAsDataframe.wma(df, column: 'Adj Close', window: 5)
195
+ YfAsDataframe.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 = YfAsDataframe::Ticker.new("MSFT")
212
+ # =>
213
+ # #<YfAsDataframe::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, YfAsDataframe.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 YfAsDataframe 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
+
255
+ ---
256
+
257
+ ## Installation
258
+
259
+ Add this line to your application's Gemfile:
260
+
261
+ ```ruby
262
+ gem 'yf_as_dataframe'
263
+ ```
264
+
265
+ And then execute:
266
+
267
+ $ bundle install
268
+
269
+ Or install it yourself as:
270
+
271
+ $ gem install yf_as_dataframe
272
+
273
+ ---
274
+
275
+ ## Development
276
+
277
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
278
+
279
+ ## Contributing
280
+
281
+ Bug reports and pull requests are welcome on GitHub at https://github.com/bmck/yf_as_dataframe.
282
+
283
+ ---
284
+
285
+ ### Legal Stuff
286
+
287
+ The **yf_as_dataframe** gem is available as open source under the **MIT Software License** (https://opensource.org/licenses/MIT). See
288
+ the [LICENSE.txt](./LICENSE.txt) file in the release for details.
289
+
290
+
291
+ AGAIN - yf_as_dataframe is **not** affiliated, endorsed, or vetted by Yahoo, Inc. It's
292
+ an open-source tool that uses Yahoo's publicly available APIs, and is
293
+ intended for research and educational purposes. You should refer to Yahoo!'s terms of use
294
+ ([here](https://policies.yahoo.com/us/en/yahoo/terms/product-atos/apiforydn/index.htm),
295
+ [here](https://legal.yahoo.com/us/en/yahoo/terms/otos/index.html), and
296
+ [here](https://policies.yahoo.com/us/en/yahoo/terms/index.htm)) for
297
+ details on your rights to use the actual data downloaded.
298
+
299
+ ---
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rubocop/rake_task"
5
+
6
+ RuboCop::RakeTask.new
7
+
8
+ task default: :rubocop
data/chart.png ADDED
Binary file
@@ -0,0 +1,68 @@
1
+ class YfAsDataframe
2
+ module Analysis
3
+ extend ActiveSupport::Concern
4
+
5
+ # attr_accessor :ticker
6
+
7
+ def self.included(base) # built-in Ruby hook for modules
8
+ base.class_eval do
9
+ original_method = instance_method(:initialize)
10
+ define_method(:initialize) do |*args, &block|
11
+ original_method.bind(self).call(*args, &block)
12
+ initialize_analysis # (your module code here)
13
+ end
14
+ end
15
+ end
16
+
17
+ def initialize_analysis
18
+ @earnings_trend = nil
19
+ @analyst_trend_details = nil
20
+ @analyst_price_target = nil
21
+ @ev_est = nil
22
+ @ps_est = nil
23
+ end
24
+
25
+
26
+ def earnings_trend #(self)
27
+ raise YFNotImplementedError.new('earnings_trend') if @earnings_trend.nil?
28
+ return earnings_trend
29
+ end
30
+
31
+ def analyst_trend_details #(self)
32
+ raise YFNotImplementedError.new('analyst_trend_details') if @analyst_trend_details.nil?
33
+ return analyst_trend_details
34
+ end
35
+
36
+ alias_method :trend_details, :analyst_trend_details
37
+
38
+ def analyst_price_target #(self)
39
+ raise YFNotImplementedError.new('analyst_price_target') if @analyst_price_target.nil?
40
+ return analyst_price_target
41
+ end
42
+
43
+ alias_method :price_targets, :analyst_price_target
44
+
45
+ def rev_est #(self)
46
+ raise YFNotImplementedError.new('rev_est') if @rev_est.nil?
47
+ return rev_est
48
+ end
49
+
50
+ alias_method :rev_forecast, :rev_est
51
+
52
+ def eps_est #(self)
53
+ raise YFNotImplementedError.new('eps_est') if @eps_est.nil?
54
+ return eps_est
55
+ end
56
+
57
+ alias_method :earnings_forecast, :eps_est
58
+
59
+ # analysis_methods = [:earnings_trend, :analyst_trend_details, :trend_details, \
60
+ # :price_targets, :analyst_price_target, :rev_est, \
61
+ # :rev_forecast, :eps_est, :earnings_forecast ]
62
+ # analysis_methods.each do |meth|
63
+ # # delegate meth, to: :analysis
64
+ # alias_method "get_#{meth}".to_sym, meth
65
+ # end
66
+
67
+ end
68
+ end