Class: Finrb::Utils

Inherits:
Object
  • Object
show all
Defined in:
lib/finrb/utils.rb

Defined Under Namespace

Classes: NlFunctionStub

Class Method Summary collapse

Class Method Details

.bdy(d:, f:, t:) ⇒ Object

Computing bank discount yield (BDY) for a T-bill

Examples:

Finrb::Utils.bdy(d=1500,f=100000,t=120)

Parameters:

  • d

    the dollar discount, which is equal to the difference between the face value of the bill and the purchase price

  • f

    the face value (par value) of the bill

  • t

    number of days remaining until maturity



36
37
38
39
40
41
42
# File 'lib/finrb/utils.rb', line 36

def self.bdy(d:, f:, t:)
  d = Flt::DecNum(d.to_s)
  f = Flt::DecNum(f.to_s)
  t = Flt::DecNum(t.to_s)

  (d * 360 / f / t)
end

.bdy2mmy(bdy:, t:) ⇒ Object

Computing money market yield (MMY) for a T-bill

Examples:

Finrb::Utils.bdy2mmy(bdy=0.045,t=120)

Parameters:

  • bdy

    bank discount yield

  • t

    number of days remaining until maturity



50
51
52
53
54
55
# File 'lib/finrb/utils.rb', line 50

def self.bdy2mmy(bdy:, t:)
  bdy = Flt::DecNum(bdy.to_s)
  t = Flt::DecNum(t.to_s)

  (bdy * 360 / (360 - (t * bdy)))
end

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

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

Examples:

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

Parameters:

  • cash

    cash

  • ms

    marketable securities

  • cl

    current liabilities



64
65
66
67
68
69
70
# File 'lib/finrb/utils.rb', line 64

def self.cash_ratio(cash:, ms:, cl:)
  cash = Flt::DecNum(cash.to_s)
  ms = Flt::DecNum(ms.to_s)
  cl = Flt::DecNum(cl.to_s)

  ((cash + ms) / cl)
end

.coefficient_variation(sd:, avg:) ⇒ Object

Computing Coefficient of variation

Examples:

Finrb::Utils.coefficient_variation(sd=0.15,avg=0.39)

Parameters:

  • sd

    standard deviation

  • avg

    average value



78
79
80
81
82
83
# File 'lib/finrb/utils.rb', line 78

def self.coefficient_variation(sd:, avg:)
  sd = Flt::DecNum(sd.to_s)
  avg = Flt::DecNum(avg.to_s)

  (sd / avg)
end

.cogs(uinv:, pinv:, units:, price:, sinv:, method: 'FIFO') ⇒ Object

Cost of goods sold and ending inventory under three methods (FIFO,LIFO,Weighted average)

Examples:

Finrb::Utils.cogs(uinv=2,pinv=2,units=[3,5],price=[3,5],sinv=7,method="FIFO")
Finrb::Utils.cogs(uinv=2,pinv=2,units=[3,5],price=[3,5],sinv=7,method="LIFO")
Finrb::Utils.cogs(uinv=2,pinv=2,units=[3,5],price=[3,5],sinv=7,method="WAC")

Parameters:

  • uinv

    units of beginning inventory

  • pinv

    price of beginning inventory

  • units

    nx1 vector of inventory units. inventory purchased ordered by time (from first to last)

  • price

    nx1 vector of inventory price. same order as units

  • sinv

    units of sold inventory

  • method (defaults to: 'FIFO')

    inventory methods: FIFO (first in first out, permitted under both US and IFRS), LIFO (late in first out, US only), WAC (weighted average cost,US and IFRS)



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/finrb/utils.rb', line 101

def self.cogs(uinv:, pinv:, units:, price:, sinv:, method: 'FIFO')
  uinv = Flt::DecNum(uinv.to_s)
  pinv = Flt::DecNum(pinv.to_s)
  units = Array.wrap(units).map { |value| Flt::DecNum(value.to_s) }
  price = Array.wrap(price).map { |value| Flt::DecNum(value.to_s) }
  sinv = Flt::DecNum(sinv.to_s)
  method = method.to_s

  n = units.size
  m = price.size
  cost_of_goods = 0
  ending_inventory = 0
  if m == n
    case method
    when 'FIFO'
      if sinv <= uinv
        cost_of_goods = sinv * pinv
        ending_inventory = (uinv - sinv) * pinv
        (0...n).each do |i|
          ending_inventory += (units[i] * price[i])
        end
      else
        cost_of_goods = uinv * pinv
        sinv -= uinv
        (0...n).each do |i|
          if sinv <= units[i]
            cost_of_goods += (sinv * price[i])
            ending_inventory = (units[i] - sinv) * price[i]
            if i < n
              temp = i + 1
              (temp...n).each do |j|
                ending_inventory += (units[j] * price[j])
              end
            end
            sinv = 0
            next
          else
            cost_of_goods += (units[i] * price[i])
            sinv -= units[i]
          end
        end
        raise(FinrbError, "Inventory is not enough to sell\n") if sinv.positive?
      end
    when 'WAC'
      ending_inventory = uinv * pinv
      tu = uinv
      (0...n).each do |i|
        ending_inventory += (units[i] * price[i])
        tu += units[i]
      end
      if tu >= sinv
        cost_of_goods = ending_inventory / tu * sinv
        ending_inventory = ending_inventory / tu * (tu - sinv)
      else
        raise(FinrbError, "Inventory is not enough to sell\n")
      end

    when 'LIFO'
      (n - 1).downto(0).each do |i|
        if sinv <= units[i]
          cost_of_goods += (sinv * price[i])
          ending_inventory = (units[i] - sinv) * price[i]
          if i > 1
            temp = i - 1
            temp.downto(0).each do |j|
              ending_inventory += (units[j] * price[j])
            end
          end
          ending_inventory += (uinv * pinv)
          sinv = 0
          next
        else
          cost_of_goods += (units[i] * price[i])
          sinv -= units[i]
        end
      end
      if sinv.positive?
        if sinv <= uinv
          cost_of_goods += (sinv * pinv)
          ending_inventory += ((uinv - sinv) * pinv)
        else
          raise(FinrbError, "Inventory is not enough to sell\n")
        end
      end
    end

  else
    raise(FinrbError, "length of units and price are not the same\n")
  end

  {
    cost_of_goods:,
    ending_inventory:
  }
