finmodeling 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. data/.gitignore +0 -0
  2. data/Gemfile +2 -0
  3. data/README.md +289 -269
  4. data/Rakefile +12 -0
  5. data/TODO.txt +113 -20
  6. data/examples/{dump_report.rb → dump_latest_10k.rb} +1 -1
  7. data/examples/list_disclosures.rb +50 -0
  8. data/examples/lists/nasdaq-mid-to-mega-tech-symbols.txt +0 -0
  9. data/examples/show_report.rb +112 -32
  10. data/examples/show_reports.rb +162 -33
  11. data/finmodeling.gemspec +4 -1
  12. data/lib/finmodeling/annual_report_filing.rb +97 -18
  13. data/lib/finmodeling/array_with_stats.rb +0 -0
  14. data/lib/finmodeling/assets_calculation.rb +12 -3
  15. data/lib/finmodeling/assets_item.rb +0 -0
  16. data/lib/finmodeling/assets_item_vectors.rb +0 -0
  17. data/lib/finmodeling/balance_sheet_analyses.rb +19 -4
  18. data/lib/finmodeling/balance_sheet_calculation.rb +52 -37
  19. data/lib/finmodeling/calculation_summary.rb +119 -14
  20. data/lib/finmodeling/can_cache_classifications.rb +0 -0
  21. data/lib/finmodeling/can_cache_summaries.rb +0 -0
  22. data/lib/finmodeling/can_choose_successive_periods.rb +15 -0
  23. data/lib/finmodeling/can_classify_rows.rb +0 -0
  24. data/lib/finmodeling/capm.rb +80 -0
  25. data/lib/finmodeling/cash_change_calculation.rb +3 -3
  26. data/lib/finmodeling/cash_change_item.rb +0 -0
  27. data/lib/finmodeling/cash_change_item_vectors.rb +0 -0
  28. data/lib/finmodeling/cash_change_summary_from_differences.rb +36 -0
  29. data/lib/finmodeling/cash_flow_statement_analyses.rb +36 -0
  30. data/lib/finmodeling/cash_flow_statement_calculation.rb +28 -52
  31. data/lib/finmodeling/classifiers.rb +2 -0
  32. data/lib/finmodeling/company.rb +0 -0
  33. data/lib/finmodeling/company_filing.rb +30 -7
  34. data/lib/finmodeling/company_filing_calculation.rb +16 -6
  35. data/lib/finmodeling/company_filings.rb +112 -46
  36. data/lib/finmodeling/comprehensive_income_calculation.rb +60 -0
  37. data/lib/finmodeling/comprehensive_income_statement_calculation.rb +74 -0
  38. data/lib/finmodeling/comprehensive_income_statement_item.rb +20 -0
  39. data/lib/finmodeling/comprehensive_income_statement_item_vectors.rb +235 -0
  40. data/lib/finmodeling/config.rb +0 -0
  41. data/lib/finmodeling/debt_cost_of_capital.rb +14 -0
  42. data/lib/finmodeling/equity_change_calculation.rb +43 -0
  43. data/lib/finmodeling/equity_change_item.rb +25 -0
  44. data/lib/finmodeling/equity_change_item_vectors.rb +156 -0
  45. data/lib/finmodeling/factory.rb +0 -0
  46. data/lib/finmodeling/fama_french_cost_of_equity.rb +119 -0
  47. data/lib/finmodeling/float_helpers.rb +14 -8
  48. data/lib/finmodeling/forecasted_reformulated_balance_sheet.rb +55 -0
  49. data/lib/finmodeling/forecasted_reformulated_income_statement.rb +110 -0
  50. data/lib/finmodeling/forecasts.rb +4 -4
  51. data/lib/finmodeling/has_string_classifer.rb +0 -0
  52. data/lib/finmodeling/income_statement_analyses.rb +23 -17
  53. data/lib/finmodeling/income_statement_calculation.rb +46 -43
  54. data/lib/finmodeling/income_statement_item.rb +1 -1
  55. data/lib/finmodeling/income_statement_item_vectors.rb +24 -13
  56. data/lib/finmodeling/invalid_filing_error.rb +4 -0
  57. data/lib/finmodeling/liabs_and_equity_calculation.rb +18 -8
  58. data/lib/finmodeling/liabs_and_equity_item.rb +1 -1
  59. data/lib/finmodeling/liabs_and_equity_item_vectors.rb +24 -24
  60. data/lib/finmodeling/linear_trend_forecasting_policy.rb +23 -0
  61. data/lib/finmodeling/net_income_calculation.rb +23 -10
  62. data/lib/finmodeling/net_income_summary_from_differences.rb +51 -0
  63. data/lib/finmodeling/paths.rb +0 -0
  64. data/lib/finmodeling/period_array.rb +8 -4
  65. data/lib/finmodeling/quarterly_report_filing.rb +9 -4
  66. data/lib/finmodeling/rate.rb +8 -0
  67. data/lib/finmodeling/ratio.rb +0 -0
  68. data/lib/finmodeling/reformulated_balance_sheet.rb +47 -88
  69. data/lib/finmodeling/reformulated_cash_flow_statement.rb +18 -41
  70. data/lib/finmodeling/reformulated_income_statement.rb +44 -206
  71. data/lib/finmodeling/reformulated_shareholder_equity_statement.rb +50 -0
  72. data/lib/finmodeling/reoi_valuation.rb +104 -0
  73. data/lib/finmodeling/shareholder_equity_statement_calculation.rb +34 -0
  74. data/lib/finmodeling/string_helpers.rb +18 -1
  75. data/lib/finmodeling/time_series_estimator.rb +25 -0
  76. data/lib/finmodeling/trailing_avg_forecasting_policy.rb +23 -0
  77. data/lib/finmodeling/version.rb +1 -1
  78. data/lib/finmodeling/weighted_avg_cost_of_capital.rb +35 -0
  79. data/lib/finmodeling/yahoo_finance_helpers.rb +20 -0
  80. data/lib/finmodeling.rb +33 -2
  81. data/spec/annual_report_filing_spec.rb +81 -45
  82. data/spec/assets_calculation_spec.rb +7 -4
  83. data/spec/assets_item_spec.rb +9 -14
  84. data/spec/balance_sheet_analyses_spec.rb +13 -13
  85. data/spec/balance_sheet_calculation_spec.rb +45 -51
  86. data/spec/calculation_summary_spec.rb +113 -21
  87. data/spec/can_classify_rows_spec.rb +0 -0
  88. data/spec/cash_change_calculation_spec.rb +1 -10
  89. data/spec/cash_change_item_spec.rb +10 -18
  90. data/spec/cash_flow_statement_calculation_spec.rb +10 -24
  91. data/spec/company_beta_spec.rb +53 -0
  92. data/spec/company_filing_calculation_spec.rb +39 -49
  93. data/spec/company_filing_spec.rb +0 -0
  94. data/spec/company_filings_spec.rb +75 -25
  95. data/spec/company_spec.rb +37 -47
  96. data/spec/comprehensive_income_statement_calculation_spec.rb +54 -0
  97. data/spec/comprehensive_income_statement_item_spec.rb +56 -0
  98. data/spec/debt_cost_of_capital_spec.rb +19 -0
  99. data/spec/equity_change_calculation_spec.rb +33 -0
  100. data/spec/equity_change_item_spec.rb +58 -0
  101. data/spec/factory_spec.rb +2 -2
  102. data/spec/forecasts_spec.rb +2 -2
  103. data/spec/income_statement_analyses_spec.rb +23 -21
  104. data/spec/income_statement_calculation_spec.rb +17 -49
  105. data/spec/income_statement_item_spec.rb +17 -29
  106. data/spec/liabs_and_equity_calculation_spec.rb +6 -3
  107. data/spec/liabs_and_equity_item_spec.rb +14 -22
  108. data/spec/linear_trend_forecasting_policy_spec.rb +37 -0
  109. data/spec/matchers/custom_matchers.rb +79 -0
  110. data/spec/mocks/calculation.rb +0 -0
  111. data/spec/mocks/income_statement_analyses.rb +0 -0
  112. data/spec/mocks/sec_query.rb +0 -0
  113. data/spec/net_income_calculation_spec.rb +16 -10
  114. data/spec/period_array.rb +0 -0
  115. data/spec/quarterly_report_filing_spec.rb +21 -38
  116. data/spec/rate_spec.rb +0 -0
  117. data/spec/ratio_spec.rb +0 -0
  118. data/spec/reformulated_balance_sheet_spec.rb +56 -33
  119. data/spec/reformulated_cash_flow_statement_spec.rb +18 -10
  120. data/spec/reformulated_income_statement_spec.rb +16 -15
  121. data/spec/reformulated_shareholder_equity_statement_spec.rb +43 -0
  122. data/spec/reoi_valuation_spec.rb +146 -0
  123. data/spec/shareholder_equity_statement_calculation_spec.rb +59 -0
  124. data/spec/spec_helper.rb +4 -1
  125. data/spec/string_helpers_spec.rb +15 -13
  126. data/spec/time_series_estimator_spec.rb +61 -0
  127. data/spec/trailing_avg_forecasting_policy_spec.rb +37 -0
  128. data/spec/weighted_avg_cost_of_capital_spec.rb +32 -0
  129. data/tools/create_equity_change_training_vectors.rb +49 -0
  130. data/tools/time_specs.sh +7 -0
  131. metadata +182 -36
  132. data/lib/finmodeling/constant_forecasting_policy.rb +0 -23
  133. data/lib/finmodeling/generic_forecasting_policy.rb +0 -19
  134. data/spec/constant_forecasting_policy_spec.rb +0 -37
  135. data/spec/generic_forecasting_policy_spec.rb +0 -33
