fundamentalista 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 432e0a27a0bed71a2f55d3574bf27c0ac4a781d08217de34f2a9c9dfc3a4ea87
4
- data.tar.gz: d8c0b9a22759ec8142e016c072b2d59a153b014f3811284c00ca0e86b34771a1
3
+ metadata.gz: a751de0b23e903aae3241633a34846881b375b79d30cf43f123a79e85e9ef756
4
+ data.tar.gz: b5518a61ec6a452ea5cb13ff6c996301e2942e712c79dbac0b5d43b1dc143b2c
5
5
  SHA512:
6
- metadata.gz: 8be12b7c9de524de12ec34b09d9216408d4c03211a2c63ff145132619ae5652ab74ce85009cf25f2ac9cbd91571328f6d7848250ae1f7265f237165a87276c2d
7
- data.tar.gz: bb4e2193d2f9ba6f76491f0ca66fc6bc5d11a253fddc1ccc1f8a61e46dee5956a8292a032c16a489b434086ea2a934d7f6c9e7fd313fb811c49812e0cc6c1412
6
+ metadata.gz: 5358331cec9f638346d55606350feaed1bf221567ae4f74495d045afe9c51d9297d2d45d09bc7816816cc9741046bd712f8e6f47b0338faf2a349155d704ed4b
7
+ data.tar.gz: ef443415389f98b381bf6d756c65cfc90358dec72c68a32de6ec8034146d2aba6a4ae87d05225394f6eeec42103e093e378b97229523b1e2689ac2628ce9cea5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.1
4
+
5
+ - EBIT derived from income before tax and interest when operating income is not reported, used by interest coverage, EV/EBIT, the magic formula and the Altman Z-score.
6
+ - Minority interest on the balance sheet, so derived total liabilities match the reported ones.
7
+ - More concepts checked against Financial Modeling Prep figures: current maturities of long term debt, finance lease interest, other short term investments.
8
+
3
9
  ## 0.1.0
4
10
 
5
11
  - Financial statements as value objects with BigDecimal figures and derived line items.
data/README.md CHANGED
@@ -90,8 +90,10 @@ EDGAR reports quarterly cash flows only year to date, and the fourth quarter onl
90
90
 
91
91
  | Statement | Reported items | Derived when missing |
92
92
  | --- | --- | --- |
93
- | `IncomeStatement` | revenue, cost of revenue, gross profit, SG&A, operating income, interest expense, income before tax, income tax, net income, depreciation and amortization, EBITDA, diluted EPS, diluted shares | gross profit, EBITDA, diluted EPS, tax rate |
94
- | `BalanceSheet` | cash, short term investments, receivables, inventory, current assets, PP&E, total assets, payables, current liabilities, total liabilities, short and long term debt, total debt, equity, retained earnings, shares outstanding | total liabilities, total debt, liquid assets, net debt, working capital, net working capital |
93
+ | `IncomeStatement` | revenue, cost of revenue, gross profit, SG&A, operating income, EBIT, interest expense, income before tax, income tax, net income, depreciation and amortization, EBITDA, diluted EPS, diluted shares | gross profit, EBIT, EBITDA, diluted EPS, tax rate |
94
+ | `BalanceSheet` | cash, short term investments, receivables, inventory, current assets, PP&E, total assets, payables, current liabilities, total liabilities, short and long term debt, total debt, equity, minority interest, retained earnings, shares outstanding | total liabilities, total debt, liquid assets, net debt, working capital, net working capital |
95
+
96
+ EBIT is operating income when the company reports one, and income before tax plus interest expense otherwise, which is what pharmaceutical and oil companies leave you; interest coverage, EV/EBIT, Greenblatt's yield and return on capital and the Altman Z-score all use it. Figures follow the line as reported: receivables are trade receivables, PP&E excludes lease right-of-use assets, cost of revenue is the company's own line.
95
97
  | `CashFlowStatement` | operating cash flow, capital expenditure, free cash flow, dividends paid, share repurchases | free cash flow, shareholder returns |
