finrb 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|