@@ -1,45 +1,37 @@
1
- # period_array_spec.rb
1
+ # liabs_and_equity_item_spec.rb
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
5
  describe FinModeling::LiabsAndEquityItem do
6
6
 
7
- before(:all) do
8
- #FinModeling::LiabsAndEquityItem.load_vectors_and_train(FinModeling::LiabsAndEquityItem::TRAINING_VECTORS)
7
+ describe ".new" do
8
+ subject { FinModeling::LiabsAndEquityItem.new("Accounts Payable Current") }
9
+ it { should be_a FinModeling::LiabsAndEquityItem }
9
10
  end
10
11
 
11
- describe "new" do
12
- it "takes a string and returns a new LiabsAndEquityItem" do
13
- laei = FinModeling::LiabsAndEquityItem.new("Accounts Payable Current")
14
- laei.should be_an_instance_of FinModeling::LiabsAndEquityItem
15
- end
16
- end
17
-
18
- describe "train" do
12
+ describe ".train" do
19
13
  it "trains the classifier that this LiabsAndEquityItem is of the given type" do
20
14
  FinModeling::LiabsAndEquityItem.new("Accounts Payable Current").train(:ol)
21
15
  end
22
16
  end
23
17
 
24
- describe "classification_estimates" do
25
- it "returns a hash with the confidence in each LiabsAndEquityItem type" do
26
- laei = FinModeling::LiabsAndEquityItem.new("Accounts Payable Current")
18
+ describe ".classification_estimates" do
19
+ subject { FinModeling::LiabsAndEquityItem.new("Accounts Payable Current").classification_estimates }
27
20
 
