finmodeling 0.1

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.
Files changed (97) hide show
  1. data/.gitignore +3 -0
  2. data/Gemfile +10 -0
  3. data/README.md +292 -0
  4. data/Rakefile +6 -0
  5. data/TODO.txt +36 -0
  6. data/examples/dump_report.rb +33 -0
  7. data/examples/lists/nasdaq-mid-to-mega-tech-symbols.txt +226 -0
  8. data/examples/show_report.rb +218 -0
  9. data/examples/show_reports.rb +77 -0
  10. data/finmodeling.gemspec +31 -0
  11. data/lib/finmodeling/annual_report_filing.rb +104 -0
  12. data/lib/finmodeling/array_with_stats.rb +22 -0
  13. data/lib/finmodeling/assets_calculation.rb +36 -0
  14. data/lib/finmodeling/assets_item.rb +14 -0
  15. data/lib/finmodeling/assets_item_vectors.rb +638 -0
  16. data/lib/finmodeling/balance_sheet_analyses.rb +33 -0
  17. data/lib/finmodeling/balance_sheet_calculation.rb +68 -0
  18. data/lib/finmodeling/calculation_summary.rb +148 -0
  19. data/lib/finmodeling/can_cache_classifications.rb +36 -0
  20. data/lib/finmodeling/can_cache_summaries.rb +16 -0
  21. data/lib/finmodeling/can_classify_rows.rb +54 -0
  22. data/lib/finmodeling/cash_change_calculation.rb +67 -0
  23. data/lib/finmodeling/cash_change_item.rb +14 -0
  24. data/lib/finmodeling/cash_change_item_vectors.rb +241 -0
  25. data/lib/finmodeling/cash_flow_statement_calculation.rb +85 -0
  26. data/lib/finmodeling/classifiers.rb +11 -0
  27. data/lib/finmodeling/company.rb +102 -0
  28. data/lib/finmodeling/company_filing.rb +64 -0
  29. data/lib/finmodeling/company_filing_calculation.rb +75 -0
  30. data/lib/finmodeling/company_filings.rb +100 -0
  31. data/lib/finmodeling/config.rb +37 -0
  32. data/lib/finmodeling/constant_forecasting_policy.rb +23 -0
  33. data/lib/finmodeling/factory.rb +27 -0
  34. data/lib/finmodeling/float_helpers.rb +17 -0
  35. data/lib/finmodeling/forecasts.rb +48 -0
  36. data/lib/finmodeling/generic_forecasting_policy.rb +19 -0
  37. data/lib/finmodeling/has_string_classifer.rb +96 -0
  38. data/lib/finmodeling/income_statement_analyses.rb +74 -0
  39. data/lib/finmodeling/income_statement_calculation.rb +71 -0
  40. data/lib/finmodeling/income_statement_item.rb +14 -0
  41. data/lib/finmodeling/income_statement_item_vectors.rb +654 -0
  42. data/lib/finmodeling/liabs_and_equity_calculation.rb +36 -0
  43. data/lib/finmodeling/liabs_and_equity_item.rb +14 -0
  44. data/lib/finmodeling/liabs_and_equity_item_vectors.rb +1936 -0
  45. data/lib/finmodeling/net_income_calculation.rb +41 -0
  46. data/lib/finmodeling/paths.rb +5 -0
  47. data/lib/finmodeling/period_array.rb +24 -0
  48. data/lib/finmodeling/quarterly_report_filing.rb +23 -0
  49. data/lib/finmodeling/rate.rb +20 -0
  50. data/lib/finmodeling/ratio.rb +20 -0
  51. data/lib/finmodeling/reformulated_balance_sheet.rb +176 -0
  52. data/lib/finmodeling/reformulated_cash_flow_statement.rb +140 -0
  53. data/lib/finmodeling/reformulated_income_statement.rb +436 -0
  54. data/lib/finmodeling/string_helpers.rb +26 -0
  55. data/lib/finmodeling/version.rb +3 -0
  56. data/lib/finmodeling.rb +70 -0
  57. data/spec/annual_report_filing_spec.rb +68 -0
  58. data/spec/assets_calculation_spec.rb +21 -0
  59. data/spec/assets_item_spec.rb +66 -0
  60. data/spec/balance_sheet_analyses_spec.rb +43 -0
  61. data/spec/balance_sheet_calculation_spec.rb +91 -0
  62. data/spec/calculation_summary_spec.rb +63 -0
  63. data/spec/can_classify_rows_spec.rb +86 -0
  64. data/spec/cash_change_calculation_spec.rb +56 -0
  65. data/spec/cash_change_item_spec.rb +66 -0
  66. data/spec/cash_flow_statement_calculation_spec.rb +108 -0
  67. data/spec/company_filing_calculation_spec.rb +74 -0
  68. data/spec/company_filing_spec.rb +30 -0
  69. data/spec/company_filings_spec.rb +55 -0
  70. data/spec/company_spec.rb +73 -0
  71. data/spec/constant_forecasting_policy_spec.rb +37 -0
  72. data/spec/factory_spec.rb +18 -0
  73. data/spec/forecasts_spec.rb +21 -0
  74. data/spec/generic_forecasting_policy_spec.rb +33 -0
  75. data/spec/income_statement_analyses_spec.rb +63 -0
  76. data/spec/income_statement_calculation_spec.rb +88 -0
  77. data/spec/income_statement_item_spec.rb +86 -0
  78. data/spec/liabs_and_equity_calculation_spec.rb +20 -0
  79. data/spec/liabs_and_equity_item_spec.rb +66 -0
  80. data/spec/mocks/calculation.rb +10 -0
  81. data/spec/mocks/income_statement_analyses.rb +93 -0
  82. data/spec/mocks/sec_query.rb +31 -0
  83. data/spec/net_income_calculation_spec.rb +23 -0
  84. data/spec/period_array.rb +52 -0
  85. data/spec/quarterly_report_filing_spec.rb +69 -0
  86. data/spec/rate_spec.rb +33 -0
  87. data/spec/ratio_spec.rb +33 -0
  88. data/spec/reformulated_balance_sheet_spec.rb +146 -0
  89. data/spec/reformulated_cash_flow_statement_spec.rb +174 -0
  90. data/spec/reformulated_income_statement_spec.rb +293 -0
  91. data/spec/spec_helper.rb +5 -0
  92. data/spec/string_helpers_spec.rb +23 -0
  93. data/tools/create_balance_sheet_training_vectors.rb +65 -0
  94. data/tools/create_cash_change_training_vectors.rb +48 -0
  95. data/tools/create_credit_debit_training_vectors.rb +51 -0
  96. data/tools/create_income_statement_training_vectors.rb +48 -0
  97. metadata +289 -0