96
98
 
97
99
  Outflows are positive amounts: `capital_expenditure` is what was spent.
@@ -3,15 +3,18 @@
3
3
  module Fundamentalista
4
4
  # The balance sheet at the end of a period. +shares_outstanding+ is a
5
5
  # share count, +ppe+ is property, plant and equipment net of
6
- # depreciation; everything else is in the reporting currency.
6
+ # depreciation, +equity+ belongs to the parent's shareholders and
7
+ # +minority_interest+ to others; everything else is in the reporting
8
+ # currency.
7
9
  class BalanceSheet < Statement
8
10
  field :cash, :short_term_investments, :receivables, :inventory, :current_assets, :ppe, :total_assets,
9
11
  :payables, :current_liabilities, :total_liabilities, :short_term_debt, :long_term_debt, :total_debt,
10
- :equity, :retained_earnings, :shares_outstanding
12
+ :equity, :minority_interest, :retained_earnings, :shares_outstanding
11
13
 
12
- # Total liabilities, derived from total assets and equity when not reported.
14
+ # Total liabilities, derived from total assets, equity and minority
15
+ # interest when not reported.
13
16
  def total_liabilities
14
- @total_liabilities || Decimal.subtract(total_assets, equity)
17
+ @total_liabilities || Decimal.subtract(total_assets, Decimal.sum(equity, minority_interest || BigDecimal('0')))
15
18
  end
16
19
 
17
20
  # Total debt, derived from short and long term debt when not reported.
@@ -5,7 +5,7 @@ module Fundamentalista
5
5
  # currency; +eps_diluted+ is per share, +diluted_shares+ a share count
6
6
  # and +sga+ the selling, general and administrative expense.
7
7
  class IncomeStatement < Statement
8
- field :revenue, :cost_of_revenue, :gross_profit, :sga, :operating_income, :interest_expense,
8
+ field :revenue, :cost_of_revenue, :gross_profit, :sga, :operating_income, :ebit, :interest_expense,
9
9
  :income_before_tax, :income_tax, :net_income, :depreciation_amortization, :ebitda,
10
10
  :eps_diluted, :diluted_shares
11
11
 
@@ -14,9 +14,16 @@ module Fundamentalista
14
14
  @gross_profit || Decimal.subtract(revenue, cost_of_revenue)
15
15
  end
16
16
 
17
- # EBITDA, derived from operating income and depreciation when not reported.
17
+ # Earnings before interest and taxes: operating income when reported,
18
+ # else income before tax plus interest expense, which is what
19
+ # companies without an operating income line leave you.
20
+ def ebit
21
+ @ebit || operating_income || Decimal.sum(income_before_tax, interest_expense)
22
+ end
23
+
24
+ # EBITDA, derived from EBIT and depreciation when not reported.
18
25
  def ebitda
19
- @ebitda || Decimal.sum(operating_income, depreciation_amortization)
26
+ @ebitda || Decimal.sum(ebit, depreciation_amortization)
20
27
  end
21
28
 
22
29
  # Diluted earnings per share, derived from net income and diluted shares
@@ -21,9 +21,10 @@ module Fundamentalista
21
21
  gross_profit: %w[GrossProfit],
22
22
  sga: ['SellingGeneralAndAdministrativeExpense', %w[GeneralAndAdministrativeExpense SellingAndMarketingExpense]],
23
23
  operating_income: %w[OperatingIncomeLoss ProfitLossFromOperatingActivities],