28
- FinModeling::LiabsAndEquityItem::TYPES.each do |klass|
29
- laei.classification_estimates.keys.include?(klass).should be_true
30
- end
31
- end
21
+ it { should be_a Hash }
22
+ specify { subject.keys.sort == FinModeling::LiabsAndEquityItem::TYPES.sort }
32
23
  end
33
24
 
34
- describe "classify" do
25
+ describe ".classify" do
26
+ let(:laei) { FinModeling::LiabsAndEquityItem.new("Accounts Payable Current") }
27
+ subject { laei.classify }
35
28
  it "returns the LiabsAndEquityItem type with the highest probability estimate" do
36
- laei = FinModeling::LiabsAndEquityItem.new("Accounts Payable Current")
37
29
  estimates = laei.classification_estimates
38
- estimates[laei.classify].should be_within(0.1).of(estimates.values.max)
30
+ estimates[subject].should be_within(0.1).of(estimates.values.max)
39
31
  end
40
32
  end
41
33
 
42
- describe "load_vectors_and_train" do
34
+ describe ".load_vectors_and_train" do
43
35
  # the before(:all) clause calls load_vectors_and_train already
44
36
  # we can just focus, here, on its effects
45
37
 
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe FinModeling::LinearTrendForecastingPolicy do
4
+ before (:all) do
5
+ @vals = { :revenue_estimator => FinModeling::TimeSeriesEstimator.new(0.04, 0.0),
6
+ :sales_pm_estimator => FinModeling::TimeSeriesEstimator.new(0.20, 0.0),
7
+ :fi_over_nfa_estimator => FinModeling::TimeSeriesEstimator.new(0.01, 0.0),
8
+ :sales_over_noa_estimator => FinModeling::TimeSeriesEstimator.new(2.00, 0.0) }
9
+ end
10
+
11
+ let(:policy) { FinModeling::LinearTrendForecastingPolicy.new(@vals) }
12
+ let(:date) { Date.today }
13
+
14
+ describe ".revenue_on" do
15
+ subject { policy.revenue_on(date) }
16
+ it { should be_a Float }
17
+ it { should be_within(0.01).of(@vals[:revenue_estimator].a) }
18
+ end
19
+
20
+ describe ".sales_pm_on" do
21
+ subject { policy.sales_pm_on(date) }
22
+ it { should be_a Float }
23
+ it { should be_within(0.01).of(@vals[:sales_pm_estimator].a) }
24
+ end
25
+
26
+ describe ".fi_over_nfa_on" do
27
+ subject { policy.fi_over_nfa_on(date) }
28
+ it { should be_a Float }
29
+ it { should be_within(0.01).of(@vals[:fi_over_nfa_estimator].a) }
30
+ end
31
+
32
+ describe ".sales_over_noa_on" do
33
+ subject { policy.sales_over_noa_on(date) }
34
+ it { should be_a Float }
35
+ it { should be_within(0.01).of(@vals[:sales_over_noa_estimator].a) }
36
+ end
37
+ end
@@ -0,0 +1,79 @@
1
+ RSpec::Matchers.define :be_in do |expected|
2
+ match do |actual|
3
+ expected.include?(actual)
4
+ end
5
+
6
+ description { "be one of #{expected}" }
7
+ failure_message_for_should { |actual| "expected one of #{expected} but got '#{actual}'" }
8
+ failure_message_for_should_not { |actual| "expected other one of #{expected} but got '#{actual}'" }
9
+ end
10
+
11
+ RSpec::Matchers.define :have_the_same_periods_as do |expected|
12
+ match do |actual|
13
+ str1 = actual .periods.map{|x| x.to_pretty_s}.join(',')
14
+ str2 = expected.periods.map{|x| x.to_pretty_s}.join(',')
15
+ str1 == str2
16
+ end
17
+ end
18
+
19
+ RSpec::Matchers.define :have_a_plausible_total do
20
+ match do |actual|
21
+ actual.total.abs >= 1.0
22
+ end
23
+
24
+ description { "have a plausible total" }
25
+ failure_message_for_should { |actual| "expected that #{actual} would have a total with an absolute value > 1.0" }
26
+ failure_message_for_should_not { |actual| "expected that #{actual} would not have a total with an absolute value > 1.0" }
27
+ end
28
+
29
+ RSpec::Matchers.define :have_the_same_last_total_as do |expected|
30
+ match do |actual|
31
+ period = actual.periods.last
32
+ val1 = actual .summary(:period=>period).total
33
+ val2 = expected.summary(:period=>period).total
34
+ (val1 - val2).abs <= 0.1
35
+ end
36
+
37
+ description { "have the same last reformulated total as #{expected}" }
38
+ failure_message_for_should { |actual| "expected that #{actual} would have the same last total as #{expected}" }
39
+ failure_message_for_should_not { |actual| "expected that #{actual} would not have the same last total as #{expected}" }
40
+ end
41
+
42
+ RSpec::Matchers.define :have_the_same_last_total do |calc|
43
+ match do |actual|
44
+ a = actual .send(calc)
45
+ e = expected.send(calc)
46
+
47
+ period = a.periods.last
48
+ val1 = a.summary(:period=>period).total
49
+ val2 = e.summary(:period=>period).total
50
+ (val1 - val2).abs <= 0.1
51
+ end
52
+ chain :as do |expected|
53
+ @expected = expected
54
+ end
55
+
56
+ description { "have #{calc} with the same last total as #{@expected}" }
57
+ failure_message_for_should { |actual| "expected that #{actual}'s #{calc} would have the same last total as #{@expected}" }
58
+ failure_message_for_should_not { |actual| "expected that #{actual}'s #{calc} would not have the same last total as #{@expected}" }
59
+ end
60
+
61
+ RSpec::Matchers.define :have_the_same_reformulated_last_total do |calc|
62
+ match do |actual|
63
+ period = actual.periods.last
64
+
65
+ params = (actual.is_a? FinModeling::IncomeStatementCalculation) ? [period, ci_calc=nil] : [period]
66
+
67
+ val1 = actual .reformulated(*params).send(calc).total
68
+ val2 = expected.reformulated(*params).send(calc).total
69
+ (val1 - val2).abs <= 0.1
70
+ end
71
+ chain :as do |expected|
72
+ @expected = expected
73
+ end
74
+
75
+ description { "have the same last reformulated total as #{@expected}" }
76
+ failure_message_for_should { |actual| "expected that #{actual} would have the same last reformulated total as #{@expected}" }
77
+ failure_message_for_should_not { |actual| "expected that #{actual} would not have the same last reformulated total as #{@expected}" }
78
+ end
79
+
File without changes
File without changes
File without changes
@@ -1,4 +1,4 @@
1
- # income_statement_calculation_spec.rb
1
+ # net_income_calculation_spec.rb
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -6,18 +6,24 @@ describe FinModeling::NetIncomeCalculation do
6
6
  before(:all) do
