Module: Finrb::Ratios

Defined in:
lib/finrb/ratios.rb,
sig/finrb.rbs

Overview

Financial-statement, leverage, and per-share ratios.

Class Method Summary collapse

Class Method Details

.cash_ratio(cash:, ms:, cl:) ⇒ decimal

cash ratio -- Liquidity ratios measure the firm's ability to satisfy its short-term obligations as they come due.

Examples:

Finrb::Ratios.cash_ratio(cash=3000,ms=2000,cl=2000)

Parameters:

  • cash

    cash

  • ms

    marketable securities

  • cl

    current liabilities

  • cash: (number)
  • ms: (number)
  • cl: (number)

Returns:

  • (decimal)


28
29
30
31
32
33
34
# File 'lib/finrb/ratios.rb', line 28

def self.cash_ratio(cash:, ms:, cl:)
  cash = Validation.decimal(cash, name: 'cash')
  ms = Validation.decimal(ms, name: 'marketable securities')
  cl = Validation.non_zero_decimal(cl, name: 'current liabilities', error: DomainError)

  ((cash + ms) / cl)
end

.current_ratio(ca:, cl:) ⇒ decimal

current ratio -- Liquidity ratios measure the firm's ability to satisfy its short-term obligations as they come due.

Examples:

Finrb::Ratios.current_ratio(ca=8000,cl=2000)

Parameters:

  • ca

    current assets

  • cl

    current liabilities

  • ca: (number)
  • cl: (number)

Returns:

  • (decimal)


42
43
44
45
46
47
# File 'lib/finrb/ratios.rb', line 42

def self.current_ratio(ca:, cl:)
  ca = Validation.decimal(ca, name: 'current assets')
  cl = Validation.non_zero_decimal(cl, name: 'current liabilities', error: DomainError)

  (ca / cl)
end

.debt_ratio(td:, ta:) ⇒ decimal

debt ratio -- Solvency ratios measure the firm's ability to satisfy its long-term obligations.

Examples:

Finrb::Ratios.debt_ratio(td=6000,ta=20000)

Parameters:

  • td

    total debt

  • ta

    total assets

  • td: (number)
  • ta: (number)

Returns:

  • (decimal)


55
56
57
58
59
60
# File 'lib/finrb/ratios.rb', line 55

def self.debt_ratio(td:, ta:)
  td = Validation.decimal(td, name: 'total debt')
  ta = Validation.non_zero_decimal(ta, name: 'total assets', error: DomainError)

  (td / ta)
end

.diluted_eps(ni:, pd:, w:, cpd: 0, cdi: 0, tax: 0, cps: 0, cds: 0, iss: 0) ⇒ decimal

diluted Earnings Per Share

Examples:

Finrb::Ratios.diluted_eps(ni=115600,pd=10000,cdi=42000,tax=0.4,w=200000,cds=60000)
Finrb::Ratios.diluted_eps(ni=115600,pd=10000,cpd=10000,w=200000,cps=40000)
Finrb::Ratios.diluted_eps(ni=115600,pd=10000,w=200000,iss=2500)
Finrb::Ratios.diluted_eps(ni=115600,pd=10000,cpd=10000,cdi=42000,tax=0.4,w=200000,cps=40000,cds=60000,iss=2500)

Parameters:

  • ni

    net income

  • pd

    preferred dividends

  • cpd (defaults to: 0)

    dividends on convertible preferred stock

  • cdi (defaults to: 0)

    interest on convertible debt

  • tax (defaults to: 0)

    tax rate

  • w

    weighted average number of common shares outstanding

  • cps (defaults to: 0)

    shares from conversion of convertible preferred stock

  • cds (defaults to: 0)

    shares from conversion of convertible debt

  • iss (defaults to: 0)

    shares issuable from stock options

  • ni: (number)
  • pd: (number)
  • w: (number)
  • cpd: (number) (defaults to: 0)
  • cdi: (number) (defaults to: 0)
  • tax: (number) (defaults to: 0)
  • cps: (number) (defaults to: 0)
  • cds: (number) (defaults to: 0)
  • iss: (number) (defaults to: 0)

Returns:

  • (decimal)


84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/finrb/ratios.rb', line 84

