finmodeling 0.1 → 0.2
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.
- data/.gitignore +0 -0
- data/Gemfile +2 -0
- data/README.md +289 -269
- data/Rakefile +12 -0
- data/TODO.txt +113 -20
- data/examples/{dump_report.rb → dump_latest_10k.rb} +1 -1
- data/examples/list_disclosures.rb +50 -0
- data/examples/lists/nasdaq-mid-to-mega-tech-symbols.txt +0 -0
- data/examples/show_report.rb +112 -32
- data/examples/show_reports.rb +162 -33
- data/finmodeling.gemspec +4 -1
- data/lib/finmodeling/annual_report_filing.rb +97 -18
- data/lib/finmodeling/array_with_stats.rb +0 -0
- data/lib/finmodeling/assets_calculation.rb +12 -3
- data/lib/finmodeling/assets_item.rb +0 -0
- data/lib/finmodeling/assets_item_vectors.rb +0 -0
- data/lib/finmodeling/balance_sheet_analyses.rb +19 -4
- data/lib/finmodeling/balance_sheet_calculation.rb +52 -37
- data/lib/finmodeling/calculation_summary.rb +119 -14
- data/lib/finmodeling/can_cache_classifications.rb +0 -0
- data/lib/finmodeling/can_cache_summaries.rb +0 -0
- data/lib/finmodeling/can_choose_successive_periods.rb +15 -0
- data/lib/finmodeling/can_classify_rows.rb +0 -0
- data/lib/finmodeling/capm.rb +80 -0
- data/lib/finmodeling/cash_change_calculation.rb +3 -3
- data/lib/finmodeling/cash_change_item.rb +0 -0
- data/lib/finmodeling/cash_change_item_vectors.rb +0 -0
- data/lib/finmodeling/cash_change_summary_from_differences.rb +36 -0
- data/lib/finmodeling/cash_flow_statement_analyses.rb +36 -0
- data/lib/finmodeling/cash_flow_statement_calculation.rb +28 -52
- data/lib/finmodeling/classifiers.rb +2 -0
- data/lib/finmodeling/company.rb +0 -0
- data/lib/finmodeling/company_filing.rb +30 -7
- data/lib/finmodeling/company_filing_calculation.rb +16 -6
- data/lib/finmodeling/company_filings.rb +112 -46
- data/lib/finmodeling/comprehensive_income_calculation.rb +60 -0
- data/lib/finmodeling/comprehensive_income_statement_calculation.rb +74 -0
- data/lib/finmodeling/comprehensive_income_statement_item.rb +20 -0
- data/lib/finmodeling/comprehensive_income_statement_item_vectors.rb +235 -0
- data/lib/finmodeling/config.rb +0 -0
- data/lib/finmodeling/debt_cost_of_capital.rb +14 -0
- data/lib/finmodeling/equity_change_calculation.rb +43 -0
- data/lib/finmodeling/equity_change_item.rb +25 -0
- data/lib/finmodeling/equity_change_item_vectors.rb +156 -0
- data/lib/finmodeling/factory.rb +0 -0
- data/lib/finmodeling/fama_french_cost_of_equity.rb +119 -0
- data/lib/finmodeling/float_helpers.rb +14 -8
- data/lib/finmodeling/forecasted_reformulated_balance_sheet.rb +55 -0
- data/lib/finmodeling/forecasted_reformulated_income_statement.rb +110 -0
- data/lib/finmodeling/forecasts.rb +4 -4
- data/lib/finmodeling/has_string_classifer.rb +0 -0
- data/lib/finmodeling/income_statement_analyses.rb +23 -17
- data/lib/finmodeling/income_statement_calculation.rb +46 -43
- data/lib/finmodeling/income_statement_item.rb +1 -1
- data/lib/finmodeling/income_statement_item_vectors.rb +24 -13
- data/lib/finmodeling/invalid_filing_error.rb +4 -0
- data/lib/finmodeling/liabs_and_equity_calculation.rb +18 -8
- data/lib/finmodeling/liabs_and_equity_item.rb +1 -1
- data/lib/finmodeling/liabs_and_equity_item_vectors.rb +24 -24
- data/lib/finmodeling/linear_trend_forecasting_policy.rb +23 -0
- data/lib/finmodeling/net_income_calculation.rb +23 -10
- data/lib/finmodeling/net_income_summary_from_differences.rb +51 -0
- data/lib/finmodeling/paths.rb +0 -0
- data/lib/finmodeling/period_array.rb +8 -4
- data/lib/finmodeling/quarterly_report_filing.rb +9 -4
- data/lib/finmodeling/rate.rb +8 -0
- data/lib/finmodeling/ratio.rb +0 -0
- data/lib/finmodeling/reformulated_balance_sheet.rb +47 -88
- data/lib/finmodeling/reformulated_cash_flow_statement.rb +18 -41
- data/lib/finmodeling/reformulated_income_statement.rb +44 -206
- data/lib/finmodeling/reformulated_shareholder_equity_statement.rb +50 -0
- data/lib/finmodeling/reoi_valuation.rb +104 -0
- data/lib/finmodeling/shareholder_equity_statement_calculation.rb +34 -0
- data/lib/finmodeling/string_helpers.rb +18 -1
- data/lib/finmodeling/time_series_estimator.rb +25 -0
- data/lib/finmodeling/trailing_avg_forecasting_policy.rb +23 -0
- data/lib/finmodeling/version.rb +1 -1
- data/lib/finmodeling/weighted_avg_cost_of_capital.rb +35 -0
- data/lib/finmodeling/yahoo_finance_helpers.rb +20 -0
- data/lib/finmodeling.rb +33 -2
- data/spec/annual_report_filing_spec.rb +81 -45
- data/spec/assets_calculation_spec.rb +7 -4
- data/spec/assets_item_spec.rb +9 -14
- data/spec/balance_sheet_analyses_spec.rb +13 -13
- data/spec/balance_sheet_calculation_spec.rb +45 -51
- data/spec/calculation_summary_spec.rb +113 -21
- data/spec/can_classify_rows_spec.rb +0 -0
- data/spec/cash_change_calculation_spec.rb +1 -10
- data/spec/cash_change_item_spec.rb +10 -18
- data/spec/cash_flow_statement_calculation_spec.rb +10 -24
- data/spec/company_beta_spec.rb +53 -0
- data/spec/company_filing_calculation_spec.rb +39 -49
- data/spec/company_filing_spec.rb +0 -0
- data/spec/company_filings_spec.rb +75 -25
- data/spec/company_spec.rb +37 -47
- data/spec/comprehensive_income_statement_calculation_spec.rb +54 -0
- data/spec/comprehensive_income_statement_item_spec.rb +56 -0
- data/spec/debt_cost_of_capital_spec.rb +19 -0
- data/spec/equity_change_calculation_spec.rb +33 -0
- data/spec/equity_change_item_spec.rb +58 -0
- data/spec/factory_spec.rb +2 -2
- data/spec/forecasts_spec.rb +2 -2
- data/spec/income_statement_analyses_spec.rb +23 -21
- data/spec/income_statement_calculation_spec.rb +17 -49
- data/spec/income_statement_item_spec.rb +17 -29
- data/spec/liabs_and_equity_calculation_spec.rb +6 -3
- data/spec/liabs_and_equity_item_spec.rb +14 -22
- data/spec/linear_trend_forecasting_policy_spec.rb +37 -0
- data/spec/matchers/custom_matchers.rb +79 -0
- data/spec/mocks/calculation.rb +0 -0
- data/spec/mocks/income_statement_analyses.rb +0 -0
- data/spec/mocks/sec_query.rb +0 -0
- data/spec/net_income_calculation_spec.rb +16 -10
- data/spec/period_array.rb +0 -0
- data/spec/quarterly_report_filing_spec.rb +21 -38
- data/spec/rate_spec.rb +0 -0
- data/spec/ratio_spec.rb +0 -0
- data/spec/reformulated_balance_sheet_spec.rb +56 -33
- data/spec/reformulated_cash_flow_statement_spec.rb +18 -10
- data/spec/reformulated_income_statement_spec.rb +16 -15
- data/spec/reformulated_shareholder_equity_statement_spec.rb +43 -0
- data/spec/reoi_valuation_spec.rb +146 -0
- data/spec/shareholder_equity_statement_calculation_spec.rb +59 -0
- data/spec/spec_helper.rb +4 -1
- data/spec/string_helpers_spec.rb +15 -13
- data/spec/time_series_estimator_spec.rb +61 -0
- data/spec/trailing_avg_forecasting_policy_spec.rb +37 -0
- data/spec/weighted_avg_cost_of_capital_spec.rb +32 -0
- data/tools/create_equity_change_training_vectors.rb +49 -0
- data/tools/time_specs.sh +7 -0
- metadata +182 -36
- data/lib/finmodeling/constant_forecasting_policy.rb +0 -23
- data/lib/finmodeling/generic_forecasting_policy.rb +0 -19
- data/spec/constant_forecasting_policy_spec.rb +0 -37
- data/spec/generic_forecasting_policy_spec.rb +0 -33
data/Rakefile
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env rake
|
|
2
2
|
require "bundler/gem_tasks"
|
|
3
3
|
|
|
4
|
+
desc "run the specs"
|
|
4
5
|
task :test do
|
|
6
|
+
sh "if git status | grep 'modified:' | grep annual_report >/dev/null; then echo \"\n\nYou should get rid of ~/.finmodeling\"; fi"
|
|
5
7
|
sh "rspec -c -fd -I. -Ispec spec/*spec.rb"
|
|
6
8
|
end
|
|
9
|
+
|
|
10
|
+
desc "purges anything cached"
|
|
11
|
+
task :purge_cache do
|
|
12
|
+
sh "rm -rf ~/.finmodeling"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
desc "purges anything cached, except the raw XBRL filing downloads."
|
|
16
|
+
task :purge_cache_except_filings do
|
|
17
|
+
sh "rm -rf ~/.finmodeling/classifiers/ ~/.finmodeling/constructors/ ~/.finmodeling/summaries/"
|
|
18
|
+
end
|
data/TODO.txt
CHANGED
|
@@ -1,36 +1,129 @@
|
|
|
1
|
-
|
|
2
|
-
- Parse this one to get at comprehensive income
|
|
3
|
-
|
|
4
|
-
Forecasts
|
|
5
|
-
- Choosing of policies should probably be bumped to a higher-level package.
|
|
6
|
-
- Need more sophisticated forecasting policies
|
|
7
|
-
- Need to have more sophisticated policies fall back on simpler ones (or none) when there's
|
|
8
|
-
too much chaos
|
|
9
|
-
|
|
10
|
-
Bugs
|
|
11
|
-
- Not all disclosures *begin* with disclosure. See CRM's most recent 10-K, for instance.
|
|
12
|
-
- The "valid vals" thing should hides gaps in data, which silently&crappily affect the regressions.
|
|
13
|
-
- show_reports doesn't check filing validity
|
|
1
|
+
XBRL items can include Footnotes. Should probably print these out.
|
|
14
2
|
|
|
15
3
|
Income Statement
|
|
16
|
-
-
|
|
17
|
-
|
|
4
|
+
- In IncomeStatement::latest_quarterly_refactored, it's checking whether the statement has any
|
|
5
|
+
quarterly periods, and if so, using the last one. There's a problem with that, some statements
|
|
6
|
+
do have quarterly periods, but don't break all lines down to the quarterly level. In this example:
|
|
7
|
+
./examples/show_reports.rb --income-detail CHRW 2011-09-01
|
|
8
|
+
The 2012-12-31 column is missing a $283M income (FIBT) because that item is only given in annual
|
|
9
|
+
periods (not the 2012-10-01..2012-12-31 quarterly period). See it in this dump:
|
|
10
|
+
./examples/dump_latest_10k.rb http://www.sec.gov/Archives/edgar/data/1043277/000104327713000004/0001043277-13-000004-index.htm
|
|
11
|
+
Need to modify that method to check whether there are quarterly PERIODS and that all leaf items
|
|
12
|
+
have that quarterly period.
|
|
13
|
+
- Improve the readability of the error checking. One option would be to move to
|
|
14
|
+
a system like ActiveRecord's error-handling, in which a class just accumulates its errors
|
|
15
|
+
nicely, and lets you print them out whenever it's convenient, and in a well-formatted way,
|
|
16
|
+
without causing an immediate exception.
|
|
18
17
|
- The classifier that had been classifying unknown credits/debits is disabled. Replace it?
|
|
19
|
-
|
|
18
|
+
(I don't even remember what this refers to...)
|
|
19
|
+
- net income != comprehensive income. pull in items from SSE? and/or parse the comprehensive
|
|
20
|
+
income statement.
|
|
20
21
|
- certain things are being misclassified as FIBT instead of OOIBT. (hedging,
|
|
21
22
|
currency exchg, etc)
|
|
22
|
-
- naming consistency (e.g., rename OIBT as OOIBT?)
|
|
23
|
-
- consistency between operating/financing vs. operational/financial?
|
|
24
23
|
- need to better understand minority interest, noncontrollable blah-blah,
|
|
25
|
-
etc.
|
|
24
|
+
etc. (not a big deal for tech companies, but important for conglomerates, mediaco's, etc)
|
|
25
|
+
- naming consistency (e.g., rename OIBT as OOIBT?)
|
|
26
|
+
- naming consistency between operating/financing vs. operational/financial?
|
|
27
|
+
- Instead of having find_calculation_arc use a discrete set of exact regexes, what about using
|
|
28
|
+
a classifier (and minimum confidence threshold), like the row classifier works?
|
|
29
|
+
- How to tell if a stock gave off a dividend? Are we tracking those somewhere?
|
|
30
|
+
|
|
31
|
+
Forecasts
|
|
32
|
+
- Refactor it. The logic is too spread around.
|
|
33
|
+
- Detect historicals that are too noisy to forecast from:
|
|
34
|
+
- R^2 of regressions?
|
|
35
|
+
- Certain ratios remaining constant-ish (e.g, composition ratios)
|
|
36
|
+
- Detect historicals with poor earnings quality:
|
|
37
|
+
- Noisy NI/C
|
|
38
|
+
- Detect forecasts that look suspect:
|
|
39
|
+
- Derived values in the forecasts (e.g., composition ratio) remain
|
|
40
|
+
with a standard deviation or two from their trend lines.
|
|
41
|
+
- Allow assumptions to be tweaked by user:
|
|
42
|
+
- How is continuing value calculated? (What long-term g?)
|
|
43
|
+
|
|
44
|
+
Comprehensive Income Statement
|
|
45
|
+
- Not very many examples, especially of less common things like FIAT. Find more.
|
|
46
|
+
- The pension and stock-expense OCIs are getting labeled as operating OCI, which is geting
|
|
47
|
+
added back in as other operating income after tax. Really, though, they should be treated
|
|
48
|
+
as a core operating expense, since they're about paying the core employees.
|
|
26
49
|
|
|
27
50
|
Balance Sheet
|
|
28
51
|
- Dig into the disclosures. They've got lots more interesting goodness.
|
|
52
|
+
- Need to reclassify: credits to shareholders' equity for stock compensation expense
|
|
53
|
+
- Minority interest?
|
|
54
|
+
- Need to reclassify: dividends payable
|
|
29
55
|
- The classifier that had been classifying unknown credits/debits is disabled. Replace it?
|
|
56
|
+
- "Redeemable Noncontrolling Interest Equity Carrying Amount"??
|
|
57
|
+
|
|
58
|
+
Try to figure out why the change in equity is not equal to comprehensive income, in cases where we know it.
|
|
59
|
+
- Some 10k's (and even some 10q's?) have Statements of SE
|
|
60
|
+
- When they don't:
|
|
61
|
+
- Some 10q's have AOCI broken out on BS. We can look for deltas
|
|
62
|
+
- Some 10q's have disclosures that list components of OCI or CI
|
|
63
|
+
- The remaining residual is probably stock-based compensation expense
|
|
64
|
+
- minority interests makes it screwey. also, preferred dividends?
|
|
30
65
|
|
|
31
66
|
Cash Flow Statement
|
|
32
|
-
- Dig into the disclosures. They've got lots more interesting goodness.
|
|
33
67
|
- not taking into account: net cash interest, tax on net interest, or non-cash
|
|
34
68
|
transactions. All 3 of these items are listed in supplementary disclosures.
|
|
35
69
|
- the classifier's success rate isn't that high.
|
|
36
70
|
- "I" is defined inversely.
|
|
71
|
+
|
|
72
|
+
Statement of Shareholder Equity
|
|
73
|
+
- Not taking into account share-based compensation, dividends payable, etc.
|
|
74
|
+
|
|
75
|
+
Cost of Capital
|
|
76
|
+
- Debt cost of capital - try to estimate before tax cost of capital by modeling
|
|
77
|
+
credit spread as a function of interest coverage. Is there a way to estimate
|
|
78
|
+
marginal (not effective) tax rate?
|
|
79
|
+
|
|
80
|
+
XBRL includes a "weight" parameter. Is that useable in place of the "mapping" idea used here?
|
|
81
|
+
|
|
82
|
+
########################################################################################################################
|
|
83
|
+
########################################################################################################################
|
|
84
|
+
########################################################################################################################
|
|
85
|
+
|
|
86
|
+
require 'finmodeling'
|
|
87
|
+
|
|
88
|
+
report_paths=["/Users/jimlindstrom/.finmodeling/filings/000110465910063219", "/Users/jimlindstrom/.finmodeling/filings/000119312509153165", "/Users/jimlindstrom/.finmodeling/filings/000119312509214859", "/Users/jimlindstrom/.finmodeling/filings/000119312510012085", "/Users/jimlindstrom/.finmodeling/filings/000119312510030774", "/Users/jimlindstrom/.finmodeling/filings/000119312510088957", "/Users/jimlindstrom/.finmodeling/filings/000119312510162840", "/Users/jimlindstrom/.finmodeling/filings/000119312510238044", "/Users/jimlindstrom/.finmodeling/filings/000119312511010144", "/Users/jimlindstrom/.finmodeling/filings/000119312511104388", "/Users/jimlindstrom/.finmodeling/filings/000119312511134428", "/Users/jimlindstrom/.finmodeling/filings/000119312511192493", "/Users/jimlindstrom/.finmodeling/filings/000119312511199078", "/Users/jimlindstrom/.finmodeling/filings/000119312511282113", "/Users/jimlindstrom/.finmodeling/filings/000119312511282235", "/Users/jimlindstrom/.finmodeling/filings/000119312512023398", "/Users/jimlindstrom/.finmodeling/filings/000119312512025336", "/Users/jimlindstrom/.finmodeling/filings/000119312512182321", "/Users/jimlindstrom/.finmodeling/filings/000119312512314552", "/Users/jimlindstrom/.finmodeling/filings/000119312512444068", "/Users/jimlindstrom/.finmodeling/filings/000119312513022339"]
|
|
89
|
+
|
|
90
|
+
report_paths.each do |report_path|
|
|
91
|
+
|
|
92
|
+
puts report_path
|
|
93
|
+
|
|
94
|
+
filing=FinModeling::AnnualReportFiling.new(report_path)
|
|
95
|
+
bs=filing.balance_sheet
|
|
96
|
+
le=bs.liabs_and_equity_calculation
|
|
97
|
+
le.periods.each do |period|
|
|
98
|
+
puts le.calculation.leaf_items(period).select{ |x| x.footnotes }.inspect
|
|
99
|
+
end
|
|
100
|
+
a=bs.assets_calculation
|
|
101
|
+
a.periods.each do |period|
|
|
102
|
+
puts a.calculation.leaf_items(period).select{ |x| x.footnotes }.inspect
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
puts
|
|
106
|
+
|
|
107
|
+
end
|
|
108
|
+
# #<Xbrlware::Item:0x007fcd631b7b18
|
|
109
|
+
# @ins=#<Xbrlware::Instance:0x007fcd63b8cdf0>,
|
|
110
|
+
# @name="CommonStockValue",
|
|
111
|
+
# @context=Id [eol_PE2035----0910-Q0009_STD_0_20091226_0],
|
|
112
|
+
# Entity { Identifier { schema [http://www.sec.gov/CIK], value [] } },
|
|
113
|
+
# period [2009-12-26],
|
|
114
|
+
# @precision=nil,
|
|
115
|
+
# @decimals="-6",
|
|
116
|
+
# @footnotes={"en-US"=>["See Note 2, \"Retrospective Adoption of New Accounting Principles\" of this Form 10-Q."]},
|
|
117
|
+
# @value="8962000000.0",
|
|
118
|
+
# @unit=#<Xbrlware::Unit:0x007fcd66db28e8 @id="iso4217_USD", @measure=["iso4217:USD"], @ns="http://www.xbrl.org/2003/instance", @nsp="">,
|
|
119
|
+
# @ns="http://xbrl.us/us-gaap/2009-01-31",
|
|
120
|
+
# @nsp="us-gaap",
|
|
121
|
+
# @def={"xbrli:balance"=>"credit", "name"=>"CommonStockValue", "nillable"=>"true", "xbrli:periodType"=>"instant", "id"=>"us-gaap_CommonStockValue", "type"=>"xbrli:monetaryItemType", "substitutionGroup"=>"xbrli:item"}>
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# several TODOs:
|
|
125
|
+
# 1. modify xbrlware-extras to write these to the constructors
|
|
126
|
+
# item = Xbrlware::Item.new(instance, name, context, value, unit, precision, decimals, footnotes)
|
|
127
|
+
# 2. modify CalculationSummary to handle printing footnoes
|
|
128
|
+
# 3. modify the various calculations to extract footnoes and stuff them into the summaries.
|
|
129
|
+
# --- And do it TDD-style.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'finmodeling'
|
|
4
|
+
|
|
5
|
+
class Arguments
|
|
6
|
+
def self.show_usage_and_exit
|
|
7
|
+
puts "usage:"
|
|
8
|
+
puts "\t#{__FILE__} <stock symbol> <start date, e.g. '2010-01-01'>"
|
|
9
|
+
exit
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.parse(args)
|
|
13
|
+
a = { :stock_symbol => nil, :start_date => nil }
|
|
14
|
+
|
|
15
|
+
self.show_usage_and_exit if args.length != 2
|
|
16
|
+
a[:stock_symbol] = args[0]
|
|
17
|
+
a[:start_date] = Time.parse(args[1])
|
|
18
|
+
|
|
19
|
+
return a
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
args = Arguments.parse(ARGV)
|
|
24
|
+
|
|
25
|
+
company = FinModeling::Company.find(args[:stock_symbol])
|
|
26
|
+
raise RuntimeError.new("couldn't find company") if !company
|
|
27
|
+
puts "company name: #{company.name}"
|
|
28
|
+
|
|
29
|
+
filings = FinModeling::CompanyFilings.new(company.filings_since_date(args[:start_date]))
|
|
30
|
+
if filings.empty?
|
|
31
|
+
puts "No filings..."
|
|
32
|
+
exit
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
disclosure_periods = {}
|
|
36
|
+
|
|
37
|
+
filings.each do |filing|
|
|
38
|
+
|
|
39
|
+
filing.disclosures.each do |disclosure|
|
|
40
|
+
disclosure_label = disclosure.summary(:period => disclosure.periods.last).title.gsub(/ \(.*/,'')
|
|
41
|
+
|
|
42
|
+
disclosure_periods[disclosure_label] ||= []
|
|
43
|
+
disclosure_periods[disclosure_label] += disclosure.periods
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
disclosure_periods.keys.sort.each do |disclosure_label|
|
|
48
|
+
puts disclosure_label.to_s + ": " + disclosure_periods[disclosure_label].map{ |x| x.to_pretty_s }.sort.uniq.join(', ')
|
|
49
|
+
end
|
|
50
|
+
|
|
File without changes
|
data/examples/show_report.rb
CHANGED
|
@@ -42,7 +42,7 @@ class Arguments
|
|
|
42
42
|
|
|
43
43
|
protected
|
|
44
44
|
|
|
45
|
-
def self.parse_just_a_url(raw_args,
|
|
45
|
+
def self.parse_just_a_url(raw_args, parsed_args)
|
|
46
46
|
self.show_usage_and_exit if raw_args.length != 2
|
|
47
47
|
|
|
48
48
|
parsed_args[:filing_url] = raw_args[0]
|
|
@@ -124,21 +124,63 @@ def print_reformulated_balance_sheet(filing, report_type)
|
|
|
124
124
|
end
|
|
125
125
|
|
|
126
126
|
def print_income_statement(filing, report_type)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
127
|
+
if filing.has_an_income_statement?
|
|
128
|
+
period = filing.income_statement.net_income_calculation.periods.yearly.last if report_type == :annual_report
|
|
129
|
+
period = filing.income_statement.net_income_calculation.periods.quarterly.last if report_type == :quarterly_report
|
|
130
|
+
puts "Income Statement (#{period.to_pretty_s})"
|
|
131
|
+
|
|
132
|
+
summaries = []
|
|
133
|
+
summaries << filing.income_statement.net_income_calculation.summary(:period => period)
|
|
134
|
+
|
|
135
|
+
print_summaries(summaries)
|
|
136
|
+
else
|
|
137
|
+
puts "Filing has no income statement."
|
|
138
|
+
puts
|
|
139
|
+
end
|
|
140
|
+
end
|
|
133
141
|
|
|
134
|
-
|
|
142
|
+
def print_comprehensive_income_statement(filing, report_type)
|
|
143
|
+
if filing.has_a_comprehensive_income_statement?
|
|
144
|
+
period = filing.comprehensive_income_statement.comprehensive_income_calculation.periods.yearly.last if report_type == :annual_report
|
|
145
|
+
period = filing.comprehensive_income_statement.comprehensive_income_calculation.periods.quarterly.last if report_type == :quarterly_report
|
|
146
|
+
puts "Comprehensive Income Statement (#{period.to_pretty_s})"
|
|
147
|
+
|
|
148
|
+
summaries = []
|
|
149
|
+
summaries << filing.comprehensive_income_statement.comprehensive_income_calculation.summary(:period => period)
|
|
150
|
+
#summaries << filing.comprehensive_income_statement.summary(:period => period) # when debugging, try printing the whole statement like this.
|
|
151
|
+
|
|
152
|
+
print_summaries(summaries)
|
|
153
|
+
else
|
|
154
|
+
puts "Filing has no comprehensive income statement."
|
|
155
|
+
puts
|
|
156
|
+
end
|
|
135
157
|
end
|
|
136
158
|
|
|
137
159
|
def print_reformulated_income_statement(filing, report_type)
|
|
138
|
-
|
|
139
|
-
|
|
160
|
+
reformed_inc_stmt = nil
|
|
161
|
+
comprehensive_inc_calc = nil
|
|
162
|
+
|
|
163
|
+
if filing.has_a_comprehensive_income_statement?
|
|
164
|
+
comprehensive_inc_calc = filing.comprehensive_income_statement.comprehensive_income_calculation
|
|
165
|
+
end
|
|
140
166
|
|
|
141
|
-
|
|
167
|
+
if filing.has_an_income_statement?
|
|
168
|
+
period = filing.income_statement.net_income_calculation.periods.yearly.last if report_type == :annual_report
|
|
169
|
+
period = filing.income_statement.net_income_calculation.periods.quarterly.last if report_type == :quarterly_report
|
|
170
|
+
|
|
171
|
+
reformed_inc_stmt = filing.income_statement.reformulated(period, comprehensive_inc_calc)
|
|
172
|
+
|
|
173
|
+
elsif filing.has_a_comprehensive_income_statement? &&
|
|
174
|
+
filing.comprehensive_income_statement
|
|
175
|
+
.comprehensive_income_calculation
|
|
176
|
+
.has_revenue_item?
|
|
177
|
+
period = filing.comprehensive_income_statement.comprehensive_income_calculation.periods.yearly.last if report_type == :annual_report
|
|
178
|
+
period = filing.comprehensive_income_statement.comprehensive_income_calculation.periods.quarterly.last if report_type == :quarterly_report
|
|
179
|
+
|
|
180
|
+
reformed_inc_stmt = filing.comprehensive_income_statement.reformulated(period, comprehensive_inc_calc)
|
|
181
|
+
else
|
|
182
|
+
raise RuntimeError.new("Can't create reformulated income statement")
|
|
183
|
+
end
|
|
142
184
|
|
|
143
185
|
summaries = []
|
|
144
186
|
summaries << reformed_inc_stmt.gross_revenue
|
|
@@ -154,27 +196,62 @@ end
|
|
|
154
196
|
def print_cash_flow_statement(filing, report_type)
|
|
155
197
|
period = filing.cash_flow_statement.periods.yearly.last if report_type == :annual_report
|
|
156
198
|
period = filing.cash_flow_statement.periods.quarterly.last if report_type == :quarterly_report
|
|
157
|
-
puts "Cash Flow Statement (#{period.to_pretty_s})"
|
|
158
|
-
|
|
159
|
-
summaries = []
|
|
160
|
-
summaries << filing.cash_flow_statement.cash_change_calculation.summary(:period => period)
|
|
161
199
|
|
|
162
|
-
|
|
200
|
+
if period
|
|
201
|
+
puts "cash flow statement (#{period.to_pretty_s})"
|
|
202
|
+
|
|
203
|
+
summaries = []
|
|
204
|
+
summaries << filing.cash_flow_statement.cash_change_calculation.summary(:period => period)
|
|
205
|
+
|
|
206
|
+
print_summaries(summaries)
|
|
207
|
+
else
|
|
208
|
+
puts "WARNING: cash flow statement period is nil!"
|
|
209
|
+
end
|
|
163
210
|
end
|
|
164
211
|
|
|
165
212
|
def print_reformulated_cash_flow_statement(filing, report_type)
|
|
166
213
|
period = filing.cash_flow_statement.periods.yearly.last if report_type == :annual_report
|
|
167
214
|
period = filing.cash_flow_statement.periods.quarterly.last if report_type == :quarterly_report
|
|
215
|
+
|
|
216
|
+
if period
|
|
217
|
+
reformed_cash_flow_stmt = filing.cash_flow_statement.reformulated(period)
|
|
218
|
+
|
|
219
|
+
summaries = []
|
|
220
|
+
summaries << reformed_cash_flow_stmt.cash_from_operations
|
|
221
|
+
summaries << reformed_cash_flow_stmt.cash_investments_in_operations
|
|
222
|
+
summaries << reformed_cash_flow_stmt.payments_to_debtholders
|
|
223
|
+
summaries << reformed_cash_flow_stmt.payments_to_stockholders
|
|
224
|
+
summaries << reformed_cash_flow_stmt.free_cash_flow
|
|
225
|
+
summaries << reformed_cash_flow_stmt.financing_flows
|
|
226
|
+
|
|
227
|
+
print_summaries(summaries)
|
|
228
|
+
else
|
|
229
|
+
puts "WARNING: reformulated cash flow statement period is nil!"
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def print_shareholder_equity_statement(filing, report_type)
|
|
234
|
+
return if !filing.has_a_shareholder_equity_statement?
|
|
235
|
+
period = filing.shareholder_equity_statement.periods.yearly.last if report_type == :annual_report
|
|
236
|
+
period = filing.shareholder_equity_statement.periods.quarterly.last if report_type == :quarterly_report
|
|
237
|
+
puts "shareholder equity statement (#{period.to_pretty_s})"
|
|
238
|
+
|
|
239
|
+
summaries = []
|
|
240
|
+
summaries << filing.shareholder_equity_statement.equity_change_calculation.summary(:period => period)
|
|
241
|
+
|
|
242
|
+
print_summaries(summaries)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def print_reformulated_shareholder_equity_statement(filing, report_type)
|
|
246
|
+
return if !filing.has_a_shareholder_equity_statement?
|
|
247
|
+
period = filing.shareholder_equity_statement.periods.yearly.last if report_type == :annual_report
|
|
248
|
+
period = filing.shareholder_equity_statement.periods.quarterly.last if report_type == :quarterly_report
|
|
168
249
|
|
|
169
|
-
|
|
250
|
+
reformed_shareholder_equity_stmt = filing.shareholder_equity_statement.reformulated(period)
|
|
170
251
|
|
|
171
252
|
summaries = []
|
|
172
|
-
summaries <<
|
|
173
|
-
summaries <<
|
|
174
|
-
summaries << reformed_cash_flow_stmt.payments_to_debtholders
|
|
175
|
-
summaries << reformed_cash_flow_stmt.payments_to_stockholders
|
|
176
|
-
summaries << reformed_cash_flow_stmt.free_cash_flow
|
|
177
|
-
summaries << reformed_cash_flow_stmt.financing_flows
|
|
253
|
+
summaries << reformed_shareholder_equity_stmt.transactions_with_shareholders
|
|
254
|
+
summaries << reformed_shareholder_equity_stmt.comprehensive_income
|
|
178
255
|
|
|
179
256
|
print_summaries(summaries)
|
|
180
257
|
end
|
|
@@ -205,14 +282,17 @@ if args[:filing_url].nil?
|
|
|
205
282
|
args[:filing_url] = get_company_filing_url(args[:stock_symbol], args[:report_type], args[:report_offset])
|
|
206
283
|
end
|
|
207
284
|
|
|
208
|
-
filing = get_filing(
|
|
209
|
-
|
|
210
|
-
print_balance_sheet(
|
|
211
|
-
print_reformulated_balance_sheet(
|
|
212
|
-
print_income_statement(
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
285
|
+
filing = get_filing(args[:filing_url], args[:report_type])
|
|
286
|
+
|
|
287
|
+
print_balance_sheet( filing, args[:report_type])
|
|
288
|
+
print_reformulated_balance_sheet( filing, args[:report_type])
|
|
289
|
+
print_income_statement( filing, args[:report_type])
|
|
290
|
+
print_comprehensive_income_statement( filing, args[:report_type])
|
|
291
|
+
print_reformulated_income_statement( filing, args[:report_type])
|
|
292
|
+
print_cash_flow_statement( filing, args[:report_type])
|
|
293
|
+
print_reformulated_cash_flow_statement( filing, args[:report_type])
|
|
294
|
+
print_shareholder_equity_statement( filing, args[:report_type])
|
|
295
|
+
print_reformulated_shareholder_equity_statement(filing, args[:report_type])
|
|
296
|
+
print_disclosures( filing, args[:report_type]) if args[:show_disclosures]
|
|
217
297
|
|
|
218
298
|
raise RuntimeError.new("filing is not valid") if !filing.is_valid?
|
data/examples/show_reports.rb
CHANGED
|
@@ -9,42 +9,108 @@ class Arguments
|
|
|
9
9
|
puts
|
|
10
10
|
puts "\tOptions:"
|
|
11
11
|
puts "\t\t--num-forecasts <num>: how many periods to forecast"
|
|
12
|
+
puts "\t\t --forecast-policy <trailing_avg|linear_trend> (default: linear_trend)"
|
|
13
|
+
puts "\t\t --do-valuation: value the company's equity. (requires >= 2 forecasts)"
|
|
14
|
+
puts "\t\t --marginal-tax-rate <num>: default is 0.36 (36%)"
|
|
15
|
+
puts "\t\t --before-tax-cost-of-debt <num>: default is 0.05 (5%)"
|
|
12
16
|
puts "\t\t--no-cache: disable caching"
|
|
13
17
|
puts "\t\t--balance-detail: show details about the balance sheet calculation"
|
|
14
18
|
puts "\t\t--income-detail: show details about the net income calculation"
|
|
19
|
+
puts "\t\t--show-disclosure <part of title>: show a particular disclosure over time"
|
|
20
|
+
puts "\t\t--show-regressions: show the regressions of calculations that are used to do forecasts"
|
|
15
21
|
exit
|
|
16
22
|
end
|
|
17
|
-
|
|
18
|
-
def self.parse(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
while
|
|
22
|
-
|
|
23
|
-
when '--no-cache'
|
|
24
|
-
FinModeling::Config.disable_caching
|
|
25
|
-
puts "Caching is #{FinModeling::Config.caching_enabled? ? "enabled" : "disabled"}"
|
|
26
|
-
when '--balance-detail'
|
|
27
|
-
FinModeling::Config.enable_balance_detail
|
|
28
|
-
puts "Balance sheet detail is #{FinModeling::Config.balance_detail_enabled? ? "enabled" : "disabled"}"
|
|
29
|
-
when '--income-detail'
|
|
30
|
-
FinModeling::Config.enable_income_detail
|
|
31
|
-
puts "Net income detail is #{FinModeling::Config.income_detail_enabled? ? "enabled" : "disabled"}"
|
|
32
|
-
when '--num-forecasts'
|
|
33
|
-
a[:num_forecasts] = args[1].to_i
|
|
34
|
-
self.show_usage_and_exit unless a[:num_forecasts] >= 1
|
|
35
|
-
puts "Forecasting #{a[:num_forecasts]} periods"
|
|
36
|
-
args = args[1..-1]
|
|
37
|
-
else
|
|
38
|
-
self.show_usage_and_exit
|
|
39
|
-
end
|
|
40
|
-
args = args[1..-1]
|
|
23
|
+
|
|
24
|
+
def self.parse(raw_args)
|
|
25
|
+
parsed_args = self.default_options
|
|
26
|
+
|
|
27
|
+
while raw_args.any? && raw_args.first =~ /^--/
|
|
28
|
+
self.parse_next_option(raw_args, parsed_args)
|
|
41
29
|
end
|
|
42
30
|
|
|
43
|
-
self.show_usage_and_exit if
|
|
44
|
-
|
|
45
|
-
|
|
31
|
+
self.show_usage_and_exit if raw_args.length != 2
|
|
32
|
+
parsed_args[:stock_symbol] = raw_args[0]
|
|
33
|
+
parsed_args[:start_date ] = Time.parse(raw_args[1])
|
|
46
34
|
|
|
47
|
-
return
|
|
35
|
+
return parsed_args
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def self.default_options
|
|
41
|
+
{ :stock_symbol => nil,
|
|
42
|
+
:start_date => nil,
|
|
43
|
+
:num_forecasts => nil,
|
|
44
|
+
:do_valuation => false,
|
|
45
|
+
:forecast_policy => :linear_trend,
|
|
46
|
+
:marginal_tax_rate => 0.36,
|
|
47
|
+
:before_tax_cost_of_debt => 0.05,
|
|
48
|
+
:show_regressions => false,
|
|
49
|
+
:disclosures => [ ] }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def self.parse_next_option(raw_args, parsed_args)
|
|
54
|
+
case raw_args.first.downcase
|
|
55
|
+
when '--no-cache'
|
|
56
|
+
FinModeling::Config.disable_caching
|
|
57
|
+
puts "Caching is #{FinModeling::Config.caching_enabled? ? "enabled" : "disabled"}"
|
|
58
|
+
|
|
59
|
+
when '--balance-detail'
|
|
60
|
+
FinModeling::Config.enable_balance_detail
|
|
61
|
+
puts "Balance sheet detail is #{FinModeling::Config.balance_detail_enabled? ? "enabled" : "disabled"}"
|
|
62
|
+
|
|
63
|
+
when '--income-detail'
|
|
64
|
+
FinModeling::Config.enable_income_detail
|
|
65
|
+
puts "Net income detail is #{FinModeling::Config.income_detail_enabled? ? "enabled" : "disabled"}"
|
|
66
|
+
|
|
67
|
+
when '--num-forecasts'
|
|
68
|
+
self.show_usage_and_exit if raw_args.length < 2
|
|
69
|
+
parsed_args[:num_forecasts] = raw_args[1].to_i
|
|
70
|
+
self.show_usage_and_exit unless parsed_args[:num_forecasts] >= 1
|
|
71
|
+
puts "Forecasting #{parsed_args[:num_forecasts]} periods"
|
|
72
|
+
raw_args.shift
|
|
73
|
+
|
|
74
|
+
when '--do-valuation'
|
|
75
|
+
parsed_args[:do_valuation] = true
|
|
76
|
+
puts "Doing valuation"
|
|
77
|
+
|
|
78
|
+
when '--forecast-policy'
|
|
79
|
+
self.show_usage_and_exit if raw_args.length < 2
|
|
80
|
+
parsed_args[:forecast_policy] = raw_args[1].to_sym
|
|
81
|
+
self.show_usage_and_exit unless [:trailing_avg, :linear_trend].include?(parsed_args[:forecast_policy])
|
|
82
|
+
puts "Forecast policy: #{parsed_args[:forecast_policy]}"
|
|
83
|
+
raw_args.shift
|
|
84
|
+
|
|
85
|
+
when '--before-tax-cost-of-debt'
|
|
86
|
+
self.show_usage_and_exit if raw_args.length < 2
|
|
87
|
+
parsed_args[:before_tax_cost_of_debt] = raw_args[1].to_f
|
|
88
|
+
self.show_usage_and_exit unless parsed_args[:before_tax_cost_of_debt] >= 0.00 && parsed_args[:before_tax_cost_of_debt] <= 1.00
|
|
89
|
+
puts "before tax cost of debt: #{parsed_args[:before_tax_cost_of_debt]}"
|
|
90
|
+
raw_args.shift
|
|
91
|
+
|
|
92
|
+
when '--marginal-tax-rate'
|
|
93
|
+
self.show_usage_and_exit if raw_args.length < 2
|
|
94
|
+
parsed_args[:marginal_tax_rate] = raw_args[1].to_f
|
|
95
|
+
self.show_usage_and_exit unless parsed_args[:marginal_tax_rate] >= 0.00 && parsed_args[:marginal_tax_rate] <= 1.00
|
|
96
|
+
puts "marginal tax rate: #{parsed_args[:marginal_tax_rate]}"
|
|
97
|
+
raw_args.shift
|
|
98
|
+
|
|
99
|
+
when '--show-regressions'
|
|
100
|
+
parsed_args[:show_regressions] = true
|
|
101
|
+
puts "Showing regressions"
|
|
102
|
+
|
|
103
|
+
when '--show-disclosure'
|
|
104
|
+
self.show_usage_and_exit if raw_args.length < 2
|
|
105
|
+
parsed_args[:disclosures] << raw_args[1]
|
|
106
|
+
puts "Showing disclosure: #{parsed_args[:disclosures].last}"
|
|
107
|
+
raw_args.shift
|
|
108
|
+
|
|
109
|
+
else
|
|
110
|
+
self.show_usage_and_exit
|
|
111
|
+
|
|
112
|
+
end
|
|
113
|
+
raw_args.shift
|
|
48
114
|
end
|
|
49
115
|
end
|
|
50
116
|
|
|
@@ -59,19 +125,82 @@ if filings.empty?
|
|
|
59
125
|
puts "No filings..."
|
|
60
126
|
exit
|
|
61
127
|
end
|
|
128
|
+
filings.each do |filing|
|
|
129
|
+
begin
|
|
130
|
+
if !filing.is_valid?
|
|
131
|
+
raise RuntimeError.new("filing is not valid. type: #{filing.class}. period: #{filing.balance_sheet.periods.last}.")
|
|
132
|
+
end
|
|
133
|
+
rescue FinModeling::InvalidFilingError => e
|
|
134
|
+
pre_msg = "\n\nFiling is not valid. type: #{filing.class}. period: #{filing.balance_sheet.periods.last}.\n"
|
|
135
|
+
raise e, pre_msg+e.message, e.backtrace
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
fl = filings.re_bs_arr.last.financial_liabilities.total
|
|
141
|
+
dcoc = FinModeling::DebtCostOfCapital.calculate(:before_tax_cost => FinModeling::Rate.new(args[:before_tax_cost_of_debt]),
|
|
142
|
+
:marginal_tax_rate => FinModeling::Rate.new(args[:marginal_tax_rate]))
|
|
143
|
+
ecoc = FinModeling::CAPM::EquityCostOfCapital.from_ticker(args[:stock_symbol])
|
|
144
|
+
#ecoc = FinModeling::FamaFrench::EquityCostOfCapital.from_ticker(args[:stock_symbol])
|
|
145
|
+
if (ecoc.value < 0.05) || (ecoc.value > 0.30)
|
|
146
|
+
puts "WARNING: cost of equity capital is highly suspect..."
|
|
147
|
+
end
|
|
148
|
+
wacc = FinModeling::WeightedAvgCostOfCapital.new(equity_market_val = YahooFinance::get_market_cap(args[:stock_symbol].dup),
|
|
149
|
+
debt_market_val = fl,
|
|
150
|
+
cost_of_equity = ecoc,
|
|
151
|
+
after_tax_cost_of_debt = dcoc)
|
|
62
152
|
|
|
63
|
-
forecasts = filings.forecasts(filings.choose_forecasting_policy, num_quarters=args[:num_forecasts]) if args[:num_forecasts]
|
|
153
|
+
forecasts = filings.forecasts(filings.choose_forecasting_policy(wacc.rate.value, args[:forecast_policy]), num_quarters=args[:num_forecasts]) if args[:num_forecasts]
|
|
64
154
|
|
|
65
155
|
bs_analyses = filings.balance_sheet_analyses
|
|
66
156
|
bs_analyses += forecasts.balance_sheet_analyses(filings) if forecasts
|
|
67
157
|
bs_analyses.totals_row_enabled = false
|
|
68
158
|
bs_analyses.print
|
|
69
|
-
|
|
159
|
+
if args[:show_regressions] && filings.balance_sheet_analyses.respond_to?(:print_regressions)
|
|
160
|
+
filings.balance_sheet_analyses.print_regressions
|
|
161
|
+
end
|
|
70
162
|
|
|
71
|
-
is_analyses = filings.income_statement_analyses
|
|
72
|
-
is_analyses += forecasts.income_statement_analyses(filings) if forecasts
|
|
163
|
+
is_analyses = filings.income_statement_analyses(wacc.rate.value)
|
|
164
|
+
is_analyses += forecasts.income_statement_analyses(filings, wacc.rate.value) if forecasts
|
|
73
165
|
is_analyses.totals_row_enabled = false
|
|
74
166
|
is_analyses.print
|
|
75
|
-
|
|
167
|
+
if args[:show_regressions] && filings.income_statement_analyses.respond_to?(:print_regressions)
|
|
168
|
+
filings.income_statement_analyses.print_regressions
|
|
169
|
+
end
|
|
76
170
|
|
|
77
171
|
filings.cash_flow_statement_analyses.print
|
|
172
|
+
if args[:show_regressions] && filings.cash_flow_statement_analyses.respond_to?(:print_regressions)
|
|
173
|
+
filings.cash_flow_statement_analyses.print_regressions
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
args[:disclosures].each do |disclosure_title|
|
|
177
|
+
title_regex = Regexp.new(disclosure_title, Regexp::IGNORECASE)
|
|
178
|
+
disclosures = filings.disclosures(title_regex, :quarterly)
|
|
179
|
+
disclosures ||= filings.disclosures(title_regex, :yearly )
|
|
180
|
+
disclosures ||= filings.disclosures(title_regex )
|
|
181
|
+
if disclosures
|
|
182
|
+
disclosures.auto_scale!
|
|
183
|
+
if (disclosures.header_row.vals - bs_analyses.header_row.vals).length == 0
|
|
184
|
+
0.upto(bs_analyses.header_row.vals.length-1) do |idx|
|
|
185
|
+
if bs_analyses.header_row.vals[idx] != disclosures.header_row.vals[idx]
|
|
186
|
+
disclosures.insert_column_before(idx, "")
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
disclosures.print
|
|
191
|
+
else
|
|
192
|
+
puts "Couldn't find disclosures called: #{title_regex}"
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
if args[:do_valuation]
|
|
197
|
+
if args[:num_forecasts] && args[:num_forecasts]>=2
|
|
198
|
+
wacc.summary.print
|
|
199
|
+
|
|
200
|
+
num_shares = YahooFinance::get_num_shares(args[:stock_symbol].dup)
|
|
201
|
+
valuation = FinModeling::ReOIValuation.new(filings, forecasts, wacc.rate, num_shares)
|
|
202
|
+
valuation.summary.print
|
|
203
|
+
else
|
|
204
|
+
puts "Oops. Can't do valuation without >= 2 forecasts"
|
|
205
|
+
end
|
|
206
|
+
end
|
data/finmodeling.gemspec
CHANGED
|
@@ -13,11 +13,14 @@ Gem::Specification.new do |gem|
|
|
|
13
13
|
gem.add_dependency("edgar")
|
|
14
14
|
|
|
15
15
|
gem.add_dependency("xbrlware-ruby19", "1.1.2.19.2")
|
|
16
|
-
gem.add_dependency("xbrlware-extras", "1.1.2.19.
|
|
16
|
+
gem.add_dependency("xbrlware-extras", "1.1.2.19.3")
|
|
17
|
+
gem.add_dependency("nasdaq_query")
|
|
17
18
|
|
|
18
19
|
gem.add_dependency("sec_query")
|
|
19
20
|
gem.add_dependency("naive_bayes")
|
|
20
21
|
gem.add_dependency("statsample")
|
|
22
|
+
gem.add_dependency("yahoofinance")
|
|
23
|
+
gem.add_dependency("gsl")
|
|
21
24
|
|
|
22
25
|
gem.add_development_dependency("rspec", "2.5")
|
|
23
26
|
gem.add_development_dependency("rake")
|