7
7
  google_2011_annual_rpt = "http://www.sec.gov/Archives/edgar/data/1288776/000119312512025336/0001193125-12-025336-index.htm"
8
8
  filing = FinModeling::AnnualReportFiling.download google_2011_annual_rpt
9
- @inc_stmt = filing.income_statement
10
- @period = @inc_stmt.periods.last
11
- @ni = @inc_stmt.net_income_calculation
9
+ @period = filing.income_statement.periods.last
10
+ @ni = filing.income_statement.net_income_calculation
12
11
  end
13
12
 
14
- describe "summary" do
15
- it "only requires a period (knows how debts/credits work and whether to flip the total)" do
16
- @ni.summary(:period=>@period).should be_an_instance_of FinModeling::CalculationSummary
17
- end
18
- it "tags each row with an Income Statement Type" do
19
- FinModeling::IncomeStatementItem::TYPES.include?(@ni.summary(:period=>@period).rows.first.type).should be_true
13
+ describe ".summary" do
14
+ subject { @ni.summary(:period=>@period) }
15
+ it { should be_a FinModeling::CalculationSummary }
16
+ it "should tag each row with an Income Statement Type" do
17
+ subject.rows.first.type.should be_in(FinModeling::IncomeStatementItem::TYPES) # FIXME: seems weak.
20
18
  end
21
19
  end
20
+
21
+ describe ".has_revenue_item?" do
22
+ pending "Find a test case..."
23
+ end
24
+
25
+ describe ".has_tax_item?" do
26
+ pending "Find a test case..."
27
+ end
22
28
  end
23
29
 
data/spec/period_array.rb CHANGED
File without changes
@@ -6,22 +6,24 @@ describe FinModeling::QuarterlyReportFiling do
6
6
  before(:all) do
7
7
  company = FinModeling::Company.new(FinModeling::Mocks::Entity.new)
8
8
  filing_url = company.quarterly_reports.last.link
9
- FinModeling::Config::disable_caching
9
+ FinModeling::Config::disable_caching
10
10
  @filing = FinModeling::QuarterlyReportFiling.download(filing_url)
11
- end
12
-
13
- after(:all) do
14
- FinModeling::Config::enable_caching
11
+ FinModeling::Config::enable_caching
15
12
  end