end

.current_ratio(ca:, cl:) ⇒ Object

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

Examples:

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

Parameters:

  • ca

    current assets

  • cl

    current liabilities



203
204
205
206
207
208
# File 'lib/finrb/utils.rb', line 203

def self.current_ratio(ca:, cl:)
  ca = Flt::DecNum(ca.to_s)
  cl = Flt::DecNum(cl.to_s)

  (ca / cl)
end

.ddb(cost:, rv:, t:) ⇒ Object

Depreciation Expense Recognition -- double-declining balance (DDB), the most common declining balance method, which applies two times the straight-line rate to the declining balance.

Examples:

Finrb::Utils.ddb(cost=1200,rv=200,t=5)

Parameters:

  • cost

    cost of long-lived assets

  • rv

    residual value of the long-lived assets at the end of its useful life. DDB does not explicitly use the asset's residual value in the calculations, but depreciation ends once the estimated residual value has been reached. If the asset is expected to have no residual value, the DB method will never fully depreciate it, so the DB method is typically changed to straight-line at some point in the asset's life.

  • t

    length of the useful life

Raises:



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/finrb/utils.rb', line 217

def self.ddb(cost:, rv:, t:)
  cost = Flt::DecNum(cost.to_s)
  rv = Flt::DecNum(rv.to_s)
  t = Flt::DecNum(t.to_s)

  raise(FinrbError, 't should be larger than 1') if t < 2

  ddb = [Flt::DecNum(0)] * t
  ddb[0] = cost * 2 / t
  if cost - ddb.first <= rv
    ddb[0] = cost - rv
  else
    cost -= ddb.first
    (1...t).each do |i|
      ddb[i] = cost * 2 / t
      if cost - ddb[i] <= rv
        ddb[i] = cost - rv
        break
      else
        cost -= ddb[i]
      end
    end
  end
  { t: (0...t).to_a, ddb: }
end

.debt_ratio(td:, ta:) ⇒ Object

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

Examples:

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

Parameters:

  • td

    total debt

  • ta

    total assets



249
250
251
252
253
254
# File 'lib/finrb/utils.rb', line 249

def self.debt_ratio(td:, ta:)
  td = Flt::DecNum(td.to_s)
  ta = Flt::DecNum(ta.to_s)

  (td / ta)
end

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

diluted Earnings Per Share

Examples:

Finrb::Utils.diluted_eps(ni=115600,pd=10000,cdi=42000,tax=0.4,w=200000,cds=60000)
Finrb::Utils.diluted_eps(ni=115600,pd=10000,cpd=10000,w=200000,cps=40000)
Finrb::Utils.diluted_eps(ni=115600,pd=10000,w=200000,iss=2500)
Finrb::Utils.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



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/finrb/utils.rb', line 278

def self.diluted_eps(ni:, pd:, w:, cpd: 0, cdi: 0, tax: 0, cps: 0, cds: 0, iss: 0)
  ni = Flt::DecNum(ni.to_s)
  pd = Flt::DecNum(pd.to_s)
  w = Flt::DecNum(w.to_s)
  cpd = Flt::DecNum(cpd.to_s)
  cdi = Flt::DecNum(cdi.to_s)
  tax = Flt::DecNum(tax.to_s)
  cps = Flt::DecNum(cps.to_s)
  cds = Flt::DecNum(cds.to_s)
  iss = Flt::DecNum(iss.to_s)

  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

.discount_rate(n:, pv:, fv:, pmt:, type: 0, lower: 0.0001, upper: 100) ⇒ Object

Computing the rate of return for each period

Examples:

Finrb::Utils.discount_rate(n=5,pv=0,fv=600,pmt=-100,type=0)

Parameters:

  • n

    number of periods

  • pv

    present value

  • fv

    future value

  • pmt

    payment per period

  • type (defaults to: 0)

    payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)

  • lower (defaults to: 0.0001)

    the lower end points of the rate of return to be searched.

  • upper (defaults to: 100)

    the upper end points of the rate of return to be searched.



306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/finrb/utils.rb', line 306

def self.discount_rate(n:, pv:, fv:, pmt:, type: 0, lower: 0.0001, upper: 100)
  n = Flt::DecNum(n.to_s)
  pv = Flt::DecNum(pv.to_s)
  fv = Flt::DecNum(fv.to_s)
  pmt = Flt::DecNum(pmt.to_s)
  type = Flt::DecNum(type.to_s)
  lower = Flt::DecNum(lower.to_s)
  upper = Flt::DecNum(upper.to_s)

  nlfunc = NlFunctionStub.new
  nlfunc.func =
    lambda do |x|
      [BigDecimal((Finrb::Utils.fv_simple(r: x.first, n:, pv:) + Finrb::Utils.fv_annuity(r: x.first, n:, pmt:, type:) - fv).to_s)]
    end

  root = [BigDecimal(((upper - lower) / 2).to_s)]
  nlsolve(nlfunc, root)
  Flt::DecNum(root.first)
