finrb 0.1.12 → 1.0.0

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.
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'decimal'
3
+ require_relative 'validation'
4
4
 
5
5
  module Finrb
6
6
  # the Transaction class provides a general interface for working with individual cash flows.
@@ -12,10 +12,10 @@ module Finrb
12
12
  # @return [Integer] the period number of the transaction
13
13
  # @note this attribute is mainly used in the case of mortgage amortization with no dates
14
14
  # @api public
15
- attr_accessor :period
15
+ attr_reader :period
16
16
  # @return [Date] the date of the transaction
17
17
  # @api public
18
- attr_accessor :date
18
+ attr_reader :date
19
19
 
20
20
  # create a new Transaction
21
21
  # @return [Transaction]
@@ -28,8 +28,11 @@ module Finrb
28
28
  # t = Transaction.new(400, :period => 3)
29
29
  # @api public
30
30
  def initialize(amount, opts = {})
31
- @amount = amount
32
- @original = amount
31
+ raise(ArgumentError, 'options must be a Hash.') unless opts.is_a?(Hash)
32
+ raise(ArgumentError, 'options may only contain date and period.') unless (opts.keys - %i[date period]).empty?
33
+
34
+ self.amount = amount
35
+ @original = @amount
33
36
 
34
37
  # Set optional attributes..
35
38
  opts.each do |key, value|
@@ -46,7 +49,20 @@ module Finrb
46
49
  # t.amount #=> 750
47
50
  # @api public
48
51
  def amount=(value)
49
- @amount = Flt::DecNum.new(value.to_s) || 0
52
+ @amount = Validation.decimal(value, name: 'amount')
53
+ end
54
+
55
+ def date=(value)
56
+ raise(ArgumentError, 'date must respond to to_date.') unless value.nil? || value.respond_to?(:to_date)
57
+
58
+ @date = value
59
+ end
60
+
61
+ def period=(value)
62
+ valid = value.nil? || (value.is_a?(Integer) && !value.negative?)
63
+ raise(ArgumentError, 'period must be a non-negative integer.') unless valid
64
+
65
+ @period = value
50
66
  end
51
67
 
52
68
  # @return [Flt::DecNum] the difference between the original transaction
@@ -85,7 +101,7 @@ module Finrb
85
101
  # pmt.amount #=> -600
86
102
  # @api public
87
103
  def modify
88
- @amount = yield(self)
104
+ self.amount = yield(self)
89
105
  end
90
106
 
91
107
  # (see #amount)