16
13
 
17
14
  subject { @filing }
18
- its(:balance_sheet) { should be_a FinModeling::BalanceSheetCalculation }
19
- its(:income_statement) { should be_a FinModeling::IncomeStatementCalculation }
20
- its(:cash_flow_statement) { should be_a FinModeling::CashFlowStatementCalculation }
21
-
22
- its(:is_valid?) { should == (@filing.income_statement.is_valid? && @filing.balance_sheet.is_valid? && @filing.cash_flow_statement.is_valid?) }
15
+ its(:balance_sheet) { should be_a FinModeling::BalanceSheetCalculation }
16
+ its(:income_statement) { should be_a FinModeling::IncomeStatementCalculation }
17
+ its(:cash_flow_statement) { should be_a FinModeling::CashFlowStatementCalculation }
18
+
19
+ context "when the report doesn't have a statement of shareholders' equity" do
20
+ its(:has_a_shareholder_equity_statement?) { should be_false }
21
+ #its(:is_valid?) { should == [@filing.income_statement,
22
+ # @filing.balance_sheet,
23
+ # @filing.cash_flow_statement].all?{|x| x.is_valid?} } # FIXME: this is failing, but I'm not sure how I want it to work.
24
+ end
23
25
 
24
- describe "write_constructor" do
26
+ context "after write_constructor()ing it to a file and then eval()ing the results" do
25
27
  before(:all) do
26
28
  file_name = "/tmp/finmodeling-quarterly-rpt.rb"
27
29
  schema_version_item_name = "@schema_version"
@@ -36,34 +38,15 @@ describe FinModeling::QuarterlyReportFiling do
36
38
  @loaded_filing = eval(item_name)
37
39
  end
38
40
 
39
- it "writes itself to a file, and saves a schema version of 1.1" do
40
- @schema_version.should be == 1.1
41
- end
42
-
43
- it "writes itself to a file, and when reloaded, has the same periods" do
44
- expected_periods = @filing.balance_sheet.periods.map{|x| x.to_pretty_s}.join(',')
45
- @loaded_filing.balance_sheet.periods.map{|x| x.to_pretty_s}.join(',').should == expected_periods
46
- end
47
- it "writes itself to a file, and when reloaded, has the same net operating assets" do
48
- period = @filing.balance_sheet.periods.last
49
- expected_noa = @filing.balance_sheet.reformulated(period).net_operating_assets.total
50
- @loaded_filing.balance_sheet.reformulated(period).net_operating_assets.total.should be_within(1.0).of(expected_noa)
51
- end
52
- it "writes itself to a file, and when reloaded, has the same net financing income" do
53
- period = @filing.income_statement.periods.last
54
- expected_nfi = @filing.income_statement.reformulated(period).net_financing_income.total
55
- @loaded_filing.income_statement.reformulated(period).net_financing_income.total.should be_within(1.0).of(expected_nfi)
56
- end
57
- it "writes itself to a file, and when reloaded, has the same net change in cash" do
58
- period = @filing.cash_flow_statement.periods.last
59
- expected_cash_change = @filing.cash_flow_statement.cash_change_calculation.summary(:period=>period).total
60
- @loaded_filing.cash_flow_statement.cash_change_calculation.summary(:period=>period).total.should be_within(1.0).of(expected_cash_change)
61
- end
62
- it "writes itself to a file, and when reloaded, has the same disclosures" do
63
- period = @filing.disclosures.first.periods.last
64
- expected_total = @filing.disclosures.first.summary(:period=>period).total
65
- @loaded_filing.disclosures.first.summary(:period=>period).total.should == expected_total
41
+ it "writes itself to a file, and saves a schema version of 1.3" do
42
+ @schema_version.should be == 1.3
66
43
  end
67
44
 
45
+ subject { @loaded_filing }
46
+ its(:balance_sheet) { should have_the_same_periods_as(@filing.balance_sheet) }
47
+ its(:balance_sheet) { should have_the_same_reformulated_last_total(:net_operating_assets).as(@filing.balance_sheet) }
48
+ its(:income_statement) { should have_the_same_reformulated_last_total(:net_financing_income).as(@filing.income_statement) }
49
+ its(:cash_flow_statement) { should have_the_same_last_total(:cash_change_calculation).as(@filing.cash_flow_statement) }
50
+ its(:disclosures) { should have_the_same_last_total(:first).as(@filing.disclosures) }
68
51
  end
69
52
  end
data/spec/rate_spec.rb CHANGED
File without changes
data/spec/ratio_spec.rb CHANGED
File without changes
@@ -20,61 +20,81 @@ describe FinModeling::ReformulatedBalanceSheet do
20
20
  @years_between_sheets = 2.0
21
21
  end
22
22
 
23
- describe "new" do
23
+ describe ".new" do
24
24
  it "takes an assets calculation and a liabs_and_equity calculation and a period and returns a CalculationSummary" do
