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:,
    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 = [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



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



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



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



493
494
495
496
497
498
499
500
501
502
503
504
# 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



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

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



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

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



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

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)



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

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



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

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



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

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



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

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



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

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



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

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



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

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



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

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



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

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



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

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)



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

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)



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

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



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

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)



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

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)



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

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)



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

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)



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

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



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

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



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

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



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

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



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

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



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

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



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

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



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

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



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

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



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

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



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

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



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

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



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

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



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

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



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

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