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/rates.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative 'decimal'
|
4
4
|
|
5
5
|
module Finrb
|
6
6
|
# the Rate class provides an interface for working with interest rates.
|
@@ -8,6 +8,47 @@ module Finrb
|
|
8
8
|
# @api public
|
9
9
|
class Rate
|
10
10
|
include Comparable
|
11
|
+
# Accepted rate types
|
12
|
+
TYPES = { apr: 'effective', apy: 'effective', effective: 'effective', nominal: 'nominal' }.freeze
|
13
|
+
public_constant :TYPES
|
14
|
+
|
15
|
+
# convert a nominal interest rate to an effective interest rate
|
16
|
+
# @return [Flt::DecNum] the effective interest rate
|
17
|
+
# @param [Numeric] rate the nominal interest rate
|
18
|
+
# @param [Numeric] periods the number of compounding periods per year
|
19
|
+
# @example
|
20
|
+
# Rate.to_effective(0.05, 4) #=> Flt::DecNum('0.05095')
|
21
|
+
# @api public
|
22
|
+
def self.to_effective(rate, periods)
|
23
|
+
rate = Flt::DecNum.new(rate.to_s)
|
24
|
+
periods = Flt::DecNum.new(periods.to_s)
|
25
|
+
|
26
|
+
if periods.infinite?
|
27
|
+
rate.exp - 1
|
28
|
+
else
|
29
|
+
(((rate / periods) + 1)**periods) - 1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# convert an effective interest rate to a nominal interest rate
|
34
|
+
# @return [Flt::DecNum] the nominal interest rate
|
35
|
+
# @param [Numeric] rate the effective interest rate
|
36
|
+
# @param [Numeric] periods the number of compounding periods per year
|
37
|
+
# @example
|
38
|
+
# Rate.to_nominal(0.06, 365) #=> Flt::DecNum('0.05827')
|
39
|
+
# @see https://www.miniwebtool.com/nominal-interest-rate-calculator/
|
40
|
+
# @api public
|
41
|
+
def self.to_nominal(rate, periods)
|
42
|
+
rate = Flt::DecNum.new(rate.to_s)
|
43
|
+
periods = Flt::DecNum.new(periods.to_s)
|
44
|
+
|
45
|
+
if periods.infinite?
|
46
|
+
(rate + 1).log
|
47
|
+
else
|
48
|
+
periods * (((rate + 1)**(1.to_f / periods)) - 1)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
11
52
|
# create a new Rate instance
|
12
53
|
# @return [Rate]
|
13
54
|
# @param [Numeric] rate the decimal value of the interest rate
|
@@ -26,33 +67,30 @@ module Finrb
|
|
26
67
|
|
27
68
|
# Set optional attributes..
|
28
69
|
opts.each do |key, value|
|
29
|
-
|
70
|
+
__send__("#{key}=", value)
|
30
71
|
end
|
31
72
|
|
32
73
|
# Set the rate in the proper way, based on the value of type.
|
33
74
|
begin
|
34
|
-
|
75
|
+
__send__("#{TYPES.fetch(type)}=", Flt::DecNum.new(rate.to_s))
|
35
76
|
rescue KeyError
|
36
77
|
raise(ArgumentError, "type must be one of #{TYPES.keys.join(', ')}", caller)
|
37
78
|
end
|
38
79
|
end
|
39
80
|
|
40
|
-
# Accepted rate types
|
41
|
-
TYPES = { apr: "effective", apy: "effective", effective: "effective", nominal: "nominal" }.freeze
|
42
|
-
|
43
81
|
# @return [Integer] the duration for which the rate is valid, in months
|
44
82
|
# @api public
|
45
83
|
attr_accessor :duration
|
46
|
-
# @return [DecNum] the effective interest rate
|
84
|
+
# @return [Flt::DecNum] the effective interest rate
|
47
85
|
# @api public
|
48
86
|
attr_reader :effective
|
49
|
-
# @return [DecNum] the nominal interest rate
|
87
|
+
# @return [Flt::DecNum] the nominal interest rate
|
50
88
|
# @api public
|
51
89
|
attr_reader :nominal
|
52
90
|
|
53
91
|
# compare two Rates, using the effective rate
|
54
92
|
# @return [Numeric] one of -1, 0, +1
|
55
|
-
# @param [Rate]
|
93
|
+
# @param [Rate] other the comparison Rate
|
56
94
|
# @example Which is better, a nominal rate of 15% compounded monthly, or 15.5% compounded semiannually?
|
57
95
|
# r1 = Rate.new(0.15, :nominal) #=> Rate.new(0.160755, :apr)
|
58
96
|
# r2 = Rate.new(0.155, :nominal, :compounds => :semiannually) #=> Rate.new(0.161006, :apr)
|
@@ -95,7 +133,7 @@ module Finrb
|
|
95
133
|
|
96
134
|
# set the effective interest rate
|
97
135
|
# @return none
|
98
|
-
# @param [DecNum] rate the effective interest rate
|
136
|
+
# @param [Flt::DecNum] rate the effective interest rate
|
99
137
|
# @api private
|
100
138
|
def effective=(rate)
|
101
139
|
@effective = rate
|
@@ -106,11 +144,11 @@ module Finrb
|
|
106
144
|
"Rate.new(#{apr.round(6)}, :apr)"
|
107
145
|
end
|
108
146
|
|
109
|
-
# @return [DecNum] the monthly effective interest rate
|
147
|
+
# @return [Flt::DecNum] the monthly effective interest rate
|
110
148
|
# @example
|
111
149
|
# rate = Rate.new(0.15, :nominal)
|
112
|
-
# rate.apr.round(6) #=> DecNum('0.160755')
|
113
|
-
# rate.monthly.round(6) #=> DecNum('0.013396')
|
150
|
+
# rate.apr.round(6) #=> Flt::DecNum('0.160755')
|
151
|
+
# rate.monthly.round(6) #=> Flt::DecNum('0.013396')
|
114
152
|
# @api public
|
115
153
|
def monthly
|
116
154
|
(effective / 12).round(15)
|
@@ -118,50 +156,13 @@ module Finrb
|
|
118
156
|
|
119
157
|
# set the nominal interest rate
|
120
158
|
# @return none
|
121
|
-
# @param [DecNum] rate the nominal interest rate
|
159
|
+
# @param [Flt::DecNum] rate the nominal interest rate
|
122
160
|
# @api private
|
123
161
|
def nominal=(rate)
|
124
162
|
@nominal = rate
|
125
163
|
@effective = Rate.to_effective(rate, @periods)
|
126
164
|
end
|
127
165
|
|
128
|
-
# convert a nominal interest rate to an effective interest rate
|
129
|
-
# @return [DecNum] the effective interest rate
|
130
|
-
# @param [Numeric] rate the nominal interest rate
|
131
|
-
# @param [Numeric] periods the number of compounding periods per year
|
132
|
-
# @example
|
133
|
-
# Rate.to_effective(0.05, 4) #=> DecNum('0.05095')
|
134
|
-
# @api public
|
135
|
-
def self.to_effective(rate, periods)
|
136
|
-
rate = Flt::DecNum.new(rate.to_s)
|
137
|
-
periods = Flt::DecNum.new(periods.to_s)
|
138
|
-
|
139
|
-
if periods.infinite?
|
140
|
-
rate.exp - 1
|
141
|
-
else
|
142
|
-
((1 + (rate / periods))**periods) - 1
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
# convert an effective interest rate to a nominal interest rate
|
147
|
-
# @return [DecNum] the nominal interest rate
|
148
|
-
# @param [Numeric] rate the effective interest rate
|
149
|
-
# @param [Numeric] periods the number of compounding periods per year
|
150
|
-
# @example
|
151
|
-
# Rate.to_nominal(0.06, 365) #=> DecNum('0.05827')
|
152
|
-
# @see https://www.miniwebtool.com/nominal-interest-rate-calculator/
|
153
|
-
# @api public
|
154
|
-
def self.to_nominal(rate, periods)
|
155
|
-
rate = Flt::DecNum.new(rate.to_s)
|
156
|
-
periods = Flt::DecNum.new(periods.to_s)
|
157
|
-
|
158
|
-
if periods.infinite?
|
159
|
-
(rate + 1).log
|
160
|
-
else
|
161
|
-
periods * (((1 + rate)**(1 / periods)) - 1)
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
166
|
private :compounds=, :effective=, :nominal=
|
166
167
|
end
|
167
168
|
end
|
data/lib/finrb/transaction.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative 'decimal'
|
4
4
|
|
5
5
|
module Finrb
|
6
6
|
# the Transaction class provides a general interface for working with individual cash flows.
|
7
7
|
# @api public
|
8
8
|
class Transaction
|
9
|
-
# @return [DecNum] the cash value of the transaction
|
9
|
+
# @return [Flt::DecNum] the cash value of the transaction
|
10
10
|
# @api public
|
11
11
|
attr_reader :amount
|
12
12
|
# @return [Integer] the period number of the transaction
|
@@ -33,7 +33,7 @@ module Finrb
|
|
33
33
|
|
34
34
|
# Set optional attributes..
|
35
35
|
opts.each do |key, value|
|
36
|
-
|
36
|
+
__send__("#{key}=", value)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -49,12 +49,12 @@ module Finrb
|
|
49
49
|
@amount = Flt::DecNum.new(value.to_s) || 0
|
50
50
|
end
|
51
51
|
|
52
|
-
# @return [DecNum] the difference between the original transaction
|
52
|
+
# @return [Flt::DecNum] the difference between the original transaction
|
53
53
|
# amount and the current amount
|
54
54
|
# @example
|
55
55
|
# t = Transaction.new(500)
|
56
56
|
# t.amount = 750
|
57
|
-
# t.difference #=> DecNum('250')
|
57
|
+
# t.difference #=> Flt::DecNum('250')
|
58
58
|
# @api public
|
59
59
|
def difference
|
60
60
|
@amount - @original
|