25
- rbs = FinModeling::ReformulatedBalanceSheet.new(@period, @bal_sheet.assets_calculation.summary(:period=>@period), @bal_sheet.liabs_and_equity_calculation.summary(:period=>@period))
26
- rbs.should be_an_instance_of FinModeling::ReformulatedBalanceSheet
25
+ rbs = FinModeling::ReformulatedBalanceSheet.new(@period,
26
+ @bal_sheet.assets_calculation .summary(:period=>@period),
27
+ @bal_sheet.liabs_and_equity_calculation.summary(:period=>@period))
28
+ rbs.should be_a FinModeling::ReformulatedBalanceSheet
27
29
  end
28
30
  end
29
31
 
30
- describe "operating_assets" do
32
+ describe ".operating_assets" do
31
33
  subject { @reformed_bal_sheet.operating_assets }
32
- it { should be_an_instance_of FinModeling::CalculationSummary }
33
- its(:total) { should be_within(0.1).of(26943000000.0) }
34
+ it { should be_a FinModeling::CalculationSummary }
35
+ let(:total_assets) { @bal_sheet.assets_calculation.summary(:period=>@period).total }
36
+ its(:total) { should be_within(0.1).of(total_assets - @reformed_bal_sheet.financial_assets.total) }
34
37
  end
35
38
 
36
- describe "financial_assets" do
39
+ describe ".financial_assets" do
37
40
  subject { @reformed_bal_sheet.financial_assets }
38
- it { should be_an_instance_of FinModeling::CalculationSummary }
39
- its(:total) { should be_within(0.1).of(45631000000.0) }
41
+ it { should be_a FinModeling::CalculationSummary }
42
+ let(:total_assets) { @bal_sheet.assets_calculation.summary(:period=>@period).total }
43
+ its(:total) { should be_within(0.1).of(total_assets - @reformed_bal_sheet.operating_assets.total) }
40
44
  end
41
45
 
42
- describe "operating_liabilities" do
46
+ describe ".operating_liabilities" do
43
47
  subject { @reformed_bal_sheet.operating_liabilities }
44
- it { should be_an_instance_of FinModeling::CalculationSummary }
45
- its(:total) { should be_within(0.1).of(6041000000.0) }
48
+ it { should be_a FinModeling::CalculationSummary }
49
+ let(:total_equity) { @reformed_bal_sheet.common_shareholders_equity.total }
50
+ let(:total_l_and_e) { @bal_sheet.liabs_and_equity_calculation.summary(:period=>@period).total }
51
+ let(:total_liabs) { total_l_and_e - total_equity }
52
+ its(:total) { should be_within(0.1).of(total_liabs - @reformed_bal_sheet.financial_liabilities.total) }
46
53
  end
47
54
 
48
- describe "financial_liabilities" do
55
+ describe ".financial_liabilities" do
49
56
  subject { @reformed_bal_sheet.financial_liabilities }
50
- it { should be_an_instance_of FinModeling::CalculationSummary }
51
- its(:total) { should be_within(0.1).of(8388000000.0) }
57
+ it { should be_a FinModeling::CalculationSummary }
58
+ let(:total_equity) { @reformed_bal_sheet.common_shareholders_equity.total }
59
+ let(:total_l_and_e) { @bal_sheet.liabs_and_equity_calculation.summary(:period=>@period).total }
60
+ let(:total_liabs) { total_l_and_e - total_equity }
61
+ its(:total) { should be_within(0.1).of(total_liabs - @reformed_bal_sheet.operating_liabilities.total) }
52
62
  end
53
63
 
54
- describe "net_operating_assets" do
64
+ describe ".net_operating_assets" do
55
65
  subject { @reformed_bal_sheet.net_operating_assets }
56
- it { should be_an_instance_of FinModeling::CalculationSummary }
57
- its(:total) { should be_within(0.1).of(20902000000.0) }
66
+ it { should be_a FinModeling::CalculationSummary }
67
+ its(:total) { should be_within(0.1).of(@reformed_bal_sheet.operating_assets.total - @reformed_bal_sheet.operating_liabilities.total) }
58
68
  end
59
69
 
60
- describe "net_financial_assets" do
70
+ describe ".net_financial_assets" do
61
71
  subject { @reformed_bal_sheet.net_financial_assets }
62
- it { should be_an_instance_of FinModeling::CalculationSummary }
63
- its(:total) { should be_within(0.1).of(37243000000.0) }
72
+ it { should be_a FinModeling::CalculationSummary }
73
+ its(:total) { should be_within(0.1).of(@reformed_bal_sheet.financial_assets.total - @reformed_bal_sheet.financial_liabilities.total) }
64
74
  end
65
75
 
66
- describe "common_shareholders_equity" do
76
+ describe ".minority_interest" do
77
+ subject { @reformed_bal_sheet.minority_interest }
78
+ it { should be_a FinModeling::CalculationSummary }
79
+ its(:total) { should be_within(0.1).of(@reformed_bal_sheet.net_operating_assets.total +
80
+ @reformed_bal_sheet.net_financial_assets.total -
81
+ @reformed_bal_sheet.common_shareholders_equity.total) }
82
+ end
83
+
84
+ describe ".common_shareholders_equity" do
67
85
  subject { @reformed_bal_sheet.common_shareholders_equity }