24
- interest_expense: %w[InterestExpense InterestExpenseNonoperating InterestExpenseDebt FinanceCosts
25
- InterestExpenseOperating InterestAndDebtExpense InterestExpenseLongTermDebt
26
- InterestExpenseBorrowings InterestPaidNet],
24
+ interest_expense: ['InterestExpense', 'InterestExpenseNonoperating',
25
+ %w[InterestExpenseDebt FinanceLeaseInterestExpense],
26
+ 'FinanceCosts', 'InterestExpenseOperating', 'InterestAndDebtExpense', 'InterestExpenseLongTermDebt',
27
+ 'InterestExpenseBorrowings', 'InterestPaidNet'],
27
28
  income_before_tax: %w[
28
29
  IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest
29
30
  IncomeLossFromContinuingOperationsBeforeIncomeTaxesMinorityInterestAndIncomeLossFromEquityMethodInvestments
@@ -44,8 +45,8 @@ module Fundamentalista
44
45
  cash: %w[CashAndCashEquivalentsAtCarryingValue CashCashEquivalentsRestrictedCashAndRestrictedCashEquivalents
45
46
  CashAndCashEquivalents],
46
47
  short_term_investments: %w[ShortTermInvestments MarketableSecuritiesCurrent
47
- AvailableForSaleSecuritiesDebtSecuritiesCurrent OtherCurrentFinancialAssets
48
- CurrentFinancialAssetsAtAmortisedCost],
48
+ AvailableForSaleSecuritiesDebtSecuritiesCurrent OtherShortTermInvestments
49
+ OtherCurrentFinancialAssets CurrentFinancialAssetsAtAmortisedCost],
49
50
  receivables: %w[AccountsReceivableNetCurrent ReceivablesNetCurrent CurrentTradeReceivables
50
51
  TradeAndOtherCurrentReceivables AccountsNotesAndLoansReceivableNetCurrent AccountsReceivableNet],
51
52
  inventory: %w[InventoryNet Inventories],
@@ -60,14 +61,15 @@ module Fundamentalista
60
61
  current_liabilities: %w[LiabilitiesCurrent CurrentLiabilities],
61
62
  total_liabilities: %w[Liabilities],
62
63
  short_term_debt: ['DebtCurrent',
63
- %w[LongTermDebtCurrent CommercialPaper ShortTermBorrowings OtherShortTermBorrowings
64
- ConvertibleDebtCurrent NotesPayableCurrent],
64
+ %w[LongTermDebtCurrent LongTermDebtAndCapitalLeaseObligationsCurrent CommercialPaper
65
+ ShortTermBorrowings OtherShortTermBorrowings ConvertibleDebtCurrent NotesPayableCurrent],
65
66
  'ShorttermBorrowings', 'CurrentBorrowings'],
66
67
  long_term_debt: %w[LongTermDebtNoncurrent LongTermDebtAndCapitalLeaseObligations LongTermDebt LongTermNotesPayable
67
68
  LongTermNotesAndLoans LongtermBorrowings NoncurrentBorrowings
68
69
  LongTermDebtAndCapitalLeaseObligationsIncludingCurrentMaturities],
69
70
  equity: %w[StockholdersEquity StockholdersEquityIncludingPortionAttributableToNoncontrollingInterest
70
71
  EquityAttributableToOwnersOfParent Equity],
72
+ minority_interest: %w[MinorityInterest NoncontrollingInterests],
71
73
  retained_earnings: %w[RetainedEarningsAccumulatedDeficit RetainedEarnings],
72
74
  shares_outstanding: %w[CommonStockSharesOutstanding NumberOfSharesOutstanding NumberOfSharesIssued
73
75
  NumberOfSharesIssuedAndFullyPaid]
