yfinrb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ae85dede3894ef988f67e2ad11cbade387915950c3387e4f593c34eb172e4d27
4
+ data.tar.gz: ff90bb244a371653b94696e1137cdeecc2a955f1acd0f355c54068073c439f06
5
+ SHA512:
6
+ metadata.gz: a5be1264d728ab72e778062b430162a27e6bf40b970893495e2db61c1760434401440b6bda8ca982088c2e9254e9452a2585d5a6e9dd5ad6d3b8157da03d0000
7
+ data.tar.gz: f40d51d8164b62fb3edcd04f98011f9450c8523460e22abfe1e052cedaa11c7edc9c8a5ce94a44602acc421e8eec822dc50c763e4a04aa43a90c02c28422f941
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 yfinrb.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,144 @@
1
+ # Yfinrb
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
+ yfinrb 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
+ ## Quick Start
30
+
31
+ ### The Ticker module
32
+
33
+ The `Ticker` class, which allows you to access ticker data:
34
+
35
+ ```ruby
36
+
37
+ msft = Yfinrb::Ticker("MSFT")
38
+
39
+ # get all stock info
40
+ msft.info
41
+
42
+ # get historical market data
43
+ hist = msft.history(period: "1mo")
44
+ hist2 = msft.history(start: '2020-01-01', fin: '2021-12-31')
45
+
46
+ # show meta information about the history (requires history() to be called first)
47
+ msft.history_metadata
48
+
49
+ # show actions (dividends, splits, capital gains)
50
+ msft.actions
51
+ msft.dividends
52
+ msft.splits
53
+ msft.capital_gains # only for mutual funds & etfs
54
+
55
+ # show share count
56
+ msft.shares_full(start: "2022-01-01", fin: nil)
57
+
58
+ # show financials:
59
+ # - income statement
60
+ msft.income_stmt
61
+ msft.quarterly_income_stmt
62
+ # - balance sheet
63
+ msft.balance_sheet
64
+ msft.quarterly_balance_sheet
65
+ # - cash flow statement
66
+ msft.cashflow
67
+ msft.quarterly_cashflow
68
+
69
+ # show holders
70
+ msft.major_holders
71
+ msft.institutional_holders
72
+ msft.mutualfund_holders
73
+ msft.insider_transactions
74
+ msft.insider_purchases
75
+ msft.insider_roster_holders
76
+
77
+ # show recommendations
78
+ msft.recommendations
79
+ msft.recommendations_summary
80
+ msft.upgrades_downgrades
81
+
82
+ # Show future and historic earnings dates, returns at most next 4 quarters and last 8 quarters by default.
83
+ msft.earnings_dates
84
+
85
+ # show ISIN code
86
+ # ISIN = International Securities Identification Number
87
+ msft.isin
88
+
89
+ # show options expirations
90
+ msft.options
91
+
92
+ # show news
93
+ msft.news
94
+
95
+ # get option chain for specific expiration
96
+ opt = msft.option_chain('2026-12-18')
97
+ # data available via: opt.calls, opt.puts
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Installation
103
+
104
+ Add this line to your application's Gemfile:
105
+
106
+ ```ruby
107
+ gem 'yfinrb'
108
+ ```
109
+
110
+ And then execute:
111
+
112
+ $ bundle install
113
+
114
+ Or install it yourself as:
115
+
116
+ $ gem install yfinrb
117
+
118
+ ---
119
+
120
+ ## Development
121
+
122
+ 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).
123
+
124
+ ## Contributing
125
+
126
+ Bug reports and pull requests are welcome on GitHub at https://github.com/bmck/yfinrb.
127
+
128
+ ---
129
+
130
+ ### Legal Stuff
131
+
132
+ The **yfinrb** gem is available as open source under the **MIT Software License** (https://opensource.org/licenses/MIT). See
133
+ the [LICENSE.txt](./LICENSE.txt) file in the release for details.
134
+
135
+
136
+ AGAIN - yfinrb is **not** affiliated, endorsed, or vetted by Yahoo, Inc. It's
137
+ an open-source tool that uses Yahoo's publicly available APIs, and is
138
+ intended for research and educational purposes. You should refer to Yahoo!'s terms of use
139
+ ([here](https://policies.yahoo.com/us/en/yahoo/terms/product-atos/apiforydn/index.htm),
140
+ [here](https://legal.yahoo.com/us/en/yahoo/terms/otos/index.html), and
141
+ [here](https://policies.yahoo.com/us/en/yahoo/terms/index.htm)) for
142
+ details on your rights to use the actual data downloaded.
143
+
144
+ ---
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
@@ -0,0 +1,68 @@
1
+ class Yfin
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
@@ -0,0 +1,302 @@
1
+ class Yfin
2
+ module Financials
3
+ include ActiveSupport::Inflector
4
+
5
+ def self.included(base) # built-in Ruby hook for modules
6
+ base.class_eval do
7
+ original_method = instance_method(:initialize)
8
+ define_method(:initialize) do |*args, &block|
9
+ original_method.bind(self).call(*args, &block)
10
+ initialize_financials # (your module code here)
11
+ end
12
+ end
13
+ end
14
+
15
+ def initialize_financials
16
+ @income_time_series = {}
17
+ @balance_sheet_time_series = {}
18
+ @cash_flow_time_series = {}
19
+ end
20
+
21
+ def income_stmt; _get_income_stmt(pretty: true); end
22
+ def quarterly_income_stmt; _get_income_stmt(pretty: true, freq: 'quarterly'); end
23
+ alias_method :quarterly_incomestmt, :quarterly_income_stmt
24
+ alias_method :quarterly_financials, :quarterly_income_stmt
25
+ alias_method :annual_incomestmt, :income_stmt
26
+ alias_method :annual_income_stmt, :income_stmt
27
+ alias_method :annual_financials, :income_stmt
28
+
29
+ def balance_sheet; _get_balance_sheet(pretty: true); end
30
+ def quarterly_balance_sheet; _get_balance_sheet(pretty: true, freq: 'quarterly'); end
31
+ alias_method :quarterly_balancesheet, :quarterly_balance_sheet
32
+ alias_method :annual_balance_sheet, :balance_sheet
33
+ alias_method :annual_balancesheet, :balance_sheet
34
+
35
+ def cash_flow; _get_cash_flow(pretty: true, freq: 'yearly'); end
36
+ alias_method :cashflow, :cash_flow
37
+ def quarterly_cash_flow; _get_cash_flow(pretty: true, freq: 'quarterly'); end
38
+ alias_method :quarterly_cashflow, :quarterly_cash_flow
39
+ alias_method :annual_cashflow, :cash_flow
40
+ alias_method :annual_cash_flow, :cash_flow
41
+
42
+
43
+
44
+
45
+
46
+
47
+
48
+
49
+
50
+ private
51
+
52
+ def _get_cash_flow(as_dict: false, pretty: false, freq: "yearly")
53
+ data = _get_cash_flow_time_series(freq)
54
+
55
+ if pretty
56
+ # data = data.dup
57
+ # data.index = Utils.camel2title(data.index, sep: ' ', acronyms: ["PPE"])
58
+ end
59
+
60
+ as_dict ? data.to_h : data
61
+ end
62
+
63
+ def _get_income_stmt(as_dict: false, pretty: false, freq: "yearly")
64
+ data = _get_income_time_series(freq)
65
+
66
+ if pretty
67
+ # data = data.dup
68
+ # data.index = Utils.camel2title(data.index, sep: ' ', acronyms: ["EBIT", "EBITDA", "EPS", "NI"])
69
+ end
70
+
71
+ as_dict ? data.to_h : data
72
+ end
73
+
74
+
75
+ def _get_balance_sheet(as_dict: false, pretty: false, freq: "yearly")
76
+ data = _get_balance_sheet_time_series(freq)
77
+
78
+ if pretty
79
+ # data = data.dup
80
+ # data.index = Utils.camel2title(data.index, sep: ' ', acronyms: ["PPE"])
81
+ end
82
+
83
+ as_dict ? data.to_h : data
84
+ end
85
+
86
+ def _get_income_time_series(freq = "yearly")
87
+ res = @income_time_series
88
+ res[freq] ||= _fetch_time_series("income", freq)
89
+ res[freq]
90
+ end
91
+
92
+ def _get_balance_sheet_time_series(freq = "yearly")
93
+ res = @balance_sheet_time_series
94
+ res[freq] ||= _fetch_time_series("balancesheet", freq)
95
+ res[freq]
96
+ end
97
+
98
+ def _get_cash_flow_time_series(freq = "yearly")
99
+ res = @cash_flow_time_series
100
+ res[freq] ||= _fetch_time_series("cashflow", freq)
101
+ res[freq]
102
+ end
103
+
104
+ def _get_financials_time_series(timescale, ts_keys)
105
+ Polars::Config.set_tbl_rows(-1)
106
+ timescale_translation = { "yearly" => "annual", "quarterly" => "quarterly" }
107
+ timescale = timescale_translation[timescale]
108
+
109
+ ts_url_base = "https://query2.finance.yahoo.com/ws/fundamentals-timeseries/v1/finance/timeseries/#{symbol}?symbol=#{symbol}"
110
+ url = ts_url_base + "&type=" + ts_keys.map { |k| "#{timescale}#{k}" }.join(",")
111
+ start_dt = DateTime.new(2016, 12, 31)
112
+ end_dt = DateTime.now.tomorrow.midnight
113
+ url += "&period1=#{start_dt.to_i}&period2=#{end_dt.to_i}"
114
+
115
+ json_str = get(url).parsed_response
116
+ data_raw = json_str["timeseries"]["result"]
117
+ data_raw.each { |d| d.delete("meta") }
118
+
119
+ timestamps = data_raw.map{|d| d['timestamp']}.flatten.uniq.compact.uniq.sort.reverse
120
+
121
+ cols = [ :metric ] + timestamps.map{|ts| Time.at(ts).utc.to_date.to_s }
122
+ df = {}; cols.each {|c| df[c] = [] }
123
+ ts_keys.each { |k| df[:metric] << k.gsub(/([A-Z]+)/,' \1').strip }
124
+
125
+ timestamps.each do |ts|
126
+ ts_date = Time.at(ts).utc.to_date.to_s
127
+
128
+ ts_keys.each_with_index do |k, ndex|
129
+ l = "#{timescale}#{k}"
130
+ d = data_raw.detect{|dd| dd.key?(l) }
131
+ if d.nil?
132
+ df[ts_date] << ''
133
+ next
134
+ end
135
+ tv = d[l].detect{|dd| dd['asOfDate'] == ts_date }
136
+ df[ts_date] << (tv.nil? ? '' : tv['reportedValue']['raw'].to_s)
137
+ end
138
+
139
+ end
140
+
141
+ df = Polars::DataFrame.new(df)
142
+ timestamps.map{|ts| Time.at(ts).utc.to_date.to_s }.each do |t|
143
+ puts t
144
+ df.replace(t, Polars::Series.new(df[t].cast(Polars::String)))
145
+ end
146
+ df
147
+ end
148
+
149
+ def _fetch_time_series(nam, timescale)
150
+ # Rails.logger.info { "#{__FILE__}:#{__LINE__}"}
151
+ allowed_names = FUNDAMENTALS_KEYS.keys + [:income]
152
+ allowed_timescales = ["yearly", "quarterly"]
153
+
154
+ raise ArgumentError, "Illegal argument: name (#{nam}) must be one of: #{allowed_names}" unless allowed_names.include?(nam.to_sym)
155
+ raise ArgumentError, "Illegal argument: timescale (#{timescale}) must be one of: #{allowed_timescales}" unless allowed_timescales.include?(timescale)
156
+
157
+ begin
158
+ statement = _create_financials_table(nam, timescale)
159
+ return statement unless statement.nil?
160
+ rescue Yfin::YfinDataException => e
161
+ Rails.logger.error {"#{@symbol}: Failed to create #{nam} financials table for reason: #{e}"}
162
+ end
163
+ Polars::DataFrame.new()
164
+ end
165
+
166
+ def _create_financials_table(nam, timescale)
167
+ nam = "financials" if nam == "income"
168
+
169
+ keys = FUNDAMENTALS_KEYS[nam.to_sym]
170
+ begin
171
+ _get_financials_time_series(timescale, keys)
172
+ rescue StandardError
173
+ nil
174
+ end
175
+ end
176
+
177
+
178
+
179
+ FUNDAMENTALS_KEYS = {
180
+ financials: [
181
+ "TaxEffectOfUnusualItems", "TaxRateForCalcs", "NormalizedEBITDA", "NormalizedDilutedEPS",
182
+ "NormalizedBasicEPS", "TotalUnusualItems", "TotalUnusualItemsExcludingGoodwill",
183
+ "NetIncomeFromContinuingOperationNetMinorityInterest", "ReconciledDepreciation",
184
+ "ReconciledCostOfRevenue", "EBITDA", "EBIT", "NetInterestIncome", "InterestExpense",
185
+ "InterestIncome", "ContinuingAndDiscontinuedDilutedEPS", "ContinuingAndDiscontinuedBasicEPS",
186
+ "NormalizedIncome", "NetIncomeFromContinuingAndDiscontinuedOperation", "TotalExpenses",
187
+ "RentExpenseSupplemental", "ReportedNormalizedDilutedEPS", "ReportedNormalizedBasicEPS",
188
+ "TotalOperatingIncomeAsReported", "DividendPerShare", "DilutedAverageShares", "BasicAverageShares",
189
+ "DilutedEPS", "DilutedEPSOtherGainsLosses", "TaxLossCarryforwardDilutedEPS",
190
+ "DilutedAccountingChange", "DilutedExtraordinary", "DilutedDiscontinuousOperations",
191
+ "DilutedContinuousOperations", "BasicEPS", "BasicEPSOtherGainsLosses", "TaxLossCarryforwardBasicEPS",
192
+ "BasicAccountingChange", "BasicExtraordinary", "BasicDiscontinuousOperations",
193
+ "BasicContinuousOperations", "DilutedNIAvailtoComStockholders", "AverageDilutionEarnings",
194
+ "NetIncomeCommonStockholders", "OtherunderPreferredStockDividend", "PreferredStockDividends",
195
+ "NetIncome", "MinorityInterests", "NetIncomeIncludingNoncontrollingInterests",
196
+ "NetIncomeFromTaxLossCarryforward", "NetIncomeExtraordinary", "NetIncomeDiscontinuousOperations",
197
+ "NetIncomeContinuousOperations", "EarningsFromEquityInterestNetOfTax", "TaxProvision",
198
+ "PretaxIncome", "OtherIncomeExpense", "OtherNonOperatingIncomeExpenses", "SpecialIncomeCharges",
199
+ "GainOnSaleOfPPE", "GainOnSaleOfBusiness", "OtherSpecialCharges", "WriteOff",
200
+ "ImpairmentOfCapitalAssets", "RestructuringAndMergernAcquisition", "SecuritiesAmortization",
201
+ "EarningsFromEquityInterest", "GainOnSaleOfSecurity", "NetNonOperatingInterestIncomeExpense",
202
+ "TotalOtherFinanceCost", "InterestExpenseNonOperating", "InterestIncomeNonOperating",
203
+ "OperatingIncome", "OperatingExpense", "OtherOperatingExpenses", "OtherTaxes",
204
+ "ProvisionForDoubtfulAccounts", "DepreciationAmortizationDepletionIncomeStatement",
205
+ "DepletionIncomeStatement", "DepreciationAndAmortizationInIncomeStatement", "Amortization",
206
+ "AmortizationOfIntangiblesIncomeStatement", "DepreciationIncomeStatement", "ResearchAndDevelopment",
207
+ "SellingGeneralAndAdministration", "SellingAndMarketingExpense", "GeneralAndAdministrativeExpense",
208
+ "OtherGandA", "InsuranceAndClaims", "RentAndLandingFees", "SalariesAndWages", "GrossProfit",
209
+ "CostOfRevenue", "TotalRevenue", "ExciseTaxes", "OperatingRevenue"
210
+ ],
211
+ balancesheet: [
212
+ "TreasurySharesNumber", "PreferredSharesNumber", "OrdinarySharesNumber", "ShareIssued", "NetDebt",
213
+ "TotalDebt", "TangibleBookValue", "InvestedCapital", "WorkingCapital", "NetTangibleAssets",
214
+ "CapitalLeaseObligations", "CommonStockEquity", "PreferredStockEquity", "TotalCapitalization",
215
+ "TotalEquityGrossMinorityInterest", "MinorityInterest", "StockholdersEquity",
216
+ "OtherEquityInterest", "GainsLossesNotAffectingRetainedEarnings", "OtherEquityAdjustments",
217
+ "FixedAssetsRevaluationReserve", "ForeignCurrencyTranslationAdjustments",
218
+ "MinimumPensionLiabilities", "UnrealizedGainLoss", "TreasuryStock", "RetainedEarnings",
219
+ "AdditionalPaidInCapital", "CapitalStock", "OtherCapitalStock", "CommonStock", "PreferredStock",
220
+ "TotalPartnershipCapital", "GeneralPartnershipCapital", "LimitedPartnershipCapital",
221
+ "TotalLiabilitiesNetMinorityInterest", "TotalNonCurrentLiabilitiesNetMinorityInterest",
222
+ "OtherNonCurrentLiabilities", "LiabilitiesHeldforSaleNonCurrent", "RestrictedCommonStock",
223
+ "PreferredSecuritiesOutsideStockEquity", "DerivativeProductLiabilities", "EmployeeBenefits",
224
+ "NonCurrentPensionAndOtherPostretirementBenefitPlans", "NonCurrentAccruedExpenses",
225
+ "DuetoRelatedPartiesNonCurrent", "TradeandOtherPayablesNonCurrent",
226
+ "NonCurrentDeferredLiabilities", "NonCurrentDeferredRevenue",
227
+ "NonCurrentDeferredTaxesLiabilities", "LongTermDebtAndCapitalLeaseObligation",
228
+ "LongTermCapitalLeaseObligation", "LongTermDebt", "LongTermProvisions", "CurrentLiabilities",
229
+ "OtherCurrentLiabilities", "CurrentDeferredLiabilities", "CurrentDeferredRevenue",
230
+ "CurrentDeferredTaxesLiabilities", "CurrentDebtAndCapitalLeaseObligation",
231
+ "CurrentCapitalLeaseObligation", "CurrentDebt", "OtherCurrentBorrowings", "LineOfCredit",
232
+ "CommercialPaper", "CurrentNotesPayable", "PensionandOtherPostRetirementBenefitPlansCurrent",
233
+ "CurrentProvisions", "PayablesAndAccruedExpenses", "CurrentAccruedExpenses", "InterestPayable",
234
+ "Payables", "OtherPayable", "DuetoRelatedPartiesCurrent", "DividendsPayable", "TotalTaxPayable",
235
+ "IncomeTaxPayable", "AccountsPayable", "TotalAssets", "TotalNonCurrentAssets",
236
+ "OtherNonCurrentAssets", "DefinedPensionBenefit", "NonCurrentPrepaidAssets",
237
+ "NonCurrentDeferredAssets", "NonCurrentDeferredTaxesAssets", "DuefromRelatedPartiesNonCurrent",
238
+ "NonCurrentNoteReceivables", "NonCurrentAccountsReceivable", "FinancialAssets",
239
+ "InvestmentsAndAdvances", "OtherInvestments", "InvestmentinFinancialAssets",
240
+ "HeldToMaturitySecurities", "AvailableForSaleSecurities",
241
+ "FinancialAssetsDesignatedasFairValueThroughProfitorLossTotal", "TradingSecurities",
242
+ "LongTermEquityInvestment", "InvestmentsinJointVenturesatCost",
243
+ "InvestmentsInOtherVenturesUnderEquityMethod", "InvestmentsinAssociatesatCost",
244
+ "InvestmentsinSubsidiariesatCost", "InvestmentProperties", "GoodwillAndOtherIntangibleAssets",
245
+ "OtherIntangibleAssets", "Goodwill", "NetPPE", "AccumulatedDepreciation", "GrossPPE", "Leases",
246
+ "ConstructionInProgress", "OtherProperties", "MachineryFurnitureEquipment",
247
+ "BuildingsAndImprovements", "LandAndImprovements", "Properties", "CurrentAssets",
248
+ "OtherCurrentAssets", "HedgingAssetsCurrent", "AssetsHeldForSaleCurrent", "CurrentDeferredAssets",
249
+ "CurrentDeferredTaxesAssets", "RestrictedCash", "PrepaidAssets", "Inventory",
250
+ "InventoriesAdjustmentsAllowances", "OtherInventories", "FinishedGoods", "WorkInProcess",
251
+ "RawMaterials", "Receivables", "ReceivablesAdjustmentsAllowances", "OtherReceivables",
252
+ "DuefromRelatedPartiesCurrent", "TaxesReceivable", "AccruedInterestReceivable", "NotesReceivable",
253
+ "LoansReceivable", "AccountsReceivable", "AllowanceForDoubtfulAccountsReceivable",
254
+ "GrossAccountsReceivable", "CashCashEquivalentsAndShortTermInvestments",
255
+ "OtherShortTermInvestments", "CashAndCashEquivalents", "CashEquivalents", "CashFinancial"
256
+ ],
257
+ cashflow: [
258
+ "ForeignSales", "DomesticSales", "AdjustedGeographySegmentData", "FreeCashFlow",
259
+ "RepurchaseOfCapitalStock", "RepaymentOfDebt", "IssuanceOfDebt", "IssuanceOfCapitalStock",
260
+ "CapitalExpenditure", "InterestPaidSupplementalData", "IncomeTaxPaidSupplementalData",
261
+ "EndCashPosition", "OtherCashAdjustmentOutsideChangeinCash", "BeginningCashPosition",
262
+ "EffectOfExchangeRateChanges", "ChangesInCash", "OtherCashAdjustmentInsideChangeinCash",
263
+ "CashFlowFromDiscontinuedOperation", "FinancingCashFlow", "CashFromDiscontinuedFinancingActivities",
264
+ "CashFlowFromContinuingFinancingActivities", "NetOtherFinancingCharges", "InterestPaidCFF",
265
+ "ProceedsFromStockOptionExercised", "CashDividendsPaid", "PreferredStockDividendPaid",
266
+ "CommonStockDividendPaid", "NetPreferredStockIssuance", "PreferredStockPayments",
267
+ "PreferredStockIssuance", "NetCommonStockIssuance", "CommonStockPayments", "CommonStockIssuance",
268
+ "NetIssuancePaymentsOfDebt", "NetShortTermDebtIssuance", "ShortTermDebtPayments",
269
+ "ShortTermDebtIssuance", "NetLongTermDebtIssuance", "LongTermDebtPayments", "LongTermDebtIssuance",
270
+ "InvestingCashFlow", "CashFromDiscontinuedInvestingActivities",
271
+ "CashFlowFromContinuingInvestingActivities", "NetOtherInvestingChanges", "InterestReceivedCFI",
272
+ "DividendsReceivedCFI", "NetInvestmentPurchaseAndSale", "SaleOfInvestment", "PurchaseOfInvestment",
273
+ "NetInvestmentPropertiesPurchaseAndSale", "SaleOfInvestmentProperties",
274
+ "PurchaseOfInvestmentProperties", "NetBusinessPurchaseAndSale", "SaleOfBusiness",
275
+ "PurchaseOfBusiness", "NetIntangiblesPurchaseAndSale", "SaleOfIntangibles", "PurchaseOfIntangibles",
276
+ "NetPPEPurchaseAndSale", "SaleOfPPE", "PurchaseOfPPE", "CapitalExpenditureReported",
277
+ "OperatingCashFlow", "CashFromDiscontinuedOperatingActivities",
278
+ "CashFlowFromContinuingOperatingActivities", "TaxesRefundPaid", "InterestReceivedCFO",
279
+ "InterestPaidCFO", "DividendReceivedCFO", "DividendPaidCFO", "ChangeInWorkingCapital",
280
+ "ChangeInOtherWorkingCapital", "ChangeInOtherCurrentLiabilities", "ChangeInOtherCurrentAssets",
281
+ "ChangeInPayablesAndAccruedExpense", "ChangeInAccruedExpense", "ChangeInInterestPayable",
282
+ "ChangeInPayable", "ChangeInDividendPayable", "ChangeInAccountPayable", "ChangeInTaxPayable",
283
+ "ChangeInIncomeTaxPayable", "ChangeInPrepaidAssets", "ChangeInInventory", "ChangeInReceivables",
284
+ "ChangesInAccountReceivables", "OtherNonCashItems", "ExcessTaxBenefitFromStockBasedCompensation",
285
+ "StockBasedCompensation", "UnrealizedGainLossOnInvestmentSecurities", "ProvisionandWriteOffofAssets",
286
+ "AssetImpairmentCharge", "AmortizationOfSecurities", "DeferredTax", "DeferredIncomeTax",
287
+ "DepreciationAmortizationDepletion", "Depletion", "DepreciationAndAmortization",
288
+ "AmortizationCashFlow", "AmortizationOfIntangibles", "Depreciation", "OperatingGainsLosses",
289
+ "PensionAndEmployeeBenefitExpense", "EarningsLossesFromEquityInvestments",
290
+ "GainLossOnInvestmentSecurities", "NetForeignCurrencyExchangeGainLoss", "GainLossOnSaleOfPPE",
291
+ "GainLossOnSaleOfBusiness", "NetIncomeFromContinuingOperations",
292
+ "CashFlowsfromusedinOperatingActivitiesDirect", "TaxesRefundPaidDirect", "InterestReceivedDirect",
293
+ "InterestPaidDirect", "DividendsReceivedDirect", "DividendsPaidDirect", "ClassesofCashPayments",
294
+ "OtherCashPaymentsfromOperatingActivities", "PaymentsonBehalfofEmployees",
295
+ "PaymentstoSuppliersforGoodsandServices", "ClassesofCashReceiptsfromOperatingActivities",
296
+ "OtherCashReceiptsfromOperatingActivities", "ReceiptsfromGovernmentGrants", "ReceiptsfromCustomers"
297
+ ]
298
+ }
299
+
300
+
301
+ end
302
+ end
@@ -0,0 +1,54 @@
1
+
2
+ class Yfin
3
+ module Fundamentals
4
+ extend ActiveSupport::Concern
5
+
6
+ def self.included(base) # built-in Ruby hook for modules
7
+ base.class_eval do
8
+ attr_reader :financials, :earnings, :shares, :ticker
9
+
10
+ original_method = instance_method(:initialize)
11
+ define_method(:initialize) do |*args, &block|
12
+ original_method.bind(self).call(*args, &block)
13
+ initialize_fundamentals # (your module code here)
14
+ end
15
+ end
16
+ end
17
+
18
+ def initialize_fundamentals
19
+ @earnings = nil
20
+ @financials = nil
21
+ @shares = nil
22
+
23
+ @financials_data = nil
24
+ @fin_data_quote = nil
25
+ @basics_already_scraped = false
26
+ end
27
+
28
+ # delegate :proxy, :tz, to: :ticker
29
+
30
+ def earnings
31
+ raise YFNotImplementedError.new('earnings') if @earnings.nil?
32
+ @earnings
33
+ end
34
+
35
+ def shares
36
+ raise YFNotImplementedError.new('shares') if @shares.nil?
37
+ @shares
38
+ end
39
+
40
+ # financials_methods = [:income_stmt, :incomestmt, :financials, :balance_sheet, :balancesheet, :cash_flow, :cashflow]
41
+ # financials_methods.each do |meth|
42
+ # delegate "get_#{meth}".to_sym, meth, to: :financials
43
+ # end
44
+
45
+ # fundamentals_methods = [:earnings, :shares]
46
+ # fundamentals_methods.each do |meth|
47
+ # alias_method "get_#{meth}".to_sym, meth
48
+ # end
49
+
50
+ # def quarterly_earnings
51
+ # earnings(freq: 'quarterly')
52
+ # end
53
+ end
54
+ end