68
- it { should be_an_instance_of FinModeling::CalculationSummary }
69
- its(:total) { should be_within(0.1).of(58145000000.0) }
86
+ it { should be_a FinModeling::CalculationSummary }
87
+ its(:total) { should be_within(0.1).of(@reformed_bal_sheet.net_operating_assets.total +
88
+ @reformed_bal_sheet.net_financial_assets.total -
89
+ @reformed_bal_sheet.minority_interest.total) }
70
90
  end
71
91
 
72
- describe "composition_ratio" do
92
+ describe ".composition_ratio" do
73
93
  subject { @reformed_bal_sheet.composition_ratio }
74
94
  it { should be_within(0.1).of(@reformed_bal_sheet.net_operating_assets.total / @reformed_bal_sheet.net_financial_assets.total) }
75
95
  end
76
96
 
77
- describe "noa_growth" do
97
+ describe ".noa_growth" do
78
98
  subject { @reformed_bal_sheet.noa_growth(@prev_reformed_bal_sheet) }
79
99
  let(:noa0) { @prev_reformed_bal_sheet.net_operating_assets.total }
80
100
  let(:noa1) { @reformed_bal_sheet.net_operating_assets.total }
@@ -82,7 +102,7 @@ describe FinModeling::ReformulatedBalanceSheet do
82
102
  it { should be_within(0.001).of(expected_growth) }
83
103
  end
84
104
 
85
- describe "cse_growth" do
105
+ describe ".cse_growth" do
86
106
  subject { @reformed_bal_sheet.cse_growth(@prev_reformed_bal_sheet) }
87
107
  let(:cse0) { @prev_reformed_bal_sheet.common_shareholders_equity.total }
88
108
  let(:cse1) { @reformed_bal_sheet.common_shareholders_equity.total }
@@ -90,11 +110,11 @@ describe FinModeling::ReformulatedBalanceSheet do
90
110
  it { should be_within(0.001).of(expected_growth) }
91
111
  end
92
112
 
93
- describe "analysis" do
113
+ describe ".analysis" do
94
114
  subject {@reformed_bal_sheet.analysis(@prev_reformed_bal_sheet) }
95
- it { should be_an_instance_of FinModeling::CalculationSummary }
115
+ it { should be_a FinModeling::CalculationSummary }
96
116
  it "contains the expected rows" do