end

.ear(r:, m:) ⇒ Object

Convert stated annual rate to the effective annual rate

Examples:

Finrb::Utils.ear(r=0.12,m=12)
Finrb::Utils.ear(0.04,365)

Parameters:

  • r

    stated annual rate

  • m

    number of compounding periods per year



335
336
337
338
339
340
# File 'lib/finrb/utils.rb', line 335

def self.ear(r:, m:)
  r = Flt::DecNum(r.to_s)
  m = Flt::DecNum(m.to_s)

  ((((r / m) + 1)**m) - 1)
end

.ear2bey(ear:) ⇒ Object

bond-equivalent yield (BEY), 2 x the semiannual discount rate

Examples:

Finrb::Utils.ear2bey(ear=0.08)

Parameters:

  • ear

    effective annual rate



361
362
363
364
365
# File 'lib/finrb/utils.rb', line 361

def self.ear2bey(ear:)
  ear = Flt::DecNum(ear.to_s)

  (((ear + 1).sqrt - 1) * 2)
end

.ear2hpr(ear:, t:) ⇒ Object

Computing HPR, the holding period return

Examples:

Finrb::Utils.ear2hpr(ear=0.05039,t=150)

Parameters:

  • ear

    effective annual rate

  • t

    number of days remaining until maturity



373
374
375
376
377
378
# File 'lib/finrb/utils.rb', line 373

def self.ear2hpr(ear:, t:)
  ear = Flt::DecNum(ear.to_s)
  t = Flt::DecNum(t.to_s)

  (((ear + 1)**(t / 365)) - 1)
end

.ear_continuous(r:) ⇒ Object

Convert stated annual rate to the effective annual rate with continuous compounding

Examples:

Finrb::Utils.ear_continuous(r=0.1)
Finrb::Utils.ear_continuous(0.03)

Parameters:

  • r

    stated annual rate



350
351
352
353
354
# File 'lib/finrb/utils.rb', line 350

def self.ear_continuous(r:)
  r = Flt::DecNum(r.to_s)

  (r.to_dec.exp - 1)
end

.eir(r:, n: 1, p: 12, type: 'e') ⇒ Object

Note:

An interest rate to be applied n times p.a. can be converted to an equivalent rate to be applied p times p.a.

Equivalent/proportional Interest Rates

Examples:

# monthly interest rat equivalent to 5% compounded per year
Finrb::Utils.eir(r=0.05,n=1,p=12)
# monthly interest rat equivalent to 5% compounded per half year
Finrb::Utils.eir(r=0.05,n=2,p=12)
# monthly interest rat equivalent to 5% compounded per quarter
Finrb::Utils.eir(r=0.05,n=4,p=12)
# annual interest rate equivalent to 5% compounded per month
Finrb::Utils.eir(r=0.05,n=12,p=1)
# this is equivalent to
Finrb::Utils.ear(r=0.05,m=12)
# quarter interest rate equivalent to 5% compounded per year
Finrb::Utils.eir(r=0.05,n=1,p=4)
# quarter interest rate equivalent to 5% compounded per month
Finrb::Utils.eir(r=0.05,n=12,p=4)
# monthly proportional interest rate which is equivalent to a simple annual interest
Finrb::Utils.eir(r=0.05,p=12,type='p')

Parameters:

  • r

    interest rate to be applied n times per year (r is annual rate!)

  • n (defaults to: 1)

    times that the interest rate r were compounded per year

  • p (defaults to: 12)

    times that the equivalent rate were compounded per year

  • type (defaults to: 'e')

    equivalent interest rates ('e',default) or proportional interest rates ('p')



415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
# File 'lib/finrb/utils.rb', line 415

def self.eir(r:, n: 1, p: 12, type: 'e')
  r = Flt::DecNum(r.to_s)
  n = Flt::DecNum(n.to_s)
  p = Flt::DecNum(p.to_s)
  type = type.to_s

  case type
  when 'e'
    eir = (((r / n) + 1)**(n / p)) - 1
  when 'p'
    eir = r / p
  else
    raise(FinrbError, "type must be 'e' or 'p'")
  end
  eir
end

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

Basic Earnings Per Share

Examples:

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

Parameters:

  • ni

    net income

  • pd

    preferred dividends

  • w

    weighted average number of common shares outstanding



439
440
441
442
443
444
445
# File 'lib/finrb/utils.rb', line 439

def self.eps(ni:, pd:, w:)
  ni = Flt::DecNum(ni.to_s)
  pd = Flt::DecNum(pd.to_s)
  w = Flt::DecNum(w.to_s)

  ((ni - pd) / w)
end

.financial_leverage(te:, ta:) ⇒ Object

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

Examples:

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

Parameters:

  • te

    total equity

  • ta

    total assets



453
454
455
456
457
458
# File 'lib/finrb/utils.rb', line 453

def self.financial_leverage(te:, ta:)
  te = Flt::DecNum(te.to_s)
  ta = Flt::DecNum(ta.to_s)

  (ta / te)
end