@@ -60,7 +60,7 @@ module Fundamentalista
60
60
  IncomeStatement.new(
61
61
  revenue: row['revenue'], cost_of_revenue: row['costOfRevenue'], gross_profit: row['grossProfit'],
62
62
  sga: row['sellingGeneralAndAdministrativeExpenses'],
63
- operating_income: row['operatingIncome'], interest_expense: row['interestExpense'],
63
+ operating_income: row['operatingIncome'], ebit: row['ebit'], interest_expense: row['interestExpense'],
64
64
  income_before_tax: row['incomeBeforeTax'], income_tax: row['incomeTaxExpense'],
65
65
  net_income: row['netIncome'], depreciation_amortization: row['depreciationAndAmortization'],
66
66
  ebitda: row['ebitda'], eps_diluted: row['epsDiluted'], diluted_shares: row['weightedAverageShsOutDil']
@@ -75,7 +75,7 @@ module Fundamentalista
75
75
  payables: row['accountPayables'],
76
76
  current_liabilities: row['totalCurrentLiabilities'], total_liabilities: row['totalLiabilities'],
77
77
  short_term_debt: row['shortTermDebt'], long_term_debt: row['longTermDebt'],
78
- total_debt: row['totalDebt'], equity: row['totalStockholdersEquity'],
78
+ total_debt: row['totalDebt'], equity: row['totalStockholdersEquity'], minority_interest: row['minorityInterest'],
79
79
  retained_earnings: row['retainedEarnings']
80
80
  )
81
81
  end
@@ -65,10 +65,10 @@ module Fundamentalista
65
65
  Decimal.ratio(nopat, Decimal.sum(average(:total_debt), average(:equity)))
66
66
  end
67
67
 
68
- # Greenblatt's return on capital: operating income over net working
69
- # capital plus net fixed assets.
68
+ # Greenblatt's return on capital: EBIT over net working capital plus net
69
+ # fixed assets.
70
70
  def return_on_capital
71
- Decimal.ratio(income.operating_income, Decimal.sum(average(:net_working_capital), average(:ppe)))
71
+ Decimal.ratio(income.ebit, Decimal.sum(average(:net_working_capital), average(:ppe)))
72
72
  end
73
73
 
74
74
  def current_ratio
@@ -96,9 +96,9 @@ module Fundamentalista
96
96
  Decimal.ratio(balance.net_debt, income.ebitda)
97
97
  end
98
98
 
99
- # Operating income over interest expense.
99
+ # EBIT over interest expense.
100
100
  def interest_coverage
101
- Decimal.ratio(income.operating_income, income.interest_expense)
101
+ Decimal.ratio(income.ebit, income.interest_expense)
102
102
  end
103
103
 
104
104
  # Average total assets over average equity, the leverage leg of DuPont.
@@ -59,7 +59,7 @@ module Fundamentalista
59
59
  [
60
60
  Decimal.ratio(balance.working_capital, assets),
61
61
  Decimal.ratio(balance.retained_earnings, assets),
62
- Decimal.ratio(period.income.operating_income, assets),
62
+ Decimal.ratio(period.income.ebit, assets),
63
63
  Decimal.ratio(market_cap, balance.total_liabilities),
64
64
  Decimal.ratio(period.income.revenue, assets)
65
65
  ]
@@ -69,9 +69,9 @@ module Fundamentalista
69
69
  Decimal.ratio(enterprise_value, income.ebitda)
70
70
  end
71
71
 
72
- # Enterprise value over operating income.
72
+ # Enterprise value over EBIT.
73
73
  def ev_to_ebit
74
- Decimal.ratio(enterprise_value, income.operating_income)
74
+ Decimal.ratio(enterprise_value, income.ebit)
75
75
  end
76
76
 
77
77
  def ev_to_sales
@@ -91,10 +91,10 @@ module Fundamentalista
91
91
  Decimal.ratio(income.eps_diluted, price)
92
92
  end
93
93
 
94
- # Greenblatt's earnings yield: operating income over enterprise value.
95
- # Rank it with Ratios#return_on_capital for the magic formula.
94
+ # Greenblatt's earnings yield: EBIT over enterprise value. Rank it with
95
+ # Ratios#return_on_capital for the magic formula.
96
96
  def ebit_yield
97
- Decimal.ratio(income.operating_income, enterprise_value)
97
+ Decimal.ratio(income.ebit, enterprise_value)
98
98
  end
99
99
 
100
100
  def fcf_yield
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Fundamentalista
4
4
  # The version of the fundamentalista gem, as a string.
5
- VERSION = '0.1.0'
5
+ VERSION = '0.1.1'
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fundamentalista
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bruno Costanzo