97
- expected_keys = ["NOA ($MM)", "NFA ($MM)", "CSE ($MM)",
117
+ expected_keys = ["NOA ($MM)", "NFA ($MM)", "Minority Interest ($MM)", "CSE ($MM)",
98
118
  "Composition Ratio", "NOA Growth", "CSE Growth" ]
99
119
 
100
120
  subject.rows.map{ |row| row.key }.should == expected_keys
@@ -105,7 +125,7 @@ describe FinModeling::ReformulatedBalanceSheet do
105
125
  before (:all) do
106
126
  @company = FinModeling::Company.find("aapl")
107
127
  @filings = FinModeling::CompanyFilings.new(@company.filings_since_date(Time.parse("2010-10-01")))
108
- @policy = FinModeling::GenericForecastingPolicy.new
128
+ @policy = FinModeling::GenericForecastingPolicy.new(:operating_revenues=>@filings.last.income_statement.latest_quarterly_reformulated(nil, nil, nil).operating_revenues.total)
109
129
 
110
130
  prev_bs_period = @filings.last.balance_sheet.periods.last
111
131
  next_bs_period_value = prev_bs_period.value.next_month.next_month.next_month
@@ -116,7 +136,7 @@ describe FinModeling::ReformulatedBalanceSheet do
116
136
  @next_is_period = Xbrlware::Context::Period.new(next_is_period_value)
117
137
  end
118
138
 
119
- let(:last_re_is) { @filings.last.income_statement.latest_quarterly_reformulated(nil) }
139
+ let(:last_re_is) { @filings.last.income_statement.latest_quarterly_reformulated(ci_calc=nil, prev_is=nil, prev_ci_calc=nil) }
120
140
  let(:last_re_bs) { @filings.last.balance_sheet.reformulated(@filings.last.balance_sheet.periods.last) }
121
141
  let(:next_re_is) { FinModeling::ReformulatedIncomeStatement.forecast_next(@next_is_period, @policy, last_re_bs, last_re_is) }
122
142
 
@@ -126,8 +146,11 @@ describe FinModeling::ReformulatedBalanceSheet do
126
146
  it "should have the given period" do
127
147
  subject.period.to_pretty_s == @next_bs_period.to_pretty_s
128
148
  end
149
+ it "should set minority interest to ...?" do
150
+ pending "not sure how to treat this"
151
+ end
129
152
  it "should set NOA to the same period's operating revenue over the policy's asset turnover" do
130
- expected_val = next_re_is.operating_revenues.total / FinModeling::Ratio.new(@policy.sales_over_noa).yearly_to_quarterly
153
+ expected_val = next_re_is.operating_revenues.total / FinModeling::Ratio.new(@policy.sales_over_noa_on(@next_bs_period.value)).yearly_to_quarterly
131
154
  subject.net_operating_assets.total.should == expected_val
132
155
  end
133
156
  it "should set CSE to last year's CSE plus this year's net income" do
@@ -15,14 +15,14 @@ describe FinModeling::ReformulatedCashFlowStatement do
15
15
 
16
16
  @inc_stmt = filing.income_statement
17
17
  @is_period = @inc_stmt.periods.last
18
- @reformed_inc_stmt = @inc_stmt.reformulated(@is_period)
18
+ @reformed_inc_stmt = @inc_stmt.reformulated(@is_period, ci_calc=nil)
19
19
 
20
20
  @cash_flow_stmt = filing.cash_flow_statement
21
21
  @period = @cash_flow_stmt.periods.last
22
22
  @reformed_cash_flow_stmt = @cash_flow_stmt.reformulated(@period)
23
23
  end
24
24
 
25
- describe "new" do
25
+ describe ".new" do
26
26
  it "takes a cash change calculation and a period and returns a CalculationSummary" do
27
27
  rcfs = FinModeling::ReformulatedCashFlowStatement.new(@period, @cash_flow_stmt.cash_change_calculation.summary(:period=>@period))
28
28
  rcfs.should be_an_instance_of FinModeling::ReformulatedCashFlowStatement
@@ -31,7 +31,7 @@ describe FinModeling::ReformulatedCashFlowStatement do
31
31
 
32
32
  subject { @reformed_cash_flow_stmt }
33
33
 
34
- describe "cash_from_operations" do
34
+ describe ".cash_from_operations" do
35
35
  subject { @reformed_cash_flow_stmt.cash_from_operations }
36
36
  it { should be_an_instance_of FinModeling::CalculationSummary }
37
37
  it "totals up the values of rows with type :c" do
@@ -44,7 +44,7 @@ describe FinModeling::ReformulatedCashFlowStatement do
44
44
  end
45
45
  end
46
46
 
47
- describe "cash_investments_in_operations" do
47
+ describe ".cash_investments_in_operations" do
48
48
  subject { @reformed_cash_flow_stmt.cash_investments_in_operations }
49
49
  it { should be_an_instance_of FinModeling::CalculationSummary }
50
50
  it "totals up the values of rows with type :i" do
@@ -57,7 +57,7 @@ describe FinModeling::ReformulatedCashFlowStatement do
57
57
  end
58
58
  end
59
59
 
60
- describe "payments_to_debtholders" do
60
+ describe ".payments_to_debtholders" do
61
61
  subject { @reformed_cash_flow_stmt.payments_to_debtholders }
62
62
  it { should be_an_instance_of FinModeling::CalculationSummary }
63
63
  it "totals up the values of rows with type :d, minus the total change in cash" do
@@ -73,7 +73,7 @@ describe FinModeling::ReformulatedCashFlowStatement do
73
73
  end
74
74
  end
75
75
 
76
- describe "payments_to_stockholders" do
76
+ describe ".payments_to_stockholders" do
77
77
  subject { @reformed_cash_flow_stmt.payments_to_stockholders }
78
78
  it { should be_an_instance_of FinModeling::CalculationSummary }
79
79
  it "totals up the values of rows with type :f" do
@@ -86,7 +86,7 @@ describe FinModeling::ReformulatedCashFlowStatement do
86
86
  end
87
87
  end
88
88
 
89
- describe "free_cash_flow" do
89
+ describe ".free_cash_flow" do
90
90
  subject { @reformed_cash_flow_stmt.free_cash_flow }
91
91
  it { should be_an_instance_of FinModeling::CalculationSummary }
92
92
  it "totals up cash from operations and cash investments in operations" do
@@ -96,13 +96,13 @@ describe FinModeling::ReformulatedCashFlowStatement do
96
96
  end
97
97
  end
98
98
 
99
- describe "ni_over_c" do
99
+ describe ".ni_over_c" do
100
100
  subject { @reformed_cash_flow_stmt.ni_over_c(@reformed_inc_stmt) }
101
101
  it { should be_an_instance_of Float }
102
102
  it { should be_within(0.1).of(@reformed_inc_stmt.comprehensive_income.total / @reformed_cash_flow_stmt.cash_from_operations.total) }
103
103
  end
104
104
 
105
- describe "financing_flows" do
105
+ describe ".financing_flows" do
106
106
  subject { @reformed_cash_flow_stmt.financing_flows }
107
107
  it { should be_an_instance_of FinModeling::CalculationSummary }
108
108
  it "totals up payments to both debtholders and stockholders" do
@@ -112,7 +112,7 @@ describe FinModeling::ReformulatedCashFlowStatement do
112
112
  end
113
113
  end
114
114
 
115
- describe "analysis" do
115
+ describe ".analysis" do
116
116
  subject { @reformed_cash_flow_stmt.analysis(@reformed_inc_stmt) }
117
117
 
118
118
  it { should be_an_instance_of FinModeling::CalculationSummary }
@@ -170,5 +170,13 @@ describe FinModeling::ReformulatedCashFlowStatement do
170
170
  end
171
171
  end
172
172
 
173
+ describe ".flows_are_balanced?" do
174
+ pending "Find examples..."
175
+ end
176
+
177
+ describe ".flows_are_plausible?" do
178
+ pending "Find examples..."
179
+ end
180
+
173
181
  end
174
182