@@ -0,0 +1,293 @@
1
+ # reformulated_income_statement_spec.rb
2
+
3
+ require 'spec_helper'
4
+
5
+ describe FinModeling::ReformulatedIncomeStatement do
6
+ before(:all) do
7
+ google_2009_annual_rpt = "http://www.sec.gov/Archives/edgar/data/1288776/000119312510030774/0001193125-10-030774-index.htm"
8
+ @filing_2009 = FinModeling::AnnualReportFiling.download google_2009_annual_rpt
9
+
10
+ google_2011_annual_rpt = "http://www.sec.gov/Archives/edgar/data/1288776/000119312512025336/0001193125-12-025336-index.htm"
11
+ @filing_2011 = FinModeling::AnnualReportFiling.download google_2011_annual_rpt
12
+
13
+ @years_between_stmts = 2.0
14
+
15
+ @inc_stmt_2009 = @filing_2009.income_statement
16
+ is_period_2009 = @inc_stmt_2009.periods.last
17
+ @reformed_inc_stmt_2009 = @inc_stmt_2009.reformulated(is_period_2009)
18
+
19
+ @bal_sheet_2009 = @filing_2009.balance_sheet
20
+ bs_period_2009 = @bal_sheet_2009.periods.last
21
+ @reformed_bal_sheet_2009 = @bal_sheet_2009.reformulated(bs_period_2009)
22
+
23
+ @inc_stmt_2011 = @filing_2011.income_statement
24
+ is_period_2011 = @inc_stmt_2011.periods.last
25
+ @reformed_inc_stmt_2011 = @inc_stmt_2011.reformulated(is_period_2011)
26
+
27
+ @bal_sheet_2011 = @filing_2011.balance_sheet
28
+ bs_period_2011 = @bal_sheet_2011.periods.last
29
+ @reformed_bal_sheet_2011 = @bal_sheet_2011.reformulated(bs_period_2011)
30
+ end
31
+
32
+ describe "operating_revenues" do
33
+ subject { @reformed_inc_stmt_2011.operating_revenues }
34
+ it { should be_an_instance_of FinModeling::CalculationSummary }
35
+ its(:total) { should be_within(0.1).of(37905000000.0) }
36
+ end
37
+
38
+ describe "cost_of_revenues" do
39
+ subject { @reformed_inc_stmt_2011.cost_of_revenues }
40
+ it { should be_an_instance_of FinModeling::CalculationSummary }
41
+ its(:total) { should be_within(0.1).of(-13188000000.0) }
42
+ end
43
+
44
+ describe "gross_revenue" do
45
+ subject { @reformed_inc_stmt_2011.gross_revenue }
46
+ it { should be_an_instance_of FinModeling::CalculationSummary }
47
+ its(:total) { should be_within(0.1).of( @reformed_inc_stmt_2011.operating_revenues.total +
48
+ @reformed_inc_stmt_2011.cost_of_revenues.total) }
49
+ end
50
+
51
+ describe "operating_expenses" do
52
+ subject { @reformed_inc_stmt_2011.operating_expenses }
53
+ it { should be_an_instance_of FinModeling::CalculationSummary }
54
+ its(:total) { should be_within(0.1).of(-12475000000.0) }
55
+ end
56
+
57
+ describe "income_from_sales_before_tax" do
58
+ subject { @reformed_inc_stmt_2011.income_from_sales_before_tax }
59
+ it { should be_an_instance_of FinModeling::CalculationSummary }
60
+ its(:total) { should be_within(0.1).of( @reformed_inc_stmt_2011.gross_revenue.total +
61
+ @reformed_inc_stmt_2011.operating_expenses.total) }
62
+ end
63
+
64
+ describe "income_from_sales_after_tax" do
65
+ subject { @reformed_inc_stmt_2011.income_from_sales_after_tax }
66
+ it { should be_an_instance_of FinModeling::CalculationSummary }
67
+ its(:total) { should be_within(0.1).of(9682400000.0) }
68
+ end
69
+
70
+ describe "operating_income_after_tax" do
71
+ subject { @reformed_inc_stmt_2011.operating_income_after_tax }
72
+ it { should be_an_instance_of FinModeling::CalculationSummary }
73
+ its(:total) { should be_within(0.1).of(9357400000.0) }
74
+ end
75
+
76
+ describe "net_financing_income" do
77
+ subject { @reformed_inc_stmt_2011.net_financing_income }
78
+ it { should be_an_instance_of FinModeling::CalculationSummary }
79
+ its(:total) { should be_within(0.1).of(379600000.0) }
80
+ end
81
+
82
+ describe "comprehensive_income" do
83
+ subject { @reformed_inc_stmt_2011.comprehensive_income }
84
+ it { should be_an_instance_of FinModeling::CalculationSummary }
85
+ its(:total) { should be_within(0.1).of(9737000000.0) }
86
+ end
87
+
88
+ describe "gross_margin" do
89
+ subject { @reformed_inc_stmt_2011.gross_margin }
90
+ it { should be_an_instance_of Float }
91
+ it { should be_within(0.1).of(@reformed_inc_stmt_2011.gross_revenue.total / @reformed_inc_stmt_2011.operating_revenues.total) }
92
+ end
93
+
94
+ describe "sales_profit_margin" do
95
+ subject { @reformed_inc_stmt_2011.sales_profit_margin }
96
+ it { should be_an_instance_of Float }
97
+ it { should be_within(0.1).of(@reformed_inc_stmt_2011.income_from_sales_after_tax.total / @reformed_inc_stmt_2011.operating_revenues.total) }
98
+ end
99
+
100
+ describe "operating_profit_margin" do
101
+ subject { @reformed_inc_stmt_2011.operating_profit_margin }
102
+ it { should be_an_instance_of Float }
103
+ it { should be_within(0.1).of(@reformed_inc_stmt_2011.operating_income_after_tax.total / @reformed_inc_stmt_2011.operating_revenues.total) }
104
+ end
105
+
106
+ describe "fi_over_sales" do
107
+ subject { @reformed_inc_stmt_2011.fi_over_sales }
108
+ it { should be_an_instance_of Float }
109
+ it { should be_within(0.1).of(@reformed_inc_stmt_2011.net_financing_income.total / @reformed_inc_stmt_2011.operating_revenues.total) }
110
+ end
111
+
112
+ describe "ni_over_sales" do
113
+ subject { @reformed_inc_stmt_2011.ni_over_sales }
114
+ it { should be_an_instance_of Float }
115
+ it { should be_within(0.1).of(@reformed_inc_stmt_2011.comprehensive_income.total / @reformed_inc_stmt_2011.operating_revenues.total) }
116
+ end
117
+
118
+ describe "sales_over_noa" do
119
+ subject { @reformed_inc_stmt_2011.sales_over_noa(@reformed_bal_sheet_2011) }
120
+ it { should be_an_instance_of Float }
121
+ it { should be_within(0.1).of(@reformed_inc_stmt_2011.operating_revenues.total / @reformed_bal_sheet_2011.net_operating_assets.total) }
122
+ end
123
+
124
+ describe "fi_over_nfa" do
125
+ subject { @reformed_inc_stmt_2011.fi_over_nfa(@reformed_bal_sheet_2011) }
126
+ it { should be_an_instance_of Float }
127
+ it { should be_within(0.1).of(@reformed_inc_stmt_2011.net_financing_income.total / @reformed_bal_sheet_2011.net_financial_assets.total) }
128
+ end
129
+
130
+ describe "revenue_growth" do
131
+ before(:all) do
132
+ rev0 = @reformed_inc_stmt_2009.operating_revenues.total
133
+ rev1 = @reformed_inc_stmt_2011.operating_revenues.total
134
+ @expected_growth = (rev1 / rev0)**(1.0/@years_between_stmts) - 1.0
135
+ end
136
+ subject { @reformed_inc_stmt_2011.revenue_growth(@reformed_inc_stmt_2009) }
137
+ it { should be_an_instance_of Float }
138
+ it { should be_within(0.1).of(@expected_growth) }
139
+ end
140
+
141
+ describe "core_oi_growth" do
142
+ before(:all) do
143
+ core_oi0 = @reformed_inc_stmt_2009.income_from_sales_after_tax.total
144
+ core_oi1 = @reformed_inc_stmt_2011.income_from_sales_after_tax.total
145
+ @expected_growth = (core_oi1 / core_oi0)**(1.0/@years_between_stmts) - 1.0
146
+ end
147
+ subject { @reformed_inc_stmt_2011.core_oi_growth(@reformed_inc_stmt_2009) }
148
+ it { should be_an_instance_of Float }
149
+ it { should be_within(0.1).of(@expected_growth) }
150
+ end
151
+
152
+ describe "oi_growth" do
153
+ before(:all) do
154
+ core_oi0 = @reformed_inc_stmt_2009.operating_income_after_tax.total
155
+ core_oi1 = @reformed_inc_stmt_2011.operating_income_after_tax.total
156
+ @expected_growth = (core_oi1 / core_oi0)**(1.0/@years_between_stmts) - 1.0
157
+ end
158
+ subject { @reformed_inc_stmt_2011.oi_growth(@reformed_inc_stmt_2009) }
159
+ it { should be_an_instance_of Float }
160
+ it { should be_within(0.1).of(@expected_growth) }
161
+ end
162
+
163
+ describe "re_oi" do
164
+ before(:all) do
165
+ @expected_rate_of_return = 0.10
166
+ @expected_re_oi = 6868337409.999998
167
+ end
168
+ subject { @reformed_inc_stmt_2011.re_oi(@reformed_bal_sheet_2009, @expected_rate_of_return) }
169
+ it { should be_an_instance_of Float }
170
+ it { should be_within(0.1).of(@expected_re_oi) }
171
+ end
172
+
173
+ describe "analysis" do
174
+ subject {@reformed_inc_stmt_2011.analysis(@reformed_bal_sheet_2011, @reformed_inc_stmt_2009, @reformed_bal_sheet_2009) }
175
+
176
+ it { should be_an_instance_of FinModeling::CalculationSummary }
177
+ it "contains the expected rows" do
178
+ expected_keys = [ "Revenue ($MM)", "Core OI ($MM)", "OI ($MM)", "FI ($MM)",
179
+ "NI ($MM)", "Gross Margin", "Sales PM", "Operating PM",
180
+ "FI / Sales", "NI / Sales", "Sales / NOA", "FI / NFA",
181
+ "Revenue Growth", "Core OI Growth", "OI Growth", "ReOI ($MM)" ]
182
+
183
+ subject.rows.map{ |row| row.key }.should == expected_keys
184
+ end
185
+ end
186
+
187
+ describe "-" do
188
+ before(:all) do
189
+ google_2011_q3_rpt = "http://www.sec.gov/Archives/edgar/data/1288776/000119312511282235/0001193125-11-282235-index.htm"
190
+ @filing_2011_q3 = FinModeling::AnnualReportFiling.download google_2011_q3_rpt
191
+
192
+ @inc_stmt_2011_q3 = @filing_2011_q3.income_statement
193
+ is_period_2011_q3 = @inc_stmt_2011_q3.periods.threequarterly.last
194
+ @reformed_inc_stmt_2011_q3 = @inc_stmt_2011_q3.reformulated(is_period_2011_q3)
195
+
196
+ @diff = @reformed_inc_stmt_2011 - @reformed_inc_stmt_2011_q3
197
+ end
198
+ subject { @diff }
199
+
200
+ it { should be_an_instance_of FinModeling::ReformulatedIncomeStatement }
201
+ its(:period) { should_not be_nil } # FIXME
202
+
203
+ it "returns the difference between the two re_is's for each calculation" do
204
+ methods = [ :operating_revenues, :cost_of_revenues, :gross_revenue,
205
+ :operating_expenses, :income_from_sales_before_tax,
206
+ :income_from_sales_after_tax, :operating_income_after_tax,
207
+ :net_financing_income, :comprehensive_income ]
208
+ #:gross_margin, :sales_profit_margin, :operating_profit_margin,
209
+ #:fi_over_sales, :ni_over_sales, :sales_over_noa,
210
+ #:fi_over_nfa, :revenue_growth, :core_oi_growth,
211
+ #:oi_growth, :re_oi ]
212
+
213
+ methods.each do |method|
214
+ expected_val = @reformed_inc_stmt_2011.send(method).total - @reformed_inc_stmt_2011_q3.send(method).total
215
+ @diff.send(method).total.should be_within(1.0).of(expected_val)
216
+ end
217
+ end
218
+
219
+ it "returns values that are close to 1/4th of the annual value" do
220
+ methods = [ :operating_revenues, :cost_of_revenues, :gross_revenue,
221
+ :operating_expenses, :income_from_sales_before_tax,
222
+ :income_from_sales_after_tax, :operating_income_after_tax,
223
+ #:net_financing_income,
224
+ :comprehensive_income ]
225
+ #:gross_margin, :sales_profit_margin, :operating_profit_margin,
226
+ #:fi_over_sales, :ni_over_sales, :sales_over_noa,
227
+ #:fi_over_nfa, :revenue_growth, :core_oi_growth,
228
+ #:oi_growth, :re_oi ]
229
+
230
+ methods.each do |method|
231
+ orig = @reformed_inc_stmt_2011.send(method).total
232
+ max = (orig > 0) ? (0.35 * orig) : (0.15 * orig)
233
+ min = (orig > 0) ? (0.15 * orig) : (0.35 * orig)
234
+ actual = @diff.send(method).total
235
+ if (actual < min) || (actual > max)
236
+ err = "#{method} returns #{actual.to_nearest_thousand.to_s.with_thousands_separators}, "
237
+ err += "which is outside bounds: [#{min.to_nearest_thousand.to_s.with_thousands_separators}, "
238
+ err += "#{max.to_nearest_thousand.to_s.with_thousands_separators}]"
239
+ puts err
240
+ end
241
+ @diff.send(method).total.should be > min
242
+ @diff.send(method).total.should be < max
243
+ end
244
+ end
245
+ end
246
+
247
+ describe "#forecast_next" do
248
+ before (:all) do
249
+ @company = FinModeling::Company.find("aapl")
250
+ @filings = FinModeling::CompanyFilings.new(@company.filings_since_date(Time.parse("2010-10-01")))
251
+ @policy = FinModeling::GenericForecastingPolicy.new
252
+
253
+ prev_bs_period = @filings.last.balance_sheet.periods.last
254
+ next_bs_period_value = prev_bs_period.value.next_month.next_month.next_month
255
+ @next_bs_period = Xbrlware::Context::Period.new(next_bs_period_value)
256
+
257
+ next_is_period_value = {"start_date" => prev_bs_period.value,
258
+ "end_date" => prev_bs_period.value.next_month.next_month.next_month }
259
+ @next_is_period = Xbrlware::Context::Period.new(next_is_period_value)
260
+ end
261
+
262
+ let(:last_re_bs) { @filings.last.balance_sheet.reformulated(@filings.last.balance_sheet.periods.last) }
263
+ let(:last_re_is) { @filings.last.income_statement.latest_quarterly_reformulated(nil) }
264
+ let(:next_re_is) { FinModeling::ReformulatedIncomeStatement.forecast_next(@next_is_period, @policy, last_re_bs, last_re_is) }
265
+ let(:next_re_bs) { FinModeling::ReformulatedBalanceSheet.forecast_next(@next_bs_period, @policy, last_re_bs, next_re_is) }
266
+
267
+ subject { next_re_is }
268
+
269
+ it { should be_a_kind_of FinModeling::ReformulatedIncomeStatement }
270
+ it "should have the given period" do
271
+ subject.period.to_pretty_s == @next_is_period.to_pretty_s
272
+ end
273
+ it "should set operating_revenue to last year's revenue times the revenue growth" do
274
+ expected_val = last_re_is.operating_revenues.total * (1.0 + FinModeling::Rate.new(@policy.revenue_growth).annualize(from=365, to=365/4.0))
275
+ subject.operating_revenues.total.should == expected_val
276
+ end
277
+ it "should set OISAT to operating revenue times sales PM" do
278
+ expected_val = subject.operating_revenues.total * @policy.sales_pm
279
+ subject.income_from_sales_after_tax.total.should == expected_val
280
+ end
281
+ it "should set NFI to fi_over_nfa times last year's NFA" do
282
+ expected_val = last_re_bs.net_financial_assets.total * (@policy.fi_over_nfa/4)
283
+ subject.net_financing_income.total.should == expected_val
284
+ end
285
+ it "should set comprehensive income to OISAT plus NFI" do
286
+ expected_val = subject.income_from_sales_after_tax.total + subject.net_financing_income.total
287
+ subject.comprehensive_income.total.should == expected_val
288
+ end
289
+ it "should have an empty analysis (with the same rows)" do
290
+ subject.analysis(next_re_bs, last_re_is, last_re_bs)
291
+ end
292
+ end
293
+ end
@@ -0,0 +1,5 @@
1
+ require 'finmodeling'
2
+
3
+ require 'mocks/sec_query'
4
+ require 'mocks/calculation'
5
+
@@ -0,0 +1,23 @@
1
+ # string_helpers_spec.rb
2
+
3
+ require 'spec_helper'
4
+
5
+ describe String do
6
+ describe "matches_regexes?" do
7
+ it "returns false if no regexes are provided" do
8
+ s = "asdfasdf"
9
+ regexes = []
10
+ s.matches_regexes?(regexes).should be_false
11
+ end
12
+ it "returns false if the string does not match any of the regexes" do
13
+ s = "asdfasdf"
14
+ regexes = [/\d/, /[A-Z]/]
15
+ s.matches_regexes?(regexes).should be_false
16
+ end
17
+ it "returns true if the string matches one or more of the regexes" do
18
+ s = "asdfasdf"
19
+ regexes = [/sdf/, /ddd/, /af+/]
20
+ s.matches_regexes?(regexes).should be_true
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH << "."
4
+
5
+ require 'finmodeling'
6
+
7
+ def get_args
8
+ if ARGV.length != 2
9
+ puts "usage #{__FILE__} <stock symbol or report URL> <assets | liabilities>"
10
+ exit
11
+ end
12
+
13
+ args = { :stock_symbol => nil, :filing_url => nil, :assets_or_liabs => nil }
14
+ arg = ARGV[0]
15
+ if arg =~ /http/
16
+ args[:filing_url] = arg
17
+ else
18
+ args[:stock_symbol] = arg.downcase
19
+ end
20
+ case ARGV[1]
21
+ when "assets"
22
+ args[:assets_or_liabs] = "assets"
23
+ when "liabilities"
24
+ args[:assets_or_liabs] = "liabilities"
25
+ else
26
+ puts "usage #{__FILE__} <stock symbol or report URL> <assets | liabilities>"
27
+ exit
28
+ end
29
+
30
+ return args
31
+ end
32
+
33
+ def get_company_filing_url(stock_symbol)
34
+ company = FinModeling::Company.find(stock_symbol)
35
+ raise RuntimeError.new("couldn't find company") if company.nil?
36
+ raise RuntimeError.new("company has no annual reports") if company.annual_reports.length == 0
37
+ filing_url = company.annual_reports.last.link
38
+
39
+ return filing_url
40
+ end
41
+
42
+ def get_filing(filing_url)
43
+ filing = FinModeling::AnnualReportFiling.download(filing_url)
44
+ return filing
45
+ end
46
+
47
+ def print_assets(filing)
48
+ period = filing.balance_sheet.assets_calculation.periods.last
49
+ items = filing.balance_sheet.assets_calculation.leaf_items(period)
50
+ items.each { |item| puts item.pretty_name }
51
+ puts
52
+ end
53
+
54
+ def print_liabilities(filing)
55
+ period = filing.balance_sheet.liabs_and_equity_calculation.periods.last
56
+ items = filing.balance_sheet.liabs_and_equity_calculation.leaf_items(period)
57
+ items.each { |item| puts item.pretty_name }
58
+ puts
59
+ end
60
+
61
+ args = get_args
62
+ filing_url = args[:filing_url] || get_company_filing_url(args[:stock_symbol])
63
+ filing = get_filing(filing_url)
64
+ print_assets(filing) if args[:assets_or_liabs] == "assets"
65
+ print_liabilities(filing) if args[:assets_or_liabs] == "liabilities"
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH << "."
4
+
5
+ require 'finmodeling'
6
+
7
+ def get_args
8
+ if ARGV.length != 1
9
+ puts "usage #{__FILE__} <stock symbol or report URL>"
10
+ exit
11
+ end
12
+
13
+ args = { :stock_symbol => nil, :filing_url => nil }
14
+ arg = ARGV[0]
15
+ if arg =~ /http/
16
+ args[:filing_url] = arg
17
+ else
18
+ args[:stock_symbol] = arg.downcase
19
+ end
20
+
21
+ return args
22
+ end
23
+
24
+ def get_company_filing_url(stock_symbol)
25
+ company = FinModeling::Company.find(stock_symbol)
26
+ raise RuntimeError.new("couldn't find company") if company.nil?
27
+ raise RuntimeError.new("company has no annual reports") if company.annual_reports.length == 0
28
+ filing_url = company.annual_reports.last.link
29
+
30
+ return filing_url
31
+ end
32
+
33
+ def get_filing(filing_url)
34
+ filing = FinModeling::AnnualReportFiling.download(filing_url)
35
+ return filing
36
+ end
37
+
38
+ def print_items(filing)
39
+ items = filing.cash_flow_statement.cash_change_calculation.leaf_items
40
+ items.each do |item|
41
+ puts " { :cci_type=>:c, :item_string=>\"#{item.pretty_name}\" },"
42
+ end
43
+ end
44
+
45
+ args = get_args
46
+ filing_url = args[:filing_url] || get_company_filing_url(args[:stock_symbol])
47
+ filing = get_filing(filing_url)
48
+ print_items(filing)
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH << "."
4
+
5
+ require 'finmodeling'
6
+
7
+ def get_args
8
+ if ARGV.length != 1
9
+ puts "usage #{__FILE__} <stock symbol or report URL>"
10
+ exit
11
+ end
12
+
13
+ args = { :stock_symbol => nil, :filing_url => nil }
14
+ arg = ARGV[0]
15
+ if arg =~ /http/
16
+ args[:filing_url] = arg
17
+ else
18
+ args[:stock_symbol] = arg.downcase
19
+ end
20
+
21
+ return args
22
+ end
23
+
24
+ def get_company_filing_url(stock_symbol)
25
+ company = FinModeling::Company.find(stock_symbol)
26
+ raise RuntimeError.new("couldn't find company") if company.nil?
27
+ raise RuntimeError.new("company has no annual reports") if company.annual_reports.length == 0
28
+ filing_url = company.annual_reports.last.link
29
+
30
+ return filing_url
31
+ end
32
+
33
+ def get_filing(filing_url)
34
+ filing = FinModeling::AnnualReportFiling.download(filing_url)
35
+ return filing
36
+ end
37
+
38
+ def print_items(filing)
39
+ items = filing.balance_sheet.leaf_items
40
+ items += filing.income_statement.leaf_items
41
+ items.each do |item|
42
+ if !item.def.nil?
43
+ puts "{ :balance_defn=>:#{item.def["xbrli:balance"]}, :item_string=>\"#{item.pretty_name}\" },"
44
+ end
45
+ end
46
+ end
47
+
48
+ args = get_args
49
+ filing_url = args[:filing_url] || get_company_filing_url(args[:stock_symbol])
50
+ filing = get_filing(filing_url)
51
+ print_items(filing)
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH << "."
4
+
5
+ require 'finmodeling'
6
+
7
+ def get_args
8
+ if ARGV.length != 1
9
+ puts "usage #{__FILE__} <stock symbol or report URL>"
10
+ exit
11
+ end
12
+
13
+ args = { :stock_symbol => nil, :filing_url => nil }
14
+ arg = ARGV[0]
15
+ if arg =~ /http/
16
+ args[:filing_url] = arg
17
+ else
18
+ args[:stock_symbol] = arg.downcase
19
+ end
20
+
21
+ return args
22
+ end
23
+
24
+ def get_company_filing_url(stock_symbol)
25
+ company = FinModeling::Company.find(stock_symbol)
26
+ raise RuntimeError.new("couldn't find company") if company.nil?
27
+ raise RuntimeError.new("company has no annual reports") if company.annual_reports.length == 0
28
+ filing_url = company.annual_reports.last.link
29
+
30
+ return filing_url
31
+ end
32
+
33
+ def get_filing(filing_url)
34
+ filing = FinModeling::AnnualReportFiling.download(filing_url)
35
+ return filing
36
+ end
37
+
38
+ def print_income_statement(filing)
39
+ period = filing.income_statement.net_income_calculation.periods.yearly.last
40
+ items = filing.income_statement.net_income_calculation.leaf_items(period)
41
+ items.each { |item| puts item.pretty_name }
42
+ puts
43
+ end
44
+
45
+ args = get_args
46
+ filing_url = args[:filing_url] || get_company_filing_url(args[:stock_symbol])
47
+ filing = get_filing(filing_url)
48
+ print_income_statement(filing) #if filing.is_valid?