data/lib/finrb/tvm.rb ADDED
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'config'
4
+ require_relative 'decimal'
5
+ require_relative 'errors'
6
+ require_relative 'numerical/brent'
7
+
8
+ module Finrb
9
+ # Time-value-of-money calculations for periodic rates and cashflows.
10
+ module TVM
11
+ module_function
12
+
13
+ def discount_rate(n:, pv:, fv:, pmt:, type: 0, lower: 0.0001, upper: 100)
14
+ n, pv, fv, pmt, type, lower, upper = decimals(n, pv, fv, pmt, type, lower, upper)
15
+ function = ->(rate) { fv_simple(r: rate, n:, pv:) + fv_annuity(r: rate, n:, pmt:, type:) - fv }
16
+
17
+ Numerical::Brent.new(tolerance: Finrb.config.eps).solve(function, lower:, upper:)
18
+ end
19
+
20
+ def fv(r:, n:, pv: 0, pmt: 0, type: 0)
21
+ r, n, pv, pmt, type = decimals(r, n, pv, pmt, type)
22
+ validate_payment_type!(type)
23
+
24
+ fv_simple(r:, n:, pv:) + fv_annuity(r:, n:, pmt:, type:)
25
+ end
26
+
27
+ def fv_annuity(r:, n:, pmt:, type: 0)
28
+ r, n, pmt, type = decimals(r, n, pmt, type)
29
+ validate_payment_type!(type)
30
+
31
+ (pmt / r * (((r + 1)**n) - 1)) * ((r + 1)**type) * -1
32
+ end
33
+
34
+ def fv_simple(r:, n:, pv:)
35
+ r, n, pv = decimals(r, n, pv)
36
+ (pv * ((r + 1)**n)) * -1
37
+ end
38
+
39
+ def fv_uneven(r:, cf:)
40
+ r = Flt::DecNum(r.to_s)
41
+ cashflows = array(cf).map { |value| Flt::DecNum(value.to_s) }
42
+
43
+ cashflows.each_with_index.sum do |cashflow, index|
44
+ fv_simple(r:, n: cashflows.size - index - 1, pv: cashflow)
45
+ end
46
+ end
47
+
48
+ def n_period(r:, pv:, fv:, pmt:, type: 0)
49
+ r, pv, fv, pmt, type = decimals(r, pv, fv, pmt, type)
50
+ validate_payment_type!(type)
51
+
52
+ numerator = ((fv * r) - (pmt * ((r + 1)**type))) * -1
53
+ denominator = (pv * r) + (pmt * ((r + 1)**type))
54
+ (numerator / denominator).log / (r + 1).log
55
+ end
56
+
57
+ def npv(r:, cf:)
58
+ cashflows = array(cf).map { |value| Flt::DecNum(value.to_s) }
59
+ (pv_uneven(r:, cf: cashflows.drop(1)) * -1) + cashflows.first
60
+ end
61
+
62
+ def pmt(r:, n:, pv:, fv:, type: 0)
63
+ r, n, pv, fv, type = decimals(r, n, pv, fv, type)
64
+ validate_payment_type!(type)
65
+
66
+ (pv + (fv / ((r + 1)**n))) * r / (1 - (Flt::DecNum(1) / ((r + 1)**n))) * -1 * ((r + 1)**(type * -1))
67
+ end
68
+
69
+ def pv(r:, n:, fv: 0, pmt: 0, type: 0)
70
+ r, n, fv, pmt, type = decimals(r, n, fv, pmt, type)
71
+ validate_payment_type!(type)
72
+
73
+ pv_simple(r:, n:, fv:) + pv_annuity(r:, n:, pmt:, type:)
74
+ end
75
+
76
+ def pv_annuity(r:, n:, pmt:, type: 0)
77
+ r, n, pmt, type = decimals(r, n, pmt, type)
78
+ validate_payment_type!(type)
79
+
80
+ (pmt / r * (1 - (Flt::DecNum(1) / ((r + 1)**n)))) * ((r + 1)**type) * -1
81
+ end
82
+
83
+ def pv_perpetuity(r:, pmt:, g: 0, type: 0)
84
+ r, pmt, g, type = decimals(r, pmt, g, type)
85
+ validate_payment_type!(type)
86
+ raise(Error, 'Error: g is not smaller than r!') if g >= r
87
+
88
+ (pmt / (r - g)) * ((r + 1)**type) * -1
89
+ end
90
+
91
+ def pv_simple(r:, n:, fv:)
92
+ r, n, fv = decimals(r, n, fv)
93
+ (fv / ((r + 1)**n)) * -1
94
+ end
95
+
96
+ def pv_uneven(r:, cf:)
97
+ r = Flt::DecNum(r.to_s)
98
+ array(cf).each_with_index.sum do |cashflow, index|
99
+ pv_simple(r:, n: index + 1, fv: cashflow)
100
+ end
101
+ end
102
+
103
+ def r_perpetuity(pmt:, pv:)
104
+ pmt, pv = decimals(pmt, pv)
105
+ pmt * -1 / pv
106
+ end
107
+
108
+ def array(value)
109
+ return [] if value.nil?
110
+ return value.to_ary || [value] if value.respond_to?(:to_ary)
111
+
112
+ [value]
113
+ end
114
+ private_class_method :array
115
+
116
+ def decimals(*values)
117
+ values.map { |value| Flt::DecNum(value.to_s) }
118
+ end
119
+ private_class_method :decimals
120
+
121
+ def validate_payment_type!(type)
122
+ raise(Error, 'Error: type should be 0 or 1!') unless [Flt::DecNum(0), Flt::DecNum(1)].include?(type)
123
+ end
124
+ private_class_method :validate_payment_type!
125
+ end
126
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'decimal'
4
+
5
+ module Finrb
6
+ # Shared validation and decimal coercion for public financial inputs.
7
+ module Validation
8
+ module_function
9
+
10
+ def decimal(value, name:)
11
+ raise(ArgumentError, "#{name} must be numeric.") unless value.is_a?(Numeric)
12
+
13
+ decimal = value.is_a?(Flt::DecNum) ? value : Flt::DecNum.new(value.to_s)
14
+ raise(ArgumentError, "#{name} must be finite.") unless decimal.finite?
15
+
16
+ decimal
17
+ rescue Flt::Num::Exception, FloatDomainError, Math::DomainError => e
18
+ raise(ArgumentError, "#{name} must be a finite numeric value.", e.backtrace)
19
+ end
20
+
21
+ def positive_integer(value, name:)
22
+ raise(ArgumentError, "#{name} must be a positive integer.") unless value.is_a?(Integer) && value.positive?
23
+
24
+ value
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Finrb
4
+ VERSION = '1.0.0'
5
+ public_constant :VERSION
6
+ end
@@ -0,0 +1,224 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'decimal'
4
+ require_relative 'errors'
5
+
6
+ module Finrb
7
+ # Money-market yield and interest-rate conversion calculations.
8
+ module Yields
9
+ # Computing bank discount yield (BDY) for a T-bill
10
+ #
11
+ # @param d the dollar discount, which is equal to the difference between the face value of the bill and the purchase price
12
+ # @param f the face value (par value) of the bill
13
+ # @param t number of days remaining until maturity
14
+ # @example
15
+ # Finrb::Yields.bdy(d=1500,f=100000,t=120)
16
+ def self.bdy(d:, f:, t:)
17
+ d = Flt::DecNum(d.to_s)
18
+ f = Flt::DecNum(f.to_s)
19
+ t = Flt::DecNum(t.to_s)
20
+
21
+ (d * 360 / f / t)
22
+ end
23
+
24
+ # Computing money market yield (MMY) for a T-bill
25
+ #
26
+ # @param bdy bank discount yield
27
+ # @param t number of days remaining until maturity
28
+ # @example
29
+ # Finrb::Yields.bdy2mmy(bdy=0.045,t=120)
30
+ def self.bdy2mmy(bdy:, t:)
31
+ bdy = Flt::DecNum(bdy.to_s)
32
+ t = Flt::DecNum(t.to_s)
33
+
34
+ (bdy * 360 / (360 - (t * bdy)))
35
+ end
36
+
37
+ # Convert stated annual rate to the effective annual rate
38
+ #
39
+ # @param r stated annual rate
40
+ # @param m number of compounding periods per year
41
+ # @example
42
+ # Finrb::Yields.ear(r=0.12,m=12)
43
+ #
44
+ # @example
45
+ # Finrb::Yields.ear(0.04,365)
46
+ def self.ear(r:, m:)
47
+ r = Flt::DecNum(r.to_s)
48
+ m = Flt::DecNum(m.to_s)
49
+
50
+ ((((r / m) + 1)**m) - 1)
51
+ end
52
+
53
+ # Convert stated annual rate to the effective annual rate with continuous compounding
54
+ #
55
+ # @param r stated annual rate
56
+ # @example
57
+ # Finrb::Yields.ear_continuous(r=0.1)
58
+ #
59
+ # @example
60
+ # Finrb::Yields.ear_continuous(0.03)
61
+ def self.ear_continuous(r:)
62
+ r = Flt::DecNum(r.to_s)
63
+
64
+ (r.exp - 1)
65
+ end
66
+
67
+ # bond-equivalent yield (BEY), 2 x the semiannual discount rate
68
+ #
69
+ # @param ear effective annual rate
70
+ # @example
71
+ # Finrb::Yields.ear2bey(ear=0.08)
72
+ def self.ear2bey(ear:)
73
+ ear = Flt::DecNum(ear.to_s)
74
+
75
+ (((ear + 1).sqrt - 1) * 2)
76
+ end
77
+
78
+ # Computing HPR, the holding period return
79
+ #
80
+ # @param ear effective annual rate
81
+ # @param t number of days remaining until maturity
82
+ # @example
83
+ # Finrb::Yields.ear2hpr(ear=0.05039,t=150)
84
+ def self.ear2hpr(ear:, t:)
85
+ ear = Flt::DecNum(ear.to_s)
86
+ t = Flt::DecNum(t.to_s)
87
+
88
+ (((ear + 1)**(t / 365)) - 1)
89
+ end
90
+
91
+ # Equivalent/proportional Interest Rates
92
+ # @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.
93
+ # @param r interest rate to be applied n times per year (r is annual rate!)
94
+ # @param n times that the interest rate r were compounded per year
95
+ # @param p times that the equivalent rate were compounded per year
96
+ # @param type equivalent interest rates ('e',default) or proportional interest rates ('p')
97
+ # @example
98
+ # # monthly interest rat equivalent to 5% compounded per year
99
+ # Finrb::Yields.eir(r=0.05,n=1,p=12)
100
+ #
101
+ # @example
102
+ # # monthly interest rat equivalent to 5% compounded per half year
103
+ # Finrb::Yields.eir(r=0.05,n=2,p=12)
104
+ #
105
+ # @example
106
+ # # monthly interest rat equivalent to 5% compounded per quarter
107
+ # Finrb::Yields.eir(r=0.05,n=4,p=12)
108
+ #
109
+ # @example
110
+ # # annual interest rate equivalent to 5% compounded per month
111
+ # Finrb::Yields.eir(r=0.05,n=12,p=1)
112
+ # # this is equivalent to
113
+ # Finrb::Yields.ear(r=0.05,m=12)
114
+ #
115
+ # @example
116
+ # # quarter interest rate equivalent to 5% compounded per year
117
+ # Finrb::Yields.eir(r=0.05,n=1,p=4)
118
+ #
119
+ # @example
120
+ # # quarter interest rate equivalent to 5% compounded per month
121
+ # Finrb::Yields.eir(r=0.05,n=12,p=4)
122
+ #
123
+ # @example
124
+ # # monthly proportional interest rate which is equivalent to a simple annual interest
125
+ # Finrb::Yields.eir(r=0.05,p=12,type='p')
126
+ def self.eir(r:, n: 1, p: 12, type: 'e')
127
+ r = Flt::DecNum(r.to_s)
128
+ n = Flt::DecNum(n.to_s)
129
+ p = Flt::DecNum(p.to_s)
130
+ type = type.to_s
131
+
132
+ case type
133
+ when 'e'
134
+ eir = (((r / n) + 1)**(n / p)) - 1
135
+ when 'p'
136
+ eir = r / p
137
+ else
138
+ raise(Error, "type must be 'e' or 'p'")
139
+ end
140
+ eir
141
+ end
142
+
143
+ # bond-equivalent yield (BEY), 2 x the semiannual discount rate
144
+ #
145
+ # @param hpr holding period return
146
+ # @param t number of month remaining until maturity
147
+ # @example
148
+ # Finrb::Yields.hpr2bey(hpr=0.02,t=3)
149
+ def self.hpr2bey(hpr:, t:)
150
+ hpr = Flt::DecNum(hpr.to_s)
151
+ t = Flt::DecNum(t.to_s)
152
+
153
+ ((((hpr + 1)**(6 / t)) - 1) * 2)
154
+ end
155
+
156
+ # Convert holding period return to the effective annual rate
157
+ #
158
+ # @param hpr holding period return
159
+ # @param t number of days remaining until maturity
160
+ # @example
161
+ # Finrb::Yields.hpr2ear(hpr=0.015228,t=120)
162
+ def self.hpr2ear(hpr:, t:)
163
+ hpr = Flt::DecNum(hpr.to_s)
164
+ t = Flt::DecNum(t.to_s)
165
+
166
+ (((hpr + 1)**(365 / t)) - 1)
167
+ end
168
+
169
+ # Computing money market yield (MMY) for a T-bill
170
+ #
171
+ # @param hpr holding period return
172
+ # @param t number of days remaining until maturity
173
+ # @example
174
+ # Finrb::Yields.hpr2mmy(hpr=0.01523,t=120)
175
+ def self.hpr2mmy(hpr:, t:)
176
+ hpr = Flt::DecNum(hpr.to_s)
177
+ t = Flt::DecNum(t.to_s)
178
+
179
+ (hpr * 360 / t)
180
+ end
181
+
182
+ # Computing HPR, the holding period return
183
+ #
184
+ # @param mmy money market yield
185
+ # @param t number of days remaining until maturity
186
+ # @example
187
+ # Finrb::Yields.mmy2hpr(mmy=0.04898,t=150)
188
+ def self.mmy2hpr(mmy:, t:)
189
+ mmy = Flt::DecNum(mmy.to_s)
190
+ t = Flt::DecNum(t.to_s)
191
+
192
+ (mmy * t / 360)
193
+ end
194
+
195
+ # Convert a given norminal rate to a continuous compounded rate
196
+ #
197
+ # @param r norminal rate
198
+ # @param m number of times compounded each year
199
+ # @example
200
+ # Finrb::Yields.r_continuous(r=0.03,m=4)
201
+ def self.r_continuous(r:, m:)
202
+ r = Flt::DecNum(r.to_s)
203
+ m = Flt::DecNum(m.to_s)
204
+
205
+ (m * ((r / m) + 1).log)
206
+ end
207
+
208
+ # Convert a given continuous compounded rate to a norminal rate
209
+ #
210
+ # @param rc continuous compounded rate
211
+ # @param m number of desired times compounded each year
212
+ # @example
213
+ # Finrb::Yields.r_norminal(0.03,1)
214
+ #
215
+ # @example
216
+ # Finrb::Yields.r_norminal(rc=0.03,m=4)
217
+ def self.r_norminal(rc:, m:)
218
+ rc = Flt::DecNum(rc.to_s)
219
+ m = Flt::DecNum(m.to_s)
220
+
221
+ (m * ((rc / m).exp - 1))
222
+ end
223
+ end
224
+ end
data/lib/finrb.rb CHANGED
@@ -1,12 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support'
3
+ require 'finrb/accounting'
4
4
  require 'finrb/cashflows'