def self.diluted_eps(ni:, pd:, w:, cpd: 0, cdi: 0, tax: 0, cps: 0, cds: 0, iss: 0)
  ni = Validation.decimal(ni, name: 'net income')
  pd = Validation.decimal(pd, name: 'preferred dividends')
  w = Validation.positive_decimal(w, name: 'weighted average common shares', error: DomainError)
  cpd = Validation.non_negative_decimal(cpd, name: 'convertible preferred dividends')
  cdi = Validation.non_negative_decimal(cdi, name: 'convertible debt interest')
  tax = Validation.decimal_between(tax, minimum: 0, maximum: 1, name: 'tax rate')
  cps = Validation.non_negative_decimal(cps, name: 'convertible preferred shares')
  cds = Validation.non_negative_decimal(cds, name: 'convertible debt shares')
  iss = Validation.non_negative_decimal(iss, name: 'incremental option shares')

  basic = (ni - pd) / w
  diluted = (ni - pd + cpd + (cdi * (1 - tax))) / (w + cps + cds + iss)
  diluted = (ni - pd + cpd) / (w + cps + iss) if diluted > basic
  diluted
end

.eps(ni:, pd:, w:) ⇒ decimal

Basic Earnings Per Share

Examples:

Finrb::Ratios.eps(ni=10000,pd=1000,w=11000)

Parameters:

  • ni

    net income

  • pd

    preferred dividends

  • w

    weighted average number of common shares outstanding

  • ni: (number)
  • pd: (number)
  • w: (number)

Returns:

  • (decimal)


108
109
110
111
112
113
114
# File 'lib/finrb/ratios.rb', line 108

def self.eps(ni:, pd:, w:)
  ni = Validation.decimal(ni, name: 'net income')
  pd = Validation.decimal(pd, name: 'preferred dividends')
  w = Validation.positive_decimal(w, name: 'weighted average common shares', error: DomainError)

  ((ni - pd) / w)
end

.financial_leverage(te:, ta:) ⇒ decimal

financial leverage -- Solvency ratios measure the firm's ability to satisfy its long-term obligations.

Examples:

Finrb::Ratios.financial_leverage(te=16000,ta=20000)

Parameters:

  • te

    total equity

  • ta

    total assets

  • te: (number)
  • ta: (number)

Returns:

  • (decimal)


122
123
124
125
126
127
# File 'lib/finrb/ratios.rb', line 122

def self.financial_leverage(te:, ta:)
  te = Validation.non_zero_decimal(te, name: 'total equity', error: DomainError)
  ta = Validation.decimal(ta, name: 'total assets')

  (ta / te)
end

.gpm(gp:, rv:) ⇒ decimal

gross profit margin -- Evaluate a company's financial performance

Examples:

Finrb::Ratios.gpm(gp=1000,rv=20000)

Parameters:

  • gp

    gross profit, equal to revenue minus cost of goods sold (cogs)

  • rv

    revenue (sales)

  • gp: (number)
  • rv: (number)

Returns:

  • (decimal)


135
136
137
138
139
140
# File 'lib/finrb/ratios.rb', line 135

def self.gpm(gp:, rv:)
  gp = Validation.decimal(gp, name: 'gross profit')
  rv = Validation.non_zero_decimal(rv, name: 'revenue', error: DomainError)

  (gp / rv)
end

.iss(amp:, ep:, n:) ⇒ decimal

calculate the net increase in common shares from the potential exercise of stock options or warrants

Examples:

Finrb::Ratios.iss(amp=20,ep=15,n=10000)

Parameters:

  • amp

    average market price over the year

  • ep

    exercise price of the options or warrants

  • n

    number of common shares that the options and warrants can be convened into

  • amp: (number)
  • ep: (number)
  • n: (number)

Returns:

  • (decimal)


149
150
151
152
153
154
155
156
157
158
159
# File 'lib/finrb/ratios.rb', line 149

def self.iss(amp:, ep:, n:)
  amp = Validation.positive_decimal(amp, name: 'average market price', error: DomainError)
  ep = Validation.non_negative_decimal(ep, name: 'exercise price')
  n = Validation.non_negative_decimal(n, name: 'option shares')

  if amp > ep
    ((amp - ep) * n / amp)
  else
    raise(DomainError, 'Average market price must be greater than exercise price.')
  end