.fv(r:, n:, pv: 0, pmt: 0, type: 0) ⇒ Object

Estimate future value (fv)

Examples:

Finrb::Utils.fv(r=0.07,n=10,pv=1000,pmt=10)

Parameters:

  • r

    discount rate, or the interest rate at which the amount will be compounded each period

  • n

    number of periods

  • pv (defaults to: 0)

    present value

  • pmt (defaults to: 0)

    payment per period

  • type (defaults to: 0)

    payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)



469
470
471
472
473
474
475
476
477
478
479
480
481
# File 'lib/finrb/utils.rb', line 469

def self.fv(r:, n:, pv: 0, pmt: 0, type: 0)
  r = Flt::DecNum(r.to_s)
  n = Flt::DecNum(n.to_s)
  pv = Flt::DecNum(pv.to_s)
  pmt = Flt::DecNum(pmt.to_s)
  type = Flt::DecNum(type.to_s)

  if type != 0 && type != 1
    raise(FinrbError, 'Error: type should be 0 or 1!')
  else
    (Finrb::Utils.fv_simple(r:, n:, pv:) + Finrb::Utils.fv_annuity(r:, n:, pmt:, type:))
  end
end

.fv_annuity(r:, n:, pmt:, type: 0) ⇒ Object

Estimate future value of an annuity

Examples:

Finrb::Utils.fv_annuity(0.03,12,-1000)
Finrb::Utils.fv_annuity(r=0.03,n=12,pmt=-1000,type=1)

Parameters:

  • r

    discount rate, or the interest rate at which the amount will be compounded each period

  • n

    number of periods

  • pmt

    payment per period

  • type (defaults to: 0)

    payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)



494
495
496
497
498
499
500
501
502
503
504
505
# File 'lib/finrb/utils.rb', line 494

def self.fv_annuity(r:, n:, pmt:, type: 0)
  r = Flt::DecNum(r.to_s)
  n = Flt::DecNum(n.to_s)
  pmt = Flt::DecNum(pmt.to_s)
  type = Flt::DecNum(type.to_s)

  if type != 0 && type != 1
    raise(FinrbError, 'Error: type should be 0 or 1!')
  else
    (pmt / r * (((r + 1)**n) - 1)) * ((r + 1)**type) * -1
  end
end

.fv_simple(r:, n:, pv:) ⇒ Object

Estimate future value (fv) of a single sum

Examples:

Finrb::Utils.fv_simple(0.08,10,-300)
Finrb::Utils.fv_simple(r=0.04,n=20,pv=-50000)

Parameters:

  • r

    discount rate, or the interest rate at which the amount will be compounded each period

  • n

    number of periods

  • pv

    present value



517
518
519
520
521
522
523
# File 'lib/finrb/utils.rb', line 517

def self.fv_simple(r:, n:, pv:)
  r = Flt::DecNum(r.to_s)
  n = Flt::DecNum(n.to_s)
  pv = Flt::DecNum(pv.to_s)

  ((pv * ((r + 1)**n)) * -1)
end

.fv_uneven(r:, cf:) ⇒ Object

Computing the future value of an uneven cash flow series

Examples:

Finrb::Utils.fv_uneven(r=0.1, cf=[-1000, -500, 0, 4000, 3500, 2000])

Parameters:

  • r

    stated annual rate

  • cf

    uneven cash flow



531
532
533
534
535
536
537
538
539
540
541
542
# File 'lib/finrb/utils.rb', line 531

def self.fv_uneven(r:, cf:)
  r = Flt::DecNum(r.to_s)
  cf = Array.wrap(cf).map { |value| Flt::DecNum(value.to_s) }

  m = cf.size
  sum = 0
  (0...m).each do |i|
    n = m - (i + 1)
    sum += Finrb::Utils.fv_simple(r:, n:, pv: cf[i])
  end
  sum
end

.geometric_mean(r:) ⇒ Object

Geometric mean return

Examples:

Finrb::Utils.geometric_mean(r=[-0.0934, 0.2345, 0.0892])

Parameters:

  • r

    returns over multiple periods



549
550
551
552
553
554
# File 'lib/finrb/utils.rb', line 549

def self.geometric_mean(r:)
  r = Array.wrap(r).map { |value| Flt::DecNum(value.to_s) }

  rs = r.map { |value| value + 1 }
  ((rs.reduce(:*)**(Flt::DecNum(1) / rs.size)) - 1)
end

.gpm(gp:, rv:) ⇒ Object

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

Examples:

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

Parameters:

  • gp

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

  • rv

    revenue (sales)



562
563
564
565
566
567
# File 'lib/finrb/utils.rb', line 562

def self.gpm(gp:, rv:)
  gp = Flt::DecNum(gp.to_s)
  rv = Flt::DecNum(rv.to_s)

  (gp / rv)
end

.harmonic_mean(p:) ⇒ Object

harmonic mean, average price

Examples:

Finrb::Utils.harmonic_mean(p=[8,9,10])

Parameters:

  • p

    price over multiple periods



573
574
575
576
577
# File 'lib/finrb/utils.rb', line 573

def self.harmonic_mean(p:)
  p = Array.wrap(p).map { |value| Flt::DecNum(value.to_s) }

  (Flt::DecNum(1) / (p.sum { |val| Flt::DecNum(1) / val } / p.size))
end

.hpr(ev:, bv:, cfr: 0) ⇒ Object

Computing HPR, the holding period return

Examples:

Finrb::Utils.hpr(ev=33,bv=30,cfr=0.5)

Parameters:

  • ev

    ending value

  • bv

    beginning value

  • cfr (defaults to: 0)

    cash flow received



586
587
588
589
590
591
592
# File 'lib/finrb/utils.rb', line 586

def self.hpr(ev:, bv:, cfr: 0)
  ev = Flt::DecNum(ev.to_s)
  bv = Flt::DecNum(bv.to_s)
  cfr = Flt::DecNum(cfr.to_s)

  ((ev - bv + cfr) / bv)
end

.hpr2bey(hpr:, t:) ⇒ Object

bond-equivalent yield (BEY), 2 x the semiannual discount rate

Examples:

Finrb::Utils.hpr2bey(hpr=0.02,t=3)

Parameters:

  • hpr

    holding period return

  • t

    number of month remaining until maturity



600
601
602
603
604
605
# File 'lib/finrb/utils.rb', line 600

def self.hpr2bey(hpr:, t:)
  hpr = Flt::DecNum(hpr.to_s)
  t = Flt::DecNum(t.to_s)

  ((((hpr + 1)**(6 / t)) - 1) * 2)
end

.hpr2ear(hpr:, t:) ⇒ Object

Convert holding period return to the effective annual rate

Examples:

Finrb::Utils.hpr2ear(hpr=0.015228,t=120)

Parameters:

  • hpr

    holding period return

  • t

    number of days remaining until maturity



613
614
615
616
617
618
# File 'lib/finrb/utils.rb', line 613

def self.hpr2ear(hpr:, t:)
  hpr = Flt::DecNum(hpr.to_s)
  t = Flt::DecNum(t.to_s)

  (((hpr + 1)**(365 / t)) - 1)
end

.hpr2mmy(hpr:, t:) ⇒ Object

Computing money market yield (MMY) for a T-bill

Examples:

Finrb::Utils.hpr2mmy(hpr=0.01523,t=120)

Parameters:

  • hpr

    holding period return

  • t

    number of days remaining until maturity



626
627
628
629
630
631
# File 'lib/finrb/utils.rb', line 626

def self.hpr2mmy(hpr:, t:)
  hpr = Flt::DecNum(hpr.to_s)
  t = Flt::DecNum(t.to_s)

  (hpr * 360 / t)
end

.irr(cf:) ⇒ Object

Computing IRR, the internal rate of return

Examples:

Finrb::Utils.irr(cf=[-5, 1.6, 2.4, 2.8])

Parameters:

  • cf

    cash flow,the first cash flow is the initial outlay



638
639
640
641
642
643
644
645
646
647
648
649
650
651
# File 'lib/finrb/utils.rb', line 638

def self.irr(cf:)
  cf = Array.wrap(cf).map { |value| Flt::DecNum(value.to_s) }

  subcf = cf.drop(1)
  nlfunc = NlFunctionStub.new
  nlfunc.func =
    lambda do |x|
      [BigDecimal(((Finrb::Utils.pv_uneven(r: x.first, cf: subcf) * -1) + cf.first).to_s)]
    end

  root = [0]
  nlsolve(nlfunc, root)
  Flt::DecNum(root.first)
end

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

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

Examples:

Finrb::Utils.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



660
661
662
663
664
665
666
667
668
669
670
# File 'lib/finrb/utils.rb', line 660

def self.iss(amp:, ep:, n:)
  amp = Flt::DecNum(amp.to_s)
  ep = Flt::DecNum(ep.to_s)
  n = Flt::DecNum(n.to_s)

  if amp > ep
    ((amp - ep) * n / amp)
  else
    raise(FinrbError, 'amp must larger than ep')
  end
end

.lt_d2e(ltd:, te:) ⇒ Object

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

Examples:

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

Parameters:

  • ltd

    long-term debt

  • te

    total equity



678
679
680
681
682
683
# File 'lib/finrb/utils.rb', line 678

def self.lt_d2e(ltd:, te:)
  ltd = Flt::DecNum(ltd.to_s)
  te = Flt::DecNum(te.to_s)

  (ltd / te)
end

.mmy2hpr(mmy:, t:) ⇒ Object

Computing HPR, the holding period return

Examples:

Finrb::Utils.mmy2hpr(mmy=0.04898,t=150)

Parameters:

  • mmy

    money market yield

  • t

    number of days remaining until maturity



691
692
693
694
695
696
# File 'lib/finrb/utils.rb', line 691

def self.mmy2hpr(mmy:, t:)
  mmy = Flt::DecNum(mmy.to_s)
  t = Flt::DecNum(t.to_s)

  (mmy * t / 360)
end

.n_period(r:, pv:, fv:, pmt:, type: 0) ⇒ Object

Estimate the number of periods

Examples:

Finrb::Utils.n_period(0.1,-10000,60000000,-50000,0)
Finrb::Utils.n_period(r=0.1,pv=-10000,fv=60000000,pmt=-50000,type=1)

Parameters:

  • r

    discount rate, or the interest rate at which the amount will be compounded each period

  • pv

    present value

  • fv

    future value

  • pmt

    payment per period

  • type (defaults to: 0)

    payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)



710
711
712
713
714
715
716
717
718
719
720
721
722
# File 'lib/finrb/utils.rb', line 710

