finmodeling 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/Gemfile +10 -0
- data/README.md +292 -0
- data/Rakefile +6 -0
- data/TODO.txt +36 -0
- data/examples/dump_report.rb +33 -0
- data/examples/lists/nasdaq-mid-to-mega-tech-symbols.txt +226 -0
- data/examples/show_report.rb +218 -0
- data/examples/show_reports.rb +77 -0
- data/finmodeling.gemspec +31 -0
- data/lib/finmodeling/annual_report_filing.rb +104 -0
- data/lib/finmodeling/array_with_stats.rb +22 -0
- data/lib/finmodeling/assets_calculation.rb +36 -0
- data/lib/finmodeling/assets_item.rb +14 -0
- data/lib/finmodeling/assets_item_vectors.rb +638 -0
- data/lib/finmodeling/balance_sheet_analyses.rb +33 -0
- data/lib/finmodeling/balance_sheet_calculation.rb +68 -0
- data/lib/finmodeling/calculation_summary.rb +148 -0
- data/lib/finmodeling/can_cache_classifications.rb +36 -0
- data/lib/finmodeling/can_cache_summaries.rb +16 -0
- data/lib/finmodeling/can_classify_rows.rb +54 -0
- data/lib/finmodeling/cash_change_calculation.rb +67 -0
- data/lib/finmodeling/cash_change_item.rb +14 -0
- data/lib/finmodeling/cash_change_item_vectors.rb +241 -0
- data/lib/finmodeling/cash_flow_statement_calculation.rb +85 -0
- data/lib/finmodeling/classifiers.rb +11 -0
- data/lib/finmodeling/company.rb +102 -0
- data/lib/finmodeling/company_filing.rb +64 -0
- data/lib/finmodeling/company_filing_calculation.rb +75 -0
- data/lib/finmodeling/company_filings.rb +100 -0
- data/lib/finmodeling/config.rb +37 -0
- data/lib/finmodeling/constant_forecasting_policy.rb +23 -0
- data/lib/finmodeling/factory.rb +27 -0
- data/lib/finmodeling/float_helpers.rb +17 -0
- data/lib/finmodeling/forecasts.rb +48 -0
- data/lib/finmodeling/generic_forecasting_policy.rb +19 -0
- data/lib/finmodeling/has_string_classifer.rb +96 -0
- data/lib/finmodeling/income_statement_analyses.rb +74 -0
- data/lib/finmodeling/income_statement_calculation.rb +71 -0
- data/lib/finmodeling/income_statement_item.rb +14 -0
- data/lib/finmodeling/income_statement_item_vectors.rb +654 -0
- data/lib/finmodeling/liabs_and_equity_calculation.rb +36 -0
- data/lib/finmodeling/liabs_and_equity_item.rb +14 -0
- data/lib/finmodeling/liabs_and_equity_item_vectors.rb +1936 -0
- data/lib/finmodeling/net_income_calculation.rb +41 -0
- data/lib/finmodeling/paths.rb +5 -0
- data/lib/finmodeling/period_array.rb +24 -0
- data/lib/finmodeling/quarterly_report_filing.rb +23 -0
- data/lib/finmodeling/rate.rb +20 -0
- data/lib/finmodeling/ratio.rb +20 -0
- data/lib/finmodeling/reformulated_balance_sheet.rb +176 -0
- data/lib/finmodeling/reformulated_cash_flow_statement.rb +140 -0
- data/lib/finmodeling/reformulated_income_statement.rb +436 -0
- data/lib/finmodeling/string_helpers.rb +26 -0
- data/lib/finmodeling/version.rb +3 -0
- data/lib/finmodeling.rb +70 -0
- data/spec/annual_report_filing_spec.rb +68 -0
- data/spec/assets_calculation_spec.rb +21 -0
- data/spec/assets_item_spec.rb +66 -0
- data/spec/balance_sheet_analyses_spec.rb +43 -0
- data/spec/balance_sheet_calculation_spec.rb +91 -0
- data/spec/calculation_summary_spec.rb +63 -0
- data/spec/can_classify_rows_spec.rb +86 -0
- data/spec/cash_change_calculation_spec.rb +56 -0
- data/spec/cash_change_item_spec.rb +66 -0
- data/spec/cash_flow_statement_calculation_spec.rb +108 -0
- data/spec/company_filing_calculation_spec.rb +74 -0
- data/spec/company_filing_spec.rb +30 -0
- data/spec/company_filings_spec.rb +55 -0
- data/spec/company_spec.rb +73 -0
- data/spec/constant_forecasting_policy_spec.rb +37 -0
- data/spec/factory_spec.rb +18 -0
- data/spec/forecasts_spec.rb +21 -0
- data/spec/generic_forecasting_policy_spec.rb +33 -0
- data/spec/income_statement_analyses_spec.rb +63 -0
- data/spec/income_statement_calculation_spec.rb +88 -0
- data/spec/income_statement_item_spec.rb +86 -0
- data/spec/liabs_and_equity_calculation_spec.rb +20 -0
- data/spec/liabs_and_equity_item_spec.rb +66 -0
- data/spec/mocks/calculation.rb +10 -0
- data/spec/mocks/income_statement_analyses.rb +93 -0
- data/spec/mocks/sec_query.rb +31 -0
- data/spec/net_income_calculation_spec.rb +23 -0
- data/spec/period_array.rb +52 -0
- data/spec/quarterly_report_filing_spec.rb +69 -0
- data/spec/rate_spec.rb +33 -0
- data/spec/ratio_spec.rb +33 -0
- data/spec/reformulated_balance_sheet_spec.rb +146 -0
- data/spec/reformulated_cash_flow_statement_spec.rb +174 -0
- data/spec/reformulated_income_statement_spec.rb +293 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/string_helpers_spec.rb +23 -0
- data/tools/create_balance_sheet_training_vectors.rb +65 -0
- data/tools/create_cash_change_training_vectors.rb +48 -0
- data/tools/create_credit_debit_training_vectors.rb +51 -0
- data/tools/create_income_statement_training_vectors.rb +48 -0
- metadata +289 -0
@@ -0,0 +1,218 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'finmodeling'
|
4
|
+
|
5
|
+
class Arguments
|
6
|
+
def self.show_usage_and_exit
|
7
|
+
puts "usage:"
|
8
|
+
puts "\t#{__FILE__} [options] <stock symbol> <10-k|10-q> <0, for most recent|-1 for prevous|-2, etc>"
|
9
|
+
puts "\t#{__FILE__} [options] <report URL> <10-k|10-q>"
|
10
|
+
puts
|
11
|
+
puts "\tOptions:"
|
12
|
+
puts "\t\t--no-cache: disables caching"
|
13
|
+
puts "\t\t--show-disclosures: prints out all the disclosure calculations in the filing"
|
14
|
+
exit
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.parse(raw_args)
|
18
|
+
parsed_args = { :stock_symbol => nil, :filing_url => nil,
|
19
|
+
:report_type => nil, :report_offset => nil,
|
20
|
+
:show_disclosures => false }
|
21
|
+
|
22
|
+
while raw_args.any? && raw_args.first =~ /^--/
|
23
|
+
case raw_args.first.downcase
|
24
|
+
when '--no-cache'
|
25
|
+
FinModeling::Config.disable_caching
|
26
|
+
puts "Caching is #{FinModeling::Config.caching_enabled? ? "enabled" : "disabled"}"
|
27
|
+
when '--show-disclosures'
|
28
|
+
parsed_args[:show_disclosures] = true
|
29
|
+
puts "Showing disclosures"
|
30
|
+
else
|
31
|
+
self.show_usage_and_exit
|
32
|
+
end
|
33
|
+
raw_args = raw_args[1..-1]
|
34
|
+
end
|
35
|
+
|
36
|
+
if raw_args[0] =~ /http/
|
37
|
+
return self.parse_just_a_url(raw_args, parsed_args)
|
38
|
+
else
|
39
|
+
return self.parse_symbol_etc(raw_args, parsed_args)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
def self.parse_just_a_url(raw_args, parsed)
|
46
|
+
self.show_usage_and_exit if raw_args.length != 2
|
47
|
+
|
48
|
+
parsed_args[:filing_url] = raw_args[0]
|
49
|
+
parsed_args[:report_type] = case raw_args[1].downcase
|
50
|
+
when "10-k"
|
51
|
+
:annual_report
|
52
|
+
when "10-q"
|
53
|
+
:quarterly_report
|
54
|
+
else
|
55
|
+
self.show_usage_and_exit
|
56
|
+
end
|
57
|
+
|
58
|
+
return parsed_args
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.parse_symbol_etc(raw_args, parsed_args)
|
62
|
+
self.show_usage_and_exit if raw_args.length != 3
|
63
|
+
|
64
|
+
parsed_args[:stock_symbol] = raw_args[0]
|
65
|
+
parsed_args[:report_type] = case raw_args[1].downcase
|
66
|
+
when "10-k"
|
67
|
+
:annual_report
|
68
|
+
when "10-q"
|
69
|
+
:quarterly_report
|
70
|
+
else
|
71
|
+
self.show_usage_and_exit
|
72
|
+
end
|
73
|
+
parsed_args[:report_offset] = raw_args[2].to_i
|
74
|
+
|
75
|
+
return parsed_args
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_company_filing_url(stock_symbol, report_type, report_offset)
|
80
|
+
company = FinModeling::Company.find(stock_symbol)
|
81
|
+
raise RuntimeError.new("couldn't find company") if company.nil?
|
82
|
+
puts "company name: #{company.name}"
|
83
|
+
|
84
|
+
filing_url = case report_type
|
85
|
+
when :annual_report
|
86
|
+
raise RuntimeError.new("company has no annual reports") if company.annual_reports.length == 0
|
87
|
+
company.annual_reports[-1+report_offset].link
|
88
|
+
when :quarterly_report
|
89
|
+
raise RuntimeError.new("company has no quarterly reports") if company.annual_reports.length == 0
|
90
|
+
company.quarterly_reports[-1+report_offset].link
|
91
|
+
end
|
92
|
+
|
93
|
+
return filing_url
|
94
|
+
end
|
95
|
+
|
96
|
+
def get_filing(filing_url, report_type)
|
97
|
+
puts "url: #{filing_url}\n"
|
98
|
+
return FinModeling::AnnualReportFiling.download( filing_url) if report_type == :annual_report
|
99
|
+
return FinModeling::QuarterlyReportFiling.download(filing_url) if report_type == :quarterly_report
|
100
|
+
end
|
101
|
+
|
102
|
+
def print_balance_sheet(filing, report_type)
|
103
|
+
period = filing.balance_sheet.periods.last
|
104
|
+
puts "Balance Sheet (#{period.to_pretty_s})"
|
105
|
+
|
106
|
+
summaries = []
|
107
|
+
summaries << filing.balance_sheet.assets_calculation.summary(:period => period)
|
108
|
+
summaries << filing.balance_sheet.liabs_and_equity_calculation.summary(:period => period)
|
109
|
+
|
110
|
+
print_summaries(summaries)
|
111
|
+
end
|
112
|
+
|
113
|
+
def print_reformulated_balance_sheet(filing, report_type)
|
114
|
+
period = filing.balance_sheet.periods.last
|
115
|
+
|
116
|
+
reformed_balance_sheet = filing.balance_sheet.reformulated(period)
|
117
|
+
|
118
|
+
summaries = []
|
119
|
+
summaries << reformed_balance_sheet.net_operating_assets
|
120
|
+
summaries << reformed_balance_sheet.net_financial_assets
|
121
|
+
summaries << reformed_balance_sheet.common_shareholders_equity
|
122
|
+
|
123
|
+
print_summaries(summaries)
|
124
|
+
end
|
125
|
+
|
126
|
+
def print_income_statement(filing, report_type)
|
127
|
+
period = filing.income_statement.net_income_calculation.periods.yearly.last if report_type == :annual_report
|
128
|
+
period = filing.income_statement.net_income_calculation.periods.quarterly.last if report_type == :quarterly_report
|
129
|
+
puts "Income Statement (#{period.to_pretty_s})"
|
130
|
+
|
131
|
+
summaries = []
|
132
|
+
summaries << filing.income_statement.net_income_calculation.summary(:period => period)
|
133
|
+
|
134
|
+
print_summaries(summaries)
|
135
|
+
end
|
136
|
+
|
137
|
+
def print_reformulated_income_statement(filing, report_type)
|
138
|
+
period = filing.income_statement.net_income_calculation.periods.yearly.last if report_type == :annual_report
|
139
|
+
period = filing.income_statement.net_income_calculation.periods.quarterly.last if report_type == :quarterly_report
|
140
|
+
|
141
|
+
reformed_inc_stmt = filing.income_statement.reformulated(period)
|
142
|
+
|
143
|
+
summaries = []
|
144
|
+
summaries << reformed_inc_stmt.gross_revenue
|
145
|
+
summaries << reformed_inc_stmt.income_from_sales_before_tax
|
146
|
+
summaries << reformed_inc_stmt.income_from_sales_after_tax
|
147
|
+
summaries << reformed_inc_stmt.operating_income_after_tax
|
148
|
+
summaries << reformed_inc_stmt.net_financing_income
|
149
|
+
summaries << reformed_inc_stmt.comprehensive_income
|
150
|
+
|
151
|
+
print_summaries(summaries)
|
152
|
+
end
|
153
|
+
|
154
|
+
def print_cash_flow_statement(filing, report_type)
|
155
|
+
period = filing.cash_flow_statement.periods.yearly.last if report_type == :annual_report
|
156
|
+
period = filing.cash_flow_statement.periods.quarterly.last if report_type == :quarterly_report
|
157
|
+
puts "Cash Flow Statement (#{period.to_pretty_s})"
|
158
|
+
|
159
|
+
summaries = []
|
160
|
+
summaries << filing.cash_flow_statement.cash_change_calculation.summary(:period => period)
|
161
|
+
|
162
|
+
print_summaries(summaries)
|
163
|
+
end
|
164
|
+
|
165
|
+
def print_reformulated_cash_flow_statement(filing, report_type)
|
166
|
+
period = filing.cash_flow_statement.periods.yearly.last if report_type == :annual_report
|
167
|
+
period = filing.cash_flow_statement.periods.quarterly.last if report_type == :quarterly_report
|
168
|
+
|
169
|
+
reformed_cash_flow_stmt = filing.cash_flow_statement.reformulated(period)
|
170
|
+
|
171
|
+
summaries = []
|
172
|
+
summaries << reformed_cash_flow_stmt.cash_from_operations
|
173
|
+
summaries << reformed_cash_flow_stmt.cash_investments_in_operations
|
174
|
+
summaries << reformed_cash_flow_stmt.payments_to_debtholders
|
175
|
+
summaries << reformed_cash_flow_stmt.payments_to_stockholders
|
176
|
+
summaries << reformed_cash_flow_stmt.free_cash_flow
|
177
|
+
summaries << reformed_cash_flow_stmt.financing_flows
|
178
|
+
|
179
|
+
print_summaries(summaries)
|
180
|
+
end
|
181
|
+
|
182
|
+
def print_disclosures(filing, report_type)
|
183
|
+
puts "Disclosures"
|
184
|
+
|
185
|
+
summaries = []
|
186
|
+
filing.disclosures.each do |disclosure|
|
187
|
+
summaries << disclosure.summary(:period => disclosure.periods.last)
|
188
|
+
end
|
189
|
+
|
190
|
+
print_summaries(summaries)
|
191
|
+
end
|
192
|
+
|
193
|
+
def print_summaries(summaries)
|
194
|
+
summaries.each do |summary|
|
195
|
+
summary.key_width = 60
|
196
|
+
summary.val_width = 18
|
197
|
+
summary.print
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
|
203
|
+
args = Arguments.parse(ARGV)
|
204
|
+
if args[:filing_url].nil?
|
205
|
+
args[:filing_url] = get_company_filing_url(args[:stock_symbol], args[:report_type], args[:report_offset])
|
206
|
+
end
|
207
|
+
|
208
|
+
filing = get_filing( args[:filing_url], args[:report_type])
|
209
|
+
|
210
|
+
print_balance_sheet( filing, args[:report_type])
|
211
|
+
print_reformulated_balance_sheet( filing, args[:report_type])
|
212
|
+
print_income_statement( filing, args[:report_type])
|
213
|
+
print_reformulated_income_statement( filing, args[:report_type])
|
214
|
+
print_cash_flow_statement( filing, args[:report_type])
|
215
|
+
print_reformulated_cash_flow_statement(filing, args[:report_type])
|
216
|
+
print_disclosures( filing, args[:report_type]) if args[:show_disclosures]
|
217
|
+
|
218
|
+
raise RuntimeError.new("filing is not valid") if !filing.is_valid?
|
@@ -0,0 +1,77 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'finmodeling'
|
4
|
+
|
5
|
+
class Arguments
|
6
|
+
def self.show_usage_and_exit
|
7
|
+
puts "usage:"
|
8
|
+
puts "\t#{__FILE__} [options] <stock symbol> <start date, e.g. '2010-01-01'>"
|
9
|
+
puts
|
10
|
+
puts "\tOptions:"
|
11
|
+
puts "\t\t--num-forecasts <num>: how many periods to forecast"
|
12
|
+
puts "\t\t--no-cache: disable caching"
|
13
|
+
puts "\t\t--balance-detail: show details about the balance sheet calculation"
|
14
|
+
puts "\t\t--income-detail: show details about the net income calculation"
|
15
|
+
exit
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.parse(args)
|
19
|
+
a = { :stock_symbol => nil, :start_date => nil, :num_forecasts => nil }
|
20
|
+
|
21
|
+
while args.any? && args.first =~ /^--/
|
22
|
+
case args.first.downcase
|
23
|
+
when '--no-cache'
|
24
|
+
FinModeling::Config.disable_caching
|
25
|
+
puts "Caching is #{FinModeling::Config.caching_enabled? ? "enabled" : "disabled"}"
|
26
|
+
when '--balance-detail'
|
27
|
+
FinModeling::Config.enable_balance_detail
|
28
|
+
puts "Balance sheet detail is #{FinModeling::Config.balance_detail_enabled? ? "enabled" : "disabled"}"
|
29
|
+
when '--income-detail'
|
30
|
+
FinModeling::Config.enable_income_detail
|
31
|
+
puts "Net income detail is #{FinModeling::Config.income_detail_enabled? ? "enabled" : "disabled"}"
|
32
|
+
when '--num-forecasts'
|
33
|
+
a[:num_forecasts] = args[1].to_i
|
34
|
+
self.show_usage_and_exit unless a[:num_forecasts] >= 1
|
35
|
+
puts "Forecasting #{a[:num_forecasts]} periods"
|
36
|
+
args = args[1..-1]
|
37
|
+
else
|
38
|
+
self.show_usage_and_exit
|
39
|
+
end
|
40
|
+
args = args[1..-1]
|
41
|
+
end
|
42
|
+
|
43
|
+
self.show_usage_and_exit if args.length != 2
|
44
|
+
a[:stock_symbol] = args[0]
|
45
|
+
a[:start_date] = Time.parse(args[1])
|
46
|
+
|
47
|
+
return a
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
args = Arguments.parse(ARGV)
|
52
|
+
|
53
|
+
company = FinModeling::Company.find(args[:stock_symbol])
|
54
|
+
raise RuntimeError.new("couldn't find company") if !company
|
55
|
+
puts "company name: #{company.name}"
|
56
|
+
|
57
|
+
filings = FinModeling::CompanyFilings.new(company.filings_since_date(args[:start_date]))
|
58
|
+
if filings.empty?
|
59
|
+
puts "No filings..."
|
60
|
+
exit
|
61
|
+
end
|
62
|
+
|
63
|
+
forecasts = filings.forecasts(filings.choose_forecasting_policy, num_quarters=args[:num_forecasts]) if args[:num_forecasts]
|
64
|
+
|
65
|
+
bs_analyses = filings.balance_sheet_analyses
|
66
|
+
bs_analyses += forecasts.balance_sheet_analyses(filings) if forecasts
|
67
|
+
bs_analyses.totals_row_enabled = false
|
68
|
+
bs_analyses.print
|
69
|
+
filings.balance_sheet_analyses.print_extras if filings.balance_sheet_analyses.respond_to?(:print_extras)
|
70
|
+
|
71
|
+
is_analyses = filings.income_statement_analyses
|
72
|
+
is_analyses += forecasts.income_statement_analyses(filings) if forecasts
|
73
|
+
is_analyses.totals_row_enabled = false
|
74
|
+
is_analyses.print
|
75
|
+
filings.income_statement_analyses.print_extras if filings.income_statement_analyses.respond_to?(:print_extras)
|
76
|
+
|
77
|
+
filings.cash_flow_statement_analyses.print
|
data/finmodeling.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/finmodeling/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Jim Lindstrom"]
|
6
|
+
gem.email = ["jim.lindstrom@gmail.com"]
|
7
|
+
gem.description = %q{A gem for manipulating XBRL financial filings}
|
8
|
+
gem.summary = %q{A gem for manipulating XBRL financial filings}
|
9
|
+
gem.homepage = "https://github.com/jimlindstrom/FinModeling"
|
10
|
+
|
11
|
+
gem.add_dependency("fileutils")
|
12
|
+
gem.add_dependency("sec_query")
|
13
|
+
gem.add_dependency("edgar")
|
14
|
+
|
15
|
+
gem.add_dependency("xbrlware-ruby19", "1.1.2.19.2")
|
16
|
+
gem.add_dependency("xbrlware-extras", "1.1.2.19.2")
|
17
|
+
|
18
|
+
gem.add_dependency("sec_query")
|
19
|
+
gem.add_dependency("naive_bayes")
|
20
|
+
gem.add_dependency("statsample")
|
21
|
+
|
22
|
+
gem.add_development_dependency("rspec", "2.5")
|
23
|
+
gem.add_development_dependency("rake")
|
24
|
+
|
25
|
+
gem.files = `git ls-files`.split($\)
|
26
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
27
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
28
|
+
gem.name = "finmodeling"
|
29
|
+
gem.require_paths = ["lib"]
|
30
|
+
gem.version = FinModeling::VERSION
|
31
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module FinModeling
|
2
|
+
|
3
|
+
class AnnualReportFiling < CompanyFiling
|
4
|
+
|
5
|
+
CONSTRUCTOR_PATH = File.join(FinModeling::BASE_PATH, "constructors/")
|
6
|
+
SCHEMA_VERSION_ITEM = "@schema_version"
|
7
|
+
CURRENT_SCHEMA_VERSION = 1.1
|
8
|
+
# History:
|
9
|
+
# 1.0: initial version
|
10
|
+
# 1.1: added CFS to quarterly filings
|
11
|
+
# added disclosures
|
12
|
+
# renamed fake(.*)report to cached(.*)report
|
13
|
+
|
14
|
+
def self.download(url)
|
15
|
+
uid = url.split("/")[-2..-1].join('-').gsub(/\.[A-zA-z]*$/, '')
|
16
|
+
constructor_file = CONSTRUCTOR_PATH + uid + '.rb'
|
17
|
+
if File.exists?(constructor_file) && FinModeling::Config.caching_enabled?
|
18
|
+
begin
|
19
|
+
eval(File.read(constructor_file))
|
20
|
+
#puts "info: annual report, cache hit. schema version: #{@schema_version}"
|
21
|
+
return @filing if @schema_version == CURRENT_SCHEMA_VERSION
|
22
|
+
rescue
|
23
|
+
#puts "warn: annual report, cache hit. error eval'ing though."
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
filing = super(url)
|
28
|
+
|
29
|
+
FileUtils.mkdir_p(CONSTRUCTOR_PATH) if !File.exists?(CONSTRUCTOR_PATH)
|
30
|
+
file = File.open(constructor_file, "w")
|
31
|
+
filing.write_constructor(file, "@filing")
|
32
|
+
file.close
|
33
|
+
|
34
|
+
return filing
|
35
|
+
end
|
36
|
+
|
37
|
+
def balance_sheet
|
38
|
+
if @balance_sheet.nil?
|
39
|
+
calculations=@taxonomy.callb.calculation
|
40
|
+
bal_sheet = calculations.find{ |x| (x.clean_downcased_title =~ /statement.*financial.*position/) or
|
41
|
+
(x.clean_downcased_title =~ /statement.*financial.*condition/) or
|
42
|
+
(x.clean_downcased_title =~ /balance.*sheet/) }
|
43
|
+
if bal_sheet.nil?
|
44
|
+
raise RuntimeError.new("Couldn't find balance sheet in: " + calculations.map{ |x| "\"#{x.clean_downcased_title}\"" }.join("; "))
|
45
|
+
end
|
46
|
+
|
47
|
+
@balance_sheet = BalanceSheetCalculation.new(bal_sheet)
|
48
|
+
end
|
49
|
+
return @balance_sheet
|
50
|
+
end
|
51
|
+
|
52
|
+
def income_statement
|
53
|
+
if @income_stmt.nil?
|
54
|
+
calculations=@taxonomy.callb.calculation
|
55
|
+
inc_stmt = calculations.find{ |x| (x.clean_downcased_title =~ /statement.*operations/) or
|
56
|
+
(x.clean_downcased_title =~ /statement[s]*.*of.*earnings/) or
|
57
|
+
(x.clean_downcased_title =~ /statement[s]*.*of.*income/) or
|
58
|
+
(x.clean_downcased_title =~ /statement[s]*.*of.*net.*income/) }
|
59
|
+
if inc_stmt.nil?
|
60
|
+
raise RuntimeError.new("Couldn't find income statement in: " + calculations.map{ |x| "\"#{x.clean_downcased_title}\"" }.join("; "))
|
61
|
+
end
|
62
|
+
|
63
|
+
@income_stmt = IncomeStatementCalculation.new(inc_stmt)
|
64
|
+
end
|
65
|
+
return @income_stmt
|
66
|
+
end
|
67
|
+
|
68
|
+
def cash_flow_statement
|
69
|
+
if @cash_flow_stmt.nil?
|
70
|
+
calculations=@taxonomy.callb.calculation
|
71
|
+
cash_flow_stmt = calculations.find{ |x| (x.clean_downcased_title =~ /statement.*cash.*flows/) or
|
72
|
+
(x.clean_downcased_title =~ /^cash flows$/) }
|
73
|
+
if cash_flow_stmt.nil?
|
74
|
+
raise RuntimeError.new("Couldn't find cash flow statement in: " + calculations.map{ |x| "\"#{x.clean_downcased_title}\"" }.join("; "))
|
75
|
+
end
|
76
|
+
|
77
|
+
@cash_flow_stmt = CashFlowStatementCalculation.new(cash_flow_stmt)
|
78
|
+
end
|
79
|
+
return @cash_flow_stmt
|
80
|
+
end
|
81
|
+
|
82
|
+
def is_valid?
|
83
|
+
return (income_statement.is_valid? and balance_sheet.is_valid? and cash_flow_statement.is_valid?)
|
84
|
+
end
|
85
|
+
|
86
|
+
def write_constructor(file, item_name)
|
87
|
+
balance_sheet.write_constructor( file, bs_name = item_name + "_bs")
|
88
|
+
income_statement.write_constructor( file, is_name = item_name + "_is")
|
89
|
+
cash_flow_statement.write_constructor(file, cfs_name = item_name + "_cfs")
|
90
|
+
|
91
|
+
names_of_discs = []
|
92
|
+
disclosures.each_with_index do |disclosure, idx|
|
93
|
+
name_of_disc = item_name + "_disc#{idx}"
|
94
|
+
disclosure.write_constructor(file, name_of_disc)
|
95
|
+
names_of_discs << name_of_disc
|
96
|
+
end
|
97
|
+
names_of_discs_str = "[" + names_of_discs.join(',') + "]"
|
98
|
+
|
99
|
+
file.puts "#{SCHEMA_VERSION_ITEM} = #{CURRENT_SCHEMA_VERSION}"
|
100
|
+
|
101
|
+
file.puts "#{item_name} = FinModeling::CachedAnnualFiling.new(#{bs_name}, #{is_name}, #{cfs_name}, #{names_of_discs_str})"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module FinModeling
|
2
|
+
|
3
|
+
class ArrayWithStats < Array
|
4
|
+
def mean
|
5
|
+
return nil if empty?
|
6
|
+
self.inject(:+) / self.length
|
7
|
+
end
|
8
|
+
|
9
|
+
def variance
|
10
|
+
x_sqrd = self.map{ |x| x*x }
|
11
|
+
x_sqrd_mean = (ArrayWithStats.new(x_sqrd).mean)
|
12
|
+
x_sqrd_mean - (mean**2)
|
13
|
+
end
|
14
|
+
|
15
|
+
def linear_regression
|
16
|
+
x = Array(0..(self.length-1)).to_scale
|
17
|
+
y = self.to_scale
|
18
|
+
Statsample::Regression.simple(x,y)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module FinModeling
|
2
|
+
|
3
|
+
class AssetsCalculation < CompanyFilingCalculation
|
4
|
+
include CanCacheClassifications
|
5
|
+
include CanCacheSummaries
|
6
|
+
include CanClassifyRows
|
7
|
+
|
8
|
+
BASE_FILENAME = File.join(FinModeling::BASE_PATH, "summaries/ai_")
|
9
|
+
|
10
|
+
ALL_STATES = [ :oa, :fa ]
|
11
|
+
NEXT_STATES = { nil => [ :oa, :fa ],
|
12
|
+
:oa => [ :oa, :fa ],
|
13
|
+
:fa => [ :oa, :fa ] }
|
14
|
+
|
15
|
+
def summary(args)
|
16
|
+
summary_cache_key = args[:period].to_pretty_s
|
17
|
+
thesummary = lookup_cached_summary(summary_cache_key)
|
18
|
+
return thesummary if !thesummary.nil?
|
19
|
+
|
20
|
+
mapping = Xbrlware::ValueMapping.new
|
21
|
+
mapping.policy[:credit] = :flip
|
22
|
+
|
23
|
+
thesummary = super(:period => args[:period], :mapping => mapping)
|
24
|
+
if !lookup_cached_classifications(BASE_FILENAME, thesummary.rows)
|
25
|
+
lookahead = [4, thesummary.rows.length-1].min
|
26
|
+
classify_rows(ALL_STATES, NEXT_STATES, thesummary.rows, FinModeling::AssetsItem, lookahead)
|
27
|
+
save_cached_classifications(BASE_FILENAME, thesummary.rows)
|
28
|
+
end
|
29
|
+
|
30
|
+
save_cached_summary(summary_cache_key, thesummary)
|
31
|
+
|
32
|
+
return thesummary
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module FinModeling
|
2
|
+
class AssetsItem < String
|
3
|
+
include HasStringClassifier
|
4
|
+
|
5
|
+
BASE_FILENAME = File.join(FinModeling::BASE_PATH, "classifiers/ai_")
|
6
|
+
TYPES = [ :oa, :fa ]
|
7
|
+
|
8
|
+
has_string_classifier(TYPES, AssetsItem)
|
9
|
+
|
10
|
+
def self.load_vectors_and_train
|
11
|
+
self._load_vectors_and_train(BASE_FILENAME, FinModeling::AssetsItem::TRAINING_VECTORS)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|