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



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

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



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

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



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

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



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

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)



100
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
# File 'lib/finrb/utils.rb', line 100

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: cost_of_goods,
    ending_inventory: 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



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

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:



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

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 = [0] * t
  ddb[0] = cost * 2 / t
  if cost - ddb[0] <= rv
    ddb[0] = cost - rv
  else
    cost -= ddb[0]
    (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: 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



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

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



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

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.



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

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[0], n: n, pv: pv) + Finrb::Utils.fv_annuity(r: x[0], n: n, pmt: pmt, type: type) - fv).to_s)]
    end

  root = [(upper - lower) / 2]
  nlsolve(nlfunc, root)
  root[0]
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



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

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



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

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

  ((((ear + 1)**0.5) - 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



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

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



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

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’)



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

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



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

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



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

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)



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

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: r, n: n, pv: pv) + Finrb::Utils.fv_annuity(r: r, n: n, pmt: pmt, type: 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)



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

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: r, n: 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(:*)**(1.to_f / 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) }

  (1.to_f / (p.sum { |val| 1.to_f / 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[0], cf: subcf) * -1) + cf[0]).to_s)]
    end

  root = [0]
  nlsolve(nlfunc, root)
  root[0]
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
723
# 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))) * -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)



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

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



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

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: r, cf: subcf) * -1) + cf[0])
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)



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

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 - (1.to_f / ((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)



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

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: r, n: n, fv: fv) + Finrb::Utils.pv_annuity(r: r, n: n, pmt: pmt, type: 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)



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

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 - (1.to_f / ((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)



847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
# File 'lib/finrb/utils.rb', line 847

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



873
874
875
876
877
878
879
# File 'lib/finrb/utils.rb', line 873

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



887
888
889
890
891
892
893
894
895
896
897
# File 'lib/finrb/utils.rb', line 887

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: 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



907
908
909
910
911
912
913
914
# File 'lib/finrb/utils.rb', line 907

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



922
923
924
925
926
927
# File 'lib/finrb/utils.rb', line 922

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



938
939
940
941
942
943
# File 'lib/finrb/utils.rb', line 938

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



951
952
953
954
955
956
# File 'lib/finrb/utils.rb', line 951

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

  (pmt * -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



964
965
966
967
968
969
# File 'lib/finrb/utils.rb', line 964

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



978
979
980
981
982
983
984
# File 'lib/finrb/utils.rb', line 978

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



993
994
995
996
997
998
999
# File 'lib/finrb/utils.rb', line 993

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



1008
1009
1010
1011
1012
1013
1014
# File 'lib/finrb/utils.rb', line 1008

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



1022
1023
1024
1025
1026
1027
# File 'lib/finrb/utils.rb', line 1022

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



1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
# File 'lib/finrb/utils.rb', line 1036

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 = 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**(1.to_f / 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



1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
# File 'lib/finrb/utils.rb', line 1064

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



1088
1089
1090
1091
1092
1093
1094
1095
1096
# File 'lib/finrb/utils.rb', line 1088

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