def self.n_period(r:, pv:, fv:, pmt:, type: 0)
  r = Flt::DecNum(r.to_s)
  pv = Flt::DecNum(pv.to_s)
  fv = Flt::DecNum(fv.to_s)
  pmt = Flt::DecNum(pmt.to_s)
  type = Flt::DecNum(type.to_s)

  if type != 0 && type != 1
    raise(FinrbError, 'Error: type should be 0 or 1!')
  else
    (((fv * r) - (pmt * ((r + 1)**type))) * Flt::DecNum(-1) / ((pv * r) + (pmt * ((r + 1)**type)))).to_dec.log / (r + 1).to_dec.log
  end
end

.npm(ni:, rv:) ⇒ Object

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

Examples:

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

Parameters:

  • ni

    net income

  • rv

    revenue (sales)



730
731
732
733
734
735
# File 'lib/finrb/utils.rb', line 730

def self.npm(ni:, rv:)
  ni = Flt::DecNum(ni.to_s)
  rv = Flt::DecNum(rv.to_s)

  (ni / rv)
end

.npv(r:, cf:) ⇒ Object

Computing NPV, the PV of the cash flows less the initial (time = 0) outlay

Examples:

Finrb::Utils.npv(r=0.12, cf=[-5, 1.6, 2.4, 2.8])

Parameters:

  • r

    discount rate, or the interest rate at which the amount will be compounded each period

  • cf

    cash flow,the first cash flow is the initial outlay



743
744
745
746
747
748
749
# File 'lib/finrb/utils.rb', line 743

def self.npv(r:, cf:)
  r = Flt::DecNum(r.to_s)
  cf = Array.wrap(cf).map { |value| Flt::DecNum(value.to_s) }

  subcf = cf.drop(1)
  ((Finrb::Utils.pv_uneven(r:, cf: subcf) * -1) + cf.first)
end

.pmt(r:, n:, pv:, fv:, type: 0) ⇒ Object

Estimate period payment

Examples:

Finrb::Utils.pmt(0.08,10,-1000,10)
Finrb::Utils.pmt(r=0.08,n=10,pv=-1000,fv=0)
Finrb::Utils.pmt(0.08,10,-1000,10,1)

Parameters:

  • r

    discount rate, or the interest rate at which the amount will be compounded each period

  • n

    number of periods

  • pv

    present value

  • fv

    future value

  • type (defaults to: 0)

    payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)



766
767
768
769
770
771
772
773
774
775
776
777
778
# File 'lib/finrb/utils.rb', line 766

def self.pmt(r:, n:, pv:, fv:, type: 0)
  r = Flt::DecNum(r.to_s)
  n = Flt::DecNum(n.to_s)
  pv = Flt::DecNum(pv.to_s)
  fv = Flt::DecNum(fv.to_s)
  type = Flt::DecNum(type.to_s)

  if type != 0 && type != 1
    raise(FinrbError, 'Error: type should be 0 or 1!')
  else
    (pv + (fv / ((r + 1)**n))) * r / (1 - (Flt::DecNum(1) / ((r + 1)**n))) * -1 * ((r + 1)**(type * -1))
  end
end

.pv(r:, n:, fv: 0, pmt: 0, type: 0) ⇒ Object

Estimate present value (pv)

Examples:

Finrb::Utils.pv(0.07,10,1000,10)
Finrb::Utils.pv(r=0.05,n=20,fv=1000,pmt=10,type=1)

Parameters:

  • r

    discount rate, or the interest rate at which the amount will be compounded each period

  • n

    number of periods

  • fv (defaults to: 0)

    future value

  • pmt (defaults to: 0)

    payment per period

  • type (defaults to: 0)

    payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)



792
793
794
795
796
797
798
799
800
801
802
803
804
# File 'lib/finrb/utils.rb', line 792

def self.pv(r:, n:, fv: 0, pmt: 0, type: 0)
  r = Flt::DecNum(r.to_s)
  n = Flt::DecNum(n.to_s)
  fv = Flt::DecNum(fv.to_s)
  pmt = Flt::DecNum(pmt.to_s)
  type = Flt::DecNum(type.to_s)

  if type != 0 && type != 1
    raise(FinrbError, 'Error: type should be 0 or 1!')
  else
    Finrb::Utils.pv_simple(r:, n:, fv:) + Finrb::Utils.pv_annuity(r:, n:, pmt:, type:)
  end
end

.pv_annuity(r:, n:, pmt:, type: 0) ⇒ Object

Estimate present value (pv) of an annuity

Examples:

Finrb::Utils.pv_annuity(0.03,12,1000)
Finrb::Utils.pv_annuity(r=0.0425,n=3,pmt=30000)

Parameters:

  • r

    discount rate, or the interest rate at which the amount will be compounded each period

  • n

    number of periods

  • pmt

    payment per period

  • type (defaults to: 0)

    payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)



817
818
819
820
821
822
823
824
825
826
827
828
# File 'lib/finrb/utils.rb', line 817

def self.pv_annuity(r:, n:, pmt:, type: 0)
  r = Flt::DecNum(r.to_s)
  n = Flt::DecNum(n.to_s)
  pmt = Flt::DecNum(pmt.to_s)
  type = Flt::DecNum(type.to_s)

  if type != 0 && type != 1
    raise(FinrbError, 'Error: type should be 0 or 1!')
  else
    (pmt / r * (1 - (Flt::DecNum(1) / ((r + 1)**n)))) * ((r + 1)**type) * -1
  end
end

.pv_perpetuity(r:, pmt:, g: 0, type: 0) ⇒ Object

