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
|
@@ -1,45 +1,37 @@
|
|
|
1
|
-
#
|
|
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
|
-
|
|
8
|
-
|
|
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 "
|
|
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
|
-
|
|
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
|
-
|
|
29
|
-
|
|
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[
|
|
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
|
+
|
data/spec/mocks/calculation.rb
CHANGED
|
File without changes
|
|
File without changes
|
data/spec/mocks/sec_query.rb
CHANGED
|
File without changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
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
|
-
@
|
|
10
|
-
@
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
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)
|
|
19
|
-
its(:income_statement)
|
|
20
|
-
its(:cash_flow_statement)
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
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.
|
|
40
|
-
@schema_version.should be == 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,
|
|
26
|
-
|
|
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
|
|
33
|
-
|
|
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
|
|
39
|
-
|
|
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
|
|
45
|
-
|
|
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
|
|
51
|
-
|
|
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
|
|
57
|
-
its(:total) { should be_within(0.1).of(
|
|
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
|
|
63
|
-
its(:total) { should be_within(0.1).of(
|
|
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 "
|
|
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
|
|
69
|
-
its(:total) { should be_within(0.1).of(
|
|
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
|
|
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.
|
|
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
|
|