end

.lt_d2e(ltd:, te:) ⇒ decimal

long-term debt-to-equity -- Solvency ratios measure the firm's ability to satisfy its long-term obligations.

Examples:

Finrb::Ratios.lt_d2e(ltd=8000,te=20000)

Parameters:

  • ltd

    long-term debt

  • te

    total equity

  • ltd: (number)
  • te: (number)

Returns:

  • (decimal)


167
168
169
170
171
172
# File 'lib/finrb/ratios.rb', line 167

def self.lt_d2e(ltd:, te:)
  ltd = Validation.decimal(ltd, name: 'long-term debt')
  te = Validation.non_zero_decimal(te, name: 'total equity', error: DomainError)

  (ltd / te)
end

.npm(ni:, rv:) ⇒ decimal

net profit margin -- Evaluate a company's financial performance

Examples:

Finrb::Ratios.npm(ni=8000,rv=20000)

Parameters:

  • ni

    net income

  • rv

    revenue (sales)

  • ni: (number)
  • rv: (number)

Returns:

  • (decimal)


180
181
182
183
184
185
# File 'lib/finrb/ratios.rb', line 180

def self.npm(ni:, rv:)
  ni = Validation.decimal(ni, name: 'net income')
  rv = Validation.non_zero_decimal(rv, name: 'revenue', error: DomainError)

  (ni / rv)
end

.quick_ratio(cash:, ms:, rc:, cl:) ⇒ decimal

quick ratio -- Liquidity ratios measure the firm's ability to satisfy its short-term obligations as they come due.

Examples:

Finrb::Ratios.quick_ratio(cash=3000,ms=2000,rc=1000,cl=2000)

Parameters:

  • cash

    cash

  • ms

    marketable securities

  • rc

    receivables

  • cl

    current liabilities

  • cash: (number)
  • ms: (number)
  • rc: (number)
  • cl: (number)

Returns:

  • (decimal)


195
196
197
198
199
200
201
202
# File 'lib/finrb/ratios.rb', line 195

def self.quick_ratio(cash:, ms:, rc:, cl:)
  cash = Validation.decimal(cash, name: 'cash')
  ms = Validation.decimal(ms, name: 'marketable securities')
  rc = Validation.decimal(rc, name: 'receivables')
  cl = Validation.non_zero_decimal(cl, name: 'current liabilities', error: DomainError)

  ((cash + ms + rc) / cl)
end

.total_d2e(td:, te:) ⇒ decimal

total debt-to-equity -- Solvency ratios measure the firm's ability to satisfy its long-term obligations.

Examples:

Finrb::Ratios.total_d2e(td=6000,te=20000)

Parameters:

  • td

    total debt

  • te

    total equity

  • td: (number)
  • te: (number)

Returns:

  • (decimal)


210
211
212
213
214
215
# File 'lib/finrb/ratios.rb', line 210

def self.total_d2e(td:, te:)
  td = Validation.decimal(td, name: 'total debt')
  te = Validation.non_zero_decimal(te, name: 'total equity', error: DomainError)

  (td / te)
end

.was(ns:, nm:) ⇒ decimal, Integer

calculate weighted average shares -- weighted average number of common shares

Examples:

s=[10000,2000];m=[12,6];Finrb::Ratios.was(ns=s,nm=m)
s=[11000,4400,-3000];m=[12,9,4];Finrb::Ratios.was(ns=s,nm=m)

Parameters:

  • ns

    n x 1 vector vector of number of shares

  • nm

    n x 1 vector vector of number of months relate to ns

  • ns: (number, numbers, nil)
  • nm: (number, numbers, nil)

Returns:

  • (decimal, Integer)


226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/finrb/ratios.rb', line 226

def self.was(ns:, nm:)
  ns = wrap_array(ns).map { |value| Validation.decimal(value, name: 'share change') }
  nm = wrap_array(nm).map { |value| Validation.decimal_between(value, minimum: 0, maximum: 12, name: 'months outstanding') }

  m = ns.size
  n = nm.size
  sum = 0
  if m == n
    (0...m).each do |i|
      sum += (ns[i] * nm[i])
    end
  else
    raise(ArgumentError, 'Share changes and months outstanding must have equal lengths.')
  end
  sum /= 12
  sum
end