5
5
  require 'finrb/config'
6
6
  require 'finrb/decimal'
7
- require 'finrb/utils'
7
+ require 'finrb/errors'
8
+ require 'finrb/precision'
9
+ require 'finrb/ratios'
10
+ require 'finrb/returns'
11
+ require 'finrb/tvm'
12
+ require 'finrb/version'
13
+ require 'finrb/yields'
8
14
 
9
- class FinrbError < StandardError; end
15
+ FinrbError = Finrb::Error
10
16
 
11
17
  # The *Finrb* module adheres to the following conventions for
12
18
  # financial calculations:
@@ -19,5 +25,4 @@ module Finrb
19
25
  autoload :Amortization, 'finrb/amortization'
20
26
  autoload :Rate, 'finrb/rates'
21
27
  autoload :Transaction, 'finrb/transaction'
22
- autoload :Utils, 'finrb/utils'
23
28
  end
data/sig/finrb.rbs ADDED
@@ -0,0 +1,204 @@
1
+ module Flt
2
+ class DecNum < Numeric
3
+ end
4
+ end
5
+
6
+ module Finrb
7
+ VERSION: String
8
+
9
+ type number = Numeric
10
+ type decimal = Flt::DecNum
11
+ type numbers = Array[number] | Enumerable[number]
12
+
13
+ interface _Configuration
14
+ def eps: () -> decimal
15
+ def guess: () -> decimal
16
+ def business_days: () -> bool
17
+ def periodic_compound: () -> bool
18
+ def to_h: () -> Hash[Symbol, untyped]
19
+ end
20
+
21
+ interface _ConfigurationBuilder
22
+ def eps: () -> untyped
23
+ def eps=: (untyped) -> untyped
24
+ def guess: () -> untyped
25
+ def guess=: (untyped) -> untyped
26
+ def business_days: () -> untyped
27
+ def business_days=: (untyped) -> untyped
28
+ def periodic_compound: () -> untyped
29
+ def periodic_compound=: (untyped) -> untyped
30
+ end
31
+
32
+ def self.config: () -> _Configuration
33
+ def self.configure: () { (_ConfigurationBuilder) -> void } -> _Configuration
34
+ def self.with_config: [A] (**untyped) { () -> A } -> A
35
+
36
+ class Error < StandardError
37
+ end
38
+
39
+ class ConvergenceError < Error
40
+ end
41
+
42
+ class DomainError < Error
43
+ end
44
+
45
+ class InvalidCashflowError < Error
46
+ end
47
+
48
+ module Precision
49
+ def self.money: (number) -> decimal
50
+ def self.rate: (number) -> decimal
51
+ def self.round: (number, places: Integer) -> decimal
52
+ end
53
+
54
+ class Rate
55
+ include Comparable
56
+
57
+ TYPES: Hash[Symbol, String]
58
+
59
+ def self.to_effective: (number, number) -> decimal
60
+ def self.to_nominal: (number, number) -> decimal
61
+
62
+ def initialize: (number, Symbol, ?Hash[Symbol, untyped]) -> void
63
+ def duration: () -> Integer?
64
+ def effective: () -> decimal
65
+ def nominal: () -> decimal
66
+ def <=>: (Rate) -> Integer?
67
+ def apr: () -> decimal
68
+ def apy: () -> decimal
69
+ def duration=: (Integer) -> Integer
70
+ def inspect: () -> String
71
+ def monthly: () -> decimal
72
+ end
73
+
74
+ class Transaction
75
+ def initialize: (number, ?Hash[Symbol, untyped]) -> void
76
+ def amount: () -> decimal
77
+ def amount=: (number) -> number
78
+ def period: () -> Integer?
79
+ def period=: (Integer?) -> Integer?
80
+ def date: () -> untyped
81
+ def date=: (untyped) -> untyped
82
+ def difference: () -> decimal
83
+ def interest?: () -> bool
84
+ def inspect: () -> String
85
+ def modify: () { (Transaction) -> number } -> number
86
+ def payment: () -> decimal
87
+ def payment?: () -> bool
88
+ end
89
+
90
+ class Interest < Transaction
91
+ end
92
+
93
+ class Payment < Transaction
94
+ end
95
+
96
+ class Amortization
97
+ def self.payment: (number, number, Integer) -> decimal
98
+
99
+ def initialize: (number, *Rate) ?{ (Transaction) -> number } -> void
100
+ def ==: (untyped) -> bool
101
+ def balance: () -> decimal
102
+ def payment: () -> decimal?
103
+ def principal: () -> decimal
104
+ def rates: () -> Array[Rate]
105
+ def additional_payments: () -> Array[decimal]
106
+ def duration: () -> Integer
107
+ def inspect: () -> String
108
+ def interest: () -> Array[decimal]
109
+ def payments: () -> Array[decimal]
110
+ end
111
+
112
+ module Cashflow
113
+ def self.irr: (Enumerable[number], ?number) -> decimal
114
+ def self.npv: (Enumerable[number], number) -> decimal
115
+ def self.xirr: (Enumerable[Transaction], ?number) -> Rate
116
+ def self.xnpv: (Enumerable[Transaction], number) -> decimal
117
+
118
+ def irr: (?number) -> decimal
119
+ def npv: (number) -> decimal
120
+ def xirr: (?number) -> Rate
121
+ def xnpv: (number) -> decimal
122
+ end
123
+
124
+ module TVM
125
+ def self.discount_rate: (n: number, pv: number, fv: number, pmt: number, ?type: Integer, ?lower: number, ?upper: number) -> decimal
126
+ def self.fv: (r: number, n: number, ?pv: number, ?pmt: number, ?type: Integer) -> decimal
127
+ def self.fv_annuity: (r: number, n: number, pmt: number, ?type: Integer) -> decimal
128
+ def self.fv_simple: (r: number, n: number, pv: number) -> decimal
129
+ def self.fv_uneven: (r: number, cf: number | numbers) -> decimal
130
+ def self.n_period: (r: number, pv: number, fv: number, pmt: number, ?type: Integer) -> decimal
131
+ def self.npv: (r: number, cf: number | numbers) -> decimal
132
+ def self.pmt: (r: number, n: number, pv: number, fv: number, ?type: Integer) -> decimal
133
+ def self.pv: (r: number, n: number, ?fv: number, ?pmt: number, ?type: Integer) -> decimal
134
+ def self.pv_annuity: (r: number, n: number, pmt: number, ?type: Integer) -> decimal
135
+ def self.pv_perpetuity: (r: number, pmt: number, ?g: number, ?type: Integer) -> decimal
136
+ def self.pv_simple: (r: number, n: number, fv: number) -> decimal
137
+ def self.pv_uneven: (r: number, cf: number | numbers) -> decimal
138
+ def self.r_perpetuity: (pmt: number, pv: number) -> decimal
139
+ end
140
+
141
+ module Accounting
142
+ type inventory_result = { cost_of_goods: decimal, ending_inventory: decimal }
143
+
144
+ def self.cogs: (uinv: number, pinv: number, units: number | numbers, price: number | numbers, sinv: number, ?method: String) -> inventory_result
145
+ def self.ddb: (cost: number, rv: number, t: Integer) -> { t: Array[Integer], ddb: Array[decimal] }
146
+ def self.slde: (cost: number, rv: number, t: number) -> decimal
147
+ end
148
+
149
+ module Ratios
150
+ def self.cash_ratio: (cash: number, ms: number, cl: number) -> decimal
151
+ def self.current_ratio: (ca: number, cl: number) -> decimal
152
+ def self.debt_ratio: (td: number, ta: number) -> decimal
153
+ def self.diluted_eps: (ni: number, pd: number, w: number, ?cpd: number, ?cdi: number, ?tax: number, ?cps: number, ?cds: number, ?iss: number) -> decimal
154
+ def self.eps: (ni: number, pd: number, w: number) -> decimal
155
+ def self.financial_leverage: (te: number, ta: number) -> decimal
156
+ def self.gpm: (gp: number, rv: number) -> decimal
157
+ def self.iss: (amp: number, ep: number, n: number) -> decimal
158
+ def self.lt_d2e: (ltd: number, te: number) -> decimal
159
+ def self.npm: (ni: number, rv: number) -> decimal
160
+ def self.quick_ratio: (cash: number, ms: number, rc: number, cl: number) -> decimal
161
+ def self.total_d2e: (td: number, te: number) -> decimal
162
+ def self.was: (ns: number | numbers | nil, nm: number | numbers | nil) -> (decimal | Integer)
163
+ end
164
+
165
+ module Returns
166
+ def self.coefficient_variation: (sd: number, avg: number) -> decimal
167
+ def self.geometric_mean: (r: number | numbers) -> decimal
168
+ def self.harmonic_mean: (p: number | numbers) -> decimal
169
+ def self.hpr: (ev: number, bv: number, ?cfr: number) -> decimal
170
+ def self.sampling_error: (sm: number, mu: number) -> decimal
171
+ def self.sf_ratio: (rp: number, rl: number, sd: number) -> decimal
172
+ def self.sharpe_ratio: (rp: number, rf: number, sd: number) -> decimal
173
+ def self.twrr: (ev: number | numbers, bv: number | numbers, cfr: number | numbers) -> decimal
174
+ def self.wpr: (r: number | numbers, w: number | numbers) -> decimal
175
+ end
176
+
177
+ module Yields
178
+ def self.bdy: (d: number, f: number, t: number) -> decimal
179
+ def self.bdy2mmy: (bdy: number, t: number) -> decimal
180
+ def self.ear: (r: number, m: number) -> decimal
181
+ def self.ear_continuous: (r: number) -> decimal
182
+ def self.ear2bey: (ear: number) -> decimal
183
+ def self.ear2hpr: (ear: number, t: number) -> decimal
184
+ def self.eir: (r: number, ?n: number, ?p: number, ?type: String) -> decimal
185
+ def self.hpr2bey: (hpr: number, t: number) -> decimal
186
+ def self.hpr2ear: (hpr: number, t: number) -> decimal
187
+ def self.hpr2mmy: (hpr: number, t: number) -> decimal
188
+ def self.mmy2hpr: (mmy: number, t: number) -> decimal
189
+ def self.r_continuous: (r: number, m: number) -> decimal
190
+ def self.r_norminal: (rc: number, m: number) -> decimal
191
+ end
192
+
193
+ module Numerical
194
+ class Brent
195
+ def initialize: (tolerance: number, ?relative_tolerance: number, ?max_iterations: Integer) -> void
196
+ def solve: (^(decimal) -> number, lower: number, upper: number) -> decimal
197
+ end
198
+
199
+ class RateSearch
200
+ def initialize: (?step: number, ?max_steps: Integer) -> void
201
+ def bracket: (^(decimal) -> number, guess: number) -> [decimal, decimal]
202
+ end
203
+ end
204
+ end