Estimate present value of a perpetuity

Examples:

Finrb::Utils.pv_perpetuity(r=0.1,pmt=1000,g=0.02)
Finrb::Utils.pv_perpetuity(r=0.1,pmt=1000,type=1)
Finrb::Utils.pv_perpetuity(r=0.1,pmt=1000)

Parameters:

  • r

    discount rate, or the interest rate at which the amount will be compounded each period

  • g (defaults to: 0)

    growth rate of perpetuity

  • pmt

    payment per period

  • type (defaults to: 0)

    payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)



844
845
846
847
848
849
850
851
852
853
854
855
856
857
# File 'lib/finrb/utils.rb', line 844

def self.pv_perpetuity(r:, pmt:, g: 0, type: 0)
  r = Flt::DecNum(r.to_s)
  pmt = Flt::DecNum(pmt.to_s)
  g = Flt::DecNum(g.to_s)
  type = Flt::DecNum(type.to_s)

  if type != 0 && type != 1
    raise(FinrbError, 'Error: type should be 0 or 1!')
  elsif g >= r
    raise(FinrbError, 'Error: g is not smaller than r!')
  else
    (pmt / (r - g)) * ((r + 1)**type) * -1
  end
end

.pv_simple(r:, n:, fv:) ⇒ Object

Estimate present value (pv) of a single sum

Examples:

Finrb::Utils.pv_simple(0.07,10,100)
Finrb::Utils.pv_simple(r=0.03,n=3,fv=1000)

Parameters:

  • r

    discount rate, or the interest rate at which the amount will be compounded each period

  • n

    number of periods

  • fv

    future value



869
870
871
872
873
874
875
# File 'lib/finrb/utils.rb', line 869

def self.pv_simple(r:, n:, fv:)
  r = Flt::DecNum(r.to_s)
  n = Flt::DecNum(n.to_s)
  fv = Flt::DecNum(fv.to_s)

  ((fv / ((r + 1)**n)) * -1)
end

.pv_uneven(r:, cf:) ⇒ Object

Computing the present value of an uneven cash flow series

Examples:

Finrb::Utils.pv_uneven(r=0.1, cf=[-1000, -500, 0, 4000, 3500, 2000])

Parameters:

  • r

    discount rate, or the interest rate at which the amount will be compounded each period

  • cf

    uneven cash flow



883
884
885
886
887
888
889
890
891
892
893
# File 'lib/finrb/utils.rb', line 883

def self.pv_uneven(r:, cf:)
  r = Flt::DecNum(r.to_s)
  cf = Array.wrap(cf).map { |value| Flt::DecNum(value.to_s) }

  n = cf.size
  sum = 0
  (0...n).each do |i|
    sum += Finrb::Utils.pv_simple(r:, n: i + 1, fv: cf[i])
  end
  sum
end

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

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

Examples:

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

Parameters:

  • cash

    cash

  • ms

    marketable securities

  • rc

    receivables

  • cl

    current liabilities



903
904
905
906
907
908
909
910
# File 'lib/finrb/utils.rb', line 903

def self.quick_ratio(cash:, ms:, rc:, cl:)
  cash = Flt::DecNum(cash.to_s)
  ms = Flt::DecNum(ms.to_s)
  rc = Flt::DecNum(rc.to_s)
  cl = Flt::DecNum(cl.to_s)

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

.r_continuous(r:, m:) ⇒ Object

Convert a given norminal rate to a continuous compounded rate

Examples:

Finrb::Utils.r_continuous(r=0.03,m=4)

Parameters:

  • r

    norminal rate

  • m

    number of times compounded each year



918
919
920
921
922
923
# File 'lib/finrb/utils.rb', line 918

def self.r_continuous(r:, m:)
  r = Flt::DecNum(r.to_s)
  m = Flt::DecNum(m.to_s)

  (m * ((r / m) + 1).to_dec.log)
end

.r_norminal(rc:, m:) ⇒ Object

Convert a given continuous compounded rate to a norminal rate

Examples:

Finrb::Utils.r_norminal(0.03,1)
Finrb::Utils.r_norminal(rc=0.03,m=4)

Parameters:

  • rc

    continuous compounded rate

  • m

    number of desired times compounded each year



934
935
936
937
938
939
# File 'lib/finrb/utils.rb', line 934

def self.r_norminal(rc:, m:)
  rc = Flt::DecNum(rc.to_s)
  m = Flt::DecNum(m.to_s)

  (m * ((rc / m).to_dec.exp - 1))
end

.r_perpetuity(pmt:, pv:) ⇒ Object

Rate of return for a perpetuity

Examples:

Finrb::Utils.r_perpetuity(pmt=4.5,pv=-75)

Parameters:

  • pmt

    payment per period

  • pv

    present value



947
948
949
950
951
952
# File 'lib/finrb/utils.rb', line 947

def self.r_perpetuity(pmt:, pv:)
  pmt = Flt::DecNum(pmt.to_s)
  pv = Flt::DecNum(pv.to_s)

  (pmt * Flt::DecNum(-1) / pv)
end

.sampling_error(sm:, mu:) ⇒ Object

Computing Sampling error

Examples:

Finrb::Utils.sampling_error(sm=0.45, mu=0.5)

Parameters:

  • sm

    sample mean

  • mu

    population mean



960
961
962
963
964
965
# File 'lib/finrb/utils.rb', line 960

