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