finrb 0.0.1 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +41 -26
- data/README.md +121 -63
- data/lib/finrb/amortization.rb +24 -24
- data/lib/finrb/cashflows.rb +7 -8
- data/lib/finrb/decimal.rb +2 -2
- data/lib/finrb/rates.rb +42 -43
- data/lib/finrb/utils.rb +459 -532
- data/lib/finrb.rb +1 -1
- metadata +29 -91
- data/.dockerignore +0 -2
- data/.gitattributes +0 -83
- data/.gitignore +0 -114
- data/.rubocop.yml +0 -19
- data/.ruby-version +0 -1
- data/.semver +0 -5
- data/.travis.yml +0 -7
- data/.yardopts +0 -1
- data/Dockerfile +0 -35
- data/Gemfile +0 -5
- data/Gemfile.lock +0 -116
- data/Rakefile +0 -33
- data/docs/.gitkeep +0 -0
- data/docs/api.md +0 -1104
- data/finrb.gemspec +0 -98
data/lib/finrb/utils.rb
CHANGED
@@ -30,29 +30,27 @@ module Finrb
|
|
30
30
|
# @param d the dollar discount, which is equal to the difference between the face value of the bill and the purchase price
|
31
31
|
# @param f the face value (par value) of the bill
|
32
32
|
# @param t number of days remaining until maturity
|
33
|
-
# @
|
34
|
-
#
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
(360 * d / f / t)
|
33
|
+
# @example
|
34
|
+
# Finrb::Utils.bdy(d=1500,f=100000,t=120)
|
35
|
+
def self.bdy(d:, f:, t:)
|
36
|
+
d = DecNum(d.to_s)
|
37
|
+
f = DecNum(f.to_s)
|
38
|
+
t = DecNum(t.to_s)
|
39
|
+
|
40
|
+
(d * 360 / f / t)
|
42
41
|
end
|
43
42
|
|
44
43
|
# Computing money market yield (MMY) for a T-bill
|
45
44
|
#
|
46
45
|
# @param bdy bank discount yield
|
47
46
|
# @param t number of days remaining until maturity
|
48
|
-
# @
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
(360 * bdy / (360 - (t * bdy)))
|
47
|
+
# @example
|
48
|
+
# Finrb::Utils.bdy2mmy(bdy=0.045,t=120)
|
49
|
+
def self.bdy2mmy(bdy:, t:)
|
50
|
+
bdy = DecNum(bdy.to_s)
|
51
|
+
t = DecNum(t.to_s)
|
52
|
+
|
53
|
+
(bdy * 360 / (360 - (t * bdy)))
|
56
54
|
end
|
57
55
|
|
58
56
|
# cash ratio -- Liquidity ratios measure the firm's ability to satisfy its short-term obligations as they come due.
|
@@ -60,13 +58,12 @@ module Finrb
|
|
60
58
|
# @param cash cash
|
61
59
|
# @param ms marketable securities
|
62
60
|
# @param cl current liabilities
|
63
|
-
# @
|
64
|
-
#
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
cl = cl.to_d
|
61
|
+
# @example
|
62
|
+
# Finrb::Utils.cash_ratio(cash=3000,ms=2000,cl=2000)
|
63
|
+
def self.cash_ratio(cash:, ms:, cl:)
|
64
|
+
cash = DecNum(cash.to_s)
|
65
|
+
ms = DecNum(ms.to_s)
|
66
|
+
cl = DecNum(cl.to_s)
|
70
67
|
|
71
68
|
((cash + ms) / cl)
|
72
69
|
end
|
@@ -75,12 +72,11 @@ module Finrb
|
|
75
72
|
#
|
76
73
|
# @param sd standard deviation
|
77
74
|
# @param avg average value
|
78
|
-
# @
|
79
|
-
#
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
avg = avg.to_d
|
75
|
+
# @example
|
76
|
+
# Finrb::Utils.coefficient_variation(sd=0.15,avg=0.39)
|
77
|
+
def self.coefficient_variation(sd:, avg:)
|
78
|
+
sd = DecNum(sd.to_s)
|
79
|
+
avg = DecNum(avg.to_s)
|
84
80
|
|
85
81
|
(sd / avg)
|
86
82
|
end
|
@@ -88,71 +84,72 @@ module Finrb
|
|
88
84
|
# Cost of goods sold and ending inventory under three methods (FIFO,LIFO,Weighted average)
|
89
85
|
#
|
90
86
|
# @param uinv units of beginning inventory
|
91
|
-
# @param pinv
|
87
|
+
# @param pinv price of beginning inventory
|
92
88
|
# @param units nx1 vector of inventory units. inventory purchased ordered by time (from first to last)
|
93
89
|
# @param price nx1 vector of inventory price. same order as units
|
94
90
|
# @param sinv units of sold inventory
|
95
91
|
# @param method 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)
|
96
|
-
# @
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
92
|
+
# @example
|
93
|
+
# Finrb::Utils.cogs(uinv=2,pinv=2,units=[3,5],price=[3,5],sinv=7,method="FIFO")
|
94
|
+
#
|
95
|
+
# @example
|
96
|
+
# Finrb::Utils.cogs(uinv=2,pinv=2,units=[3,5],price=[3,5],sinv=7,method="LIFO")
|
97
|
+
#
|
98
|
+
# @example
|
99
|
+
# Finrb::Utils.cogs(uinv=2,pinv=2,units=[3,5],price=[3,5],sinv=7,method="WAC")
|
100
|
+
def self.cogs(uinv:, pinv:, units:, price:, sinv:, method: 'FIFO')
|
101
|
+
uinv = DecNum(uinv.to_s)
|
102
|
+
pinv = DecNum(pinv.to_s)
|
103
|
+
units = Array.wrap(units).map { |value| DecNum(value.to_s) }
|
104
|
+
price = Array.wrap(price).map { |value| DecNum(value.to_s) }
|
105
|
+
sinv = DecNum(sinv.to_s)
|
109
106
|
method = method.to_s
|
110
107
|
|
111
108
|
n = units.size
|
112
109
|
m = price.size
|
113
|
-
|
114
|
-
|
110
|
+
cost_of_goods = 0
|
111
|
+
ending_inventory = 0
|
115
112
|
if m == n
|
116
113
|
case method
|
117
114
|
when 'FIFO'
|
118
115
|
if sinv <= uinv
|
119
|
-
|
120
|
-
|
116
|
+
cost_of_goods = sinv * pinv
|
117
|
+
ending_inventory = (uinv - sinv) * pinv
|
121
118
|
(0...n).each do |i|
|
122
|
-
|
119
|
+
ending_inventory += (units[i] * price[i])
|
123
120
|
end
|
124
121
|
else
|
125
|
-
|
122
|
+
cost_of_goods = uinv * pinv
|
126
123
|
sinv -= uinv
|
127
124
|
(0...n).each do |i|
|
128
125
|
if sinv <= units[i]
|
129
|
-
|
130
|
-
|
126
|
+
cost_of_goods += (sinv * price[i])
|
127
|
+
ending_inventory = (units[i] - sinv) * price[i]
|
131
128
|
if i < n
|
132
129
|
temp = i + 1
|
133
130
|
(temp...n).each do |j|
|
134
|
-
|
131
|
+
ending_inventory += (units[j] * price[j])
|
135
132
|
end
|
136
133
|
end
|
137
134
|
sinv = 0
|
138
135
|
next
|
139
136
|
else
|
140
|
-
|
137
|
+
cost_of_goods += (units[i] * price[i])
|
141
138
|
sinv -= units[i]
|
142
139
|
end
|
143
140
|
end
|
144
141
|
raise(FinrbError, "Inventory is not enough to sell\n") if sinv.positive?
|
145
142
|
end
|
146
143
|
when 'WAC'
|
147
|
-
|
144
|
+
ending_inventory = uinv * pinv
|
148
145
|
tu = uinv
|
149
146
|
(0...n).each do |i|
|
150
|
-
|
147
|
+
ending_inventory += (units[i] * price[i])
|
151
148
|
tu += units[i]
|
152
149
|
end
|
153
150
|
if tu >= sinv
|
154
|
-
|
155
|
-
|
151
|
+
cost_of_goods = ending_inventory / tu * sinv
|
152
|
+
ending_inventory = ending_inventory / tu * (tu - sinv)
|
156
153
|
else
|
157
154
|
raise(FinrbError, "Inventory is not enough to sell\n")
|
158
155
|
end
|
@@ -160,26 +157,26 @@ module Finrb
|
|
160
157
|
when 'LIFO'
|
161
158
|
(n - 1).downto(0).each do |i|
|
162
159
|
if sinv <= units[i]
|
163
|
-
|
164
|
-
|
160
|
+
cost_of_goods += (sinv * price[i])
|
161
|
+
ending_inventory = (units[i] - sinv) * price[i]
|
165
162
|
if i > 1
|
166
163
|
temp = i - 1
|
167
|
-
|
168
|
-
|
164
|
+
temp.downto(0).each do |j|
|
165
|
+
ending_inventory += (units[j] * price[j])
|
169
166
|
end
|
170
167
|
end
|
171
|
-
|
168
|
+
ending_inventory += (uinv * pinv)
|
172
169
|
sinv = 0
|
173
170
|
next
|
174
171
|
else
|
175
|
-
|
172
|
+
cost_of_goods += (units[i] * price[i])
|
176
173
|
sinv -= units[i]
|
177
174
|
end
|
178
175
|
end
|
179
176
|
if sinv.positive?
|
180
177
|
if sinv <= uinv
|
181
|
-
|
182
|
-
|
178
|
+
cost_of_goods += (sinv * pinv)
|
179
|
+
ending_inventory += ((uinv - sinv) * pinv)
|
183
180
|
else
|
184
181
|
raise(FinrbError, "Inventory is not enough to sell\n")
|
185
182
|
end
|
@@ -190,19 +187,21 @@ module Finrb
|
|
190
187
|
raise(FinrbError, "length of units and price are not the same\n")
|
191
188
|
end
|
192
189
|
|
193
|
-
|
190
|
+
{
|
191
|
+
cost_of_goods: cost_of_goods,
|
192
|
+
ending_inventory: ending_inventory
|
193
|
+
}
|
194
194
|
end
|
195
195
|
|
196
196
|
# current ratio -- Liquidity ratios measure the firm's ability to satisfy its short-term obligations as they come due.
|
197
197
|
#
|
198
198
|
# @param ca current assets
|
199
199
|
# @param cl current liabilities
|
200
|
-
# @
|
201
|
-
#
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
cl = cl.to_d
|
200
|
+
# @example
|
201
|
+
# Finrb::Utils.current_ratio(ca=8000,cl=2000)
|
202
|
+
def self.current_ratio(ca:, cl:)
|
203
|
+
ca = DecNum(ca.to_s)
|
204
|
+
cl = DecNum(cl.to_s)
|
206
205
|
|
207
206
|
(ca / cl)
|
208
207
|
end
|
@@ -212,24 +211,23 @@ module Finrb
|
|
212
211
|
# @param cost cost of long-lived assets
|
213
212
|
# @param 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.
|
214
213
|
# @param t length of the useful life
|
215
|
-
# @
|
216
|
-
#
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
t = t.to_d
|
214
|
+
# @example
|
215
|
+
# Finrb::Utils.ddb(cost=1200,rv=200,t=5)
|
216
|
+
def self.ddb(cost:, rv:, t:)
|
217
|
+
cost = DecNum(cost.to_s)
|
218
|
+
rv = DecNum(rv.to_s)
|
219
|
+
t = DecNum(t.to_s)
|
222
220
|
|
223
221
|
raise(FinrbError, 't should be larger than 1') if t < 2
|
224
222
|
|
225
223
|
ddb = [0] * t
|
226
|
-
ddb[0] =
|
224
|
+
ddb[0] = cost * 2 / t
|
227
225
|
if cost - ddb[0] <= rv
|
228
226
|
ddb[0] = cost - rv
|
229
227
|
else
|
230
228
|
cost -= ddb[0]
|
231
229
|
(1...t).each do |i|
|
232
|
-
ddb[i] =
|
230
|
+
ddb[i] = cost * 2 / t
|
233
231
|
if cost - ddb[i] <= rv
|
234
232
|
ddb[i] = cost - rv
|
235
233
|
break
|
@@ -238,19 +236,18 @@ module Finrb
|
|
238
236
|
end
|
239
237
|
end
|
240
238
|
end
|
241
|
-
{ t: (0...t).to_a, ddb: }
|
239
|
+
{ t: (0...t).to_a, ddb: ddb }
|
242
240
|
end
|
243
241
|
|
244
242
|
# debt ratio -- Solvency ratios measure the firm's ability to satisfy its long-term obligations.
|
245
243
|
#
|
246
244
|
# @param td total debt
|
247
245
|
# @param ta total assets
|
248
|
-
# @
|
249
|
-
#
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
ta = ta.to_d
|
246
|
+
# @example
|
247
|
+
# Finrb::Utils.debt_ratio(td=6000,ta=20000)
|
248
|
+
def self.debt_ratio(td:, ta:)
|
249
|
+
td = DecNum(td.to_s)
|
250
|
+
ta = DecNum(ta.to_s)
|
254
251
|
|
255
252
|
(td / ta)
|
256
253
|
end
|
@@ -266,25 +263,27 @@ module Finrb
|
|
266
263
|
# @param cps shares from conversion of convertible preferred stock
|
267
264
|
# @param cds shares from conversion of convertible debt
|
268
265
|
# @param iss shares issuable from stock options
|
269
|
-
# @
|
270
|
-
#
|
271
|
-
#
|
272
|
-
#
|
273
|
-
#
|
274
|
-
#
|
275
|
-
#
|
276
|
-
#
|
277
|
-
#
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
266
|
+
# @example
|
267
|
+
# Finrb::Utils.diluted_eps(ni=115600,pd=10000,cdi=42000,tax=0.4,w=200000,cds=60000)
|
268
|
+
#
|
269
|
+
# @example
|
270
|
+
# Finrb::Utils.diluted_eps(ni=115600,pd=10000,cpd=10000,w=200000,cps=40000)
|
271
|
+
#
|
272
|
+
# @example
|
273
|
+
# Finrb::Utils.diluted_eps(ni=115600,pd=10000,w=200000,iss=2500)
|
274
|
+
#
|
275
|
+
# @example
|
276
|
+
# Finrb::Utils.diluted_eps(ni=115600,pd=10000,cpd=10000,cdi=42000,tax=0.4,w=200000,cps=40000,cds=60000,iss=2500)
|
277
|
+
def self.diluted_eps(ni:, pd:, w:, cpd: 0, cdi: 0, tax: 0, cps: 0, cds: 0, iss: 0)
|
278
|
+
ni = DecNum(ni.to_s)
|
279
|
+
pd = DecNum(pd.to_s)
|
280
|
+
w = DecNum(w.to_s)
|
281
|
+
cpd = DecNum(cpd.to_s)
|
282
|
+
cdi = DecNum(cdi.to_s)
|
283
|
+
tax = DecNum(tax.to_s)
|
284
|
+
cps = DecNum(cps.to_s)
|
285
|
+
cds = DecNum(cds.to_s)
|
286
|
+
iss = DecNum(iss.to_s)
|
288
287
|
|
289
288
|
basic = (ni - pd) / w
|
290
289
|
diluted = (ni - pd + cpd + (cdi * (1 - tax))) / (w + cps + cds + iss)
|
@@ -301,23 +300,22 @@ module Finrb
|
|
301
300
|
# @param type payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)
|
302
301
|
# @param lower the lower end points of the rate of return to be searched.
|
303
302
|
# @param upper the upper end points of the rate of return to be searched.
|
304
|
-
# @
|
305
|
-
#
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
lower = lower.to_d
|
315
|
-
upper = upper.to_d
|
303
|
+
# @example
|
304
|
+
# Finrb::Utils.discount_rate(n=5,pv=0,fv=600,pmt=-100,type=0)
|
305
|
+
def self.discount_rate(n:, pv:, fv:, pmt:, type: 0, lower: 0.0001, upper: 100)
|
306
|
+
n = DecNum(n.to_s)
|
307
|
+
pv = DecNum(pv.to_s)
|
308
|
+
fv = DecNum(fv.to_s)
|
309
|
+
pmt = DecNum(pmt.to_s)
|
310
|
+
type = DecNum(type.to_s)
|
311
|
+
lower = DecNum(lower.to_s)
|
312
|
+
upper = DecNum(upper.to_s)
|
316
313
|
|
317
314
|
nlfunc = NlFunctionStub.new
|
318
|
-
nlfunc.func =
|
319
|
-
|
320
|
-
|
315
|
+
nlfunc.func =
|
316
|
+
lambda do |x|
|
317
|
+
[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)]
|
318
|
+
end
|
321
319
|
|
322
320
|
root = [(upper - lower) / 2]
|
323
321
|
nlsolve(nlfunc, root)
|
@@ -328,97 +326,100 @@ module Finrb
|
|
328
326
|
#
|
329
327
|
# @param r stated annual rate
|
330
328
|
# @param m number of compounding periods per year
|
331
|
-
# @
|
332
|
-
#
|
333
|
-
# ear(r=0.12,m=12)
|
329
|
+
# @example
|
330
|
+
# Finrb::Utils.ear(r=0.12,m=12)
|
334
331
|
#
|
335
|
-
#
|
336
|
-
|
337
|
-
|
338
|
-
|
332
|
+
# @example
|
333
|
+
# Finrb::Utils.ear(0.04,365)
|
334
|
+
def self.ear(r:, m:)
|
335
|
+
r = DecNum(r.to_s)
|
336
|
+
m = DecNum(m.to_s)
|
339
337
|
|
340
|
-
(((
|
338
|
+
((((r / m) + 1)**m) - 1)
|
341
339
|
end
|
342
340
|
|
343
341
|
# Convert stated annual rate to the effective annual rate with continuous compounding
|
344
342
|
#
|
345
343
|
# @param r stated annual rate
|
346
|
-
# @
|
347
|
-
#
|
348
|
-
# Finrb::Utils.ear_continuous(r=0.1)
|
344
|
+
# @example
|
345
|
+
# Finrb::Utils.ear_continuous(r=0.1)
|
349
346
|
#
|
350
|
-
#
|
351
|
-
|
352
|
-
|
347
|
+
# @example
|
348
|
+
# Finrb::Utils.ear_continuous(0.03)
|
349
|
+
def self.ear_continuous(r:)
|
350
|
+
r = DecNum(r.to_s)
|
353
351
|
|
354
|
-
(r.
|
352
|
+
(r.to_dec.exp - 1)
|
355
353
|
end
|
356
354
|
|
357
355
|
# bond-equivalent yield (BEY), 2 x the semiannual discount rate
|
358
356
|
#
|
359
357
|
# @param ear effective annual rate
|
360
|
-
# @
|
361
|
-
#
|
362
|
-
|
363
|
-
|
364
|
-
ear = ear.to_d
|
358
|
+
# @example
|
359
|
+
# Finrb::Utils.ear2bey(ear=0.08)
|
360
|
+
def self.ear2bey(ear:)
|
361
|
+
ear = DecNum(ear.to_s)
|
365
362
|
|
366
|
-
((((
|
363
|
+
((((ear + 1)**0.5) - 1) * 2)
|
367
364
|
end
|
368
365
|
|
369
366
|
# Computing HPR, the holding period return
|
370
367
|
#
|
371
368
|
# @param ear effective annual rate
|
372
369
|
# @param t number of days remaining until maturity
|
373
|
-
# @
|
374
|
-
#
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
(((1 + ear)**(t / 365)) - 1)
|
370
|
+
# @example
|
371
|
+
# Finrb::Utils.ear2hpr(ear=0.05039,t=150)
|
372
|
+
def self.ear2hpr(ear:, t:)
|
373
|
+
ear = DecNum(ear.to_s)
|
374
|
+
t = DecNum(t.to_s)
|
375
|
+
|
376
|
+
(((ear + 1)**(t / 365)) - 1)
|
381
377
|
end
|
382
378
|
|
383
379
|
# Equivalent/proportional Interest Rates
|
384
|
-
# @
|
380
|
+
# @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.
|
385
381
|
# @param r interest rate to be applied n times per year (r is annual rate!)
|
386
382
|
# @param n times that the interest rate r were compounded per year
|
387
383
|
# @param p times that the equivalent rate were compounded per year
|
388
384
|
# @param type equivalent interest rates ('e',default) or proportional interest rates ('p')
|
389
|
-
# @
|
390
|
-
#
|
391
|
-
#
|
392
|
-
#
|
393
|
-
#
|
394
|
-
#
|
395
|
-
#
|
396
|
-
#
|
397
|
-
#
|
398
|
-
#
|
399
|
-
#
|
400
|
-
#
|
401
|
-
#
|
402
|
-
#
|
403
|
-
#
|
404
|
-
#
|
405
|
-
#
|
406
|
-
#
|
407
|
-
#
|
408
|
-
#
|
409
|
-
#
|
410
|
-
#
|
411
|
-
#
|
412
|
-
#
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
385
|
+
# @example
|
386
|
+
# # monthly interest rat equivalent to 5% compounded per year
|
387
|
+
# Finrb::Utils.eir(r=0.05,n=1,p=12)
|
388
|
+
#
|
389
|
+
# @example
|
390
|
+
# # monthly interest rat equivalent to 5% compounded per half year
|
391
|
+
# Finrb::Utils.eir(r=0.05,n=2,p=12)
|
392
|
+
#
|
393
|
+
# @example
|
394
|
+
# # monthly interest rat equivalent to 5% compounded per quarter
|
395
|
+
# Finrb::Utils.eir(r=0.05,n=4,p=12)
|
396
|
+
#
|
397
|
+
# @example
|
398
|
+
# # annual interest rate equivalent to 5% compounded per month
|
399
|
+
# Finrb::Utils.eir(r=0.05,n=12,p=1)
|
400
|
+
# # this is equivalent to
|
401
|
+
# Finrb::Utils.ear(r=0.05,m=12)
|
402
|
+
#
|
403
|
+
# @example
|
404
|
+
# # quarter interest rate equivalent to 5% compounded per year
|
405
|
+
# Finrb::Utils.eir(r=0.05,n=1,p=4)
|
406
|
+
#
|
407
|
+
# @example
|
408
|
+
# # quarter interest rate equivalent to 5% compounded per month
|
409
|
+
# Finrb::Utils.eir(r=0.05,n=12,p=4)
|
410
|
+
#
|
411
|
+
# @example
|
412
|
+
# # monthly proportional interest rate which is equivalent to a simple annual interest
|
413
|
+
# Finrb::Utils.eir(r=0.05,p=12,type='p')
|
414
|
+
def self.eir(r:, n: 1, p: 12, type: 'e')
|
415
|
+
r = DecNum(r.to_s)
|
416
|
+
n = DecNum(n.to_s)
|
417
|
+
p = DecNum(p.to_s)
|
417
418
|
type = type.to_s
|
418
419
|
|
419
420
|
case type
|
420
421
|
when 'e'
|
421
|
-
eir = ((
|
422
|
+
eir = (((r / n) + 1)**(n / p)) - 1
|
422
423
|
when 'p'
|
423
424
|
eir = r / p
|
424
425
|
else
|
@@ -432,13 +433,12 @@ module Finrb
|
|
432
433
|
# @param ni net income
|
433
434
|
# @param pd preferred dividends
|
434
435
|
# @param w weighted average number of common shares outstanding
|
435
|
-
# @
|
436
|
-
#
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
w = w.to_d
|
436
|
+
# @example
|
437
|
+
# Finrb::Utils.eps(ni=10000,pd=1000,w=11000)
|
438
|
+
def self.eps(ni:, pd:, w:)
|
439
|
+
ni = DecNum(ni.to_s)
|
440
|
+
pd = DecNum(pd.to_s)
|
441
|
+
w = DecNum(w.to_s)
|
442
442
|
|
443
443
|
((ni - pd) / w)
|
444
444
|
end
|
@@ -447,12 +447,11 @@ module Finrb
|
|
447
447
|
#
|
448
448
|
# @param te total equity
|
449
449
|
# @param ta total assets
|
450
|
-
# @
|
451
|
-
#
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
ta = ta.to_d
|
450
|
+
# @example
|
451
|
+
# Finrb::Utils.financial_leverage(te=16000,ta=20000)
|
452
|
+
def self.financial_leverage(te:, ta:)
|
453
|
+
te = DecNum(te.to_s)
|
454
|
+
ta = DecNum(ta.to_s)
|
456
455
|
|
457
456
|
(ta / te)
|
458
457
|
end
|
@@ -464,20 +463,19 @@ module Finrb
|
|
464
463
|
# @param pv present value
|
465
464
|
# @param pmt payment per period
|
466
465
|
# @param type payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)
|
467
|
-
# @
|
468
|
-
#
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
type = type.to_d
|
466
|
+
# @example
|
467
|
+
# Finrb::Utils.fv(r=0.07,n=10,pv=1000,pmt=10)
|
468
|
+
def self.fv(r:, n:, pv: 0, pmt: 0, type: 0)
|
469
|
+
r = DecNum(r.to_s)
|
470
|
+
n = DecNum(n.to_s)
|
471
|
+
pv = DecNum(pv.to_s)
|
472
|
+
pmt = DecNum(pmt.to_s)
|
473
|
+
type = DecNum(type.to_s)
|
476
474
|
|
477
475
|
if type != 0 && type != 1
|
478
476
|
raise(FinrbError, 'Error: type should be 0 or 1!')
|
479
477
|
else
|
480
|
-
(Finrb::Utils.fv_simple(r, n, pv) + Finrb::Utils.fv_annuity(r, n, pmt, type))
|
478
|
+
(Finrb::Utils.fv_simple(r: r, n: n, pv: pv) + Finrb::Utils.fv_annuity(r: r, n: n, pmt: pmt, type: type))
|
481
479
|
end
|
482
480
|
end
|
483
481
|
|
@@ -487,21 +485,21 @@ module Finrb
|
|
487
485
|
# @param n number of periods
|
488
486
|
# @param pmt payment per period
|
489
487
|
# @param type payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)
|
490
|
-
# @
|
491
|
-
#
|
492
|
-
# Finrb::Utils.fv_annuity(0.03,12,-1000)
|
488
|
+
# @example
|
489
|
+
# Finrb::Utils.fv_annuity(0.03,12,-1000)
|
493
490
|
#
|
494
|
-
#
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
491
|
+
# @example
|
492
|
+
# Finrb::Utils.fv_annuity(r=0.03,n=12,pmt=-1000,type=1)
|
493
|
+
def self.fv_annuity(r:, n:, pmt:, type: 0)
|
494
|
+
r = DecNum(r.to_s)
|
495
|
+
n = DecNum(n.to_s)
|
496
|
+
pmt = DecNum(pmt.to_s)
|
497
|
+
type = DecNum(type.to_s)
|
500
498
|
|
501
499
|
if type != 0 && type != 1
|
502
500
|
raise(FinrbError, 'Error: type should be 0 or 1!')
|
503
501
|
else
|
504
|
-
(pmt / r * (((
|
502
|
+
(pmt / r * (((r + 1)**n) - 1)) * ((r + 1)**type) * -1
|
505
503
|
|
506
504
|
end
|
507
505
|
end
|
@@ -511,35 +509,34 @@ module Finrb
|
|
511
509
|
# @param r discount rate, or the interest rate at which the amount will be compounded each period
|
512
510
|
# @param n number of periods
|
513
511
|
# @param pv present value
|
514
|
-
# @
|
515
|
-
#
|
516
|
-
# Finrb::Utils.fv_simple(0.08,10,-300)
|
512
|
+
# @example
|
513
|
+
# Finrb::Utils.fv_simple(0.08,10,-300)
|
517
514
|
#
|
518
|
-
#
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
515
|
+
# @example
|
516
|
+
# Finrb::Utils.fv_simple(r=0.04,n=20,pv=-50000)
|
517
|
+
def self.fv_simple(r:, n:, pv:)
|
518
|
+
r = DecNum(r.to_s)
|
519
|
+
n = DecNum(n.to_s)
|
520
|
+
pv = DecNum(pv.to_s)
|
523
521
|
|
524
|
-
((pv * ((
|
522
|
+
((pv * ((r + 1)**n)) * -1)
|
525
523
|
end
|
526
524
|
|
527
525
|
# Computing the future value of an uneven cash flow series
|
528
526
|
#
|
529
527
|
# @param r stated annual rate
|
530
528
|
# @param cf uneven cash flow
|
531
|
-
# @
|
532
|
-
#
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
cf = Array.wrap(cf).map(&:to_d)
|
529
|
+
# @example
|
530
|
+
# Finrb::Utils.fv_uneven(r=0.1, cf=[-1000, -500, 0, 4000, 3500, 2000])
|
531
|
+
def self.fv_uneven(r:, cf:)
|
532
|
+
r = DecNum(r.to_s)
|
533
|
+
cf = Array.wrap(cf).map { |value| DecNum(value.to_s) }
|
537
534
|
|
538
535
|
m = cf.size
|
539
536
|
sum = 0
|
540
537
|
(0...m).each do |i|
|
541
|
-
n = m - i
|
542
|
-
sum += Finrb::Utils.fv_simple(r, n, cf[i])
|
538
|
+
n = m - (i + 1)
|
539
|
+
sum += Finrb::Utils.fv_simple(r: r, n: n, pv: cf[i])
|
543
540
|
end
|
544
541
|
sum
|
545
542
|
end
|
@@ -547,39 +544,36 @@ module Finrb
|
|
547
544
|
# Geometric mean return
|
548
545
|
#
|
549
546
|
# @param r returns over multiple periods
|
550
|
-
# @
|
551
|
-
#
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
rs
|
557
|
-
((rs.reduce(:*)**(1 / rs.size)) - 1)
|
547
|
+
# @example
|
548
|
+
# Finrb::Utils.geometric_mean(r=[-0.0934, 0.2345, 0.0892])
|
549
|
+
def self.geometric_mean(r:)
|
550
|
+
r = Array.wrap(r).map { |value| DecNum(value.to_s) }
|
551
|
+
|
552
|
+
rs = r.map { |value| value + 1 }
|
553
|
+
((rs.reduce(:*)**(1.to_f / rs.size)) - 1)
|
558
554
|
end
|
559
555
|
|
560
556
|
# gross profit margin -- Evaluate a company's financial performance
|
561
557
|
#
|
562
558
|
# @param gp gross profit, equal to revenue minus cost of goods sold (cogs)
|
563
559
|
# @param rv revenue (sales)
|
564
|
-
# @
|
565
|
-
#
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
rv = rv.to_d
|
560
|
+
# @example
|
561
|
+
# Finrb::Utils.gpm(gp=1000,rv=20000)
|
562
|
+
def self.gpm(gp:, rv:)
|
563
|
+
gp = DecNum(gp.to_s)
|
564
|
+
rv = DecNum(rv.to_s)
|
570
565
|
|
571
566
|
(gp / rv)
|
572
567
|
end
|
573
568
|
|
574
569
|
# harmonic mean, average price
|
575
570
|
# @param p price over multiple periods
|
576
|
-
# @
|
577
|
-
#
|
578
|
-
|
579
|
-
|
580
|
-
p = Array.wrap(p).map(&:to_d)
|
571
|
+
# @example
|
572
|
+
# Finrb::Utils.harmonic_mean(p=[8,9,10])
|
573
|
+
def self.harmonic_mean(p:)
|
574
|
+
p = Array.wrap(p).map { |value| DecNum(value.to_s) }
|
581
575
|
|
582
|
-
(1 / (p.sum { |val| 1 / val } / p.size))
|
576
|
+
(1.to_f / (p.sum { |val| 1.to_f / val } / p.size))
|
583
577
|
end
|
584
578
|
|
585
579
|
# Computing HPR, the holding period return
|
@@ -587,13 +581,12 @@ module Finrb
|
|
587
581
|
# @param ev ending value
|
588
582
|
# @param bv beginning value
|
589
583
|
# @param cfr cash flow received
|
590
|
-
# @
|
591
|
-
#
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
cfr = cfr.to_d
|
584
|
+
# @example
|
585
|
+
# Finrb::Utils.hpr(ev=33,bv=30,cfr=0.5)
|
586
|
+
def self.hpr(ev:, bv:, cfr: 0)
|
587
|
+
ev = DecNum(ev.to_s)
|
588
|
+
bv = DecNum(bv.to_s)
|
589
|
+
cfr = DecNum(cfr.to_s)
|
597
590
|
|
598
591
|
((ev - bv + cfr) / bv)
|
599
592
|
end
|
@@ -602,122 +595,72 @@ module Finrb
|
|
602
595
|
#
|
603
596
|
# @param hpr holding period return
|
604
597
|
# @param t number of month remaining until maturity
|
605
|
-
# @
|
606
|
-
#
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
((((1 + hpr)**(6 / t)) - 1) * 2)
|
598
|
+
# @example
|
599
|
+
# Finrb::Utils.hpr2bey(hpr=0.02,t=3)
|
600
|
+
def self.hpr2bey(hpr:, t:)
|
601
|
+
hpr = DecNum(hpr.to_s)
|
602
|
+
t = DecNum(t.to_s)
|
603
|
+
|
604
|
+
((((hpr + 1)**(6 / t)) - 1) * 2)
|
613
605
|
end
|
614
606
|
|
615
607
|
# Convert holding period return to the effective annual rate
|
616
608
|
#
|
617
609
|
# @param hpr holding period return
|
618
610
|
# @param t number of days remaining until maturity
|
619
|
-
# @
|
620
|
-
#
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
(((1 + hpr)**(365 / t)) - 1)
|
611
|
+
# @example
|
612
|
+
# Finrb::Utils.hpr2ear(hpr=0.015228,t=120)
|
613
|
+
def self.hpr2ear(hpr:, t:)
|
614
|
+
hpr = DecNum(hpr.to_s)
|
615
|
+
t = DecNum(t.to_s)
|
616
|
+
|
617
|
+
(((hpr + 1)**(365 / t)) - 1)
|
627
618
|
end
|
628
619
|
|
629
620
|
# Computing money market yield (MMY) for a T-bill
|
630
621
|
#
|
631
622
|
# @param hpr holding period return
|
632
623
|
# @param t number of days remaining until maturity
|
633
|
-
# @
|
634
|
-
#
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
(360 * hpr / t)
|
624
|
+
# @example
|
625
|
+
# Finrb::Utils.hpr2mmy(hpr=0.01523,t=120)
|
626
|
+
def self.hpr2mmy(hpr:, t:)
|
627
|
+
hpr = DecNum(hpr.to_s)
|
628
|
+
t = DecNum(t.to_s)
|
629
|
+
|
630
|
+
(hpr * 360 / t)
|
641
631
|
end
|
642
632
|
|
643
633
|
# Computing IRR, the internal rate of return
|
644
634
|
#
|
645
635
|
# @param cf cash flow,the first cash flow is the initial outlay
|
646
|
-
# @
|
647
|
-
#
|
648
|
-
|
649
|
-
|
650
|
-
def self.irr(cf)
|
651
|
-
cf = Array.wrap(cf).map(&:to_d)
|
636
|
+
# @example
|
637
|
+
# Finrb::Utils.irr(cf=[-5, 1.6, 2.4, 2.8])
|
638
|
+
def self.irr(cf:)
|
639
|
+
cf = Array.wrap(cf).map { |value| DecNum(value.to_s) }
|
652
640
|
|
653
|
-
n = cf.size
|
654
641
|
subcf = cf.drop(1)
|
655
|
-
|
656
642
|
nlfunc = NlFunctionStub.new
|
657
|
-
nlfunc.func =
|
658
|
-
|
659
|
-
|
643
|
+
nlfunc.func =
|
644
|
+
lambda do |x|
|
645
|
+
[BigDecimal(((Finrb::Utils.pv_uneven(r: x[0], cf: subcf) * -1) + cf[0]).to_s)]
|
646
|
+
end
|
660
647
|
|
661
648
|
root = [0]
|
662
649
|
nlsolve(nlfunc, root)
|
663
650
|
root[0]
|
664
651
|
end
|
665
652
|
|
666
|
-
# Computing IRR, the internal rate of return
|
667
|
-
# @description This function is the same as irr but can calculate negative value. This function may take a very long time. You can use larger cutoff and larger step to get a less precision irr first. Then based on the result, change from and to, to narrow down the interval, and use a smaller step to get a more precision irr.
|
668
|
-
# @param cf cash flow,the first cash flow is the initial outlay
|
669
|
-
# @param cutoff threshold to take npv as zero
|
670
|
-
# @param from smallest irr to try
|
671
|
-
# @param to largest irr to try
|
672
|
-
# @param step increment of the irr
|
673
|
-
# @export
|
674
|
-
# @examples
|
675
|
-
# irr2(cf=c(-5, 1.6, 2.4, 2.8))
|
676
|
-
# irr2(cf=c(-200, 50, 60, -70, 30, 20))
|
677
|
-
def self.irr2(cf, cutoff = 0.1, from = -1, to = 10, step = 0.000001)
|
678
|
-
cf = Array.wrap(cf).map(&:to_d)
|
679
|
-
cutoff = cutoff.to_d
|
680
|
-
from = from.to_d
|
681
|
-
to = to.to_d
|
682
|
-
step = step.to_d
|
683
|
-
|
684
|
-
r0 = nil
|
685
|
-
n = cf.size
|
686
|
-
from.step((to - 1), step).each do |r|
|
687
|
-
npv = cf[0]
|
688
|
-
(1...n).each do |i|
|
689
|
-
npv += (cf[i] / ((1 + r)**(i - 1)))
|
690
|
-
end
|
691
|
-
next if npv.nil?
|
692
|
-
|
693
|
-
if npv.abs < cutoff
|
694
|
-
r0 = r
|
695
|
-
break
|
696
|
-
end
|
697
|
-
end
|
698
|
-
|
699
|
-
if r0.nil?
|
700
|
-
raise(
|
701
|
-
FinrbError,
|
702
|
-
'can not find irr in the given interval, you can try smaller step, and/or larger to, and/or larger cutoff'
|
703
|
-
)
|
704
|
-
end
|
705
|
-
|
706
|
-
r0
|
707
|
-
end
|
708
|
-
|
709
653
|
# calculate the net increase in common shares from the potential exercise of stock options or warrants
|
710
654
|
#
|
711
655
|
# @param amp average market price over the year
|
712
656
|
# @param ep exercise price of the options or warrants
|
713
657
|
# @param n number of common shares that the options and warrants can be convened into
|
714
|
-
# @
|
715
|
-
#
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
n = n.to_d
|
658
|
+
# @example
|
659
|
+
# Finrb::Utils.iss(amp=20,ep=15,n=10000)
|
660
|
+
def self.iss(amp:, ep:, n:)
|
661
|
+
amp = DecNum(amp.to_s)
|
662
|
+
ep = DecNum(ep.to_s)
|
663
|
+
n = DecNum(n.to_s)
|
721
664
|
|
722
665
|
if amp > ep
|
723
666
|
((amp - ep) * n / amp)
|
@@ -730,12 +673,11 @@ module Finrb
|
|
730
673
|
#
|
731
674
|
# @param ltd long-term debt
|
732
675
|
# @param te total equity
|
733
|
-
# @
|
734
|
-
#
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
te = te.to_d
|
676
|
+
# @example
|
677
|
+
# Finrb::Utils.lt_d2e(ltd=8000,te=20000)
|
678
|
+
def self.lt_d2e(ltd:, te:)
|
679
|
+
ltd = DecNum(ltd.to_s)
|
680
|
+
te = DecNum(te.to_s)
|
739
681
|
|
740
682
|
(ltd / te)
|
741
683
|
end
|
@@ -744,12 +686,11 @@ module Finrb
|
|
744
686
|
#
|
745
687
|
# @param mmy money market yield
|
746
688
|
# @param t number of days remaining until maturity
|
747
|
-
# @
|
748
|
-
#
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
t = t.to_d
|
689
|
+
# @example
|
690
|
+
# Finrb::Utils.mmy2hpr(mmy=0.04898,t=150)
|
691
|
+
def self.mmy2hpr(mmy:, t:)
|
692
|
+
mmy = DecNum(mmy.to_s)
|
693
|
+
t = DecNum(t.to_s)
|
753
694
|
|
754
695
|
(mmy * t / 360)
|
755
696
|
end
|
@@ -761,22 +702,22 @@ module Finrb
|
|
761
702
|
# @param fv future value
|
762
703
|
# @param pmt payment per period
|
763
704
|
# @param type payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)
|
764
|
-
# @
|
765
|
-
#
|
766
|
-
#
|
767
|
-
#
|
768
|
-
#
|
769
|
-
def self.n_period(r
|
770
|
-
r = r.
|
771
|
-
pv = pv.
|
772
|
-
fv = fv.
|
773
|
-
pmt = pmt.
|
774
|
-
type = type.
|
705
|
+
# @example
|
706
|
+
# Finrb::Utils.n_period(0.1,-10000,60000000,-50000,0)
|
707
|
+
#
|
708
|
+
# @example
|
709
|
+
# Finrb::Utils.n_period(r=0.1,pv=-10000,fv=60000000,pmt=-50000,type=1)
|
710
|
+
def self.n_period(r:, pv:, fv:, pmt:, type: 0)
|
711
|
+
r = DecNum(r.to_s)
|
712
|
+
pv = DecNum(pv.to_s)
|
713
|
+
fv = DecNum(fv.to_s)
|
714
|
+
pmt = DecNum(pmt.to_s)
|
715
|
+
type = DecNum(type.to_s)
|
775
716
|
|
776
717
|
if type != 0 && type != 1
|
777
718
|
raise(FinrbError, 'Error: type should be 0 or 1!')
|
778
719
|
else
|
779
|
-
(
|
720
|
+
(((fv * r) - (pmt * ((r + 1)**type))) * -1 / ((pv * r) + (pmt * ((r + 1)**type)))).to_dec.log / (r + 1).to_dec.log
|
780
721
|
|
781
722
|
end
|
782
723
|
end
|
@@ -785,12 +726,11 @@ module Finrb
|
|
785
726
|
#
|
786
727
|
# @param ni net income
|
787
728
|
# @param rv revenue (sales)
|
788
|
-
# @
|
789
|
-
#
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
rv = rv.to_d
|
729
|
+
# @example
|
730
|
+
# Finrb::Utils.npm(ni=8000,rv=20000)
|
731
|
+
def self.npm(ni:, rv:)
|
732
|
+
ni = DecNum(ni.to_s)
|
733
|
+
rv = DecNum(rv.to_s)
|
794
734
|
|
795
735
|
(ni / rv)
|
796
736
|
end
|
@@ -799,16 +739,14 @@ module Finrb
|
|
799
739
|
#
|
800
740
|
# @param r discount rate, or the interest rate at which the amount will be compounded each period
|
801
741
|
# @param cf cash flow,the first cash flow is the initial outlay
|
802
|
-
# @
|
803
|
-
#
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
cf = Array.wrap(cf).map(&:to_d)
|
742
|
+
# @example
|
743
|
+
# Finrb::Utils.npv(r=0.12, cf=[-5, 1.6, 2.4, 2.8])
|
744
|
+
def self.npv(r:, cf:)
|
745
|
+
r = DecNum(r.to_s)
|
746
|
+
cf = Array.wrap(cf).map { |value| DecNum(value.to_s) }
|
808
747
|
|
809
|
-
n = cf.size
|
810
748
|
subcf = cf.drop(1)
|
811
|
-
((
|
749
|
+
((Finrb::Utils.pv_uneven(r: r, cf: subcf) * -1) + cf[0])
|
812
750
|
end
|
813
751
|
|
814
752
|
# Estimate period payment
|
@@ -818,25 +756,25 @@ module Finrb
|
|
818
756
|
# @param pv present value
|
819
757
|
# @param fv future value
|
820
758
|
# @param type payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)
|
821
|
-
# @
|
822
|
-
#
|
823
|
-
# pmt(0.08,10,-1000,10)
|
759
|
+
# @example
|
760
|
+
# Finrb::Utils.pmt(0.08,10,-1000,10)
|
824
761
|
#
|
825
|
-
#
|
762
|
+
# @example
|
763
|
+
# Finrb::Utils.pmt(r=0.08,n=10,pv=-1000,fv=0)
|
826
764
|
#
|
827
|
-
#
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
765
|
+
# @example
|
766
|
+
# Finrb::Utils.pmt(0.08,10,-1000,10,1)
|
767
|
+
def self.pmt(r:, n:, pv:, fv:, type: 0)
|
768
|
+
r = DecNum(r.to_s)
|
769
|
+
n = DecNum(n.to_s)
|
770
|
+
pv = DecNum(pv.to_s)
|
771
|
+
fv = DecNum(fv.to_s)
|
772
|
+
type = DecNum(type.to_s)
|
834
773
|
|
835
774
|
if type != 0 && type != 1
|
836
775
|
raise(FinrbError, 'Error: type should be 0 or 1!')
|
837
776
|
else
|
838
|
-
(pv + (fv / ((
|
839
|
-
|
777
|
+
(pv + (fv / ((r + 1)**n))) * r / (1 - (1.to_f / ((r + 1)**n))) * -1 * ((r + 1)**(type * -1))
|
840
778
|
end
|
841
779
|
end
|
842
780
|
|
@@ -847,22 +785,22 @@ module Finrb
|
|
847
785
|
# @param fv future value
|
848
786
|
# @param pmt payment per period
|
849
787
|
# @param type payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)
|
850
|
-
# @
|
851
|
-
#
|
852
|
-
#
|
853
|
-
#
|
854
|
-
#
|
855
|
-
def self.pv(r
|
856
|
-
r = r.
|
857
|
-
n = n.
|
858
|
-
fv = fv.
|
859
|
-
pmt = pmt.
|
860
|
-
type = type.
|
788
|
+
# @example
|
789
|
+
# Finrb::Utils.pv(0.07,10,1000,10)
|
790
|
+
#
|
791
|
+
# @example
|
792
|
+
# Finrb::Utils.pv(r=0.05,n=20,fv=1000,pmt=10,type=1)
|
793
|
+
def self.pv(r:, n:, fv: 0, pmt: 0, type: 0)
|
794
|
+
r = DecNum(r.to_s)
|
795
|
+
n = DecNum(n.to_s)
|
796
|
+
fv = DecNum(fv.to_s)
|
797
|
+
pmt = DecNum(pmt.to_s)
|
798
|
+
type = DecNum(type.to_s)
|
861
799
|
|
862
800
|
if type != 0 && type != 1
|
863
801
|
raise(FinrbError, 'Error: type should be 0 or 1!')
|
864
802
|
else
|
865
|
-
Finrb::Utils.pv_simple(r, n, fv) + Finrb::Utils.pv_annuity(r, n, pmt, type)
|
803
|
+
Finrb::Utils.pv_simple(r: r, n: n, fv: fv) + Finrb::Utils.pv_annuity(r: r, n: n, pmt: pmt, type: type)
|
866
804
|
|
867
805
|
end
|
868
806
|
end
|
@@ -873,21 +811,21 @@ module Finrb
|
|
873
811
|
# @param n number of periods
|
874
812
|
# @param pmt payment per period
|
875
813
|
# @param type payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)
|
876
|
-
# @
|
877
|
-
#
|
878
|
-
# Finrb::Utils.pv_annuity(0.03,12,1000)
|
814
|
+
# @example
|
815
|
+
# Finrb::Utils.pv_annuity(0.03,12,1000)
|
879
816
|
#
|
880
|
-
#
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
817
|
+
# @example
|
818
|
+
# Finrb::Utils.pv_annuity(r=0.0425,n=3,pmt=30000)
|
819
|
+
def self.pv_annuity(r:, n:, pmt:, type: 0)
|
820
|
+
r = DecNum(r.to_s)
|
821
|
+
n = DecNum(n.to_s)
|
822
|
+
pmt = DecNum(pmt.to_s)
|
823
|
+
type = DecNum(type.to_s)
|
886
824
|
|
887
825
|
if type != 0 && type != 1
|
888
826
|
raise(FinrbError, 'Error: type should be 0 or 1!')
|
889
827
|
else
|
890
|
-
(pmt / r * (1 - (1 / ((
|
828
|
+
(pmt / r * (1 - (1.to_f / ((r + 1)**n)))) * ((r + 1)**type) * -1
|
891
829
|
|
892
830
|
end
|
893
831
|
end
|
@@ -898,25 +836,26 @@ module Finrb
|
|
898
836
|
# @param g growth rate of perpetuity
|
899
837
|
# @param pmt payment per period
|
900
838
|
# @param type payments occur at the end of each period (type=0); payments occur at the beginning of each period (type=1)
|
901
|
-
# @
|
902
|
-
#
|
903
|
-
# Finrb::Utils.pv_perpetuity(r=0.1,pmt=1000,g=0.02)
|
839
|
+
# @example
|
840
|
+
# Finrb::Utils.pv_perpetuity(r=0.1,pmt=1000,g=0.02)
|
904
841
|
#
|
905
|
-
#
|
842
|
+
# @example
|
843
|
+
# Finrb::Utils.pv_perpetuity(r=0.1,pmt=1000,type=1)
|
906
844
|
#
|
907
|
-
#
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
845
|
+
# @example
|
846
|
+
# Finrb::Utils.pv_perpetuity(r=0.1,pmt=1000)
|
847
|
+
def self.pv_perpetuity(r:, pmt:, g: 0, type: 0)
|
848
|
+
r = DecNum(r.to_s)
|
849
|
+
pmt = DecNum(pmt.to_s)
|
850
|
+
g = DecNum(g.to_s)
|
851
|
+
type = DecNum(type.to_s)
|
913
852
|
|
914
853
|
if type != 0 && type != 1
|
915
854
|
raise(FinrbError, 'Error: type should be 0 or 1!')
|
916
855
|
elsif g >= r
|
917
856
|
raise(FinrbError, 'Error: g is not smaller than r!')
|
918
857
|
else
|
919
|
-
(pmt / (r - g)) * ((
|
858
|
+
(pmt / (r - g)) * ((r + 1)**type) * -1
|
920
859
|
|
921
860
|
end
|
922
861
|
end
|
@@ -926,34 +865,33 @@ module Finrb
|
|
926
865
|
# @param r discount rate, or the interest rate at which the amount will be compounded each period
|
927
866
|
# @param n number of periods
|
928
867
|
# @param fv future value
|
929
|
-
# @
|
930
|
-
#
|
931
|
-
# Finrb::Utils.pv_simple(0.07,10,100)
|
868
|
+
# @example
|
869
|
+
# Finrb::Utils.pv_simple(0.07,10,100)
|
932
870
|
#
|
933
|
-
#
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
871
|
+
# @example
|
872
|
+
# Finrb::Utils.pv_simple(r=0.03,n=3,fv=1000)
|
873
|
+
def self.pv_simple(r:, n:, fv:)
|
874
|
+
r = DecNum(r.to_s)
|
875
|
+
n = DecNum(n.to_s)
|
876
|
+
fv = DecNum(fv.to_s)
|
938
877
|
|
939
|
-
((fv / ((
|
878
|
+
((fv / ((r + 1)**n)) * -1)
|
940
879
|
end
|
941
880
|
|
942
881
|
# Computing the present value of an uneven cash flow series
|
943
882
|
#
|
944
883
|
# @param r discount rate, or the interest rate at which the amount will be compounded each period
|
945
884
|
# @param cf uneven cash flow
|
946
|
-
# @
|
947
|
-
#
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
cf = Array.wrap(cf).map(&:to_d)
|
885
|
+
# @example
|
886
|
+
# Finrb::Utils.pv_uneven(r=0.1, cf=[-1000, -500, 0, 4000, 3500, 2000])
|
887
|
+
def self.pv_uneven(r:, cf:)
|
888
|
+
r = DecNum(r.to_s)
|
889
|
+
cf = Array.wrap(cf).map { |value| DecNum(value.to_s) }
|
952
890
|
|
953
891
|
n = cf.size
|
954
892
|
sum = 0
|
955
893
|
(0...n).each do |i|
|
956
|
-
sum += Finrb::Utils.pv_simple(r, i, cf[i])
|
894
|
+
sum += Finrb::Utils.pv_simple(r: r, n: i + 1, fv: cf[i])
|
957
895
|
end
|
958
896
|
sum
|
959
897
|
end
|
@@ -964,14 +902,13 @@ module Finrb
|
|
964
902
|
# @param ms marketable securities
|
965
903
|
# @param rc receivables
|
966
904
|
# @param cl current liabilities
|
967
|
-
# @
|
968
|
-
#
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
cl = cl.to_d
|
905
|
+
# @example
|
906
|
+
# Finrb::Utils.quick_ratio(cash=3000,ms=2000,rc=1000,cl=2000)
|
907
|
+
def self.quick_ratio(cash:, ms:, rc:, cl:)
|
908
|
+
cash = DecNum(cash.to_s)
|
909
|
+
ms = DecNum(ms.to_s)
|
910
|
+
rc = DecNum(rc.to_s)
|
911
|
+
cl = DecNum(cl.to_s)
|
975
912
|
|
976
913
|
((cash + ms + rc) / cl)
|
977
914
|
end
|
@@ -980,56 +917,53 @@ module Finrb
|
|
980
917
|
#
|
981
918
|
# @param r norminal rate
|
982
919
|
# @param m number of times compounded each year
|
983
|
-
# @
|
984
|
-
#
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
(m * (1 + (r / m)).to_d.log)
|
920
|
+
# @example
|
921
|
+
# Finrb::Utils.r_continuous(r=0.03,m=4)
|
922
|
+
def self.r_continuous(r:, m:)
|
923
|
+
r = DecNum(r.to_s)
|
924
|
+
m = DecNum(m.to_s)
|
925
|
+
|
926
|
+
(m * ((r / m) + 1).to_dec.log)
|
991
927
|
end
|
992
928
|
|
993
929
|
# Convert a given continuous compounded rate to a norminal rate
|
994
930
|
#
|
995
931
|
# @param rc continuous compounded rate
|
996
932
|
# @param m number of desired times compounded each year
|
997
|
-
# @
|
998
|
-
#
|
999
|
-
# Finrb::Utils.r_norminal(0.03,1)
|
933
|
+
# @example
|
934
|
+
# Finrb::Utils.r_norminal(0.03,1)
|
1000
935
|
#
|
1001
|
-
#
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
936
|
+
# @example
|
937
|
+
# Finrb::Utils.r_norminal(rc=0.03,m=4)
|
938
|
+
def self.r_norminal(rc:, m:)
|
939
|
+
rc = DecNum(rc.to_s)
|
940
|
+
m = DecNum(m.to_s)
|
1005
941
|
|
1006
|
-
(m * ((rc / m).
|
942
|
+
(m * ((rc / m).to_dec.exp - 1))
|
1007
943
|
end
|
1008
944
|
|
1009
945
|
# Rate of return for a perpetuity
|
1010
946
|
#
|
1011
947
|
# @param pmt payment per period
|
1012
948
|
# @param pv present value
|
1013
|
-
# @
|
1014
|
-
#
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
(-1 * pmt / pv)
|
949
|
+
# @example
|
950
|
+
# Finrb::Utils.r_perpetuity(pmt=4.5,pv=-75)
|
951
|
+
def self.r_perpetuity(pmt:, pv:)
|
952
|
+
pmt = DecNum(pmt.to_s)
|
953
|
+
pv = DecNum(pv.to_s)
|
954
|
+
|
955
|
+
(pmt * -1 / pv)
|
1021
956
|
end
|
1022
957
|
|
1023
958
|
# Computing Sampling error
|
1024
959
|
#
|
1025
960
|
# @param sm sample mean
|
1026
961
|
# @param mu population mean
|
1027
|
-
# @
|
1028
|
-
#
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
mu = mu.to_d
|
962
|
+
# @example
|
963
|
+
# Finrb::Utils.sampling_error(sm=0.45, mu=0.5)
|
964
|
+
def self.sampling_error(sm:, mu:)
|
965
|
+
sm = DecNum(sm.to_s)
|
966
|
+
mu = DecNum(mu.to_s)
|
1033
967
|
|
1034
968
|
(sm - mu)
|
1035
969
|
end
|
@@ -1039,13 +973,12 @@ module Finrb
|
|
1039
973
|
# @param rp portfolio return
|
1040
974
|
# @param rl threshold level return
|
1041
975
|
# @param sd standard deviation of portfolio retwns
|
1042
|
-
# @
|
1043
|
-
#
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
sd = sd.to_d
|
976
|
+
# @example
|
977
|
+
# Finrb::Utils.sf_ratio(rp=0.09,rl=0.03,sd=0.12)
|
978
|
+
def self.sf_ratio(rp:, rl:, sd:)
|
979
|
+
rp = DecNum(rp.to_s)
|
980
|
+
rl = DecNum(rl.to_s)
|
981
|
+
sd = DecNum(sd.to_s)
|
1049
982
|
|
1050
983
|
((rp - rl) / sd)
|
1051
984
|
end
|
@@ -1055,13 +988,12 @@ module Finrb
|
|
1055
988
|
# @param rp portfolio return
|
1056
989
|
# @param rf risk-free return
|
1057
990
|
# @param sd standard deviation of portfolio retwns
|
1058
|
-
# @
|
1059
|
-
#
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
sd = sd.to_d
|
991
|
+
# @example
|
992
|
+
# Finrb::Utils.sharpe_ratio(rp=0.038,rf=0.015,sd=0.07)
|
993
|
+
def self.sharpe_ratio(rp:, rf:, sd:)
|
994
|
+
rp = DecNum(rp.to_s)
|
995
|
+
rf = DecNum(rf.to_s)
|
996
|
+
sd = DecNum(sd.to_s)
|
1065
997
|
|
1066
998
|
((rp - rf) / sd)
|
1067
999
|
end
|
@@ -1071,13 +1003,12 @@ module Finrb
|
|
1071
1003
|
# @param cost cost of long-lived assets
|
1072
1004
|
# @param rv residual value of the long-lived assets at the end of its useful life
|
1073
1005
|
# @param t length of the useful life
|
1074
|
-
# @
|
1075
|
-
#
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
t = t.to_d
|
1006
|
+
# @example
|
1007
|
+
# Finrb::Utils.slde(cost=1200,rv=200,t=5)
|
1008
|
+
def self.slde(cost:, rv:, t:)
|
1009
|
+
cost = DecNum(cost.to_s)
|
1010
|
+
rv = DecNum(rv.to_s)
|
1011
|
+
t = DecNum(t.to_s)
|
1081
1012
|
|
1082
1013
|
((cost - rv) / t)
|
1083
1014
|
end
|
@@ -1086,12 +1017,11 @@ module Finrb
|
|
1086
1017
|
#
|
1087
1018
|
# @param td total debt
|
1088
1019
|
# @param te total equity
|
1089
|
-
# @
|
1090
|
-
#
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
te = te.to_d
|
1020
|
+
# @example
|
1021
|
+
# Finrb::Utils.total_d2e(td=6000,te=20000)
|
1022
|
+
def self.total_d2e(td:, te:)
|
1023
|
+
td = DecNum(td.to_s)
|
1024
|
+
te = DecNum(te.to_s)
|
1095
1025
|
|
1096
1026
|
(td / te)
|
1097
1027
|
end
|
@@ -1101,13 +1031,12 @@ module Finrb
|
|
1101
1031
|
# @param ev ordered ending value list
|
1102
1032
|
# @param bv ordered beginning value list
|
1103
1033
|
# @param cfr ordered cash flow received list
|
1104
|
-
# @
|
1105
|
-
#
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
cfr = Array.wrap(cfr).map(&:to_d)
|
1034
|
+
# @example
|
1035
|
+
# Finrb::Utils.twrr(ev=[120,260],bv=[100,240],cfr=[2,4])
|
1036
|
+
def self.twrr(ev:, bv:, cfr:)
|
1037
|
+
ev = Array.wrap(ev).map { |value| DecNum(value.to_s) }
|
1038
|
+
bv = Array.wrap(bv).map { |value| DecNum(value.to_s) }
|
1039
|
+
cfr = Array.wrap(cfr).map { |value| DecNum(value.to_s) }
|
1111
1040
|
|
1112
1041
|
r = ev.size
|
1113
1042
|
s = bv.size
|
@@ -1117,9 +1046,9 @@ module Finrb
|
|
1117
1046
|
raise(FinrbError, 'Different number of values!')
|
1118
1047
|
else
|
1119
1048
|
(0...r).each do |i|
|
1120
|
-
wr *= (hpr(ev[i], bv[i], cfr[i]) + 1)
|
1049
|
+
wr *= (Finrb::Utils.hpr(ev: ev[i], bv: bv[i], cfr: cfr[i]) + 1)
|
1121
1050
|
end
|
1122
|
-
((wr**(1 / r)) - 1)
|
1051
|
+
((wr**(1.to_f / r)) - 1)
|
1123
1052
|
end
|
1124
1053
|
end
|
1125
1054
|
|
@@ -1127,14 +1056,14 @@ module Finrb
|
|
1127
1056
|
#
|
1128
1057
|
# @param ns n x 1 vector vector of number of shares
|
1129
1058
|
# @param nm n x 1 vector vector of number of months relate to ns
|
1130
|
-
# @
|
1131
|
-
#
|
1132
|
-
# s=c(10000,2000);m=c(12,6);was(ns=s,nm=m)
|
1059
|
+
# @example
|
1060
|
+
# s=[10000,2000];m=[12,6];Finrb::Utils.was(ns=s,nm=m)
|
1133
1061
|
#
|
1134
|
-
#
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1062
|
+
# @example
|
1063
|
+
# s=[11000,4400,-3000];m=[12,9,4];Finrb::Utils.was(ns=s,nm=m)
|
1064
|
+
def self.was(ns:, nm:)
|
1065
|
+
ns = Array.wrap(ns).map { |value| DecNum(value.to_s) }
|
1066
|
+
nm = Array.wrap(nm).map { |value| DecNum(value.to_s) }
|
1138
1067
|
|
1139
1068
|
m = ns.size
|
1140
1069
|
n = nm.size
|
@@ -1154,16 +1083,14 @@ module Finrb
|
|
1154
1083
|
#
|
1155
1084
|
# @param r returns of the individual assets in the portfolio
|
1156
1085
|
# @param w corresponding weights associated with each of the individual assets
|
1157
|
-
# @
|
1158
|
-
#
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
w = Array.wrap(w).map(&:to_d)
|
1086
|
+
# @example
|
1087
|
+
# Finrb::Utils.wpr(r=[0.12, 0.07, 0.03],w=[0.5,0.4,0.1])
|
1088
|
+
def self.wpr(r:, w:)
|
1089
|
+
r = Array.wrap(r).map { |value| DecNum(value.to_s) }
|
1090
|
+
w = Array.wrap(w).map { |value| DecNum(value.to_s) }
|
1163
1091
|
|
1164
1092
|
if w.sum != 1
|
1165
1093
|
puts('sum of weights is NOT equal to 1!') # TODO: need to change
|
1166
|
-
else
|
1167
1094
|
end
|
1168
1095
|
r.zip(w).sum { |arr| arr.reduce(:*) }
|
1169
1096
|
end
|