def self.sampling_error(sm:, mu:)
  sm = Flt::DecNum(sm.to_s)
  mu = Flt::DecNum(mu.to_s)

  (sm - mu)
end

.sf_ratio(rp:, rl:, sd:) ⇒ Object

Computing Roy's safety-first ratio

Examples:

Finrb::Utils.sf_ratio(rp=0.09,rl=0.03,sd=0.12)

Parameters:

  • rp

    portfolio return

  • rl

    threshold level return

  • sd

    standard deviation of portfolio retwns



974
975
976
977
978
979
980
# File 'lib/finrb/utils.rb', line 974

def self.sf_ratio(rp:, rl:, sd:)
  rp = Flt::DecNum(rp.to_s)
  rl = Flt::DecNum(rl.to_s)
  sd = Flt::DecNum(sd.to_s)

  ((rp - rl) / sd)
end

.sharpe_ratio(rp:, rf:, sd:) ⇒ Object

Computing Sharpe Ratio

Examples:

Finrb::Utils.sharpe_ratio(rp=0.038,rf=0.015,sd=0.07)

Parameters:

  • rp

    portfolio return

  • rf

    risk-free return

  • sd

    standard deviation of portfolio retwns



989
990
991
992
993
994
995
# File 'lib/finrb/utils.rb', line 989

def self.sharpe_ratio(rp:, rf:, sd:)
  rp = Flt::DecNum(rp.to_s)
  rf = Flt::DecNum(rf.to_s)
  sd = Flt::DecNum(sd.to_s)

  ((rp - rf) / sd)
end

.slde(cost:, rv:, t:) ⇒ Object

Depreciation Expense Recognition -- Straight-line depreciation (SL) allocates an equal amount of depreciation each year over the asset's useful life

Examples:

Finrb::Utils.slde(cost=1200,rv=200,t=5)

Parameters:

  • cost

    cost of long-lived assets

  • rv

    residual value of the long-lived assets at the end of its useful life

  • t

    length of the useful life



1004
1005
1006
1007
1008
1009
1010
# File 'lib/finrb/utils.rb', line 1004

def self.slde(cost:, rv:, t:)
  cost = Flt::DecNum(cost.to_s)
  rv = Flt::DecNum(rv.to_s)
  t = Flt::DecNum(t.to_s)

  ((cost - rv) / t)
end

.total_d2e(td:, te:) ⇒ Object

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

Examples:

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

Parameters:

  • td

    total debt

  • te

    total equity



1018
1019
1020
1021
1022
1023
# File 'lib/finrb/utils.rb', line 1018

def self.total_d2e(td:, te:)
  td = Flt::DecNum(td.to_s)
  te = Flt::DecNum(te.to_s)

  (td / te)
end

.twrr(ev:, bv:, cfr:) ⇒ Object

Computing TWRR, the time-weighted rate of return

Examples:

Finrb::Utils.twrr(ev=[120,260],bv=[100,240],cfr=[2,4])

Parameters:

  • ev

    ordered ending value list

  • bv

    ordered beginning value list

  • cfr

    ordered cash flow received list



1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
# File 'lib/finrb/utils.rb', line 1032

def self.twrr(ev:, bv:, cfr:)
  ev = Array.wrap(ev).map { |value| Flt::DecNum(value.to_s) }
  bv = Array.wrap(bv).map { |value| Flt::DecNum(value.to_s) }
  cfr = Array.wrap(cfr).map { |value| Flt::DecNum(value.to_s) }

  r = ev.size
  s = bv.size
  t = cfr.size
  wr = Flt::DecNum(1)
  if r != s || r != t || s != t
    raise(FinrbError, 'Different number of values!')
  else
    (0...r).each do |i|
      wr *= (Finrb::Utils.hpr(ev: ev[i], bv: bv[i], cfr: cfr[i]) + 1)
    end
    ((wr**(Flt::DecNum(1) / r)) - 1)
  end
end

.was(ns:, nm:) ⇒ Object

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

Examples:

s=[10000,2000];m=[12,6];Finrb::Utils.was(ns=s,nm=m)
s=[11000,4400,-3000];m=[12,9,4];Finrb::Utils.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



1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
# File 'lib/finrb/utils.rb', line 1060

def self.was(ns:, nm:)
  ns = Array.wrap(ns).map { |value| Flt::DecNum(value.to_s) }
  nm = Array.wrap(nm).map { |value| Flt::DecNum(value.to_s) }

  m = ns.size
  n = nm.size
  sum = 0
  if m == n
    (0...m).each do |i|
      sum += (ns[i] * nm[i])
    end
  else
    raise(FinrbError, 'length of ns and nm must be equal')
  end
  sum /= 12
  sum
end

.wpr(r:, w:) ⇒ Object

Weighted mean as a portfolio return

Examples:

Finrb::Utils.wpr(r=[0.12, 0.07, 0.03],w=[0.5,0.4,0.1])

Parameters:

  • r

    returns of the individual assets in the portfolio

  • w

    corresponding weights associated with each of the individual assets



1084
1085
1086
1087
1088
1089
1090
1091
1092
# File 'lib/finrb/utils.rb', line 1084

def self.wpr(r:, w:)
  r = Array.wrap(r).map { |value| Flt::DecNum(value.to_s) }
  w = Array.wrap(w).map { |value| Flt::DecNum(value.to_s) }

  # TODO: need to change
  puts('sum of weights is NOT equal to 1!') if w.sum != 1

  r.zip(w).sum { |arr| arr.reduce(:*) }
end